manual micros 2010

287
Microcontroladores Instituto Tecnológico Superior de Teziutlán Academia de Ingeniería Mecatrónica Cuerpo Académico Calidad y Mejora Continua en Servicios Tecnológicos Recopilador M.S.C. Miguel Montiel Martínez

Upload: manuel-villega-acosta

Post on 22-Jan-2016

89 views

Category:

Documents


3 download

DESCRIPTION

Aprender a progrmar microcontroladores

TRANSCRIPT

Page 1: Manual Micros 2010

MicrocontroladoresInstituto Tecnológico Superior de Teziutlán

Academia de Ingeniería MecatrónicaCuerpo Académico Calidad y Mejora Continua en Servicios Tecnológicos

RecopiladorM.S.C. Miguel Montiel Martínez

Page 2: Manual Micros 2010

PRESENTACIÓN

En esta recopilación se presentan las características, programación e interfaces generales de los microcontroladores ATMega32U4, siendo este dispositivo elegido por contar con una razonable cantidad de memoria FLASH (32KB), RAM (2KB) y EEPROM (1KB), un módulo USB que le permite comunicarse con un equipo de cómputo por medio del protocolo USB-CDC y sobre todo, de tener un bootloader de fábrica el cual permite su programación desde un entorno propietario, así como desde un entorno abierto.

Este microcontrolador permite muy bien su interacción con el compilador libre AVR-GCC y/o WIN-AVR, esto dependerá del gusto personal de la persona que interactué y siga las prácticas sugeridas en este repositorio.

Es importante agregar que este dispositivo fue elegido entre otras cosas por la facilidad e interaccionar con la Herramienta XFuzzy 3.1 de la Universidad de .... con la cual se puede generar de una manera muy sencilla las librerias necesarias en AVR-GCC para desarrollar un sistema difuso de pequeña a mediana complejidad, de igual forma, con miras a interactuar con otras materias tales como Control, Control Digital y Programación Avanzada de la Retícula de formación para un Ingeniero en Mecatrónica, donde se solicita al estudiante como competencia previa el conocimiento de microcontroladores, sus interfaces de potencia y comunicación para lograr el diseño de sistemas de control ya sean monitoreados o controlados digitalmente.

El microcontrolador ATMega32U4 cuenta además con la capacidad de ser programado como un dispositivo “Teensyduino”, de esta forma se acerca al estudiante a material que se encuentra en gran abundancia en el entorno digital que ahora nos vemos inmersos.

Se deja al lector el irse profundizando en la lectura de los contenidos propuestos y en caso de encontrar errores en la redacción y/o en la captura, por favor hacérmelos saber.

Finalmente no me queda mas que agradecer la lectura de estos textos que han sido recopilados o elaborados por mi persona.

Atentamente

Miguel Montiel Martínez

Recopilador

Page 3: Manual Micros 2010

Índice de contenidoUnidad 1 Conceptos introductorios a los microcontroladores...................................................................6

1.1 Diferencia entre microcontrolador, microcomputadora y microprocesador...................................7

1.2 Características y aplicaciones de los microcontroladores...............................................................9

1.3 Tipos de arquitecturas computacionales........................................................................................13

1.3.1 La arquitectura de un microcontrolador................................................................................13

1.4 Tipos de Microcontroladores y sus fabricantes.............................................................................16

Unidad 2 Arquitectura interna de un microcontrolador...........................................................................19

2.1 Componentes del Microcontrolador..............................................................................................20

2.2 Registro internos............................................................................................................................20

2.3 Tipos y distribución de las memorias internas..............................................................................21

2.4 Periféricos......................................................................................................................................22

2.5 Las instrucciones del microcontrolador.........................................................................................23

Unidad 3 Características Eléctricas del Microcontrolador.......................................................................25

3.1 Distribución de terminales.............................................................................................................26

3.2 Características del reloj del sistema..............................................................................................33

3.3 El Reset y sus posibles fuentes......................................................................................................40

3.4 Características de la fuente de alimentación y consumo de potencia del MCU............................41

3.4.1 Modo Idle..............................................................................................................................41

3.4.2 Modo Reducción de ruido en ADC.......................................................................................41

3.4.3 Modo Power-down................................................................................................................41

3.4.4 Modo Power-save..................................................................................................................41

3.4.5 Modo Standby........................................................................................................................42

3.4.6 Velocidad máxima vs velocidad............................................................................................42

Unidad 4 Herramientas de desarrollo de los microcontroladores............................................................44

4.1 Ambiente Integrado de desarrollo (IDE) para microcontroladores...............................................45

4.1.1 Ensamblador y Compilador...................................................................................................46

4.1.2 Simulador, debugger y emulador...........................................................................................51

4.1.3 Equipos programadores (downloaders) de microcontroladores............................................53

4.2 Ejemplos de uso de herramientas de desarrollo............................................................................59

Unidad 5 Puertos de entrada y salida.......................................................................................................62

5.1 Arquitectura de los E/S..................................................................................................................63

5.2 Configuración y características eléctricas de los puertos de E/S..................................................63

5.3 Usos de los puertos con interfaces para dispositivos periféricos como:.......................................64

Page 4: Manual Micros 2010

5.3.1 Teclados Lineales y Matriciales.............................................................................................64

5.3.2 Display de 7 segmentos.........................................................................................................71

5.3.3 Detectores de proximidad......................................................................................................78

5.3.3.2 El sensor Infrarrojo modulado en frecuencia.................................................................78

5.3.3.3 El Sensor ultrasónico SRF-04........................................................................................78

5.4 Uso de los puertos para manejo de potencia con interfaces con:..................................................80

5.4.1 Transistores, Darlingtons, MOSFETS y relevadores.............................................................80

5.4.2 Optotransistores, optoacopladores y optotriacs.....................................................................86

5.4.3 Puentes H discretos e Integrados...........................................................................................90

5.5 Ejemplo del uso de las interfaces para controlar:..........................................................................91

5.5.1 Motores de DC.......................................................................................................................91

5.5.2 Motores a pasos...................................................................................................................100

5.5.3 Servomotores.......................................................................................................................102

Unidad 6 Interrupciones en un microcontrolador..................................................................................107

6.1 El manejo de las interrupciones...................................................................................................108

6.1.1 Tipos de interrupciones........................................................................................................108

6.1.2 Los vectores de interrupción................................................................................................108

6.1.3 Las acciones del MCU al responder a una interrupción......................................................110

6.1.4 Características de la rutina manejadora de interrupción......................................................111

6.2 Las interrupciones externas.........................................................................................................112

6.2.1 Características y configuración............................................................................................112

6.2.2 Programación y uso.............................................................................................................112

6.3 Fuentes internas de interrupciones..............................................................................................127

6.3.1 De los timer y contadores....................................................................................................127

Cálculo de la Temporización en Modo Normal............................................................................135

6.3.2 ADC..........................................................................................................................................139

6.3.3 De la comunicación serial....................................................................................................139

6.3.4 Del comparador analógico...................................................................................................141

6.3.5 De la EEPROM...................................................................................................................142

6.4 Ejemplos de aplicaciones de las interrupciones..........................................................................142

Unidad 7 Programación del microcontrolador con aplicaciones...........................................................177

7.1 Técnicas de control de motores usando:......................................................................................178

7.1.1 PWM....................................................................................................................................178

7.1.1.1 Configurando el PWM en el ATMega32U4 con el Timer 0........................................183

7.1.2 Encoders incrementales como sensor de velocidad y sentido de giroscopio.......................187

Page 5: Manual Micros 2010

7.2 Control de sentido de giro, de posición y de velocidad...............................................................192

7.2.1 Motores de corriente directamente......................................................................................195

7.2.2 Motores de pasos.................................................................................................................201

7.2.2.1 Cálculo de la potencia disipada en un controlador MOSFET para un motor a pasos usando la técnica de medios pasos...........................................................................................201

7.4.2.2 Cálculo de la energía disipada durante el tiempo Tr...............................................202

7.2.2.3 Determinación de la energía disipada en TLD........................................................204

7.2.2.4 Determinación de la energía disipada en el tiempo de espera.................................204

7.2.2.5 Determinación de la energía total disipada y potencia total disipada en el mosfet de conmutación........................................................................................................................205

Unidad 8 El convertidor ADC y DAC...................................................................................................208

8.1 Arquitectura Interna.....................................................................................................................209

8.2 Configuración y programación....................................................................................................209

Unidad 9 Puertos seriales y memoria EEPROM...................................................................................219

9.1 El USART....................................................................................................................................220

9.1.1 Librerías para el control del puerto serial............................................................................220

9.1.2 Ejemplo de recepción de datos desde una terminal de comunicación serial GtkTerm o CuteCom hacia el microcontrolador ATmega32U4......................................................................225

9.1.3 Acceso como usuario normal al puerto serial e instalación de RxTx..................................227

9.1.5 Envío de Datos del microcontrolador hacia el PC usando Scilab 5.x.................................232

9.2 TWI (I2C)....................................................................................................................................237

9.3 Leer y escribir sobre EEPROM I2C............................................................................................249

9.3.1 Lectura y escritura simple de sobre una EEPROM I2C......................................................250

9.3.2 Lectura escritura controlada por el puerto de comunicación serial.....................................254

Referencias........................................................................................................................................283

Page 6: Manual Micros 2010

Unidad 1

Conceptos introductorios a los microcontroladores

Page 7: Manual Micros 2010

Unidad 1 Conceptos introductorios a los microcontroladores

1.1 Diferencia entre microcontrolador, microcomputadora y microprocesador.

1.2 Características y aplicaciones de los microcontroladores

1.3 Tipos de arquitecturas computacionales.

1.4 Tipos de Microcontroladores y sus fabricantes.

Competencia específica

catalogar los diferentes tipos y características de los microcontroladores.

Actividades de aprendizaje

• Cuadro Comparativo: Marcar las diferencias mas importantes entre Microcomputadora, Microcontrolador y Microprocesador.

• Investigación documental: Acuñar las principales características sobre microcontroladores de 8 bits y sus fabricantes.

Page 8: Manual Micros 2010

1.1 Diferencia entre microcontrolador, microcomputadora y microprocesador

Es común escuchar que los términos microcontrolador, microcomputadora y microprocesador se intercambian, sin embargo, cada uno es diferente del otro, y es importante entender la diferencia en este punto.

Definiciones:

Microprocesador. Es una unidad central de procesamiento en un único circuito; en los 60's los diseños de microprocesadores se hacían mediante arreglos de varios circuitos MSI y LSI.

Intel, coloca todos los componentes de un CPU en un solo circuito (Unidad lógico Aritmética, Decodificador de instrucciones circuíteria de control de bus, etc.) al cual denomina 4004, es entonces cuando nace el Microprocesador (MPU).

Microcomputadora. Cuando un microprocesador y circuiteria periférica de entrada y salida, memoria se colocan reunidos en una pequeña computadora, específicamente para la adquisición de datos o

aplicaciones de control, se le denomina microcomputadora.

Entonces, sí fueramos a diseñar un circuito con el microprocesador 8088, se requeriría de una memoria EEPROM para almacenar el programa, circuitos de memoria RAM para almacenar las variables y resultados y finalmente circuitos de interface E/S para interaccionar con el mundo exterior. Todo esto Reunido es una microcomputadora.

Microcontrolador. En una extensión a la lógica, cuando los componentes que conforman a una microcomputadora son colocados en un solo chip de silicio, se le denomina a esto un Microcontrolador.

Texas Instruments fue el primer fabricante del microcontrolador, con la serie TMS1000. Esta serie de microcontroladores tenia la sufiente RAM, ROM y terminales de E/S como para controlar un horno de microondas, usarse en temporizadores industriales y en calculadoras.

Este texto puede comprenderse un poco mejor a partir del mapa conceptual figura 1: MCU, MPU,microcomputadora.

Page 9: Manual Micros 2010

Actividad de aprendizaje:

Cuadro Comparativo: Marcar las diferencias mas importantes entre Microcomputadora, Microcontrolador y Microprocesador.

Para elaborar esta actividad, se requiere del uso de un equipo de cómputo y presentarlo en sesion.

figura 1: MCU, MPU, microcomputadora

Page 10: Manual Micros 2010

1.2 Características y aplicaciones de los microcontroladores

Los microcontroladores son divertidos, son el corazón y alma de muchas aplicaciones de uso diario y lo mejor de todo, los microcontroladores son fáciles de usar y de diseñar con ellos, todo esto desde el punto de vista del diseñador. En la siguiente figura, se presenta un esquema generalizado de las partes que constan a un microcontrolador (veáse figura 2: Partes e interfaces de un microcontrolador).

De esta forma se puede definir que:

LA CPU: Es la Unidad Central de Procesamiento o coloquialmente “el corazon del controlador”, su tarea es la de buscar instrucciones almacenadas en la memoria del programa, decodificar esas instrucciones y ejecutarlas. El CPU en sí está compuesto por registros, una o varias ALU, decodificador de instrucciones y circuiteria de control.

MEMORIA de PROGRAMA: La memomoria de programa almacena las instrucciones que conforman

figura 2: Partes e interfaces de un microcontrolador

Fuente: (Gadre, 2000)

Page 11: Manual Micros 2010

al programa; en caso de tener un programa muy grande, la memoria puede ser particionada, en una memoria interna y en una memoria externa. Generalmente esta memoria es de tipo no volátil, es decir, al perder energía el microcontrolador, la memoria no se borra (EPROM, EEPROM, FLASH, mask ROM o OTP).

RAM: La RAM es la memoria de datos del controlador, ya que es usada para este propósito. La CPU usa la RAM para almacenar datos y la PILA (stack). La pila se utiliza para guardar las direcciones de retorno al que debe regresar el programa cuando se termina de ejecutar una subrutina o interrupción.

RELOJ: El controlador ejecuta el programa con cierta cadencia. El ritmo de ejecución está determinado por la frecuencia del oscilador. El reloj oscilador puede ser interno (oscilador tipo RC) externo con un elemento de temporización tales como un cristal oscilador, un circuito resonante LC o un circuito RC. Tan pronto se aplica voltaje al microcontrolador, el oscilador comienza a trabajar.

RESET y DETECTOR de BAJO VOLTAJE: El circuito de reset permite asegurar que todos los componentes y el circuito de control tienen un estado inicial predeterminado y son inicilizados de forma adecuada. El detector de bajo voltaje es un circuito que monitorea la fuente de alimentación, en caso de un descenso de voltaje, se da la indicación de RESET.

PUERTO SERIAL: El puerto serial es un componente muy útil del microcontrolador, ya que se utiliza para comunicación con otros dispositivos externos. Existen dos tipos de puertos seriales: Síncronos y Asíncronos. Para la transferencia síncrona es necesaria una señal de reloj con cada bit de datos enviado, aunque en la comunicación´asíncrona, la señal de reloj no es necesaria, pero la temporización está embebida en los dispositivos que se omunicarán, sin embargo es requerida un bit de sincronia, denominados bit de Inicio y bit de paro.

PUERTOS ANALÓGICOS: Las entradas analógicas se utilizan con los convertidores analógicos a digitales. Un controlador puede tener un ADC o comparadores analógico. Los ADC se utilizan para adquirir datos de dispositivos como sensores de temperatura y sensores de presión. Una salida analógica se usa para conversión Digital a Analógica. La mayor parte de los microcontroladores vienen con módulos PWM los cuales permiten generar una señal analógica a través de un filtro RC.

PUERTOS DIGITALES:El microcontrolador usa estos puertos para intercambiar datos digitales con el mundo exterior.

TEMPORIZADOR/TIMER: El timer es un elemento usado por el controlador para temporizar eventos, por ejemplo, puede ser usado para enviar datos a un display cada determinado tiempo. El timer tamien puede ser usado para contar eventos, tanto externos como internos. De este modo al timer se le denomina contador.

TIMER PERRO GUARDIÁN: Este temporizador especial (WDT) se utiliza para prevenir cuelgues por software. Trabaja de la siguiente manera: Una vez inicializado el WDT se incrementa con una señal de

Page 12: Manual Micros 2010

reloj, Si el programa del usuario no resetea el WDT, el contador se desborda y causa un RESET. En consecuencia al activar este timer, el programador debe tener en cuenta causar cada determinado tiempo una señal de reseteo del WDT. De este modo se presupone que si el programa de usuario no resetea al WDT entonces ha fallado, lo que significa un posible comportamiento indeseable, y en consecuencia, es mejor reinicializar.

RTC. Es un Reloj de tiempo real que tiene la tarea de mantener el tiempo de los días y fechas

Page 13: Manual Micros 2010

Desarrollando aplicaciones con microcontroladores

1. Primero y mas importante, define los requerimientos.

2. Crea la suficiente documentación para dar soporte a los requerimientos en formato de diagrama de bloques, diagrama de flujo, diagramas de temporización.

3. Busca el hardware mas adecuado para otorgar la funcionalidad mas adecuada. Esto auxilia al diseñador a decidir si requiere de un microcontrolador o no.

4. Si es necesario un microcontrolador, identifica el microcontrolador más adecuado para ser el cerebro de tu aplicación.

5. Identificado una vez el controlador a utilizar, vuelve a verificar si el microcontrolador elegido satisface los requerimientos de velocidad, energía consumida, etc. De otra forma vuelve al paso 4.

6. El paso siguiente, es adquirir las herramientas necesarias para desarrollar el hardware y el software, estas herramientas pueden ser ensambladores, compilador (en caso de programar en lenguaje de alto nivel), simulador del controlador, y si es posible, un emulador del hardware, una tarjeta de evaluación, el programador, etc.

7. Si estas familiarizado con un controlador en partícular, puedes iniciar tu diseño y ensamblar un prototipo, sino, comienza a familiarizarte, escribiendo primero algunos programas de muestra y probando sobre la tarjeta de evaluación o sobre el simulador.

8. Una vez familiarizado, comienza a particionar el software en bloques que puedan ser escritos como subrutinas y ser probados de forma independiente. El desarrollo del hardware puede ir en forma paralela, y así entrar en una fase de prueba y depuración. Estos ciclos se realizan de forma iterativa.

9. Finalmente, se integra todo el software y el hardware y nuevamente se prueba, de nuevo se entra en la fase de prueba – depuración, hasta que todo trabaje.

10. Durante la escritura del software y el desarrollo del hardware, algo que no debes perder de vista es la documentación. Documentar el diseño es extremadamente importante, no solo por mantener una memoria de tu trabajo, también para pruebas durante el ciclo de vida del dispositivo y futuras revisiones.

11. La etapa final, involucra la implementación del sistema en el ambiente de objetivo.

Page 14: Manual Micros 2010

1.3 Tipos de arquitecturas computacionales.

¿Qué es arquitectura computacional?

1.3.1 La arquitectura de un microcontrolador

La arquitectura del microcontrolador puede clasificarse con base diversas características. Una muy común es a través del número de instrucciones:

• CISC

• RISC

• MISC

Otra clasificación se basa en la forma en que se accede a la memoria de datos y de programa, el modelo unificado o Arquitectura Von Neumman (14figura 4: Arquitectura Memoria Unificada) y la Arquitectura Harvard (figura 5: Arquitectura Memoria Separada), donde la cual se encuentran separadas la memoria de datos y la memoria de programa.

figura 3: Definiciones de arquitectura de computadoras

Page 15: Manual Micros 2010

Una clasificación mas, se basa en la forma en que los datos internos son manipulados y almacenados dentro del procesador:

• Pila

• acumulador

• registro-memoria

• registro-registro

Para esclarecer la diferencia entre estas arquitecturas, tomemos como ejemplo el siguiente cálculo:

C← A−B

donde A, B y C son variables.

Modelo Pila: En una máquina de tipo pila, los cálculos se determinan de la siguiente manera:

Push A Primero la CPU toma los valores de la pila y almacena los operandos de regreso en la pila. Para cargar una variable en la pila, la instrucción Push es utilizada. La pila opera siempre colocando los últimos valores en la parte superior. La CPU toma los valores superiores de la pila y realiza una operación. El resultado se devuelve a la pila.

Push B

Sub

Pop C

Modelo Acumulador:

En una máquina de este tipo, un operando siempre se encuentre en el registro acumulador, de hecho, todas las operaciones tienen como centro al acumulador.

Load A ;carga el acumulador con la variable A

Sub B ;resta el valor de la variable B del acumulador y el resultado se devuelve al acumulador

Store C ;se lee el contenido del acumulador (A-B) y se almacenada en la variable C.

figura 4: Arquitectura Memoria Unificadafigura 5: Arquitectura Memoria Separada

Page 16: Manual Micros 2010

Modelo Registro-memoria

En esta arquitectura, los operandos se leen desde la memoria hacia un registro definido y el resultado se escribe directamente a memoria.

Load Rx, A ; Carga el registro Rx con la variable A

Sub Rx,B ; Resta la variable B del contenido del registro Rx

y almacena el resultado en el registro Rx

Store C ;almacena el valor de Rx en la variable C

Modelo Registro-registro

En este modelo, se accede a la memoria para almacenar los operandos a procesar y se realiza la operación directamente entre registros. En el caso de microcontroladores, en este tipo de arquitectura comúnmente es posible usar hasta 32 registros diferentes.

Load Rx,A ; Carga el registro Rx con la variable A

Load Ry,B ; Carga el registro Ry con la variable B

Sub Rz,Rx,Ry ; Se realiza la operacion Rx – Ry y se almacena en Rz

Store C,Rz ; Rz se almacena en la variable C

Page 17: Manual Micros 2010

1.4 Tipos de Microcontroladores y sus fabricantes.

En el mercado existe una gran diversidad de microcontroladores y microprocesadores, y elegir uno en particular, puede ser una pesadilla, generalmente se inicia enumerando los requerimientos en términos de las características y los costos. Aunque la elección final puede ser dictada por otros elementos, tales como la marca, popularidad, el “expertise” del diseñador local.

La lista que a continuación se presenta es tomada de Gadre (2001), quien consideró en ese entonces como los microcontroladores más populares de 8 bits.

Compañia Dispositivo Memoria On-Chip Otras características

AB Semicon Ltd AB180-20 Nil 2 timer de 16 bits, UART, unidad aritmética de punto fijo de 32 bits, controlador DMA

Atmel Corp ATtiny11 1-kbyte Flash 1 timer de 8bits, comparador analógico, WDT, Oscilador integrado, una interrupción externa.

Dallas Semi DS80C310 256- RAM 4 ciclos de reloj por ciclo máquina, UART, 3 timers 16 bits, 10 fuentes de interrupción externa e interna

Hitachi H8/3640 8kByte de ROM

512 Byte de RAM

3 timer de 8 bits, 1 timer de 16 bits, 1 timer PWM de 14 bits, 1 WDT, 2 puertos SCI, 8 ADC de 8 bits

Microchip PIC16CR54C 768 Byte de ROM

25 Byte de RAM

12 terminales E/S, timer de 8 bits, terminales con alta corriente para manejo directo de LED, oscilador RC

Motorola 68HC705KJ1 1240 byte OTP

64 byte RAM

Timer multifunción de 15 etapas, Oscilador integrado, Reset por bajo voltaje, perro guardián, interrupción de teclado, puerto E/S de alta corriente.

STMicro ST6203CB1 1 kByte de ROM

64- Byte de RAM

Comparador analogico, E/S programable, detector de bajo voltaje, timer de 8 bits, perro guardián.

Page 18: Manual Micros 2010

Actividad de aprendizaje

Resumen: Acuñar las principales características sobre microcontroladores de 8 bits y sus fabricantes

Page 19: Manual Micros 2010

Unidad 2

Arquitectura interna de un microcontrolador

Page 20: Manual Micros 2010

Unidad 2 Arquitectura interna de un microcontrolador

2.1 Componentes del Microcontrolador.

2.2 Registro internos.

2.3 Tipos y distribución de las memorias internas.

2.4 Periféricos

2.5 Las instrucciones del microcontrolador.

Competencia específica

Definir la arquitectura interna del microcontrolador.

Actividades de aprendizaje

• Mapa Conceptual: En un mapa conceptual colocar los componentes mas relevantes del microcontrolador ATmega32U4.

• Cuadro Comparativo: Elaborar un cuadro en el que se expongan las características de los periféricos internos de los microcontroladores ATmega48 y ATmega32U4 y el tipo de memorias que utilizan.

Page 21: Manual Micros 2010

2.1 Componentes del Microcontrolador.El microcontrolador a estudiar es un AVR, explícitamente el ATMega32u4, el cual a modo de resumen en la siguiente figura se muestran los componentes que contiene este dispositivo, además sirve como referencia para comparar los componentes de este microcontrolador con el ATmega48.

2.2 Registro internos.Los registros de esta microcontrolador son accedidos en formato de 8 bits de forma ortogonal, ya sea por la ALU, un dispositivo de E/S, etc., en la figura figura 7: Arquitectura AVR se muestra la arquitectura del núcleo AVR.

Notesé que son un total de 38 registros de propósito general, donde 6 de estos registros de 8 bits, pueden ser utilizados como tres registros de 16 bits para direccionamiento indirecto.

Además de estos registros de propósito general se cuenta con registros de propósito específico, tales como.

El registro de estados contiene información acerca del resultado más recientemente ejecutado por una instrucción aritmética. Esta información puede ser usada para alterar el flujo del programa. Es

figura 6: Cuadro comparativo entre microcontroladores

Page 22: Manual Micros 2010

importante advertir que el registro de estados no se guarda automáticamente cuando entra una interrupción, por lo que se hace necesario su debido uso por medio de software.

Apuntador de Pila

La pila es principalmente usada para almacenar datos temporales, para almacenar variables locales y direcciones de retorno, las cuales serán usadas al terminar una rutina de servicio de interrupción o una llamada de subrutina.

El registro apuntador de Pila, siempre apunta hacia la parte más alta de la pila, considere que la pila está implementada para crecer de localidades altas de memoria hacia localidades bajas de memoria, lo cual implica que la instrucción PUSH decrementa el valor del apuntador de Pila.

2.3 Tipos y distribución de las memorias internas.En esta sección se describe las diferentes memorias en el ATMega32u4. La arquitectura AVR tiene dos principales espacios de memoria, el espacio de memoria de Datos y el espacio de memoria de Programa, adicionalmente, el ATMega32u4 cuenta con una memoria EEPROM para almacenamiento de datos. Todos los espacios de memoria son lineales y regulares. (Esto es una ventaja con respecto a los pic de gama media que cuentan con memoria paginada)

figura 7: Arquitectura AVR

Page 23: Manual Micros 2010

2.4 PeriféricosLos periféricos con los que cuenta el ATMega32u4 son los siguientes:

• PLL para el control de USB y timer de alta velocidad, de 32 hasta 96MHz

• Un temporizador de 8 bits con preescalador separado y modo de comparación

• Dos temporizadores de 16 bits con preescalador separado y modos de comparación y captura

• Un temporizado de alta velocidad con resolución de 10 bits con PLL (64MHz) y modo de comparación

• Cuatro canales PWM de 8 bits

• Cuatro canales PWM con resolución programable de 2 a 16 bits

• Seis canales PWM para operaciones de alta velocidad, con resolución programable de 2 a 11 bits.

figura 8: Mapeo de memoria del ATMega32U4

Page 24: Manual Micros 2010

• Modulador de comparación a la salida

• ADC de 12 canales con resolución de 10 bits

• Interface Maestro-Esclavo SPI

• Interface I2C (TWI)

• Perro guardián programable con oscilador integrado independiente

• Comparador analógico Integrado

• Interrupción y salida del modo Sleep en cambio de nivel de Pin

• Sensor de temperatura integrado.

2.5 Las instrucciones del microcontrolador.Las instrucciones del microcontrolador ATMega32u4 se dividen en las siguientes partes

• instrucciones aritméticas y lógicas

• Instrucciones de ramificado

• Instrucciones de bit y prueba de bit

• instrucciones para transferencia de datos

• Instrucciones de microcontrolador

Estas instrucciones se caracterizan por ejecutarse, la mayoría de ellas (solo las de salto no) en un solo ciclo máquina, mas información puede encontrarse en el apartado 32 instruction Set Summary del data sheet de este microcontrolador

Page 25: Manual Micros 2010

Unidad 3

Características Eléctricas del Microcontrolador

Page 26: Manual Micros 2010

Unidad 3 Características Eléctricas del Microcontrolador

3.1 Distribución de terminales

3.2 Características del reloj del sistema

3.3 El Reset y sus posibles fuentes

3.4 Características de la fuente de alimentación y consumo de potencia del MCU

Competencia específica

Analizar las características eléctricas del microcontrolador.

Actividades de aprendizaje:

• Investigación Documental: Realizar la lectura de las características del reloj del sistema y elaborar una síntesis de las mismas.

• Mapa Cognitivo (Tipo SOL): Definir el RESET y distinguir sus posibles fuentes mediante un mapa cognitivo tipo Sol.

• Mapa Mental: Enlistar las características de la fuente de alimentación y consumo de potencia del microcontrolador.

Page 27: Manual Micros 2010

3.1 Distribución de terminalesEl microcontrolador ATMega32U4 es un dispositivo que contiene múltiples elementos de entrada y salida, totalmente configurables, tanto como digitales como analógicos, este dispotivo se encuentra en empaquetados tanto QNF como en TQFP, en la figura siguiente se muestra el “PINOUT” o distribución de las terminales de este microcontrolador en partícular.

A continuación se presenta la descripción que el fabricante da de cada uno de los terminales de este microcontrolador.

Vcc.

Terminal para la alimentación.

figura 9: Pinout del microcontrolador ATMega32U4

Page 28: Manual Micros 2010

GND.

Tierra

PORTB (PB7..PB0)

Es un puerto de Entradas – Salidas (E/S) bidireccional con resistencias de pull-up internas (elegibles para cada bit en particular). El puerto B tiene propiedades simétricas tanto como para drenar, así como para alimentar una carga conectada a cada terminal. Como entradas, las terminales del puerto B, drenarán muy poca corriente del exterior cuando las resistencia de pull-up estén activadas. Las terminales de este puerto se ponen en alta impedancia cuando una condición de reset se activa, o sí el reloj no está funcionando.

El puerto B en particular tiene mejores características de manejo de cargas que otros puertos.

Por otra parte este puerto tiene otras funciones especiales, las cuales son características del ATMega32u4 y se enlistan en la Tabla 1: Características especiales del Puerto B en el ATMega32U4

Page 29: Manual Micros 2010

Terminal del Puerto

Función Alterna

PB7 OC0A/OC1C/PCINT7/nRTS

(Salida en comparación y PWM en módulo A para el Temporizador 0, Salida en comparación y PWM en módulo C para el Temporizador 1, Pin de interrupción 7 en Flanco, señal nRTS para control de flujo en la UART ).

PB6 OC1B/PCINT6/OC4B/ADC13

(Salida en comparación y PWM en módulo B del Temporizador 1, Pin de interrupción 6 en Flanco, Salida en comparación y PWM en Módulo B del Temporizador 4, Terminal del canal 13 de conversión analógico a digital).

PB5 OC1A/PCINT5/nOC4B/ADC12

(Salida en comparación y PWM en módulo A para el Temporizador 1, Pin de interrupción 5 en Flanco, Salida negada en comparación y PWM en Módulo B del Temporizador 4, Terminal del canal 12 de conversión analógico a digital).

PB4 PCINT4/ADC11

(Pin de interrupción 4 en Flanco, Terminal del canal 11 de conversión analógico a digital).

PB3 PDO/MISO/PCINT3

(Salida de Programación de Datos, Terminal Master Input Slave Output del módulo SPI, Pin de interrupción 3 en Flanco).

PB2 PDI/MOSI/PCINT2

(Entada de Programación de Datos, Terminal Master Output Slave Input del módulo SPI, Pin de interrupción 2 en Flanco).

PB1 SCK/PCINT1

(Terminal de Reloj Serial para módulo SPI, Pin de interrupción 1 en Flanco).

PB0 nSS/PCINT0

(Terminal Select Slave activa en bajo para el módulo SPI, Pin de interrupción 0 en Flanco).

Tabla 1: Características especiales del Puerto B en el ATMega32U4

Fuente (AVR, 2010)

Puerto C (PC7, PC6)

Es un puerto de Entradas – Salidas (E/S) bidireccional con resistencias de pull-up internas (elegibles para cada bit en particular).El puerto C tiene propiedades simétricas tanto como para drenar, así como para alimentar una carga conectada a cada terminal. Como entradas, las terminales del puerto C, drenarán muy poca corriente del exterior cuando las resistencia de pull-up estén activadas. Las terminales de este puerto se ponen en alta impedancia cuando una condición de reset se activa,

Page 30: Manual Micros 2010

inclusive sí el reloj no está funcionando.

Solo los terminales 7 y 6 se encuentran disponibles

Por otra parte este puerto tiene otras funciones especiales, las cuales son características del ATMega32u4 y se enlistan en la Tabla 2: Características especiales del Puerto C en el ATMega32U4

Terminal del Puerto

Función Alterna

PC7 ICP3/CLKO/OC4A

(Terminal de Captura de entrada del Timer 3, Terminal de salida de Reloj (Divido por el Reloj del sistema con fines de sincronización), Salida en Comparación y PWM en módulo A del Temporizador 4).

PC6 OC3A/nOC4A

(Salida en Comparación y PEM en módulo A del Temporizador 3 y Salida negada en comparación y PWM en Módulo A del Temporizador 4)

Tabla 2: Características especiales del Puerto C en el ATMega32U4

Fuente: (AVR, 2010)

Puerto D (PD7..PD0)

Es un puerto de Entradas – Salidas (E/S) bidireccional con resistencias de pull-up internas (elegibles para cada bit en particular).El puerto D tiene propiedades simétricas tanto como para drenar, así como para alimentar una carga conectada a cada terminal. Como entradas, las terminales del puerto D, drenarán muy poca corriente del exterior cuando las resistencia de pull-up estén activadas. Las terminales de este puerto se ponen en alta impedancia cuando una condición de reset se activa, inclusive sí el reloj no está funcionando.

Por otra parte este puerto tiene otras funciones especiales, las cuales son características del ATMega32u4 y se enlistan en la Tabla 1: Características especiales del Puerto B en el ATMega32U4

Page 31: Manual Micros 2010

Terminal del Puerto

Función Alterna

PD7 T0/OC4D/ADC10

(Entrada para el Temporizador 0, Salida en Comparación y PWM en módulo D del Temporizador 4, Terminal del canal 10 de conversión analógico a digital).

PD6 T1/nOC4D/ADC9

(Entrada para el Temporizador 1, Salida negada en Comparación y PWM en módulo D del Temporizador 4, Terminal del canal 9 de conversión analógico a digital).

PD5 XCK1/nCTS

(Entrada/Salida externa de Reloj para la UART1, señal nCTS para control de flujo en la UART).

PD4 ICP1/ADC8

(Terminal de Captura de entrada del Timer 1, Terminal del canal 8 de conversión analógico a digital).

PD3 nINT3/TXD1

(Entrada de Interrupción externa 3, Pin de Transmisión de USART1).

PD2 nINT2/RXD1

(Entrada de Interrupción externa 2, Pin de Recepción de USART1).

PD1 nINT1/SDA

(Entrada de Interrupción externa 1, Terminal de Datos de Protocolo TWI/I2C).

PD0 nINT0/SCL/OC0B

(Entrada de Interrupción externa 0, Terminal de Reloj de Protocolo TWI/I2C, Salida en comparación de módulo B del Temporizador 0).

Tabla 3: Características especiales del Puerto D en el ATMega32U4

Fuente: (AVR,2010)

Puerto E (PE6,PE2)

Es un puerto de Entradas – Salidas (E/S) bidireccional con resistencias de pull-up internas (elegibles para cada bit en particular).El puerto E tiene propiedades simétricas tanto como para drenar, así como para alimentar una carga conectada a cada terminal. Como entradas, las terminales del puerto E, drenarán muy poca corriente del exterior cuando las resistencia de pull-up estén activadas. Las terminales de este puerto se ponen en alta impedancia cuando una condición de reset se activa, inclusive sí el reloj no está funcionando.

Únicamente los terminales 6 y 2 están presentes.

Por otra parte este puerto tiene otras funciones especiales, las cuales son características del ATMega32u4 y se enlistan en la

Page 32: Manual Micros 2010

Terminal del Puerto

Función Alterna

PE6 INT6/AIN0

( Entrada de Interrupción externa 6, Entrada positiva del comparador analógico ).

PE2 nHWB

(Activación del Bootloader)

Tabla 4: Características especiales del Puerto E en el ATMega32U4

Fuente: (AVR,2010)

Puerto F (PF7..PF4, PF1, PF0)

El puerto F sirve como entradas analógicas para el convertidor Analógico a Digital.

Es un puerto de Entradas – Salidas (E/S) bidireccional con resistencias de pull-up internas (elegibles para cada bit en particular).El puerto F tiene propiedades simétricas tanto como para drenar, así como para alimentar una carga conectada a cada terminal. Como entradas, las terminales del puerto F, drenarán muy poca corriente del exterior cuando las resistencia de pull-up estén activadas. Las terminales de este puerto se ponen en alta impedancia cuando una condición de reset se activa, inclusive sí el reloj no está funcionando.

Los bits 2 y 3 no se encuentran presentes en el microcontrolador.

El Puerto F sirve también como interfaz JTAG. Si la interfaz JTAG se encuentra habilitada,las resistencias de pull-up en las terminales PF7(TMI), PF5(TMS) y PF4(TCK) se activarán incluso si pudiese ocurrir un evento de reset.

D-

Puerto negativo de datos de Full Speed/Low Speed del módulo USB. Debe conectarse en serie con una resistencia de 22 ohms.

D+

Puerto positivo de datos de Full Speed/Low Speed del módulo USB. Debe conectarse en serie con una resistencia de 22 ohms.

UGND

Terminal de tierra para el USB

UVCC

Terminal para la alimentación del regulador interno de voltaje para el USB

UCAP

Terminal para la alimentación del regulador interno de voltaje para el USB, esta terminal deberá conectarse a un capacitor externo de 1uF.

VBUS

Entrada monitor del Voltaje USB

Page 33: Manual Micros 2010

nRESET

Entrada de Reset, un nivel en BAJO, con una duración mayor a la establecida por la mínima longitud de pulso, genera un reset. Incluso si el reloj no está trabajando. La duración del pulso mínimo depende de la configuración del microcontrolador, se debe advertir que pulsos que tengan una menor duración no garantizan que el evento de reset ocurra.

XTAL1

Entrada del Amplificador Inversor para el oscilador y entrada para el circuito interno operacional del reloj interno.

XTAL2

Salida del Amplificador Inversor para el oscilador

AVCC

AVCC es la fuente de alimentación (entrada) para todos los canales de conversión analógica a digital. Si el ADC no es utilizado, esta terminal deberá conectarse externamente a Vcc. Si el ADC es usado, entonces, deberá conectarse a Vcc a través de un filtro pasa bajos.

AREF

Esta es la terminal de referencia analógica (entrada) para el ADC.

Page 34: Manual Micros 2010

3.2 Características del reloj del sistema

A lo largo del presente escrito se describirán las características de los relojes que presenta internamente el microcontrolador ATMEGA32U4, así como la forma en que se encuentran distribuidos y la manera en que interactúan entre ellos. Se comenzará con un capítulo introductorio que nos presenta un bosquejo general de los temas a tratar así como una sección de antecedentes que nos empapen de la historia más importante acerca del desarrollo de los clocks de un microcontrolador. El en desarrollo se hablará de las fuentes de reloj, parámetros de rendimiento y la forma en que funcionan conjuntamente en el AVR.

INTRODUCCIÓNEl reloj de un sistema computarizado, por ejemplo el de un microcontrolador, se utiliza principalmente para cumplir dos tareas básicas que son:

1. Para sincronizar las diversas operaciones que realizan los diferentes subcomponentes del sistema informático.

2. Para saber la hora.

El reloj físicamente es un circuito integrado que emite una cantidad de pulsos por segundo, de manera constante. Al número de pulsos que emite el reloj cada segundo se le llama frecuencia de reloj. Las frecuencias de reloj se miden en ciclos sobre segundo, también llamados hertzios, siendo cada pulso un ciclo de reloj. Como la frecuencia de reloj es de varios millones de pulsos por segundo se expresa habitualmente en megaHertzs. “El reloj marca la velocidad de proceso del microcontrolador generando una señal periódica que es utilizada por todos los componentes del sistema informático para sincronizar y coordinar las actividades operativas y así evitar que un componente maneje unos datos incorrectamente o que una velocidad de transmisión de datos entre dos componentes sea distinta (Beltrán, 2008).

Cuanto mayor sea la frecuencia de reloj mayor será la velocidad de proceso del microcontrolador y podrá realizar mayor cantidad de instrucciones elementales en un segundo. En la temporización síncrona, la aparición de un evento está determinada por el reloj. El bus incluye una línea de reloj que es común a todos los dispositivos, y se suelen sincronizar durante el flanco de subida; considerando que se denomina flanco de subida al instante en que la señal de reloj cambia de estado bajo a alto. La mayoría de los eventos duran un ciclo de reloj. Cabe mencionar que en un microcontrolador se tienen diversas fuentes de generación de una señal de reloj y además cada uno de los componentes del hardware funciona a una determinada frecuencia de reloj teniendo así una amplia variedad de maneras para hacer funcionar el sistema embebido; claro todo dependerá de los parámetros de funcionamiento establecidos por el fabricante. Particularmente para el AVR ATMEGA32U4 se tiene toda una distribución compleja de relojes, es por ello que enseguida se describirán las características más importantes de cada uno de ellos.

Page 35: Manual Micros 2010

ANTECEDENTES

Un oscilador de cristal es un circuito oscilador electrónico que utiliza la resonancia mecánica de un cristal de vibración de material piezoeléctrico para crear una señal eléctrica con una frecuencia muy precisa. Esta frecuencia se utiliza comúnmente para controlar el tiempo, para proporcionar una señal de reloj estable de circuitos integrados digitales como en los microcontroladores, y para estabilizar las frecuencias de los transmisores y receptores de radio.

La piezoelectricidad fue descubierta por Jacques y Pierre Curie en 1880. Paul Langevin investigó primero resonadores de cuarzo para uso en sonar durante la Primera Guerra Mundial I. El primer oscilador controlado por cristal, usando un cristal de sal de Rochelle, fue construido en 1917 y patentado en 1918 por Alexander M. Nicholson en los Bell Telephone Laboratories, aunque su prioridad fue discutida por Walter Guyton Cady, quien construyó el primer oscilador de cristal de cuarzo en 1921.

Osciladores de cristal de cuarzo fueron desarrollados para las referencias de frecuencia de alta estabilidad durante los años 1920 y 1930. En 1926 se utilizaron cristales de cuarzo para controlar la frecuencia de las emisoras de radio y eran populares entre los operadores de radio aficionados. En 1928, Warren Marrison desarrolló el primer reloj de cuarzo. Con una precisión de hasta 1 segundo en 30 años, los relojes de cuarzo se convirtieron en relojes más precisos del mundo hasta que se desarrollaron los relojes atómicos en los años 1950. La escasez de cristales durante la guerra provocada por la demanda de control de la frecuencia exacta de radios y radares militares y navales estimularon la investigación de posguerra en el cultivo de cuarzo sintético, y en 1950 se desarrolló un proceso hidrotérmico para el crecimiento de cristales de cuarzo a escala comercial en los Laboratorios Bell. Por la década de 1970 prácticamente todos los cristales utilizados en la electrónica eran sintéticos. A pesar de que los osciladores de cristal aún más comúnmente utilizan cristales de cuarzo, los dispositivos que utilizan otros materiales son cada vez más comunes, tales como resonadores cerámicos.

En primer lugar se mostrará la manera en que está distribuido el reloj del sistema en el ATMEGA32U4, para lo cual se tiene la siguiente imagen:

Page 36: Manual Micros 2010

Se nota en el diagrama anterior que el reloj del AVR puede tomarse de diversas fuentes entre las que están: un cristal oscilador, un reloj externo, el oscilador del perro guardián o del oscilador RC calibrado. Esto significa que el usuario tiene la posibilidad de usar algunas de estas opciones según le convenga y esto dependerá de la aplicación que se le dé al microcontrolador, además de algunas características de hardware ya establecidas. El multiplexor de reloj tiene la función de “escoger” cuál de las señales de reloj conectadas se usará, una vez seleccionada, la señal es llevada a un prescalador que se encarga se multiplicarla por un factor menor a 1 de tal manera que la señal saliente sea de menor frecuencia, es entonces que el tren de pulsos llega a la unidad de control del relojes del AVR y a la entrada del multiplexor del PLL. Para el caso de la unidad de control esta se encargará de direccionar la señal de reloj a los diversos módulos o componentes del ATMEGA32U4 formando así las señales de reloj siguientes: clkPLL, clkCPU, clkADC, clkFLASH, clkI/O.

En el caso del PLL es importante mencionar que la entrada al mismo debe tener una frecuencia de 8 Mhz, es por ello que primero hay una etapa de prescalamiento; la función del PLL será elevar la frecuencia de la señal de reloj de entrada con el fin de mandar trenes de pulsos al USB o al timer de alta velocidad. Una vez dicho lo anterior ahora se describirá a cada uno de los constituyentes del reloj del sistema.

Reloj del CPU (clkCPU)Este reloj controla las partes del sistema que tiene que ver con el funcionamiento del núcleo del AVR, de esta forma si se inhabilita este reloj el núcleo del CPU no podrá realizar cálculos ni operaciones. Dicho de otra forma en el reloj que da la cadencia a todo el microcontrolador. El funcionamiento de este reloj es comparable con un metrónomo con su péndulo que oscila de izquierda a derecha. El intervalo de tiempo que el péndulo tarda en recorrer esa distancia y regresar a su punto inicial se denomina ciclo.

figura 10: Sistema de reloj del ATMega32U4

Page 37: Manual Micros 2010

Reloj de entradas/salidas (clkI/O)Es usado por la mayoría de los módulos I/O, como lo son los Timers/Contadores, SPI y USART. Además este reloj es usado por el módulo de interrupción externo, pero hay que mencionar que algunas interrupciones externas son asíncronas lo que significa que pueden ser detectadas sin necesidad de que el reloj I/O esté activado.

Reloj flash (clkFLASH)Controla las operaciones de la interfaz flash y usualmente se activa al mismo tiempo que lo hace el reloj del CPU.

Reloj del convertidor analógico-digital (clkADC)Permite detener a los relojes clk I/O y clk CPU con la finalidad de reducir el ruido generado por el circuito digital, ya que según André-Marie Ampére (1831) “la circulación de la intensidad del campo magnético en un contorno cerrado es igual a la corriente que lo recorre en ese contorno de tal forma que si la corriente es variable se produce un campo magnético variable” y además según Faraday (1831) “ el voltaje inducido en un circuito cerrado es directamente proporcional a la rapidez con que cambia en el tiempo el flujo magnético que atraviesa una superficie cualquiera con el circuito como borde”, lo que significa que la señal alterna de los relojes produce una corriente eléctrica que afecta al CAD. De esta forma si se inhabilitan los relojes se realiza una mejor conversión de la señal de entrada.

Reloj del prescalador PLL (clkPLL)El PLL requiere una entrada de 8 MHz, pero como las fuentes de reloj pueden ser superiores a este valor surge la necesidad de un prescalador que permite reducir la frecuencia de la señal de entrada hasta tener los 8 MHz requeridos. Un multiplexor en el PLL se encargará de escoger entre las diversas señales de reloj que cumplan el requerimiento de frecuencia mencionado, cabe decir que el oscilador RC calibrado ya viene definido para trabajar a 8 MHz.

Reloj del timer de alta velocidad (clkTMR)La frecuencia máxima del reloj para este timer depende del voltaje suministrado al AVR, pero en general se llega a un máximo de 64 MHz a 5 V. Esta señal de reloj proviene del postescalador del PLL que permite nuevamente reducir el valor de frecuencia de la señal de reloj pero ahora de la que sale del PLL que en general alcanza un valor máximo de 96 Mhz.

Reloj del USB (clkUSB)

figura 11: Formas de onda de reloj

Page 38: Manual Micros 2010

El hardware USB necesita una frecuencia de operación de 48 MHz, es por ello que se necesita del postescalador que permita dividir en 2 la frecuencia de salida del PLL que como se mencionó anteriormente tiene un valor común de 96 Mhz.

Fuentes de RelojComo ya se mencionó anteriormente este microcontrolador cuanta con diversas fuente de reloj. En la tabla siguiente se ven dichas opciones con el respectivo valor que debe poseer el conjunto de 4 bits que conforman al fusible CKSEL.

Es importante hacer notar que los “1” significan no programados mientras que los “0” significan sí programados. El AVR posee un oscilador de cristal de bajo consumo que puede alcanzar frecuencias entre 8 y 16 MHz, además cuenta internamente con el oscilador RC calibrado que funciona a 8 MHz. Además es notorio que se puede colocar un reloj externo a placa o cambiar el que tiene, aunque esto último no es recomendable.

Cristal oscilador de bajo consumoLos pines XTAL1 y XTAL2 son la entrada y salida, respectivamente, de un amplificador inversor el cual puede ser configurado para usarse como un oscilador. Este cristal brinda un bajo consumo de potencia, pero no es capaz de mantener más entradas de reloj. Para conectarlo correctamente es necesario colocar dos capacitores en ambas entradas.

figura 12: Opciones para configurar el reloj

figura 13: Conexión de cristal de bajo consumo

Page 39: Manual Micros 2010

El valor de los capacitores debe ser igual y dependerá de algunos factores como son la frecuencia de operación y el ruido generado por el mismo circuito. Además es necesario programar el fusible CKSEL según sea necesario; la imagen siguiente indica los valores recomendados por el fabricante.

Cristal oscilador de baja frecuenciaEl microcontrolador puede usar un cristal de 32.768 kHz como fuente para un oscilador dedicada a operar en bajas frecuencias. El cristal deberá conectarse de la misma forma que se ve en la ilustración 5.

Oscilador interno RC calibradoLa frecuencia nominal que posee es de 8 MHz a una temperatura de 25°C y voltaje de 3V. Este reloj puede ser seleccionado al programar los fusibles CKSEL como se nota en la siguiente imagen.

Cuando este oscilador es usado como un chip de reloj, el oscilador del perro guardián seguirá siendo usado por el timer perro guardián y por el reset time-out.

Reloj externoEl AVR puede usar una fuente de reloj externa como se muestra en la siguiente imagen.

figura 14: Palabra en FUSES para la conexión de oscilador de bajo consumo

figura 15: Palabra para seleccionar el reloj interno

figura 16: Conexión de Reloj externo

Page 40: Manual Micros 2010

Como se nota en la imagen anterior se usan los mismos pines que en el reloj de bajo consumo y baja frecuencia, sólo cambia la inclusión de un oscilador totalmente ajeno a la placa del ATMEGA32U4. Como es de esperarse es necesario programar algunos fusibles CKSEL con la finalidad de habilitar esta fuente de reloj.

PLLEl PLL es usado para generar frecuencias altas usadas en la interfaz de USB o en el módulo del timer de alta velocidad. El PLL interno de este microcontrolador produce frecuencias de reloj entre 32 MHz y 96 MHz con una entrada promedio de 8 MHz. En la ilustración que se ve a continuación se muestra el proceso por medio del cual son alimentados el USB y el timer gracias al PLL, cabe decir que se divide la frecuencia entre 1.5 para el TMR y entre 2 para el USB.

figura 17: Sistema de reloj de PLL

Page 41: Manual Micros 2010

3.3 El Reset y sus posibles fuentes

La figura que se muestra a continuación

figura 18: fuentes de reset

Page 42: Manual Micros 2010

3.4 Características de la fuente de alimentación y consumo de potencia del MCU

El ATMEGA32U4 es un microcontrolador de 8 bits de bajo consumo, esto se consigue al entrar en los modos de bajo consumo, en los cuales los módulos que no se utilizan se desactivan con el fin ahorrar energía.

Para habilitar los modos de bajo consumo, el bit SE en el registro SMCR debe estar en estado ALTO y una instrucción SLEEP debe ser ejecutada. Los bits SM2, SM1 Y SM0 en el registro SMCR permiten elegir cual será el modo de bajo consumo que se activará (Idle, Reducción de ruido en ADC, Power-down, Power-save o Standby).

Si una interrupción ocurre mientras el MCU se encuentra en modo SLEEP, se pondrá en estado activo, bajo el siguiente esquema: El MCU se pone en HALT por cuatro ciclos mas el tiempo de arranque y se ejecuta entonces la rutina de interrupción.

Si un reset ocurre durante el modo SLEEP, el MCU se “despierta” e inicia desde el vector de RESET.

3.4.1 Modo Idle

Este modo de bajo consumo detiene al CPU, pero permite que los siguientes periféricos sigan operando USB, SPI, USART, Comparador analógico, ADC, interface TWI, Contadores/Temporizadores, Perro Guardián y el sistema de interrupciones. Este modo básicamente detiene el clkCPU y el clkFLASH.

3.4.2 Modo Reducción de ruido en ADC

En este modo se detiene al CPU pero permite que el ADC, interrupciones externas, interfaz TWI, y el Perro Guardián sigan operando; para salir de este modo, además de la interrupción por conversión terminada, también es posible por medio interrupciones del TWI, EEPROM, interrupción externa o cambio de nivel, así como los reset ocasionados por el perro guardián, reset externo y reset por detección de bajo voltaje.

3.4.3 Modo Power-down

En este modo el oscilador externo es detenido, mientras las interrupciones externas, la interfaz TWI y el perro guardián permanecen operativos. Este modo particularmente, detiene todos los relojs, solo permite la operación de módulos asíncronos.

Para salir de este modo se deberá ocasionar un RESET a través de el Perro guardián, de forma externa o por detección de bajo voltaje, y por interrupciones externas, cambio en nivel de pin, TWI (address match) y las fuentes asíncronas de interrupción USB (VBUSTI, WAKEUPI).

3.4.4 Modo Power-save

Este modo es idéntico al modo Power-down

Page 43: Manual Micros 2010

3.4.5 Modo Standby

Este modo es indéntico al modo power-down con la excepción de que el oscilador permanece corriendo. De este modo, se requieren de seis ciclos de reloj para despertar al dispositivo.

3.4.6 Velocidad máxima vs velocidad

La frecuencia máxima de operación depende del valor de Vcc aplicado al microcontrolador, tal y como se muestra en la figura 19: Relación entre velocidad y alimentación, en esta curva se visualiza una relación lineal entre 2.7V < Vcc < 5.5V

figura 19: Relación entre velocidad y alimentación

Page 44: Manual Micros 2010

Unidad 4

Herramientas de desarrollo de los microcontroladores

Page 45: Manual Micros 2010

Unidad 4 Herramientas de desarrollo de los microcontroladores

4.1 Ambiente Integrado de desarrollo (IDE) para microcontroladores

4.1.1 Ensamblador y Compilador.

4.1.2 Simulador, debugger y emulador.

4.1.3 Equipos programadores (downloaders) de microcontroladores.

4.2 Ejemplos de uso de herramientas de desarrollo.

Competencia específica

Utilizar las herramientas de desarrollo de los microcontroladores.

Actividades de aprendizaje:

• Videotutorial: Desarrollar un videotutorial para mostrar como se compila, programa y se prueba un programa básico del ATmega32U4 con una duración de 7 minutos.

• Simulaciones: Comprobar la programación del MCU mediante ejemplos de uso de las herramientas de desarrollo.

Page 46: Manual Micros 2010

4.1 Ambiente Integrado de desarrollo (IDE) para microcontroladores

Atmel Studio 6 es el Entorno de Desarrollo Integrado (IDE) de Atmel para el desarrollo de proyectos con sus productos relacionados con sus microcontroladores.

Durante muchos años los IDEs de Atmel para sus microcontroladores se mantuvieron separados en dos versiones principalmente. Por un lado estaba el AVR Studio, que soportaba sus microcontroladores AVR de 8 bits, entre los tinyAVR, los megaAVR y los Xmega. Eventualmente aparecían nuevas versiones AVR Studio 4.xx pero era esencialmente el mismo y con ese 4 tan inamovible como el nombre de una estación radial. En tanto que por otro lado teníamos al AVR32 Studio, que era desde luego la plataforma análoga pero para trabajar con los microcontroladores AVR de 32 bits.

Recién en 2011 Atmel decide lanzar su totalmente renovado Studio 5, esta vez fusionando el soporte para sus microcontroladores emblema de 8 bits y de 32 bits, es decir,

AVR Studio 5 = AVR Studio + AVR32 Studio

En 2012 Atmel vuelve a repotenciar su Studio dándoles cabida esta vez a sus microcontroladores con procesador ARM de la serie Cortex-M, denominados SAM3 y SAM4. Como era de esperarse, el nombre ya no va precedido por la palabra AVR. Ahora se llama simplemente ATmel Studio 6. Sin embargo, al igual que las versiones anteriores, los usuarios de los AVR lo suelen llamar simplemente Studio 6, a secas.

Entre las herramientas que incluye el nuevo Atmel Studio 6 nos deben interesar las siguientes:

• Un editor de códigos, para editar los programas. Como todo gran editor permite mostrar los códigos fuente a colores, con números de línea, etc.

• Un administrador de proyectos, que además de trabajar con programas en ensamblador, le da un completo soporte a los compiladores ARM GCC, AVR32 GCC y AVR GCC. A diferencia de versiones anteriores ahora es menos flexible la integración con los compiladores comerciales como CodeVision AVR o ImageCraft AVR.

• El ensamblador AVRASM, para trabajar con programas en ensamblador. • Los compiladores de software libre AVR32 GCC y AVR GCC en su versión para Windows

(WinAVR), para desarrollar programas en C para los AVR de 8 y 32 bits, como los tinyAVR, megaAVR, XMEGA y AVR32. En versiones pasadas de Atmel Studio 6, este compilador se debía instalar por separado.

• El compilador ARM GCC, que es otro derivado de la colección GCC pero adaptado para los microcontroladores ARM.

• El simulador AVR Simulator, para simular los programas de los AVR tanto si están escritos en lenguaje C o ensamblador. Todavía no está disponible un simulador para los microcontroladores con procesador ARM.

• El paquete Atmel Software Framework o ASF, que es un conjunto de más de 1000 proyectos escritos en lenguaje C para los AVR de 8 bits y para los ARM y AVR de 32 bits. Incluye librerías y APIs que facilitan la interface con todos los periféricos de los microcontroladores, desde los puertos hasta los módulos USB o CAN.

• Un completo sistema de ayuda integrado con servidor local. Había algunos problemas con esta

Page 47: Manual Micros 2010

característica en el Studio 5 pero en Atmel Studio 6 las cosas andan muy bien. • Atmel Studio 6 permite trabajar con más de 300 microcontroladores, entre AVR y ARM. Atmel

Studio 6 ya no soporta los siguientes dispositivos, que aún están disponibles en el Studio 4, ATtiny11, ATtiny12, ATtiny15, ATtiny22, AT90S1200, AT90S2313, AT90S2323, AT90S2343, AT90S4433, AT90S8515, AT90S8535, ATmega323, ATmega161, ATmega163, ATmega103, ATmega165, ATmega169, ATmega406, ATmega16HVA, ATmega16HVA2, ATmega64HVE, ATmega32U6, AT90PWM2, AT90PWM3, AT90SCR100, AT86RF401.

4.1.1 Ensamblador y Compilador.

La siguiente es la distribución por defecto de las ventanas de Atmel Studio 6. En primer plano tenemos a Start Page o Página de Inicio, a la derecha está la ventana Solution Explorer y abajo, la ventana Output.

Hacer estas reubicaciones es divertido sobre todo si tenemos en cuenta que podemos regresar a la distribución inicial yendo al menú Window Reset Window Layout. Y si queremos volver a tener la página Start Page para ver a la mariquita de nuevo vamos al menú View Start Page. Nota que esta opción también tiene un icono en la barra de herramientas. Es el menú View donde también puedes encontrar las otras ventanas y no en el menú Window.

Antes que mostrar una típica descripción de cada uno de los elementos del entorno de Atmel Studio 6 los iré presentando a medida que hagan su aparición y sean requeridos.

Proyectos y soluciones en C

A diferencia de los compiladores Basic, donde basta con crear un archivo BAS suelto y luego compilarlo, los programas en C siempre forman parte de un proyecto.

Page 48: Manual Micros 2010

Actualmente desarrollar proyectos en C con Atmel Studio 6 es más sencillo que en versiones anteriores debido en gran parte a que está adaptado para trabajar especialmente con los compiladores libres GCC AVR32 y AVR GCC (WinAVR).

Una Solución (Solution) es un conjunto formado por uno o varios proyectos, así que todo proyecto debe pertenecer a alguna Solución. Atmel Studio 6 puede trabajar con uno solo o con todos los proyectos de la Solución al mismo tiempo, pero solo puede administrar una Solución a la vez.

Creación de un proyecto en C

Abierto Atmel Studio 6 vamos al menú File New Project o hacemos clic en New Project de Start Page.

De cualquier modo llegaremos al mismo asistente, donde empezamos por seguir lo que indica la siguiente figura. El nombre y la ubicación del proyecto pueden ser los que desees.

Ten en cuenta que Atmel Studio 6 creará una nueva carpeta (con el nombre del proyecto) dentro de la ubicación indicada. Observa que el nombre de la Solución es el mismo que el del proyecto.

Todo proyecto debe pertenecer a alguna Solución, y como estamos creando el primer proyecto, Atmel Studio 6 le asignará una Solución automáticamente. Cuando creemos los siguientes proyectos tendremos la opción de elegir si pertenecerán a ésta o a una Solución nueva.

Si activas la casilla Create directory for Solution, la Solución (que es un archivo a fin de cuentas) se alojará en la carpeta que debía ser para el proyecto, y el proyecto junto con sus archivos generados irán a parar a una sub carpeta con el mismo nombre. Esto puede ser conveniente cuando se tiene una Solución con varios proyectos. Yo sé que parece enredado pero con un par de prácticas lo entiendes mejor y te acostumbras.

Normalmente prefiero tener un proyecto por cada Solución, de modo que no tengo que marcar la casilla indicada y puedo tener todos los archivos del proyecto y de la Solución dentro de la misma carpeta sin que se confundan.

Le damos clic a OK y tendremos una ventana mucho menos traumática. Solo seleccionamos el AVR con el que trabajaremos. En el futuro podremos cambiar este microcontrolador por otro. También puedes aprovechar esta ventana para reconocer las memorias de cada dispositivo y para ver las herramientas que tienen disponibles desde Atmel Studio 6.

En seguida tendremos nuestro proyecto con el Editor de Código mostrándonos el archivo de código fuente principal listo para que lo editemos. Observa que el Explorador de la Solución o Solution Explorer muestra los Proyectos de la Solución así como los archivos de cada Proyecto. Debajo está el marco Properties que informa las propiedades de cada archivo seleccionado arriba, como su ubicación.

De todas las ventanas aquí mostradas o las que puedan surgir en adelante la que no deberías perder de vista es el Explorador de la Solución. Desde allí accedes a todos los archivos del proyecto (los abres con doble clic) y también puedes construir el proyecto así como establecer su configuración. Si se te llega a perder esta ventana la puedes visualizar yendo al menú View Solution Explorer.

Page 49: Manual Micros 2010

Compiladores para microcontroladores AVR

Un microcontrolador ejecuta el programa que lleva grabado en su memoria FLASH. Ese programa está guardado allí en formato de código máquina (a base de unos y ceros) y nosotros lo podemos cambiar por otro programa que queramos (a eso se llama grabar el microcontrolador). Pero antes tenemos que crear ese programa. Lo podemos hacer de tres formas.

• Escribiendo el código máquina directamente con unos y ceros o sus equivalentes en números hexadecimales. Es un método factible pero que muy pocos se atreverían a intentar. El programa escrito puede ser un simple archivo de texto (con extensión .hex) que luego será decodificado por el software grabador de microcontroladores. Un programa en código máquina luce más o menos así.

:020000020000FC:1000000012E01EBF1FEF1DBF36D0F0E0E8E15BD06D:10001000F0E0E8E458D0FFCF0D0D0A207777772E77:10002000637572736F6D6963726F732E636F6D208A:100030000D0A203D3D3D3D3D3D3D3D3D3D3D3D3D70:100040003D3D3D3D3D3D20000D0D0A20546573743E:10005000696E67207468652054574920696E74651D:100060007266616365200D0A00000D48692074689E:10007000657265210000B0E0A0EC1C9112601C9339:100080001127B0E0A5EC1C9318E6B0E0A4EC1C939B:1000900016E0B0E0A2EC1C9318E1B0E0A1EC1C93D8:1000A0000895B0E0A0EC1C9115FFFBCFB0E0A6ECEA:1000B0000C930895B0E0A0EC1C9117FFFBCFB0E0CB:1000C000A6EC0C9108950591002311F0EADFFBCF17:1000D0000895FF93EF93F0E0ECE03197F1F7EF91A3:1000E000FF910895000000000000089508953AEF80:1000F00011D03AEF0FD008953AEF0CC034E60AC0A1:100100003EE108C030E106C035E004C032E002C084:1001100031E000C0FF93EF93F1E0EAE43197F1F7AB:0A012000EF91FF913A95B1F70895B1:00000001FF

Tabla 5: Código máquina

• Escribiendo el programa en código ensamblador. El ensamblador es el lenguaje más elemental de los microcontroladores y muchos aún lo usamos como recurso auxiliar. Sin embargo, sigue siendo muy engorroso como método de desarrollo ya que si queremos, por ejemplo, que el microcontrolador ejecute una simple división de números puede tomar cerca de 100 líneas de código ensamblador. El programa escrito en este lenguaje sigue siendo un archivo de texto (esta vez con extensión .asm) que luego será convertido en código máquina por un software de computadora llamado también ensamblador (AVRasm en el caso de los microcontroladores AVR). A continuación se lista un ejemplo de programa en ensamblador.

Page 50: Manual Micros 2010

;//////////////////////////////////////////////////////////////;/// FileName: main.asm;//////////////////////////////////////////////////////////////

.nolist

.include "m48Pdef.inc"

.list

.def arg = R16 ; argumento para funciones

.def tmp = R17 ; para operaciones temporales

.def status = R18 ;

.def del = R19 ;

.def AddressHigh = R27 ; Apuntador X

.def AddressLow = R26 ;

;//////////////////////////////////////////////////////////////; Code program;//////////////////////////////////////////////////////////////.cseg.org 0x0000 ; Reset vector addressStart: ; Setup Stack Pointer ldi tmp, high(RAMEND) out SPH, tmp ldi tmp, low(RAMEND) out SPL, tmp

rcall usart_init ; Inicializa la usart.

ldi ZH, high(2*StrTest) ldi ZL, low(2*StrTest) rcall puts ldi ZH, high(2*StrType) ldi ZL, low(2*StrType) rcall putsMain: rjmp Main

;//////////////////////////////////////////////////////////////////////; Strings. Null ended stringsStrTest: .db 0x0D,0x0D, 0x0A, " algun texto " .db 0x0D,0x0A, " =================== ", 0x00StrType: .db 0x0D,0x0D, 0x0A, " Probando la com TWI ", 0x0D, 0x0A,0x00StrHi: .db 0x0D, "Hola!!! :)", 0x00

;////////////////////////////////////////////////////////////////////// .include "usart.asm" .include "delays.asm" .exit

Tabla 6: Ejemplo de código fuente en ensamblador

• Escribiendo el programa en un lenguaje de alto nivel. Los dos lenguajes más usados son el C y

Page 51: Manual Micros 2010

el Basic. Con menos frecuencia se aprecia el Pascal. En este caso el código a escribir es más comprensible para nosotros, los humanos. Por ejemplo, para una división es suficiente con escribir una sentencia como a = b/c. El programa escrito en este lenguaje también es un archivo de texto (ahora con extension .c, .bas o .pas) que luego será convertido en código ensamblador por el compilador y luego convertido de código ensamblador en código maquina por el ensamblador del compilador. Abajo tenemos un ejemplo de un programa escrito en lenguaje C.

/******************************************************************** * FileName: main.c * Purpose: Comunicación básica por USART0 * Processor: ATmel AVR con módulo TWI * Compiler: AVR IAR C y AVR GCC (WinAVR) * *******************************************************************/

#include "avr_compiler.h"#include "usart.h"

int main(void){ char name[20]; usart_init(); // Inicializar USART0 @ 9600-8N1 puts("\n\r algun texto "); puts("\n\r =================== \n\r"); puts("\n\r - ¿Cuál es tu nombre?... \n\r - "); scanf("%s", name); printf(" - Gusto en conocerte, %s", name); while(1);}

Tabla 7: Ejemplo de código fuente en C

Los compiladores son las herramientas de programación mas potentes que existen. En resumen, el compilador traduce el programa escrito en su lenguaje (C, Basic, Pascal u otro) en código ensamblador y luego generará los archivos de depuración (*.dbg, *.cof, *.d31, etc.) necesarios y de ejecución (*.hex).

Al trabajar con un compilador el programador ya no tiene que preocuparse (o lo hace muy poco) por los vericuetos del hardware ni por el ensamblador nativo de cada microcontrolador. Esto simplifica de manera asombrosa el desarrrollo de proyectos.

El compilador convierte el código fuente en el código máquina de cada microcontrolador sin inportar mucho cuál sea. Por ejemplo, un código escrito para un ATmega128P podría ser facilmente compilado para un ATxmega64A3U u otro y viceversa. Incluso es posible adaptar el código para un microcontrolador de otra marca, por ejemplo, de Freescale o Microchip. Eso se llama portabilidad.

Conocer un lenguaje de programación como el C es un mundo aparte y es raro que una persona trate de aprenderlo al mismo tiempo que va conociendo el microcontrolador. En cursomicros se ofrece un capítulo entero sobre el lenguaje C aunque puede no ser suficiente dada su complejidad comparado con lenguajes como el Basic.

Page 52: Manual Micros 2010

A continuación se describen brevemente los principales compiladores para los microcontroladores AVR. Para conocer más de su uso se presentan posteriormente los tutoriales respectivos.

• El Compilador CodeVisionAVR • El Compilador AVR IAR C • El Compilador AVR GCC • El Compilador Bascom AVR • El Compilador ImageCraft C • El Compilador mikroC for AVR

El compilador AVR GCC

Como su nombre lo revela, AVR GCC es un software derivado del compilador libre GCC (Gnu C Compiler). Tiene por tanto todo el respaldo de la comunidad OpenSource.

En el pasado el principal inconveniente del compilador AVR GCC era que no tenía un IDE propio. Los programadores debían valerse de otros entornos como CodeBlocks o Eclipse. Pero con el paso del tiempo el AVR Studio de ATmel lo fue incorporando cada vez más hasta convertirlo en la actualidad en su compilador casi oficial para sus microcontroladores AVR, todo gracias a su prestigio. Ahora ya no es necesario buscar el compilador AVR GCC por separado, pues AVR Studio 5 y Atmel Studio 6 lo incluyen en su paquete de instalación. De hecho, incluyen una versión del compilador que es mejor (?) que la disponible yendo a la web de AVR GCC para Windows (WinAVR) http://winavr.sourceforge.net.

4.1.2 Simulador, debugger y emulador.

La simulación es un proceso donde se busca proponer un sistema físico en marcha a partir de un software, a fin de visualizar el posible comportamiento del sistema real, antes de su implementación, de esta forma se permite evitar costos por fallas o por pruebas destructivas.

En cuanto al microcontrolador ATmega48 se refiere, podemos encontrar en el sofftware ISIS, propiedad de Labcenter Electronics, un buen simulador, ya que permite no solo conocer el comportamiento lógico del dispositivo, sino que se aproxima un poco mas a la realidad al poner a disposición del usuario, un conjunto de elementos que simulan dispositivos analógicos y digitales, permitiendo así, una mayor interacción y una mejor predicción en cuanto al posible comportamiento del sistema implementado.

Por otra parte, el IDE AVR Studio, también cuenta con un simulador de acciones lógicas del microcontrolador, el cual permite verificar el valor de cada registro, accediendo incluso a los valores bit a bit, de esta forma, aunque con una interfaz un poco osca, permite una gran manipulación de bits dentro del programa del microcontrolador en cuestión.

Simulando Atmega48 con ISIS de PROTEUS.

Los pasos a seguir para la simulación del programa de un micrcontrolador ATmega48 son los siguientes:

1. De primera instancia, debemos contar ya con un programa compilado en AVR Studio y generado un código en Hexadecimal o archivo de depuración.

2. Iniciar el software ISIS

3. Dar clic en el boton “Pick From Libraries”

4. De la ventana que aparece, escribir en el campo señalado por la etiqueta Keywords : Atmega48

Page 53: Manual Micros 2010

5. Y en la sección Results de la misma ventana elegir el microcontrolador ATMEGA48 (solamente o el primero de la lista)

6. Dar clic en el botón OK, si es que ya no se requieren de mas componentes.

7. La acción anterior causará que aparezca el nombre del microcontrolador elegido en la ventana devices.

8. Con un clic del ratón, sobre el nombre, podrás colocar el microcontrolador simulado sobre el área de trabajo de ISIS, con un nuevo clic del ratón., apareciendo éste de color rojo y mediante movimientos del raton, podrás colocarlo en una posición de tu elección, con un nuevo clic.

Antes de dar el último clic

Después de dar el último clic

9. Dar un doble clic sobre el componente para ver sus propiedades.

Page 54: Manual Micros 2010

10. sasasa

4.1.3 Equipos programadores (downloaders) de microcontroladores.

Los downloaders son programadores del código hexadecimal que se genera cuando se ha compilado y linkeado correctamente un programa para el microcontrolador

El uso de bootloader permite que un microcontrolador no requiera del uso de un downloader, esto a cambio de un pequeño coste de espacio de memoria de programa, que es donde se almacena el bootloader. A continuación se aborda la secuencia de pasos a seguir a fin de hacer funcionar la tarjeta que contiene al microcontrolador ATMega32u4

Este clon cuenta con la ventaja de ser un micro con modulo USB integrado, ya que tiene el atmega32u4, el cual de acuerdo al vendedor puede ser programado con sketchs arduino o mediante avr-gcc como un micro normal, pero cuenta con la ventaja de tener un bootloader, el cual le permite grabar al microcontrolador sin necesidad de un programador externo.

figura 20: Tarjeta para prácticas

fuente:(ComunidadAtmel,2010)

Page 55: Manual Micros 2010

Para trabajarlo en modo arduino en Windows, se requiere del software de Arduino, el plug in de Teensyduino y finalmente de Flip. Pero como tengo unas cajas Linux, entonces vamos a echarlo a andar aquí. En otro post les comentaré mi motivación.

Se van a requerir que se descarguen software de los links que a continuación expongo:

http://arduino.cc/en/Main/Software

http://www.pjrc.com/teensy/td_download.html

https://sourceforge.net/projects/dfu-programmer/files/latest/download?source=files

(al final se trabajará con línea de comandos- problemas de dependencias en Fedora18)

No eran problemas de dependencias solo hay que cambiar un poco el archivo .pro, quedando de la siguiente manera#-------------------------------------------------

#

# Project created by QtCreator 2011-05-31T09:58:34

#

#-------------------------------------------------

QT += core gui

TARGET = easydfu

TEMPLATE = app

SOURCES += main.cpp\

easydfu.cpp

HEADERS += easydfu.h

FORMS += easydfu.ui

RESOURCES += \

icons.qrc

INCLUDEPATH += "/usr/include/QxtCore/"

LIBS += -lQxtCore -lQxtGui

La linea que se cambio fue

INCLUDEPATH+="/usr/include/qxt/QxtCore"

y en el archivo easydfu.h la línea 31 que dice

#include qxt/QxtGui/QxtGlobalShortcut

Page 56: Manual Micros 2010

se cambia por#include QxtGui/QxtGlobalShortcut

no pongo los signos de mayor que y menor que por que me edita el blogspot ;P

y finalmente el archivo easydfu.cpp se modifican la línea 30 para que el código quede así:

ui->setupUi(this);

//modificado para que lo encuentre el root

programPath = "/usr/local/bin/dfu-programmer";

En Ubuntu (12.04) mi otra box, pude instalar el siguiente paquete

https://sourceforge.net/projects/dfu-programmer/?source=dlp

Que es un cargador gráfico del .hex generado hacia el micro, mas o menos tipo Flip (ya tambien en Fedora18)

Se descargan los paquetes de acuerdo al tipo de sistema que tengamos ya sea de 32 o 64 bits.

Se descomprime el archivo arduino-X.X.X-linuxXX.tgz

El archivo teensyduino.64bit se le dan permisos de ejecución, solo da clic derecho sobre el icono, selecciona propiedades, da clic en la pestaña Permisos y sobre la casilla "es ejecutable" coloca una paloma mediante un clic.

Da un doble clic para instalar y saldrá la siguiente pantalla

Da clic en Next y elige el lugar donde descomprimiste el software de arduino.

Page 57: Manual Micros 2010

Escoge las librerias que te interesa instalar (yo seleccioné todas y di clic en siguiente)

al dar siguiente, ya nos permitirá instalar el software de Teensy

Una vez instalado nos aparece la ventana que indica que ya ha terminado la instalación.

Page 58: Manual Micros 2010

Da clic en el botón Done.

Ahora ejecuta el software de arduino.

Y elige la tarjeta Teensy 2.0 del menu Herramientas -> Board ->Teensyduino 2.0

De esta forma ya podremos generar sketch's para la tarjeta, el siguiente paso consiste en instalar DFU, que es el software a utilizar en lugar de Flip de atmel (Esto es por que flip aun no es compatible

Page 59: Manual Micros 2010

con Linux)

Se descomprime el archivo dfu-programmer-0.6.0

ingresamos en la carpeta descomprimida

abrimos una terminal ahi y tecleamos el comando $./bootstrap.sh

luego $./configure

$make

$sudo make install

La instalacion la realiza en /usr/local/bin, por lo que hay que tener cuidado ya que su no ve este directorio así que para invocar como superusuario debera hacer esto

$ sudo /usr/local/bin/dfu-programmer atmega32u4 erase por ejemplo

para programar un sketch realizado$sudo /usr/local/bin/dfu-programmer atmega32u4 flash /home/miguel/sketchbook/sketch_may15a/sketch_may15a.cpp.hex

y para que funcione

$sudo /usr/local/bin/dfu-programmer atmega32u4 start

Para la instalación del entorno gráfico (si compila pero no carga correctamente al dfu-programmer).

Se descomprime easydfu_1.0_src.tar.gz

Entramos a la carpeta

ejecutamos la orden qmake de la siguiente manera

qmake-qt4 EasyDFU.pro (recuerda las modificaciones indicadas al inicio del post)

y luego make

se debe usar como root o mediante el comando sudo

Esta es una prueba de que está corriendo el software

Page 60: Manual Micros 2010

4.2 Ejemplos de uso de herramientas de desarrollo.Code Blocks es un IDE multiplataforma para lenguaje C, en esta entrada describiré brevemente como configurar el Code Blocks para que en Manajro se pueda programar un AVR, en este caso tenemos el ATmega32U4

La primera parte es muy sencilla ya que solo hay que seguir un asistente, el problema es que cuando se pretende compilar el nuevo codigo, envia un error

/usr/lib/libm.so: file not recognized: File format not recognized

Process terminated with status 1 (0 minutes, 0 seconds)

0 errors, 0 warnings

Esto es a causa de que el IDE no está correctamente configurado para funcionar con el AVR GCC, por lo tanto solo hay que redireccionarlo, tal y como se indica en esta entrada de AVR Freaks

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=99954&view=next

De acuerdo a lo que ahi se indica debemos ir al menu settings, luego al menu Compiler..

Seleccionar el compilador "GNU AVR GCC Compiler"

Page 61: Manual Micros 2010

Ir a la pestaña "Search directories" y en la sub-pestaña "Linker"

cambia la ruta por

/usr/lib/avr/lib/

que actualmente dice /usr/lib

ahora ir a la sub-pestaña "Compiler" y editar la entrada para que diga lo siguiente:

/usr/lib/avr/include/avr

Entonces, ahora si al compilar tendremos el siguiente resultado :)

Como puntosiguiente se muestran los enlaces a videos desarrollados por estudiantes de la carrera de Ingeniería Mecatrónica donde se muestra la forma de usar el IDE mediante un ejemplo simple:

Page 62: Manual Micros 2010

Unidad 5

Puertos de entrada y salida

Page 63: Manual Micros 2010

Unidad 5 Puertos de entrada y salida

5.1 Arquitectura de los E/S

5.2 Configuración y características eléctricas de los puertos de E/S

5.3 Usos de los puertos con interfaces para dispositivos periféricos como:

5.3.1 Teclados (lineales y matriciales)

5.3.2 Display de siete segmentos.

5.3.3 Detectores de proximidad.

5.4 Usos de los puertos para manejo de potencia con interfaces con:

5.4.1 Transistores, Darlington, MOSFETs y Relevadores.

5.4.2 Optotransistores, optoacopladores y optotriacs.

5.4.3 Puentes H discretos (con transistores, con MOSFET) e integrados (L293, L298)

5.5 Ejemplos de uso de las interfaces para controlar:

5.5.1 Motores DC

5.5.2 Motores de pasos

5.5.3 Servomotores.

Competencia específica

Manejar los puertos de entrada y salida

Actividades de aprendizaje:

• Mapa conceptual: Realizar la lectura de la arquitectura de los puertos E/S del uC ATmega32U4 y elaborar un mapa conceptual que contenga los elementos mas relevantes.

Page 64: Manual Micros 2010

5.1 Arquitectura de los E/STodos los puertos del AVR tienen la funcionalidad de lectura – modificación – escritura cuando se utilizan como puertos de Entrada – Salida. Esto significa que la dirección de un puerto de un pin puede cambiar sin cambiar accidentalmente la dirección de cualquier otro pin mediante las instrucciones SBI y CBI. La misma situación aplica cuando se configura un pin como salida e incluso con las resistencias de pull up internas.

Es importante señalar que las terminales del microcontrolador tienen simetría en cuanto al sinking y sourcing de corriente, la cual es suficiente para controlar de forma directa un LED. Agregando además que cada terminal de forma independiente, puede ser habilitada con una resistencia de pull-up, y tiene diodos de protección a su entrada, tal y como se muestra en la figura 21: Esquema eléctrico deprotección de una terminal E/S.

Son tres las direcciones de memoria de E/S asignadas para cada Puerto:

• Registro de Datos – PORTx

• Registro de dirección de Datos – DDRDx

• Registro de Entrada de Terminales – PINx (Este registro de solo lectura)

5.2 Configuración y características eléctricas de los puertos de E/SLa importancia de la lectura y escritura de los puertos de un microcontrolador, así como el saber como se debe configurar éstos, es tal que si este punto no se conoce a detalle, todas las demás secciones no podrán ser comprendidas.

En el caso de los microcontroladores AVR, los puertos configurados como entrada, el voltaje para que tenga un valor cero (bajo) es de 0.2Vcc, si el valor de alimentación oscila entre 2.7V y 5.5V, en el caso de los voltajes de estado alto, se toma como valor máximo Vcc + 0.5 en el mismo rango de alimentación.

Para los puertos configurados como salida, el estado bajo es de 0.7V y el estado alto tendrá un voltaje de 4.2V

figura 21: Esquema eléctrico de protección de una terminal E/S

Page 65: Manual Micros 2010

5.3 Usos de los puertos con interfaces para dispositivos periféricos como:

5.3.1 Teclados Lineales y Matriciales

Los teclados matriciales son ensamblados en forma de matriz, tal y como se muestra en XXXX. El diagrama muestra un teclado como una matriz de 4x4 o 16 teclas organizadas en 4 filas y 4 columnas. El circuito de la figura anteriormente menciona muestra que, sí no se ha presionado ninguna tecla, todas las conexiones permanecen abiertas, pero cuando una tecla se presiona, se establece una conexión columna-reglón.

Las tareas básicas que se debe realizar un microcontrolador para decodificar un teclado matricial se enlistan a continuación:

• Chechar si una tecla se oprimió

• En caso de ser verdadero el punto anterior proseguir, sino salir

• Rastrear los renglones para encontrar la columna activaciones

• Descifrar o decodificar que tecla se oprimió.

A fin de detallar la secuencia de microcontrolador, se expone el siguiente diagrama de flujo

figura 22: Teclado matricial 4 x 4

Page 66: Manual Micros 2010

Como verá en el diagrama de flujo se describe el procedimiento de lectura del teclado matricial, así como el valor de retorno que se define con la ecuación

tecla=4∗R[ i ]+col ;

donde el valor de la columna va 0 a 3, y en consecuencia la función de lectura de teclado matricial propone devolver valores que oscilan entre 0 y 15, cabe señalar que en este algoritmo no se contempla el valor devuelto en caso de no presionar tecla alguna. En el código fuente en Tabla 9: Código deejemplo de teclado matricial se propone que el valor devuelto sea 16 en caso de que no se presione tecla alguna.

Además se introduce en este contexto el uso de macros para configurar las salidas de los reglones y que éstas sean llamadas desde la función que lee el teclado matricial, como ejemplo (Tabla 8: Macro para laactivación de lectura por columna) se coloca el código de una macro de ejemplo;

#define vSetKeyPadR2() {set_bit(PORT_KEY_R1,PIN_KEY_R1); clear_bit(PORT_KEY_R2,PIN_KEY_R2);\

set_bit(PORT_KEY_R3,PIN_KEY_R3); set_bit(PORT_KEY_R4,PIN_KEY_R4);}

Tabla 8: Macro para la activación de lectura por columna

En esta macro puede visualizarse que solo un reglon se coloca en estado alto, indicando que está será la fila activa a escanear, además observe que la declaración de la macro se realiza mediante la directiva #define que en el lenguaje C en cursos iniciales, se utiliza como un elemento de definición para constantes.

figura 23: Lectura de un teclado matricial

Page 67: Manual Micros 2010

/**

*

*

*

* @author miguel

* @date 03/03/2013

* @brief Programa que lee un teclado matricial y saca por los pines

* pines pin_X0, pin_X1, pin_X2, pin_X3 y pin_X4

* considere que las entradas son c1 .. c3

* y que las salidas son r1 .. r3

*

* @file main.c

*/

#include <avr/io.h>

#define clear_bit(sfr,bit) (_SFR_BYTE(sfr) &=~_BV(bit))

#define set_bit(sfr,bit) (_SFR_BYTE(sfr)|=_BV(bit))

#define F_CPU 20000000UL

#include <util/delay.h>

/************************************************************************/

/* entradas */

/************************************************************************/

#define PIN_KEY_C1 PD4 //1

#define PORT_KEY_C1 PIND

#define PIN_KEY_C2 PD5 //2

#define PORT_KEY_C2 PIND

#define PIN_KEY_C3 PD6 //3

#define PORT_KEY_C3 PIND

#define PIN_KEY_C4 PD7 //4

#define PORT_KEY_C4 PIND

/************************************************************************/

/* Configura entradas */

/************************************************************************/

#define CPIN_KEY_C1 DDD4

#define CPORT_KEY_C1 DDRD

#define CPIN_KEY_C2 DDD5

#define CPORT_KEY_C2 DDRD

Page 68: Manual Micros 2010

#define CPIN_KEY_C3 DDD6

#define CPORT_KEY_C3 DDRD

#define CPIN_KEY_C4 DDD7

#define CPORT_KEY_C4 DDRD

/************************************************************************/

/* Salidas */

/************************************************************************/

#define PIN_KEY_R1 PD0 //A

#define PORT_KEY_R1 PORTD

#define PIN_KEY_R2 PD1 //B

#define PORT_KEY_R2 PORTD

#define PIN_KEY_R3 PD2 //C

#define PORT_KEY_R3 PORTD

#define PIN_KEY_R4 PD3 //D

#define PORT_KEY_R4 PORTD

/************************************************************************/

/* Configura salidas */

/************************************************************************/

#define CPIN_KEY_R1 DDD0

#define CPORT_KEY_R1 DDRD

#define CPIN_KEY_R2 DDD1

#define CPORT_KEY_R2 DDRD

#define CPIN_KEY_R3 DDD2

#define CPORT_KEY_R3 DDRD

#define CPIN_KEY_R4 DDD3

#define CPORT_KEY_R4 DDRD

/************************************************************************/

/* @brief Macros para colocar un valor bajo en cada fila y ser detectada

* en las columnas

* @params vacio

* @returns vacio */

/************************************************************************/

#define vSetKeyPadR1() {clear_bit(PORT_KEY_R1,PIN_KEY_R1); set_bit(PORT_KEY_R2,PIN_KEY_R2);\

set_bit(PORT_KEY_R3,PIN_KEY_R3); set_bit(PORT_KEY_R4,PIN_KEY_R4);}

#define vSetKeyPadR2() {set_bit(PORT_KEY_R1,PIN_KEY_R1); clear_bit(PORT_KEY_R2,PIN_KEY_R2);\

set_bit(PORT_KEY_R3,PIN_KEY_R3); set_bit(PORT_KEY_R4,PIN_KEY_R4);}

Page 69: Manual Micros 2010

#define vSetKeyPadR3() {set_bit(PORT_KEY_R1,PIN_KEY_R1); set_bit(PORT_KEY_R2,PIN_KEY_R2);\

clear_bit(PORT_KEY_R3,PIN_KEY_R3); set_bit(PORT_KEY_R4,PIN_KEY_R4);}

#define vSetKeyPadR4() {set_bit(PORT_KEY_R1,PIN_KEY_R1); set_bit(PORT_KEY_R2,PIN_KEY_R2);\

set_bit(PORT_KEY_R3,PIN_KEY_R3); clear_bit(PORT_KEY_R4,PIN_KEY_R4);}

//Prototipos de funcion para teclado matricial

void vInitKeyPad(void);

unsigned char ui8_TestKeyPad(void);

/**

* Salidas para leds

*/

#define pin_X0 PB0

#define Ppin_X0 PORTB

#define pin_X1 PB1

#define Ppin_X1 PORTB

#define pin_X2 PB2

#define Ppin_X2 PORTB

#define pin_X3 PB3

#define Ppin_X3 PORTB

#define pin_X4 PB4

#define Ppin_X4 PORTB

/**

* Configuracion para salidas

*/

#define cpin_X0 DDB0

#define cPpin_X0 DDRB

#define cpin_X1 DDB1

#define cPpin_X1 DDRB

#define cpin_X2 DDB2

#define cPpin_X2 DDRB

#define cpin_X3 DDB3

#define cPpin_X3 DDRB

#define cpin_X4 DDB4

#define cPpin_X4 DDRB

/***

* Programa Principal

*/

int main(void)

{

Page 70: Manual Micros 2010

unsigned char tecla=16;

vInitKeyPad();

set_bit(cPpin_X0,cpin_X0);

set_bit(cPpin_X1,cpin_X1);

set_bit(cPpin_X2,cpin_X2);

set_bit(cPpin_X3,cpin_X3);

set_bit(cPpin_X4,cpin_X4);

while(1)

{

tecla= ui8_TestKeyPad();

if(bit_is_set(tecla,0))

set_bit(Ppin_X0, pin_X0);

else

clear_bit(Ppin_X0, pin_X0);

if(bit_is_set(tecla,1))

set_bit(Ppin_X1, pin_X1);

else

clear_bit(Ppin_X1, pin_X1);

if(bit_is_set(tecla,2))

set_bit(Ppin_X2, pin_X2);

else

clear_bit(Ppin_X2, pin_X2);

if(bit_is_set(tecla,3))

set_bit(Ppin_X3,pin_X3);

else

clear_bit(Ppin_X3, pin_X3);

if(bit_is_set(tecla,4))

set_bit(Ppin_X4,pin_X4);

else

clear_bit(Ppin_X4, pin_X4);

}

}

/**

* @brief funcion que inicializa el teclado

Page 71: Manual Micros 2010

*/

void vInitKeyPad(void)

{

//configurando salidas - renglones

set_bit(CPORT_KEY_R1, CPIN_KEY_R1); set_bit(PORT_KEY_R1,PIN_KEY_R1);

set_bit(CPORT_KEY_R2, CPIN_KEY_R2); set_bit(PORT_KEY_R2,PIN_KEY_R2);

set_bit(CPORT_KEY_R3, CPIN_KEY_R3); set_bit(PORT_KEY_R3,PIN_KEY_R3);

set_bit(CPORT_KEY_R4, CPIN_KEY_R4); set_bit(PORT_KEY_R4,PIN_KEY_R4);

//configurando entradas - columnas

clear_bit(CPORT_KEY_C1, CPIN_KEY_C1);

clear_bit(CPORT_KEY_C2, CPIN_KEY_C2);

clear_bit(CPORT_KEY_C3, CPIN_KEY_C3);

clear_bit(CPORT_KEY_C4, CPIN_KEY_C4);

//colocando resistencias de pull up a las columnas

set_bit(PORT_KEY_C1,PIN_KEY_C1);

set_bit(PORT_KEY_C2,PIN_KEY_C2);

set_bit(PORT_KEY_C3,PIN_KEY_C3);

set_bit(PORT_KEY_C4,PIN_KEY_C4);

}

/**

* @brief funcion que permite escanear el teclado y devuelve un valor entre 0 y 16

* dependiendo si se presiona alguna tecla o no

*

* @returns devuelve un tipo char sin signo entre 0 a 16, si no se presiona ninguna

* tecla devuelve 16, si se presiona una tecla regresa un valor de 0 a 15

*

* Ejemplo:

* \verbatim

* tecla=ui8_TestKeyPad();

* \endverbatim

*/

unsigned char ui8_TestKeyPad(void)

{

unsigned char k;

for(k=0; k< 16; k++)

{

switch(k)

{

case 0:

vSetKeyPadR1();

Page 72: Manual Micros 2010

break;

case 4:

vSetKeyPadR2();

break;

case 8:

vSetKeyPadR3();

break;

case 12:

vSetKeyPadR4();

break;

}

if(bit_is_clear(PORT_KEY_C1,PIN_KEY_C1)){return(k);}

k++;

if(bit_is_clear(PORT_KEY_C2,PIN_KEY_C2)){return(k);}

k++;

if(bit_is_clear(PORT_KEY_C3,PIN_KEY_C3)){return(k);}

k++;

if(bit_is_clear(PORT_KEY_C4,PIN_KEY_C4)){return(k);}

}

return (16);

}

Tabla 9: Código de ejemplo de teclado matricial

5.3.2 Display de 7 segmentos

Una de las aplicaciones más populares de los LED’s es la de señalización. Quizás la más utilizada sea la de 7 LED’s colocadas en forma de ocho tal y como se indica en la Ilustración 1. Aunque externamente su forma difiere considerablemente de un diodo LED típico, internamente están constituidos por una serie de diodos LED con unas determinadas conexiones internas. En la Ilustración 1 se indica el esquema eléctrico de las conexiones del interior de un indicador luminoso de 7 segmentos (EPSA, 2001).

Page 73: Manual Micros 2010

La figura 24 muestra un indicador de siete segmentos. Contiene siete LED rectangulares (a - g), en el que cada uno recibe el nombre de segmento porque forma parte del símbolo que está mostrando. Con un indicador de siete segmentos se pueden formar los dígitos del 0 al 9, también las letras a, c, e y f y las letras minúsculas b y d. Los entrenadores de microprocesadores usan a menudo indicadores de siete segmentos para mostrar todos los dígitos del 0 al 9 más a, b, c, d, e y f.

Polarizando los diferentes diodos, se iluminaran los segmentos correspondientes. De esta manera podemos señalizar todos los números en base 10. Por ejemplo, si queremos representar el número de 1 en el display deberemos mandar señal a los diodos b y c, y los otros diodos deben de tener tensión cero. Esto lo podemos escribir así 0110000(0). El primer dígito representa al diodo a, el segundo al b, el tercero al c, y así sucesivamente. Un cero representa que no polarizamos el diodo, es decir no le aplicamos tensión. Un uno representa que el diodo esta polarizado, y por lo tanto, emite luz. Muchas veces aparece un octavo segmento, entre paréntesis en el ejemplo anterior, que funciona como punto decimal.

figura 24: Conexiones display de 7 segmentos

figura 25: Pinout display de 7 segmentos

Page 74: Manual Micros 2010

/**

* @author miguel montiel mtz

* @date 03/03/2013

* @brief Programa que muestra en un display de 7 segmentos

* un numero que sale por el puerto con caracteristica

* de ser flexible en su conexion

*

* Al ser flexible, debe declarar pin a pin y puerto

* a puerto a ser utilizado

* \verbatim

* seg_a --> pin

* seg_b

* seg_c

* seg_d

* seg_e

* seg_f

* seg_g

*

* pseg_a --> Puerto de conexion

* pseg_b

* .

* .

* .

* pseg_g

*

* Del mismo modo se deben declarar los puerto para ser configurados

* como salidas

*

* cseg_a --> bit en el registro DDRx

* cseg_b

* cseg_c

* .

* .

* cseg_g

*

* cpseg_a --> Puerto de conexion

* cpseg_b

* .

* .

* .

* cpseg_g

*\endverbatim

* Si desea utilizar una configuración diferente, solo debe cambiar los

Page 75: Manual Micros 2010

* valores de estas macros indicadas

*

* @file display.c

*/

#include <avr/io.h>

#define clear_bit(sfr,bit) (_SFR_BYTE(sfr) &=~_BV(bit))

#define set_bit(sfr,bit) (_SFR_BYTE(sfr)|=_BV(bit))

#define F_CPU 20000000UL

#include <util/delay.h>

/**

* pines de conexion

*/

#define seg_a PB0

#define seg_b PB1

#define seg_c PB2

#define seg_d PB3

#define seg_e PD0

#define seg_f PD1

#define seg_g PD2

/**

* Puertos de los pines de conexion

*/

#define pseg_a PORTB

#define pseg_b PORTB

#define pseg_c PORTB

#define pseg_d PORTB

#define pseg_e PORTD

#define pseg_f PORTD

#define pseg_g PORTD

/**

* Configuracion de pines y puertos

*/

#define cseg_a DDB0

#define cseg_b DDB1

#define cseg_c DDB2

#define cseg_d DDB3

Page 76: Manual Micros 2010

#define cseg_e DDD0

#define cseg_f DDD1

#define cseg_g DDD2

#define cpseg_a DDRB

#define cpseg_b DDRB

#define cpseg_c DDRB

#define cpseg_d DDRB

#define cpseg_e DDRD

#define cpseg_f DDRD

#define cpseg_g DDRD

void initDisplay(void);

void Print(unsigned char value);

int main(void)

{

unsigned char contador=0;

while(1)

{

for(contador=0;contador <16; contador++)

{

Print(contador);

_delay_ms(500);

}

}

}

/**

* @brief Funcion que permite inicializar el display

*/

void initDisplay(void)

{

set_bit(cpseg_a, cseg_a);

set_bit(cpseg_b, cseg_b);

set_bit(cpseg_c, cseg_c);

set_bit(cpseg_d, cseg_d);

set_bit(cpseg_e, cseg_e);

set_bit(cpseg_f, cseg_f );

set_bit(cpseg_g, cseg_g);

}

/**

Page 77: Manual Micros 2010

* @brief Funcion que permite imprimir hacia el display

* la configuracion de conexion es

* Xgfedcba

*/

void Print(unsigned char value)

{

unsigned char out=0x00;

switch(value)

{

case 0:

out=0x3f;

break;

case 1:

out=0x79;

break;

case 2:

out=0x24;

break;

case 3:

out=0x4f;

break;

case 4:

out=0x66;

break;

case 5:

out=0x6d;

break;

case 6:

out=0x7d;

break;

case 7:

out=0x07;

break;

case 8:

out=0x7f;

break;

case 9:

out=0x6f;

break;

case 10:

out=0x3f;

break;

Page 78: Manual Micros 2010

case 11:

out=0x7a;

break;

case 12:

out=0x53;

break;

case 13:

out=0x7c;

break;

case 14:

out=0x5b;

break;

case 15:

out=0x1b;

break;

}

if(bit_is_set(out,6)) set_bit(pseg_g,seg_g);

else clear_bit(pseg_g,seg_g);

if(bit_is_set(out,5)) set_bit(pseg_f,seg_f);

else clear_bit(pseg_f,seg_f);

if(bit_is_set(out,4)) set_bit(pseg_e,seg_e);

else clear_bit(pseg_e,seg_e);

if(bit_is_set(out,3)) set_bit(pseg_d,seg_d);

else clear_bit(pseg_d,seg_d);

if(bit_is_set(out,2)) set_bit(pseg_c,seg_c);

else clear_bit(pseg_c,seg_c);

if(bit_is_set(out,1)) set_bit(pseg_b,seg_b);

else clear_bit(pseg_b,seg_b);

if(bit_is_set(out,0)) set_bit(pseg_a,seg_a);

else clear_bit(pseg_a,seg_a);

}

Tabla 10: Código de ejemplo para display de siete segmentos

Page 79: Manual Micros 2010

5.3.3 Detectores de proximidad

De acuerdo a la definición que se ofrece en Wikipedia un detector de proximidad es “un transductor que detecta objetos o señales que se encuentran cerca del elemento sensor”.

A continuación se mostrarán dos ejemplos de sensores de proximidad, una basada en ondas infrarrojas y otra basada en ondas ultraónicas.

5.3.3.2 El sensor Infrarrojo modulado en frecuencia

En un detector de rayos infrarrojos, el elemento sensor es un fotodiodo o un foto transistor, a su vez éste elemento se conecta a un dispositivo que amplifica y adapta la señal de salida. En este caso particular, la señal infrarroja se modula en frecuencia y es del tipo reflexión sobre objetos.

En el circuito que se muestra, se basa en el decodificador de tonos el cual, a través de esta configuración, genera una frecuencia determinada por los valores de la resistencia de 10k y el capacitor de 100nF que están conectados entre las terminales 5 y 6, esta frecuencia se aplica para llevar a saturación y corte al transistor 2N2222, el cual a su vez permite generar ráfagas de luz infrarroja a la frecuencia establecida previamente. Por la línea 3 se recibe la frecuencia reflejada sobre un objeto.

5.3.3.3 El Sensor ultrasónico SRF-04

Este dispositivo, permite la medición de distancias a través de ráfagas ultrasónicas emitidas por un microcontrolador, cuando en una de sus terminales denominada Disparo recibe un pulso cuya duración en estado en alto es de 10 milisegundos.

Ilustración 1: modulación en frecuencia para sensor infrarrojo

fuente: (Pablin, 2008)

Page 80: Manual Micros 2010

El SRF-04 devuelve un pulso positivo por medio de la terminal ECO, cuyo ancho de pulso es proporcional al tiempo que dura en ir y venir la ráfaga ultrasónica emitida. Una gráfica de tiempos se propone a continuación (figura 26: Diagrama de funcionamiento de sensor ultrasónico):

El dispositivo cuenta con 5 terminales, dos de ellas, las más importantes ya fueron descritas anteriormente, la figura muestra como primer terminal a la alimentación de este dispositivo, seguida de la terminal de Eco, la cual es una salida, como tercera terminal se tiene al PIN Disparo, el cual se usa para indicar al sensor una petición de medición, la cuarta terminal es de alta impedancia o no conección (en algunos modelos clones esta terminal no está disponible) y finalmente la terminal de tierra. (Veáse la figura 27: Terminales del SRF-04)

El cálculo de la distancia

El SRF-04 proporciona un pulso proporcional a la distancia, esto es, si el ancho del pulso está medido en microsegundos, entonces la división entre 58, entonces el resultado estará en centímetros, o si se divide entre 148, la distancia estará en pulgadas.

Alcance del SRF-04 y forma de la onda

En el sensor ultrasónico SRF-04 tiene un patron de onda de forma cónica y la amplitud de dicha onda depende del área de superficie, la frecuencia y el tipo de transductor que se utiliza, considere que estas

figura 26: Diagrama de funcionamiento de sensor ultrasónico

Fuente: (Devantech Ltd, 2003)

figura 27: Terminales del SRF-04Fuente: (Devantech Ltd, 2003)

Page 81: Manual Micros 2010

formas son fijas, se pone a consideración que las unidades del eje vertical de la figura que se presenta a continuación está en dB. Y que la apertura del cono es de 55°

Debe tomarse en cuenta que para un montaje sobre superficies, el fabricante recomienda una altura mínima de 30cm sobre el nivel de superficie, montajes mas bajos, requieren que el sensor se apunte un poco hacia arriba, a fin de evitar los reflejos del suelo.

5.4 Uso de los puertos para manejo de potencia con interfaces con:

5.4.1 Transistores, Darlingtons, MOSFETS y relevadores

Muchas veces se presenta la difícil situación de manejar corrientes o tensiones más grandes que las que entrega un circuito digital, y entonces nos disponemos al uso de transistores, el tema es hacer que estos trabajen en modo corte y saturación sin estados intermedios, es decir que cambien su estado de plena conducción a un profundo corte, y eso es lo que veremos en este pequeño tutorial.

Los transistores a utilizar en estos casos deben tener la suficiente ganancia para que la onda cuadrada, aplicada en su entrada (Base), no sufra ninguna deformación en la salida (Colector o Emisor), o sea que conserve perfecta simetría y sus flancos ascendente y descendente se mantengan bien verticales.

La corriente máxima que puede circular de colector a emisor está limitada por la tensión de polarización de Base y el Resistor o la carga del colector.

Polarización de un transistor NPN como Emisor Común

En este caso el emisor está conectado a masa, se dice que este terminal es común a la señal de base y de colector. El utilizado en este caso un BC547 y estos son algunos de sus datos:

• Tensión Base-Colector (VCBO) = 50 V

• Corriente de Colector (Ic) = 100mA = 0,1A

figura 28: rango de detección

Page 82: Manual Micros 2010

figura 29: Transistor inversor

Cuando la base de Q1 se polariza positivamente, éste conduce la máxima corriente, que le permite Rc.

Rc es la resistencia de carga, que bien podría ser un LED, un relé, etc.

Ic = E/R = 12V / 2200 = 0,0054 = 5,4 mA

Ib = E/R = 12V / 10000 = 0,0012 = 1,2 mA

Es decir la corriente total Colector-Emisor es 6,6mA.

Conexión como seguidor emisivo:

En esta situación se toma la señal de salida desde el Emisor donde se encuentra la Resistencia de carga, observa que este esquema comparado al anterior tiene la misma fase de salida que la de entrada.

figura 30: seguidor emisivo

También hay casos en que necesitas que el transistor esté conduciendo permanentemente (estado de saturación) y que pase al corte ante la presencia de un pulso eléctrico, esto sería lo inverso de lo visto anteriormente, para lograr esto, los circuitos anteriores quedan como están y sólo se reemplazan los transistores por los complementarios, o sea donde hay un NPN se conecta un PNP.

Cuando la señal es negativa

En ocasiones se da el caso en que las señales lógicas recibidas son negativas o de nivel bajo, para entonces se puede utilizar un transistor PNP, por ejemplo: el BC557, que es complementario del BC547, para conseguir los mismos resultados. En la siguiente figura se representa esta condición, es decir, un acoplamiento con transistor PNP.

Page 83: Manual Micros 2010

figura 31: Acoplamiento con transistor PNP

Análisis para la conexión de un RELE

El diodo en paralelo con la bobina del relé cumple la función de absorber las tensiones que se generan en todos los circuitos inductivos.

Si la bobina del relé tiene 50 ohm de resistencia y funciona a 12 V, puedes calcular el consumo de corriente que tiene el relé, para así saber que transistor utilizar:

Ic = E/R = 12V / 50 = 0,24 = 240 mA

figura 32: Conexión básica de relevador

Con este resultado no se puede utilizar el BC547, cuya corriente máxima es de 100mA, pero si lo puede hacer un BC337, es conveniente no superar el 50% de la corriente que entregan los transistores.

Ahora bien, si la señal que se aplique a la base del transistor tiene la suficiente amplitud (tensión) y suficiente intensidad (Amper), no habrá dificultad y la corriente de base también será suficiente para

saturar el transistor, que conmutará en forma efectiva el relé.

Montajes Darlington:

En esta conexión se utiliza un BC337 (NPN) el cual si soporta los 240mA que se necesitaba anteriormente, pero además un transistor de baja potencia como el BC547 (NPN).

En este tipo de montajes, hay que lograr previamente una ganancia en corriente y esta corriente aplicarla a la base del BC337, esta es la finalidad del montaje en Darlington.

Page 84: Manual Micros 2010

figura 33: Montaje Darlington

En este circuito el Transistor BC337 es el que recibe la carga del relé y el BC547 solamente soporta la corriente de base del BC337, además la ganancia se multiplica sin cargar la salida del componente que entrega la señal, ya que ahora la corriente que drena el 547 es tomada de la misma fuente y aplicada a la base del 337. De este modo la resistencia de base del 547 puede ser elevada ya que necesitamos una corriente mucho menor en la misma.

En el siguiente gráfico se describe como lograr la conmutación de un relé con un transistor de salida NPN. incluso utilizando tensiones diferentes.

figura 34: Doble transistor de activación

En esta situación como vemos es necesario agregar un transistor de baja potencia, ya que la corriene que debe manejar es la de base. Con la entrada en "1": El BC547 conduce y envía a masa la base del BC337 de este modo se mantiene el corte.

Con la entrada en "0": El 547 pasa al corte y su colector queda "abierto", ahora sí se polariza la base del 337 y conmutando el relé.

Otro caso de conmutación con diferentes tensiones.

Suponiendo que el consumo de un relé sea 200mA.

Para los cálculos de polarización siempre se debe tomar el menor Beta-B-(hfe) que indiquen los manuales de los transistores, o sea que si dice 100 a 300, tomamos 100. Veamos que corriente de base se necesita de acuerdo a estos datos:

Ib = Ic / Hfe = 200mA / 100 = 2mA

Donde:

Page 85: Manual Micros 2010

• Ib = Intensidad de Base (en mA) • Ic = Intensidad de Colector • Hfe = Ganancia

figura 35: Cálculo de conexión a Relevador

Ahora veamos que valor de resistencia de base es necesario para lograr 2mA con una fuente de 5V, que es la salida que entrega el separador del ejemplo

R = E / I = 5V / 0,002A = 2500 ohm (un valor normalizado es 2k2)

MOSFET

Los MOSFET, o transistores de efecto de campo metal-óxido (por sus siglas en inglés), tienen características que los hacen útiles para alternar los dispositivos electrónicos en apagados o encendidos. El dispositivo consume muy poca corriente por sí mismo, normalmente debajo de 1 microamperio, mientras que puede controlar decenas de amperios de corriente. Un canal N, un MOSFET en modo de mejoramiento alternará un dispositivo a encendido cuando tenga un voltaje de más de unos cuantos voltios a través de sus patas de fuente y compuerta. Cuando su voltaje está en ceros, el MOSFET se apaga. Puedes fácilmente arreglar esto con unos cuantos dólares en piezas.

Polarización del transistor MOSFET

En la figura , la corriente de saturación del drenador en el circuito mostrado es:

I D (sat)=V DD

RD

Y la tensión de corte de drenador es VDD. La figura muestra la recta de carga para DC entre una corriente de saturación de ID(sat) y una tensión de corte VDD.

Cuando VGS = 0, el punto Q está en el extremo inferior de la recta de carga para continua indicando corte. Cuando VGS = VGS (on) el punto Q está en el extremo superior de la recta de carga, indicando saturación.

Page 86: Manual Micros 2010

Cuando la corriente de saturación es menor que la ID(on) el dispositivo está polarizado en una zona óhmica, es decir, un MOSFET de enriquecimiento está polarizado en la zona óhmica cuando se satisface la condición:

I D (sat)< I D(on) cuando V GS=V GS (on )

Si la condición anterior se cumple, entonces el MOSFET en saturación, se comporta como una pequeña resistencia equivalente, la cual se lee en las hojas de datos como RDS(ON).

Considere el siguiente ejemplo: Un transistor MOSFET, que se encuentra conectado como se indica en la figura , el cual cuenta con las siguientes características :

VGS(on) 4,5V

ID(on) 75 mA

RDS(on) 6 Ω

Solución:

figura 36: circuito saturaciónfigura 37: curva característica

figura 38: Saturación de un MOSFET

Page 87: Manual Micros 2010

La corriente de saturación para este circuito es:

I D (sat)=20V1k Ω

=20mA

De la operación anterior se puede ver claramente que ID(on) > ID(sat), por lo tanto, en saturación, el MOSFET se comportará como una resistencia pequeña, siendo así, entonces que los circuitos equivalentes serán:

5.4.2 Optotransistores, optoacopladores y optotriacs

Los Optoacopladores u Optoaisladores son dispositivos que podemos encontrar en múltiples aplicaciones dentro de un equipo electrónico, cuando una señal debe ser transmitida desde un circuito específico a otro, sin que exista conexión eléctrica entre ambos. A pesar de ser un elemento muy utilizado, encierra muchos misterios en su interior y estas incógnitas se profundizan cuando su funcionamiento correcto se pone en duda. ¿Se pueden controlar?¿Cómo sabemos si funcionan correctamente? Por lo general, la transmisión de la información dentro de un Optoacoplador se realiza desde un LED infrarrojo que no responde, en las mediciones con el multimetro, a lo que conocemos como un LED tradicional. ¿Qué podemos hacer entonces? Veamos si en este artículo podemos encontrar las respuestas que necesitamos.

La evolución de los semiconductores en el mundo electrónico encontró en los optoacopladores al reemplazo ideal para dejar de lado al relé (o relay) y al transformador, en especial en aplicaciones digitales, donde la velocidad de transferencia y la conservación de la forma de onda debía ser tan fiel como fuera posible en la salida, reflejando en forma idéntica al formato que presentaba en la entrada. En el caso del relé, la transferencia de una señal analógica es imposible, del mismo modo que sucede con los transformadores a determinadas frecuencias y con formas de onda “especiales”. El optoacoplador fue la solución empleada en múltiples aplicaciones que requerían importantes cambios de niveles de tensión entre los circuitos enlazados, donde se requería aislación de determinado tipo de ruidos en la transmisión de datos; o en espacios industriales, donde se pudiera (o pudiese) controlar mediante un impulso lógico, de baja tensión, una carga con elevados consumos en corriente alterna. Básicamente, si pudiéramos resumirlo en una frase, podría ser “la solución de baja potencia a la

figura 39: Circuito equivalente en saturación

figura 40: Circuito equivalente en corte

Page 88: Manual Micros 2010

activación aislada galvánicamente de cargas, mediante un sistema de control”

A pesar de que un optoacoplador o “acoplador de señales eléctricas mediante un enlace óptico” puede tomar formatos físicos muy variados, su arquitectura es siempre reiterada en el concepto fundamental. Por un lado, se utiliza para transmitir la información un diodo LED infrarrojo, construido a base de un compuesto de Arseniuro de Galio, que se enlaza en forma óptica con un detector encargado de capturar esa información luminosa y transformarla en una señal eléctrica idéntica, en su composición de niveles, a la que el LED emite. Luego, la naturaleza de este detector nos brindará una respuesta acorde al tipo de señal aplicada al LED y a la función específica para la que fue construido ese detector que trae consigo el optoacoplador.

Por ejemplo, si el elemento receptor (o detector) es un fototransistor, podremos utilizar el dispositivo para transferir señales analógicas como puede ser audio o video. Si en cambio es otro fotodiodo, o un foto-SCR, nos será útil como “rectificador controlado y aislado eléctricamente”. De este modo, los detectores se multiplican en formatos y tipo de aplicación, como puede ser un Triac (para trabajar con corrientes alternas) y hasta podemos encontrar puertas lógicas, como detectores dentro de un optoacoplador. Lo que siempre conservará su naturaleza es el elemento transmisor o emisor; siempre será un diodo (o un conjunto de ellos) LED infrarrojo.

figura 41: Ejemplos de optoacopladores

figura 42: Optoacoplador de herradura

figura 43: Optoacoplador de reflexión

Page 89: Manual Micros 2010

Otro tema muy importante es la gran variedad de encapsulados que encontraremos delante de nuestros ojos y aunque no lo creamos posible, será un optoacoplador. Por ejemplo, uno muy popular dentro del mundo de los robots “sigue-líneas” es el CNY70, que trabaja por reflexión. Otro tipo de acoplador óptico muy popular es el que trae una forma de “U” y su activación se basa, ya no en un reflejo, sino en una interrupción de un haz detectado en forma permanente (en el tercer video hacemos un ensayo con uno). El extremo más conocido y “familiar”, es el que viene en el mismo tipo de encapsulado que un circuito integrado tradicional, pero con menor cantidad de pines por lado. Es decir, notarás que traen dos o tres pines por lado y eso, además de llamarte la atención, te estará indicando que estás (99%) frente a un optoacoplador. De todos modos, estos últimos ofrecen una presentación múltiple en un mismo encapsulado y su aspecto es el de un circuito integrado clásico con presentaciones de hasta 8 pines por lado (4 optoacopladores individuales en un mismo encapsulado).

Cómo verificar el funcionamiento

No te preocupes, no te sientas como un marciano si te invade la duda de su accionar adecuado y no sabes por dónde comenzar a medir; ni qué parámetros controlar y mucho menos cómo hacerlo. La comprobación de funcionamiento de este tipo de dispositivos no es sencilla. Seamos sinceros y realistas desde el comienzo: indefectiblemente (no tienes opción) debes retirarlo del lugar de trabajo donde se encuentre para realizar algunas pruebas que no son complejas, que en muy corto tiempo la puedes realizar y los materiales necesarios para llevarlas a cabo son muy básicos, muy elementales. Todo esto vale si deseas hacer un trabajo apropiado, claro está. El primero que debemos hacer a un optoacoplador es, por lógica, inspeccionarlo físicamente. Observarlo y verificar que su estructura esté correcta sin demostraciones de quemazón o quebraduras en su estructura física. En el caso de los que se encuentran en encapsulado tipo circuito integrado, suelen “quebrarse” al explotar y eso facilita mucho el diagnóstico. Sin embargo, cuando su aspecto es óptimo debemos comenzar con la medición estática más elemental que podemos hacer: mediante el uso del multímetro (en posición para medir diodos si es digital, en R X 1 si es analógico) buscar entre los pines hasta encontrar el LED. Recuerda: NO es un LED convencional por lo tanto, el valor obtenido en la medición podrá resultarte algo extraño.

Una vez descubierto y comprobado el LED, podemos pasar a hacer otro tipo de mediciones que puedan ayudarnos a incrementar la seguridad de un buen funcionamiento; esto es, que la información introducida en el LED se pueda recuperar en el detector. Para esto, necesitaremos dos multímetros y algunos cables con pinzas caimanes o “cocodrilo” en sus extremos, para apoyarnos físicamente en el trabajo, porque mantener cuatro puntas de medición con sólo dos manos suele ser algo complicado de hacer. Por lo tanto, un par de cables y algunos pines de resistencias cortados pueden ser de gran ayuda. Una vez identificado el LED, ya tenemos la posibilidad de activar el emisor, por lo tanto, la búsqueda con el segundo instrumento estará orientada a comprobar el funcionamiento del elemento receptor o el detector que recibe el haz infrarrojo.

figura 44: Empaquetados de optoacopladores

Page 90: Manual Micros 2010

Desde que conozco a los optoacopladores, el método mostrado hasta aquí es, por lo general, suficiente como para detectar el buen funcionamiento de este dispositivo sin necesidad de recurrir a buscar en la web la hoja de datos del elemento que estamos ensayando. Sin embargo, no ha faltado el diablo a la cita en varias ocasiones y a pesar de encontrar estas mediciones correctas, el optoacoplador no funcionaba en su lugar de trabajo, en la aplicación. Afuera las mediciones eran óptimas, mientras que en circuito, bajo condiciones de trabajo, el dispositivo no funcionaba de manera correcta. Si lo analizamos en forma detenida, puede existir una fuga de corriente desde el emisor hacia el detector y los resultados “parecen” ser los correctos, sin embargo, la aislación a ambos lados de los elementos que componen el optoacoplador no se cumple como debería ser. Por lo tanto, a las mediciones efectuadas, deberíamos agregarle un método dinámico de ensayo, con tensión de trabajo que nos permita comprobar los elementos, a la vez que también nos demuestre que la aislación está presente entre los elementos.

Avancemos hacia el método dinámico

En este punto te preguntarás los motivos por los cuales no cambiamos directamente esta “piedra en el zapato” que cuesta unas pocas monedas, antes de perder tanto tiempo en ensayos, sin embargo, cuando descubres que no tienes uno nuevo para reemplazarlo (ni lo conseguirás en varios días), estarás de acuerdo en que sigamos hacia el ensayo dinámico. Para realizar este trabajo, debemos ante todo, saber con qué elemento estamos trabajando, conocer su nomenclatura y por supuesto (ahora sí) tener acceso a su hoja de datos. Para esto último, existen muchos espacios en la web donde encontrar la información necesaria que nos permitirá conocer la arquitectura interna del componente con el que estamos trabajando, al que intentamos hacerle los controles sanitarios, para saber si goza de buena salud. Si no tenemos un espacio de preferencia donde encontrar este tipo de información, bastará con escribir la nomenclatura en cualquier buscador web y apuntar nuestra lectura hacia los archivos PDF que siempre aparecen. Una vez que tenemos ese resultado, podemos saber de qué manera ensayar nuestro optoacoplador.

Durante la primera etapa del ensayo, lo más importante dentro de la hoja de datos será descubrir las

figura 45: Características mecánicas de empaquetados

Page 91: Manual Micros 2010

características funcionales del LED y no confundirnos entre los valores máximos y absolutos que puede soportar el dispositivo, respecto a los óptimos que se pueden utilizar para un funcionamiento adecuado y seguro, garantizando una larga vida útil. Y como por algún lado debemos comenzar, vamos a hacerlo con uno de los optoacopladores más populares, económicos y “adoptados” por la industria electrónica (De nada sirve, durante el aprendizaje, hablar de componentes que verás solo una vez en tu vida). Por lo tanto, veamos algunas particularidades que debemos tener en cuenta al momento de leer la hoja de datos de un PC817: un optoacoplador analógico clásico, con un fotodiodo infrarrojo (emisor) y un fototransistor (detector) que nos ofrece en su salida los pines Colector-Emisor, para tomar allí “en forma aislada y proporcional”, las variaciones de intensidad luminosa que entregue el LED infrarojo.

Como mencionamos antes, los valores máximos absolutos del PC817 hablan de una corriente de LED en forma directa (Forward Current) de 50mA, sin embargo, trabajando a ese régimen el optoacoplador puede durar unos pocos minutos, antes de calcinarse. Insistamos en este concepto: “eso es el máximo absoluto, no el valor seguro de trabajo”. Para saber cuál es esta “corriente segura de trabajo” tenemos dos métodos: uno es observando las curvas presentes en las hojas de datos que nos muestren los valores usuales dentro del “Área de Operación Segura” (SOA, Security Operation Area). En el gráfico mostrado abajo (derecha), es el área que se encuentra debajo de la línea de puntos. Para ejemplo, podemos observar que con una corriente de LED de 5mA, 10mA (y un poco más también) podemos trabajar sin problemas en todo el rango de tensiones (entre colector y emisor) que permite aprovechar el fototransistor del PC817. Observa que si lo haces trabajar con una corriente de LED de 20mA no podrás llegar a emplear valores de tensión de 6Volts en el fototransistor. Hasta podríamos decir que trabajar con 5Volts sería estar muy cerca de la zona “no segura”

5.4.3 Puentes H discretos e Integrados.

Debido a la pequeña potencia que suministran los microcontroladores, sólo podemos hacer funcionar directamente unos LED y poco más. Por este motivo es necesario amplificar las salidas en función de las cargas que vayamos a controlar. Un método sencillo y económico es emplear el integrado ULN2003A, que es un conjunto de Darlington (darlington array) montados en un chip con el que podemos controlar cargas de hasta medio amper.. El chip lleva diodos de protección contra las sobretensiones producidas por cargas inductivas. Esto lo hace ideal para gobernar relés (Chavarrea & Chiluisa, 2013).

El L293D son cuádruples de alta corriente conductores de media -H. ElL293 está diseñado para proporcionar corrientes de excitación bidireccional de hasta 1 A con tensiones desde 4,5 V a 36 V. El L293D está diseñado para proporcionar corrientes de excitación bidireccional dehasta600 mA a voltajes

figura 46: pinout del ULN2803

Page 92: Manual Micros 2010

de 4,5 V a 36 V. Ambos dispositivos están diseñados para manejar cargas inductivas, como relés, solenoides, dc y motores bipolares paso a paso, así como otros high-current/highvoltageCargas en aplicaciones de alimentación positiva.

Todas las entradas están TTL compatible. Cada salida es un circuito duro tótem completo, con un transistor Darlington y una fuente de pseudo- Darlington. Los conductores están habilitadas en parejas, con los conductores 1 y 2 habilitadas por 1,2 EN y conductores 3 y 4 habilitadas por 3,4 E-S Cuando una entrada de habilitación es alta, los controladores asociados están habilitados y su salidas están activos y en fase con sus entradas. Cuando la entrada habilitada es bajo, los conductores son personas con discapacidad y sus salidas están apagados y en el estado de alta impedancia. Con las entradas de datos adecuadas, cada par de conductores formas a- H completa (o puente) de accionamiento reversible adecuado para solenoide o motor aplicaciones.

5.5 Ejemplo del uso de las interfaces para controlar:

5.5.1 Motores de DC

Elaborar un circuito que permita controlar un motor de corriente directa de 12V usando una interface de potencia L293D, programando un microcontrolador ATmega48 el cual contiene tres entradas y tres salidas, además considera el siguiente funcionamiento:

• Inicialmente el motor debe estar detenido. start = stop = 1; I_nD = X.

• El motor se mueve si se presiona el botón start = 0 y el botón I_nD = 1 a la izquierda.

• El motor se mueve si se presiona el botón start = 0 y el botón I_nD = 0 a la derecha.

• Para los casos anteriores al dejar de pulsar start el motor se mantiene girando en el sentido indicado por I_nD.

• El motor se detiene si el botón de stop es presionado y se mantiene así aún después de soltarlo. O si el botón de stop se mantiene presionado, no importan los estados de start o de I_nD, el motor permanece detenido (Biblioman, 2013).

Los pines se asignarán a las siguientes terminales:

Id Descripción Puerto Tipo

start Botón de inicio PINC1 Entrada

stop Botón de paro PINC2 Entrada

figura 47: Pinout del L293

Page 93: Manual Micros 2010

I_nD Botón de sentido PINB0 Entrada

a Salida hacia L293 PD0 Salida

b Salida hacia L293 PD1 Salida

En Salida de hablitación de L293 PD2 Salida

Resolución: Primero se debe plantear el diagrama de estados en función de la descripción del problema. En este caso, utilizaremos el software Qfsm (http://qfsm.sourceforge.net). Sin embargo es necesario dar formatos de entradas y salidas, ya que en este software las entradas se definirán como valores binarios.

Formato para entradas Formato para salidas

start stop I_nD a b En

1 1 1 0 0 0

Los números que están sobre las flechas indican las señales de entrada que provienen de start,stop e I_nD, y los números que están dentro de los estados, corresponden a las salidas a,b,En.

Agregar que el estado final indicado es el estado Detenido, es por esa causa que en el diagrama de estaos, se encuentra señalado con doble anillo.

El software permite generar entre otros códigos HDL , el de AHDL, que por su sintáxis es muy similar al lenguaje C. En el cuadro que a continuación se presenta, se indica el código fuente generado.

figura 48: Diagrama de estados propuesto

Izquierda

011

Derecha

101

Detenido

000

101

100

110

111

010

011

100

111 011

010

110

101

110010

111

011

rst_n

Page 94: Manual Micros 2010

% This file was generated by %

% Qfsm Version 0.52 %

% (C) Stefan Duffner, Rainer Strobel %

SUBDESIGN Motor

(clock, reset :INPUT;

start,stop,I_nD :INPUT;

:OUTPUT;

a,b,En :OUTPUT;)

VARIABLE

fsm : MACHINE OF BITS(s0, s1)

WITH STATES (

Detenido = B"00",

Derecha = B"01",

Izquierda = B"10");

reset_async : NODE;

_asynca, _asyncb, _asyncEn : NODE;

BEGIN

reset_sync = DFF(reset,clock,VCC,VCC);

fsm.reset = reset_sync;

fsm.clk = clock;

a = DFF(a_async,clock,VCC,VCC);

b = DFF(b_async,clock,VCC,VCC);

En = DFF(En_async,clock,VCC,VCC);

CASE fsm IS

WHEN Detenido =>

IF (start,stop,I_nD) == B"101" THEN

END IF;

IF (start,stop,I_nD) == B"100" THEN

END IF;

IF (start,stop,I_nD) == B"110" THEN

END IF;

IF (start,stop,I_nD) == B"111" THEN

END IF;

IF (start,stop,I_nD) == B"010" THEN

fsm = Derecha;

(_asynca, _asyncb, _asyncEn) = B"101";

END IF;

IF (start,stop,I_nD) == B"011" THEN

Page 95: Manual Micros 2010

fsm = Izquierda;

(_asynca, _asyncb, _asyncEn) = B"011";

END IF;

WHEN Derecha =>

IF (start,stop,I_nD) == B"100" THEN

fsm = Detenido;

(_asynca, _asyncb, _asyncEn) = B"000";

END IF;

IF (start,stop,I_nD) == B"111" THEN

fsm = Izquierda;

(_asynca, _asyncb, _asyncEn) = B"011";

END IF;

IF (start,stop,I_nD) == B"011" THEN

fsm = Izquierda;

(_asynca, _asyncb, _asyncEn) = B"011";

END IF;

IF (start,stop,I_nD) == B"010" THEN

END IF;

IF (start,stop,I_nD) == B"110" THEN

END IF;

WHEN Izquierda =>

IF (start,stop,I_nD) == B"101" THEN

fsm = Detenido;

(_asynca, _asyncb, _asyncEn) = B"000";

END IF;

IF (start,stop,I_nD) == B"110" THEN

fsm = Derecha;

(_asynca, _asyncb, _asyncEn) = B"101";

END IF;

IF (start,stop,I_nD) == B"010" THEN

fsm = Derecha;

(_asynca, _asyncb, _asyncEn) = B"101";

END IF;

IF (start,stop,I_nD) == B"111" THEN

END IF;

IF (start,stop,I_nD) == B"011" THEN

END IF;

END CASE;

END;

Tabla 11: Código de AHDL para control por FSM

Del código, solo se tomarán los if dentro de cada case, en donde exista una indicación de cambio de

Page 96: Manual Micros 2010

estado para traducirlo al lenguaje C, por ejemplo

IF (start,stop,I_nD) == B"011" THEN

fsm = Izquierda;

(_asynca, _asyncb, _asyncEn) = B"011";

END IF;

Estas líneas se traducen a C

IF (start,stop,I_nD) == B"111" THEN

END IF;Estas líneas se ignoran

Para pasar al lenguaje C, son declarados como #define los estados y se les asigna un valor, y se agrega además una variable denominada ESTADO, la cual almacenará de forma temporal el estado actual.

En el cuadro siguiente, se muestra el cuadro donde se expone el código C traducido a partir del código AHDL generado por el software Qfsm.

Page 97: Manual Micros 2010

#include <avr/io.h>

#define F_CPU 1000000UL

#include <util/delay.h>

/*Definición de macros para set y reset de bits*/

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=(_BV(bit)))

#define clearbit(sfr,bit) (_SFR_BYTE(sfr)&=~(_BV(bit)))

/*Definicion de entradas y salidas*/

#define start PINC1

#define pstart PINC

#define rpstart PORTC

#define stop PINC2

#define pstop PINC

#define rpstop PORTC

#define I_nD PINB0

#define pI_nD PINB

#define rpI_nD PORTB

#define a PD0

#define Pa PORTD

#define b PD1

#define Pb PORTD

#define En PD2

#define pEn PORTD

/*Defincion para configuraciòn de entradas y salidas*/

#define cstart DDC1

#define cpstart DDRC

#define cstop DDC2

#define cpstop DDRC

#define cI_nD DDB0

#define cpI_nD DDRB

#define ca DDD0

#define cPa DDRD

#define cb DDD1

#define cPb DDRD

#define cEn DDD2

#define cpEn DDRD

/*Definicion de estados*/

#define DETENIDO 0

Page 98: Manual Micros 2010

#define DERECHA 1

#define IZQUIERDA 2

int main(void)

{

/*Creación del estado inicial*/

unsigned char ESTADO=DETENIDO;

/*configurar entradas*/

clearbit(cpstart,cstart);

clearbit(cpstop,cstop);

clearbit(cpI_nD,cI_nD);

/*configurar resistencia pull-up*/

setbit(rpstart,start);

setbit(rpstop,stop);

setbit(rpI_nD,I_nD);

/*configurar salidas*/

setbit(cPa,ca);

setbit(cPb,cb);

setbit(cpEn,cEn);

/*Condiciones iniciales*/

clearbit(Pa,a);

clearbit(Pb,b);

clearbit(pEn,En);

while(1)

{

switch(ESTADO)

{

case DETENIDO:

{

if(bit_is_clear(pstart,start) && bit_is_set(pstop,stop) && bit_is_clear(pI_nD,I_nD))

{

ESTADO = DERECHA;

setbit(Pa,a);

clearbit(Pb,b);

setbit(pEn,En);

}

Page 99: Manual Micros 2010

if(bit_is_clear(pstart,start) && bit_is_set(pstop,stop) && bit_is_set(pI_nD,I_nD))

{

ESTADO = IZQUIERDA;

clearbit(Pa,a);

setbit(Pb,b);

setbit(pEn,En);

}

break;

}

case DERECHA:

{

if(bit_is_set(pstart,start) && bit_is_clear(pstop,stop) && bit_is_clear(pI_nD,I_nD))

{

ESTADO = DETENIDO;

clearbit(Pa,a);

clearbit(Pb,b);

clearbit(pEn,En);

}

if(bit_is_set(pstart,start) && bit_is_set(pstop,stop) && bit_is_set(pI_nD,I_nD))

{

ESTADO = IZQUIERDA;

clearbit(Pa,a);

setbit(Pb,b);

setbit(pEn,En);

}

if(bit_is_clear(pstart,start) && bit_is_set(pstop,stop) && bit_is_set(pI_nD,I_nD))

{

ESTADO = IZQUIERDA;

clearbit(Pa,a);

setbit(Pb,b);

setbit(pEn,En);

}

break;

}

case IZQUIERDA:

{

if(bit_is_set(pstart,start) && bit_is_clear(pstop,stop) && bit_is_set(pI_nD,I_nD))

{

ESTADO = DETENIDO;

clearbit(Pa,a);

Page 100: Manual Micros 2010

clearbit(Pb,b);

clearbit(pEn,En);

}

if(bit_is_set(pstart,start) && bit_is_set(pstop,stop) && bit_is_clear(pI_nD,I_nD))

{

ESTADO = DERECHA;

setbit(Pa,a);

clearbit(Pb,b);

setbit(pEn,En);

}

if(bit_is_clear(pstart,start) && bit_is_set(pstop,stop) && bit_is_clear(pI_nD,I_nD))

{

ESTADO = DERECHA;

setbit(Pa,a);

clearbit(Pb,b);

setbit(pEn,En);

}

break;

}

default: break;

}

}

}

Tabla 12: Código para control por FSM

Finalmente se presenta el esquema que muestra las conexiones del circuito

a

Page 101: Manual Micros 2010

5.5.2 Motores a pasos

Las notas siguientes salen del documento expuesto por la Facultad de Ingeniería (UNLP, 2010).

¿Qué es un motor a pasos?

Es un actuador electromagnético rotatorio que convierten mecánicamente entradas de pulsos digitales a movimiento rotatorio incremental de la flecha .

La rotación no solo tiene una relación directa al número de pulsos de entrada , sino que la velocidad está relacionada a la frecuencia de los pulsos.

Existen tres tipos de motores a pasos, los de reluctancia variable, los de imán permanente y los híbridos.

Los cuales se clasifican como motores bipolares y unipolares, de acuerdo a su tipo de conexión.

Los motores unipolares, suelen tener 5 o 6 cables de salida.

figura 49: circuito estados lógicos

Page 102: Manual Micros 2010

Un motor bipolar por otra parte cuenta con solo 4 hilos de conexión y requiere de inversión de fase para su adecuado funcionamiento.

Control por medio de los circuito L297 y L298

Desarrollar el accionamiento de un motor a pasos, mediante el circuito de control L297, que realiza las funciones de generador de fases y troceado de la corriente que circula por los devanados y el driver de potencia L298. Se recomienda ampliamente la lectura de las siguientes notas de aplicación:

• AN280. “Controlling Voltaje transient in full bridge drives applications”

• AN468. “Constant-current chopper driver ups stepper motor performance”

• AN470. “The L297 stepper motor controller”

figura 50: motor a pasos unipolar

figura 51: Motor a pasos bipolar

Page 103: Manual Micros 2010

5.5.3 Servomotores

Las notas presentes pueden encontrarse en la página web del autor (Carletti, 2007).

En primer lugar quiero aclarar que, si bien hoy se utiliza ampliamente la palabra abreviada "servo", la verdadera denominación de lo que voy a describir aquí es "servomotor". Existen otra clase de servos (o mejor expresado, servomecanismos) que no son precisamente motores. También hay servos no rotativos.

Por ejemplo, los sistemas que poseen cilindros hidráulicos pueden ser servocontrolados. Estos cilindros hidráulicos o neumáticos, en su versión más simple, se mueven de extremo a extremo. Pero no siempre es así. En muchos casos es necesario que posean realimentación, lo que les permite ubicarse con precisión en cualquier lugar de su recorrido. Para esto se utilizan sensores de recorrido lineales, como potenciómetros lineales, sistemas ópticos o unos dispositivos llamados LDVT.

De modo que, aclaremos, un actuador mecánico controlado no siempre debe ser rotativo, aunque la mayoría de las veces así es.

Definamos, ahora:

Un servomotor es un motor eléctrico que consta con la capacidad de ser controlado, tanto en velocidad como en posición.

Un servomecanismo es un actuador mecánico —generalmente un motor, aunque no exclusivamente—, que posee los suficientes elementos de control como para que se puedan monitorizar los parámetros de su actuación mecánica, como su posición, velocidad, torque, etc.

En realidad se utilizan muchos otros tipos de servos (o servomotores, mejor) en equipos industriales y comerciales, desde una diskettera en nuestra computadora —o en la videocassettera hogareña—, a las unidades de almacenaje y entrada y salida de datos de grandes sistemas de computación (hoy, más que nada, discos magnéticos), y hasta en los ascensores en edificios. El motor de un ascensor, junto con su equipo de control y detectores de posicionamiento, no es ni más ni menos que un servomotor. El mecanismo que saca para afuera el porta-CD de la lectora de CD de su computadora es un servomotor.

¿Qué convierte un motor en servomotor? O mejor dicho ¿por qué se considera que algunos motores son servomotores y otros no? La respuesta no es demasiado complicada: un servomotor tiene integrado o adosado al menos un detector que permita conocer su posicionamiento y/o velocidad. A los detectores de posición se les llama "encoders".

Aclarado esto, pasaré a esos servos a los que se refieren en los sitios que dije antes. Hablo de los servos para radiocontrol de modelos, como los de marca Futaba, Hitec, etc. Se trata de elementos para control de posición de alerones, timón, dirección (en autos), alimentación de combustible, etc, para modelos a escala, que se han vuelto populares en robótica porque entre los disponibles en el comercio hay algunos bastante económicos, lo que los hace de más fácil acceso cuando se trata de la construcción de proyectos personales de robótica y automatización casera.

De estos servos de modelismo, comencemos con los servos que se conocen como "analógicos".

Servo analógico para modelismo

Estos servomotores se componen, en esencia, de un motor de corriente continua, un juego de

figura 52: Servomotor DC aeromodelismo

Page 104: Manual Micros 2010

engranajes para la reducción de velocidad, un potenciómetro ubicado sobre el eje de salida (que se usa para conocer la posición) y una plaqueta de circuito para el control.

Como una imagen vale más que mil palabras, veamos un despiece.

figura 53: Desensamble de un servo

Si lo que se desea controlar es la posición de un servomecanismo, como en este caso, en lugar de un tacómetro (que es para medir velocidad) necesitamos un encoder de posición. Si hablamos de un servo cuyo movimiento es giratorio, será necesario un encoder (un detector que codifica la posición) que nos dé un valor diferente a su salida según cual sea su posición en grados.

Los servos que se usan en modelismo son de este tipo. Como dije antes, por lo general poseen un motor de CC, que gira a velocidad alta, una serie de engranajes para producir la reducción de velocidad de giro y acrecentar su capacidad de torque, un potenciómetro conectado al eje de salida (que es ni más ni menos que el encoder) y un circuito de control de la realimentación.

Estos servos reciben señal por tres cables: alimentación para el motor y la pequeña plaqueta de circuito del control (a través de dos cables, positivo y negativo/masa), y una señal controladora que determina la posición que se requiere. La alimentación de estos servos es, normalmente, de entre 4,8 y 6 voltios.

El estándar de esta señal controladora para todos los servos de este tipo, elegido para facilitar el uso en radiocontrol, es un pulso de onda cuadrada de 1,5 milisegundos que se repite a un ritmo de entre 10 a 22 ms. Mientras el pulso se mantenga en ese ancho, el servo se ubicará en la posición central de su recorrido. Si el ancho de pulso disminuye, el servo se mueve de manera proporcional hacia un lado. Si el ancho de pulso aumenta, el servo gira hacia el otro lado. Generalmente el rango de giro de un servo de éstos cubre entre 90° y 180° de la circunferencia total, o un poco más, según la marca y modelo.

figura 54: Cables de un servo estándar

Page 105: Manual Micros 2010

figura 55: Señales y posiciones de un servo

Práctica propuesta

Elaborar un contador que se desborde al llegar a 5, mostrando este resultado en un display de 7 segmentos de ánodo común, el cual será alimentado por una fuente de 12V a través de una interfaz basada en el circuito integrado ULN2803 (o ULN2003), la entrada del contador será realizada por la detección de un objeto a una distancia de 8 cm o menor, de un sensor ultrasónico.

En la siguiente figura se muestra el circuito funcionando

figura 56: Secuencia para leer el sensor ultrasónico

Page 106: Manual Micros 2010

A continuación se propone un circuito de conexiones para esta prácticamente

figura 57: Práctica sensor ultrasónico

figura 58: circuito medidor de distancia ultrasónico

Page 107: Manual Micros 2010

Unidad 6

Interrupciones en un microcontrolador

Page 108: Manual Micros 2010

Unidad 6 Interrupciones en un microcontrolador

6.1 El manejo de las interrupciones.

6.1.1 Tipos de interrupciones.

6.1.2 Los vectores de interrupción.

6.1.3 Las acciones del MCU al responder a una interrupción.

6.1.4 Características de la rutina manejadora de interrupción

6.2 Las interrupciones externas

6.2.1 Características y configuración

6.2.2 Programación y uso.

6.3 Fuentes internas de interrupciones

6.3.1 De los timer y contadores

6.3.2 ADC

6.3.3 De la comunicación serial

6.3.4 Del comparador analógico.

6.3.5 De la EEPROM

6.4 Ejemplos de aplicaciones de las interrupciones.

Competencia específica

Programar y aplicar las interrupciones en un microcontrolador.

Actividades de aprendizaje:

Mapa Conceptual: Investigar y catalogar mediante un mapa conceptual los tipos de interrupciones, las acciones del microcontrolador al responder a una interrupción, características de la rutina manejadora de interrupción del MCU ATmega32U4.

Page 109: Manual Micros 2010

6.1 El manejo de las interrupciones.Hay una analogía que siempre recuerdo desde que la leí en un buen libro de Turbo Pascal cuando aprendía a programar en dicho lenguaje. Cuando vamos a recibir una visita en nuestra casa podemos ir a la puerta a cada momento para ver si ya llegó y atenderla apropiadamente, o podemos quedarnos haciendo nuestras labores cotidianas esperando a que sea la visita quien llame a la puerta para ir a recibirla.

Ir a la puerta constantemente se compara por ejemplo con testear los puertos del AVR para ver si se presionó algún pulsador o algún teclado y actuar en consecuencia. Eso se conoce como técnica Polling o de sondeo e implica el desperdicio de recursos y ciclos de CPU.

En este capítulo aprenderemos a atender nuestras visitas justo cuando llamen a la puerta para que el AVR no se canse en vano y que se ponga a “dormir”, si fuera posible. Ésta es solo una pequeña muestra de lo que se puede conseguir con las interrupciones.

6.1.1 Tipos de interrupciones.

Una interrupción es una llamada “inesperada”, urgente e inmediata a una función especial denominada Interrupt Service Routine (ISR).

El mecanismo funciona así: sin importar lo que esté haciendo en main o cualquier función relacionada con main, cuando ocurra la interrupción el CPU hará una pausa y pasará a ejecutar el código de ISR. Tras terminarlo, el CPU regresará a la tarea que estaba realizando antes de la interrupción, justo donde la había suspendido.

Aunque es posible provocar interrupciones desde el programa ejecutándolas como si fueran funciones ordinarias, las interrupciones son disparadas (llamadas) por eventos del hardware del microcontrolador. El evento puede ser algún cambio en cierto pin de E/S, el desbordamiento de un Timer, la llegada de un dato serial, etc. Se puede deducir por tanto que las fuentes de interrupción están relacionadas con la cantidad de recursos del microcontrolador.

6.1.2 Los vectores de interrupción.

Cada interrupción está identificada por un Vector de Interrupción, que no es otra cosa que una dirección particular en la memoria FLASH. Todos los Vectores están ubicados en posiciones consecutivas de la memoria FLASH y forman la denominada Tabla de Vectores de Interrupción. El RESET no es una interrupción pero su dirección 0x0000 también se conoce como Vector de Reset. Por defecto, la Tabla de Vectores de Interrupción está ubicada en las primeras posiciones de la memoria, tal como se ve abajo. Solo cuando se habilita el uso de la Sección de Boot Loader toda la tabla se desplazará al inicio de dicha sección.

Enseguida se presenta una tabla con las 35 interrupciones posibles en los ATmegaXX4. Debemos recordar que solo los ATmega1284 tienen el Timer3 y por tanto las 4 interrupciones relacionadas con el Timer3 no estarán disponibles en los otros megaAVR de esta serie. Aprenderemos de a poco y para empezar en este capítulo nos ocuparemos de las 7 interrupciones externas, desde INT0 hasta PCINT3. Las restantes serán estudiadas en sus módulos respectivos.

Page 110: Manual Micros 2010

Num Vector Dirección de ProgramaNombre de

Vector de InterrupciónFuente de interrupción

1 0x0000 RESETExternal Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, and JTAG AVR Reset

2 0x0002 INT0 External Interrupt Request 0

3 0x0004 INT1 External Interrupt Request 1

4 0x0006 INT2 External Interrupt Request 2

5 0x0008 PCINT0 Pin Change Interrupt Request 0

6 0x000A PCINT1 Pin Change Interrupt Request 1

7 0x000C PCINT2 Pin Change Interrupt Request 2

8 0x000E PCINT3 Pin Change Interrupt Request 3

9 0x0010 WDT Watchdog Time-out Interrupt

10 0x0012 TIMER2_COMPA Timer/Counter2 Compare Match A

11 0x0014 TIMER2_COMPB Timer/Counter2 Compare Match B

12 0x0016 TIMER2_OVF Timer/Counter2 Overflow

13 0x0018 TIMER1_CAPT Timer/Counter1 Capture Event

14 0x001A TIMER1_COMPA Timer/Counter1 Compare Match A

15 0x001C TIMER1_COMPB Timer/Counter1 Compare Match B

16 0x001E TIMER1_OVF Timer/Counter1 Overflow

17 0x0020 TIMER0_COMPA Timer/Counter0 Compare Match A

18 0x0022 TIMER0_COMPB Timer/Counter0 Compare match B

19 0x0024 TIMER0_OVF Timer/Counter0 Overflow

20 0x0026 SPI_STC SPI Serial Transfer Complete

21 0x0028 USART0_RX USART0 Rx Complete

22 0x002A USART0_UDRE USART0 Data Register Empty

23 0x002C USART0_TX USART0 Tx Complete

24 0x002E ANALOG_COMP Analog Comparator

25 0x0030 ADC ADC Conversion Complete

26 0x0032 EE_READY EEPROM Ready

27 0x0034 TWI 2-wire Serial Interface

28 0x0036 SPM_READY Store Program Memory Ready

Page 111: Manual Micros 2010

Num Vector Dirección de ProgramaNombre de

Vector de InterrupciónFuente de interrupción

29 0x0038 USART1_RX USART1 Rx Complete

30 0x003A USART1_UDRE USART1 Data Register Empty

31 0x003C USART1_TX USART1 Tx Complete

32 0x003E TIMER3_CAPT Timer/Counter3 Capture Event

33 0x0040 TIMER3_COMPA Timer/Counter3 Compare Match A

34 0x0042 TIMER3_COMPB Timer/Counter3 Compare Match B

35 0x0044 TIMER3_OVF Timer/Counter3 Overflow

Tabla 13: Vectores de Interrupción

6.1.3 Las acciones del MCU al responder a una interrupción.

Para entender cómo funciona el mecanismo de las interrupciones en bajo nivel, recordemos que el Contador de Programa es un registro que dirige cada una de las instrucciones que ejecuta el CPU. Pues bien, al dispararse la interrupción el hardware guardará en la Pila el valor actual del Contador de Programa y lo actualizará con el valor del Vector de Interrupción respectivo, de modo que el CPU pasará a ejecutar el código que se encuentre a partir de esa dirección. Al final del código de la interrupción debe haber una instrucción de retorno que restaure el Contador de Programa con el valor que se había guardado en la Pila. La instrucción es reti y la pone el compilador.

Si se llegara a producir el evento excepcional en que se disparen dos o más interrupciones al mismo tiempo, se ejecutarán las interrupciones en orden de prioridad. Tiene mayor prioridad la interrupción cuyo Vector se ubique más abajo, es decir, entre todas, la interrupción INT0 tiene siempre las de ganar.

La estructura y características de la Tabla de Vectores de Interrupción pueden variar entre las diferentes familias de megaAVR y a veces entre diferentes partes de una misma serie. Por ejemplo, los megaAVR de la serie ATmegaXX8 no tienen la interrupción externa INT2 y tampoco las interrupciones PCINT3 (porque les falta el puerto A). Además, el ATmega48 no dispone de la funcionalidad de Boot Loader, así que este AVR no puede desplazar su Tabla de Vectores de Interrupción. La ausencia de algunas interrupciones hace que los otros Vectores cambien de valor.

En cualquier caso, para nosotros, los programadores en C o Basic, es suficiente tener en cuenta los nombres de los Vectores de Interrupción, que en la tabla de arriba se resaltan con enlaces en en azul.

Los nombres de los Vectores de Interrupción presentados corresponden al datasheet y no necesariamente son idénticos a los que utilizan los compiladores AVR GCC o AVR IAR C. Estos nombres se encuentran definidos en los archivos de dispositivo de cada AVR, ubicados en la carpeta include de cada compilador. La instalación por defecto de AVR GCC con Atmel Studio 6 en Windows 7 marca la ruta C:\Program Files (x86)\Atmel\Atmel Studio 6.0\extensions\Atmel\AVRGCC\3.4.0.65\AVRToolchain\avr\include\avr. Allí los puedes ubicar, y de hecho es recomendable examinarlos de vez en cuando.

Pero si por el momento deseas ahorrarte el trabajo te diré que la única diferencia es el apéndice _vect.

Page 112: Manual Micros 2010

Es decir, en todos los archivos de dispositivo de AVR IAR C y de AVR GCC (en sus versiones actuales) los nombres de los Vectores de Interrupción son los mismos que aparecen en el datasheet pero con el añadido _vect, como se muestra en la siguiente tabla de ejemplo. Está de más decir que en nuestros programas debemos usar la forma con _vect.

Nombre de Vector de Interrupción

en datasheet

Nombre de Vector de Interrupción en archivo de dispositivo

INT0 INT0_vect

INT1 INT1_vect

INT2 INT2_vect

PCINT0 PCINT0_vect

PCINT1 PCINT1_vect

PCINT2 PCINT2_vect

PCINT3 PCINT3_vect

TIMER0_COMPA TIMER0_COMPA_vect

TIMER0_COMPB TIMER0_COMPB_vect

TIMER0_OVF TIMER0_OVF_vect

USART0_RX USART0_RX_vect

USART0_UDRE USART0_UDRE_vect

USART0_TX USART0_TX_vect

Tabla 14: Equivalencias entre vectores del datasheet y AVRGCC

6.1.4 Características de la rutina manejadora de interrupción

En el compilador AVR GCC (WinAVR) la función de interrupción se escribe con la palabra reservada ISR acompañada del Vector_de_Interrupcion. En las versiones anteriores del compilador se solía usar SIGNAL en vez de ISR pero actualmente ese método está considerado «deprecated» (censurado).

Recordemos que el Vector_de_Interrupcion debe tener la terminación _vect, como se indicó anteriormente, y si tienes dudas puedes buscar en la carpeta include del directorio de instalación de AVR GCC (WinAVR).

ISR (Vector_de_Interrupcion){ // Código de la función de interrupción. // No requiere limpiar el flag respectivo. El flag se limpia por hardware}

Page 113: Manual Micros 2010

6.2 Las interrupciones externas

6.2.1 Características y configuración

Las interrupciones externas son disparadas por las terminales INT0 e INT1 o cualquiera de las PCINT23..0, observése que si son habilitadas las interrupciones, estas se dispararán si los pines INT0, INT1 o PCINT23..0 son configurados como salidas, la anterior característica provee una forma de generar una interrupción por software.

Las interrupciones INT0 e INT1 pueden ser disparadas mediante un flanco de subida, de bajada o por bajo nivel; esta especificación puede ser realizada para el registro A de control de interrupciones externas (EICRA).

Los bits para controlar el sensado de la interrupción son los bits denominados ISC11 e ISC10 para la INT1 y para la INT0, son los bits ISC01 e ISC00. Estos bits responden a la siguiente tabla:

ISCx1 ISCx0 Descripción

0 0 En nivel bajo, INTx genera una petición de interrupción

0 1 Cualquier cambio lógico en INTx genera una petición de Interrupción

1 0 En flanco de bajada, INTx genera una petición de interrupción.

1 1 En flanco de subida, INTx genera una petición de interrupción

Tabla 15: Control de sensado de Interrupción externa

Para habilitar las interrupciones, es importante recurrir al registro de enmascaramiento de interrupciones externas (EIMSK), donde los bits 1 y cero sirve para habilitación de las interrupciones externas al ser seteados.

6.2.2 Programación y uso.

En estas prácticas de ejemplo evitaremos programas sofisticados con códigos grandes que desvíen la atención hacia una breve aplicación de la teoría expuesta. Por eso no nos vendrá mal volver a los socorridos LEDs parpadeantes.

El programa tendrá dos tareas: la rutina principal se encargará de parpadear un LED y la función de interrupción hará bascular otro LED cada vez que presionemos un pulsador. Esto será como fusionar dos programas que alguna vez hicimos.

De las señales que se generan al presionar el botón escogeremos el flanco de bajada para disparar la interrupción INT0.

Cada aplicación puede tener sus propias especificaciones, pero, en general, un buen hábito de programación es poner la sentencia sie(); que setea el bit I del registro SREG cuando ya todo esté listo para atender a la interrupción.

Page 114: Manual Micros 2010

Al analizar la estructura del programa, notamos que la función ISR es totalmente independiente de main, es decir, no es referenciada desde ningún punto de main.

Una vez habilitada, la interrupción se disparará cuando alguien presione el botón (en el flanco de bajada). En ese preciso instante (quizá cuando se esté ejecutando PINC = 0x02 o quizá en algún punto dentro de delay_ms(600)) el CPU pasará a ejecutar la función ISR. Al salir de ISR, el CPU regresará a continuar la tarea que estaba ejecutando antes de la interrupción.

/****************************************************************************** * FileName: main.c * Purpose: Uso de la interrupción INTx * Processor: megaAVR * Compiler: AVR IAR C y AVR GCC (WinAVR) * Author: Shawn Johnson. http://www.cursomicros.com. * * Copyright (C) 2008 - 2013 Shawn Johnson. All rights reserved. * * License: Se permiten el uso y la redistribución de este código con * modificaciones o sin ellas, siempre que se mantengan esta * licencia y las notas de autor y copyright de arriba. *****************************************************************************/

#include <avr/io.h>#define F_CPU 1000000UL#include <util/delay.h>

//****************************************************************************// Interrupt Service Routine, ISR// Esta función se ejecuta cuando se detecta un flanco de bajada en el pin INT0//****************************************************************************ISR (INT0_vect){ PINC = 0x01; // Conmutar pin PC0 delay_ms(40); // Para pasar los rebotes}

//****************************************************************************// Función principal//****************************************************************************int main(void){ DDRC = 0x03; // Pines PC0 y PC1 para salida (LEDs) PORTD = 0x04; // Habilitar pull-up de pin PD2/INT0 (pulsador) /* Habilitar y configurar la interrupción INT0 para que se dispare con * cada flanco de bajada detectado en el pin INT0 (PD2) */ EIMSK = (1<<INT0); // Habilitar INT0 EICRA = (2<<INT0*2); // Elegir flanco de bajada (modo 2)

sei(); // Habilitación general de interrupciones while(1) // Bucle infinito { PINC = 0x02; // Conmutar pin PC1 delay_ms(600); // Pausa de 600ms }}

Tabla 16: Código para configuración de interrupciones externas - Shawn Johnson

Page 115: Manual Micros 2010

Practica LCD

Escriba un programa para el microcontrolador AVR, donde haciendo uso de una pantalla LCD de dos lineas por 16 caracteres, se muestre el mensaje “hola” en la primera línea y la séptima posición, y en la segunda línea, el mensaje “mundo” en la segunda línea y en la séptima posición.

Seiscientos milisegundos después, limpiar la pantalla, y ahora presentar en la segunda línea un contador de 0 a 98 que se autoincrementa cada 35milisegundos, al terminar, limpiar la pantalla y mantenerla así 200 milisegundos. Véase las imágenes:

Page 116: Manual Micros 2010

#include <avr/io.h>

#define F_CPU 1000000UL

#include <util/delay.h>

#include "lcd.h"

int main(void)

{

unsigned char i;

char buff[7];

lcd_init();

while(1)

{

lcd_gotorc(1,7);

lcd_puts("Hola");

lcd_gotorc(2,7);

lcd_puts("Mundo");

_delay_ms(600);

lcd_clear();

_delay_ms(400);

for(i=0;i<99;i++)

{

sprintf(buff, "hola%d" ,i);

lcd_gotorc(2,5);

lcd_puts(buff);

_delay_ms(35);

}

lcd_clear();

_delay_ms(200);

}

}

Tabla 17: Ejemplo de uso de librerías LCD de Shawn Johnson

Librerias lcd

Page 117: Manual Micros 2010

/******************************************************************************

* FileName: lcd.h

* Purpose: Librería de funciones para controlar un display LCD con chip

* Hitachi HD44780 o compatible. La interface es de 4 bits.

* Processor: ATmel AVR

* Compiler: AVR IAR C y AVR GCC (WinAVR)

* Author: Shawn Johnson. http://www.cursomicros.com.

*

* Copyright (C) 2008 - 2013 Shawn Johnson. All rights reserved.

*

* License: Se permiten el uso y la redistribución de este código con

* modificaciones o sin ellas, siempre que se mantengan esta

* licencia y las notas de autor y copyright de arriba.

*****************************************************************************/

#include <avr/io.h>

#define F_CPU 1000000UL

#include <util/delay.h>

//****************************************************************************

// CONFIGURACIÓN DE LOS PINES DE INTERFACE

//****************************************************************************

/* Define el puerto a donde se conectará el bus de datos del LCD

* Se utilizará el nible alto del puerto escogido (ejem. PB4-DB4,...,PB7-DB7)

*/

#define lcd_DATAout PORTB // Registro PORT del puerto

#define lcd_DATAin PINB // Registro PIN del puerto

#define lcd_DATAddr DDRB // Registro DDR del puerto

/* Define el puerto a donde se conectarán las líneas de control del LCD

* E, RW y RS. Puede ser el mismo puerto del bus de datos.

*/

#define lcd_CTRLout PORTB // Registro PORT del puerto

#define lcd_CTRLin PINB // Registro PIN del puerto

#define lcd_CTRLddr DDRB // Registro DDR del puerto

/* Define los números de los pines del puerto anterior que corresponderán a

* las líneas E, RW y RS del LCD.

*/

#define lcd_E 3 // Pin Enable

#define lcd_RW 2 // Pin Read/Write

#define lcd_RS 1 // Pin Register Select

Page 118: Manual Micros 2010

//****************************************************************************

// CÓDIGOS DE COMANDO USUALES

//****************************************************************************

#define LCD_CLEAR 0x01 // Limpiar Display

#define LCD_RETHOM 0x02 // Cursor a inicio de línea 1

#define LCD_LINE1 0x80 // Línea 1 posición 0

#define LCD_LINE2 0xC0 // Línea 2 posición 0

#define LCD_DDRAM 0x80 // Dirección 0x00 de DDRAM

#define LCD_CGRAM 0x40 // Dirección 0x00 de CGRAM

#define LCD_CURSOR 0x0E // Mostrar solo Cursor

#define LCD_BLINK 0x0D // Mostrar solo Blink

#define LCD_CURBLK 0x0F // Mostrar Cursor + Blink

#define LCD_NOCURBLK 0x0C // No mostrar ni Cursor ni Blink

//****************************************************************************

// PROTOTIPOS DE FUNCIONES

//****************************************************************************

void lcd_init(void); // Inicializa el LCD

void lcd_puts(char * s); // Envía una cadena ram al LCD

void lcd_gotorc(char r, char c); // Cursor a fila r, columna c

void lcd_clear(void); // Limpia el LCD y regresa el cursor al inicio

void lcd_data(char dat); // Envía una instrucción de dato al LCD

void lcd_cmd(char com); // Envía una instrucción de comando al LCD

char lcd_read(char RS); // Lee un dato del LCD

void lcd_write(char inst, char RS); // Escribe una instrucción en el LCD

void lcd_nibble(char nibble);

void ldelay_ms(unsigned char );

Tabla 18: Librería LCD de Shawn Johnson - lcd.h

Lcd.c

Page 119: Manual Micros 2010

/******************************************************************************

* FileName: lcd.c

* Purpose: Librería de funciones para controlar un display LCD con chip

* Hitachi HD44780 o compatible. La interface es de 4 bits.

* Processor: ATmel AVR

* Compiler: AVR IAR C y AVR GCC (WinAVR)

* Author: Shawn Johnson. http://www.cursomicros.com.

*

* Copyright (C) 2008 - 2013 Shawn Johnson. All rights reserved.

*

* License: Se permiten el uso y la redistribución de este código con

* modificaciones o sin ellas, siempre que se mantengan esta

* licencia y las notas de autor y copyright de arriba.

*****************************************************************************/

#include "lcd.h"

//****************************************************************************

// Ejecuta la inicialización software completa del LCD. La configuración es

// de: interface de 4 bits, despliegue de 2 líneas y caracteres de 5x7 puntos.

//****************************************************************************

void lcd_init(void)

{

/* Configurar las direcciones de los pines de interface del LCD */

lcd_DATAddr |= 0xF0;

lcd_CTRLddr |= (1<<lcd_E)|(1<<lcd_RW)|(1<<lcd_RS);

/* Secuencia de inicialización del LCD en modo de 4 bits*/

lcd_CTRLout &= ~((1<<lcd_E)|(1<<lcd_RW)|(1<<lcd_RS));

ldelay_ms(45); // > 40 ms

lcd_nibble(0x30); // Function Set: 8-bit

ldelay_ms(5); // > 4.1 ms

lcd_nibble(0x30); // Function Set: 8-bit

ldelay_ms(1); // > 100 µs

lcd_nibble(0x30); // Function Set: 8-bit

ldelay_ms(1); // > 40 µs

lcd_nibble(0x20); // Function Set: 4-bit

ldelay_ms(1); // > 40 µs

lcd_nibble(0x20); // Function Set: 4-bit, 2lines, 4×7font

lcd_nibble(0x80); //

lcd_write(0x0C, 0); // Display ON/OFF Control: Display on, Cursor off, Blink off

lcd_write(0x01, 0); // Clear Display

lcd_write(0x06, 0); // Entry Mode Set

Page 120: Manual Micros 2010

}

//****************************************************************************

// Escribe una instrucción en el LCD:

// Si RS = 0 la instrucción es de comando (Function Set, Entry Mode set, etc).

// Si RS = 1 la instrucción es de dato y va a la DDRAM o CGRAM.

//****************************************************************************

void lcd_write(char inst, char RS)

{

while(lcd_read(0)&0x80); // Esperar mientras LCD esté ocupado

if(RS)

lcd_CTRLout |= (1<<lcd_RS); // Para escribir en DDRAM o CGRAM

else

lcd_CTRLout &= ~(1<<lcd_RS); // Para escribir en Registro de Comandos

_delay_us(5); // Permite actualizar el Puntero de RAM

lcd_nibble(inst); // Enviar nibble alto

lcd_nibble(inst<<4); // Enviar nibble bajo

}

//****************************************************************************

// Envía el nibble alto de 'nibble' al LCD.

//****************************************************************************

void lcd_nibble(char nibble)

{

lcd_CTRLout &= ~(1<<lcd_RW); // Establecer Modo de escritura

lcd_DATAddr |= 0xF0; // Hacer nibble alto de bus de datos salida

lcd_DATAout = (nibble&0xF0)|(lcd_DATAout&0x0F); // Colocar dato

_delay_us(2); // tAS, set-up time > 140 ns

lcd_CTRLout |= (1<<lcd_E); // Pulso de Enable

_delay_us(2); // Enable pulse width > 450 ns

lcd_CTRLout &= ~(1<<lcd_E); //

lcd_DATAddr &= 0x0F; // Hacer nibble alto entrada

}

//****************************************************************************

// Lee un byte de dato del LCD.

// Si RS = 1 se lee la locación de DDRAM o CGRAM direccionada actualmente.

// Si RS = 0 se lee el 'bit de Busy Flag' + el 'Puntero de RAM'.

//****************************************************************************

char lcd_read(char RS)

{

char high, low;

if(RS)

Page 121: Manual Micros 2010

lcd_CTRLout |= (1<<lcd_RS); // Para leer de DDRAM o CGRAM

else

lcd_CTRLout &= ~(1<<lcd_RS); // Para leer Busy Flag + Puntero de RAM

lcd_CTRLout |= (1<<lcd_RW); // Establecer Modo Lectura

lcd_DATAddr &= 0x0F; // Hacer nibble alto entrada

_delay_us(2); // tAS, set-up time > 140 ns

lcd_CTRLout |= (1<<lcd_E); // Habilitar LCD

_delay_us(2); // Data Delay Time > 1320 ns

high = lcd_DATAin; // Leer nibble alto

lcd_CTRLout &= ~(1<<lcd_E); // Para que el LCD prepare el nibble bajo

_delay_us(2); // Enable cycle time > 1200 ns

lcd_CTRLout |= (1<<lcd_E); // Habilitar LCD

_delay_us(2); // Data Delay Time > 1320 ns

low = lcd_DATAin; // Leer nibble bajo

lcd_CTRLout &= ~(1<<lcd_E); //

return (high&0xF0)|(low>>4); // Juntar nibbles leídos

}

//****************************************************************************

// Envían cadenas RAM terminadas en nulo al LCD.

//****************************************************************************

void lcd_puts(char * s)

{

unsigned char c, i=0;

while(c = s[i++])

lcd_write(c, 1); // Instrucción 'Write Data to DDRAM/CGRAM'

}

//****************************************************************************

// Ubica el cursor del LCD en la columna c de la línea r.

//****************************************************************************

void lcd_gotorc(char r, char c)

{

if(r==1) r = LCD_LINE1;

else r = LCD_LINE2;

lcd_write(r+c-1, 0); // Instrucción 'Set DDRAM Address'

}

//****************************************************************************

// Limpia la pantalla del LCD y regresa el cursor a la primera posición

// de la línea 1.

//****************************************************************************

void lcd_clear(void)

Page 122: Manual Micros 2010

{

lcd_write(LCD_CLEAR, 0); // Instrucción 'Clear Display'

}

//****************************************************************************

// Envían instrucciones de comando y de datos al LCD.

//****************************************************************************

void lcd_cmd(char com)

{

lcd_write(com, 0); // Cualquier instrucción de comando

}

void lcd_data(char dat)

{

lcd_write(dat, 1); // Instrucción 'Write Data to DDRAM/CGRAM'

}

//****************************************************************************

// Genera un delay de n milisegundos

//****************************************************************************

void ldelay_ms(unsigned char n)

{

while(n--)

_delay_us(1000);

}

Tabla 19: Librería lcd de Shawn Johnson -lcd.c

Circuito que se ensamblará :

Page 123: Manual Micros 2010

Práctica física. A través del uso de interrupciones externas, controla el arranque, paro y sentido de giro de un motor indicando en una pantalla de cristal líquido alfanumérica de 16 caracteres por 2 líneas

• Inicialmente el motor debe estar detenido y en la pantalla de indicar el mensaje “Motor Detenido”

• Si el usuario presiona el botón de inicio, el motor deberá girar en el sentido indicado por el botón Der (Interrupción 0 ) o Izq (Interrupción 1). Inicialmente el giro deberá ser a la Izquierda.

• Una vez arrancado el motor, mediante el empleo de interrupciones, cambie el sentido de giro del motor, con los botones Der e Izq.

• Al presionar el botón de STOP, el motor debe detenerse e indicar lo consecuente en la pantalla LCD.

• Si se mantiene presionado el botón de STOP, el motor no debe de arrancar, con botón alguno, ni causar ningún tipo de indicación en la pantalla LCD.

Page 124: Manual Micros 2010

El circuito a ensamblar es el siguiente:

El código fuente a utilizar es:

figura 59: circuito con LCD e interrupciones

Page 125: Manual Micros 2010

#include <avr/io.h>

#define F_CPU 1000000UL

#include <util/delay.h>

#include <avr/interrupt.h>

#include "lcd.h"

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=(_BV(bit)))

#define clearbit(sfr,bit) (_SFR_BYTE(sfr) &= ~ (_BV(bit)))

/**

* @brief Definición para crear el tipo de datos booleano

* se utiliza como

*

* boolean variable = {valor binario}

*/

/**

* @brief Macros para definir puertos de conexion del motor

*/

#define start PINC1

#define pstart PINC

#define rpstart PORTC

#define stop PINC2

#define pstop PINC

#define rpstop PORTC

#define I_nD PIND2

#define pI_nD PIND

#define rpI_nD PORTD

#define a PC3

#define Pa PORTC

#define b PC4

#define Pb PORTC

#define En PC5

#define pEn PORTC

/*Defincion para configuraciòn de entradas y salidas*/

#define cstart DDC1

#define cpstart DDRC

#define cstop DDC2

#define cpstop DDRC

#define cI_nD DDD2

#define cpI_nD DDRD

Page 126: Manual Micros 2010

#define ca DDC3

#define cPa DDRC

#define cb DDC4

#define cPb DDRC

#define cEn DDC5

#define cpEn DDRC

/*

* Se crea una variale del tipo booleano para indicar el sentido de

* giro del motor

*/

typedef enum {false, true} boolean;

boolean Derecha = false;

/**

* @brief Rutina de Interrupción Externa 1

* Cuando se activa la interrupcion permite cambiar un flag

* a fin de dar sentido de giro a la izquierda al motor

*/

ISR(INT1_vect)

{

Derecha = false;

}

/**

* @brief Rutina de Interrupción Externa 0

* Cuando se activa la interrupcion permite cambiar un flag

* a fin de dar sentido de giro a la derecha al motor*/

ISR(INT0_vect)

{

Derecha = true;

}

int main(void)

{

Page 127: Manual Micros 2010

/*

* Configuracion de E/S y Resistencias de pullup

*/

lcd_init();

clearbit(cpstart,cstart);

clearbit(cpstop,cstop);

clearbit(cpI_nD,cI_nD);

setbit(rpstart, start);

setbit(rpstop,stop);

setbit(rpI_nD,I_nD);

setbit(PORTD,PD3);

setbit(cPa,ca);

setbit(cPb,cb);

setbit(cpEn,cEn);

/*

* Habilitar y configurar la interrupción INT0 para que se dispare con

* cada flanco de bajada detectado en INT0 (PD2)

*/

setbit(EIMSK,INT0);

setbit(EICRA,ISC01);

clearbit(EICRA,ISC00);

setbit(EIMSK,INT1); //habilita la int1

setbit(EICRA,ISC11); //peticion de interrupcion en flanco de bajada

clearbit(EICRA,ISC10);

sei();

while(1)

{

lcd_gotorc(1,5);

lcd_puts("MOTOR");

lcd_gotorc(2,4); //renglon 2 columna 4

lcd_puts(" DETENIDO ");

clearbit(pEn,En);

if(bit_is_clear(pstart,start) && bit_is_set(pstop,stop))

{

while(bit_is_set(pstop,stop))

Page 128: Manual Micros 2010

{

while(Derecha == false && bit_is_set(pstop,stop))

{

lcd_gotorc(2,4);

lcd_puts("IZQUIERDA");

setbit(Pa,a);

clearbit(Pb,b);

setbit(pEn,En);

}

while(Derecha == true && bit_is_set(pstop,stop))

{

lcd_gotorc(2,4);

lcd_puts(" DERECHA ");

clearbit(Pa,a);

setbit(Pb,b);

setbit(pEn,En);

}

}

}

clearbit(pEn,En);

}

}

Tabla 20: Código para control de puente H

6.3 Fuentes internas de interrupciones

6.3.1 De los timer y contadores

Los Timers son módulos que trabajan en paralelo con el procesador, permitiendo que las operaciones de temporización y conteo se puedan llevar a cabo de manera eficiente, mientras el procesador se ocupa de otras tareas.

Normalmente los megaAVR cuentan con tres Timers, llamados Timer0, Timer1 y Timer2. A veces desaparece el Timer2 y otras veces aparece adicionalmente el Timer3 o el Timer4. Todos los Timers pueden trabajar en modo de PWM pero esta funcionalidad está mejor implementada en unos Timers (1 y 3) que en otros. Por su relativa limitación, el Timer0 está más destinado a las temporizaciones y otro tanto a los conteos. El Timer2 por su parte fue diseñado con la característica adicional para trabajar con un XTAL de reloj externo, de 32kHz.

En primer lugar nos ocuparemos de los Timers de 8 bits, o sea, del Timer0 y del Timer2.

Page 129: Manual Micros 2010

Luego estudiaremos los Timers de 16 bits, que son el Timer1 y el Timer3. De hecho, solo trataremos el Timer1 porque el Timer3 es su perfecto clon, si vale la expresión.

El Timer0 y el Timer2

Dada la paridad de características entre el Timer0 y el Timer2, no las vamos a mencionar simultáneamente para no fatigarnos de términos. Simplemente vamos a referirnos al Timer0 y se dará por hecho que lo mismo es aplicable para el Timer2, salvo que se indique explícitamente lo contario. Las principales diferencias se dejarán notar solo al inicio y al final, luego el tratamiento será muy parejo.

Naturalmente, el control de cada Timer a nivel de programación requiere del trato específico de sus registros de configuración. Pero tampoco esto es de preocupación pues lo único que cambia es el número 0 por el número 2 en cada registro y bit de registro. Por ejemplo, los registros de E/S del Timer0 son:

TCNT0. TCCR0A, TCCR0B, OCR0A, OCR0B, TIMSK0 y TIFR0.

En tanto que para el Timer2 son:

TCNT2. TCCR2A, TCCR2B, OCR2A, OCR2B, TIMSK2 y TIFR2.

Aparte de ellos, tenemos al registro GTCCR, el cual es de uso común para todos los Timers desde el Timer0 hasta el Timer3, y el registro ASSR, que es de uso exclusivo del Timer2 y que controla las características distintivas del funcionamiento asíncrono de este Timer.

Del mismo modo, en los nombres de los bits de cada registro, solo cambian el número 0 por el 2. Por ejemplo, los mapas de bits de los registros TCCR0A y TCCR2A son, respectivamente:

Registro TCCR0ATCCR0A COM0A1 COM0A0 COM0B1 COM0B0 --- --- WGM00 ADPS0

Registro TCCR2ATCCR2A COM2A1 COM2A0 COM2B1 COM2B0 --- --- WGM21 WGM20

Queda claro entonces que bastará con referirnos al Timer0, entendiendo que las mismas características, ventajas y limitaciones citadas serán igualmente aplicables al Timer2, salvo, repito, que se indique lo contrario. Empecemos, entonces.

El nombre completo del Timer0 es Timer/Counter0 o Temporizador/Contador 0, pero por comodidad nos referimos a él simplemente como Timer0.

El siguiente esquema ayudará para entender la operación común del Timer0. Las operaciones específicas de cada modo particular las describiremos en su momento.

• El

figura 60: Arquitectura del Temporizador 0

Page 130: Manual Micros 2010

elemento central del Timer0 es su contador, que es el mismo registro TCNT0. Como es un registro de 8 bits, decimos que el Timer0 es de 8 bits. El Timer0 puede avanzar hacia adelante o hacia atrás, según se programe, impulsado por la señal de su reloj, el cual puede ser interno o externo. Cuando nos referirnos al avance del Timer en realidad nos referimos al avance de su contador, el registro TCNT0.

• Con sus 8 bits, el Timer0 puede contar en todo su rango, o sea, entre 0 y 255. Cuando el Timer0 opera solo en modo ascendente y llega a su valor máximo de 255, continuará después contando desde 0 otra vez, cíclicamente. Esta transición de 255 a 0 es el famoso Desbordamiento y es un concepto clave en los Timers. El desbordamiento del Timer0 activa el bit de flag TOV0. También es posible hacer que el Timer0 cuente solo hasta un tope establecido por el registro OCR0A.

• El Timer0 tiene dos comparadores que en todo momento están comparando el valor del registro TCNT0 con los registros OCR0A y OCR0B. Cada igualdad detectada entre los registros indicados se conoce como Coincidencia y es el segundo concepto clave de los Timers del AVR. La coincidencia entre TCNT0 y OCR0A activa el bit de flag OCF0A y la coincidencia entre TCNT0 y OCR0B activa el bit de flag OCF0B.

• El Desbordamiento del Timer0 y cada una de sus dos Coincidencias se pueden programar para disparar interrupciones. Los detalles de las interrupciones serán vistos con paciencia en su sección respectiva.

Desde el punto de vista de la programación, podemos controlar el Timer0 con tres tipos de bits:

• Los bits CS (de Clock Select). Los bits CS02, CS01 y CS00 se encargan de configurar todo lo relacionado con el reloj y el prescaler del Timer.

• Los bits WGM (de Waveform Generator Mode). Los bits WGM02, WGM01 y WGM00 trabajan con los comparadores para producir ondas cuadradas de acuerdo con la configuración de los bits. En realidad, su función implica más que eso, pues establecen el modo en que operará el Timer0, ya sea modo Normal, CTC o PWM.

• Los bits COM (de Compare Output Mode). Son los bits COM0A1 y COM0A0 los que en última instancia deciden si las ondas generadas por los comparadores salen o no por los pines OC0A y OC0B del AVR. El tipo de onda más popular es PWM y es habitualmente el único caso en que se dejan salir las ondas. Cuando el Timer0 va a trabajar como simple contador o temporizador, los bits COM quedan con su valor por defecto de 0, con lo cual los pines OC0A y OC0B quedan desconectados del Timer y se pueden seguir usando como puertos de E/S generales.

El reloj del Timer0 es la señal digital, periódica o no, cuyos pulsos hacen avanzar el Timer. La fuente de reloj del Timer0 puede ser interna o externa.

• Reloj Interno. Aquí el reloj del Timer0 deriva del mismo oscilador interno del sistema F_CPU. Como se ve en la figura, en este caso la señal pasa previamente por el prescaler, que puede dividir la frecuencia de F_CPU por un valor seleccionado por nosotros. Los prescalers del Timer0 y del Timer2 no son idénticos, aunque tengan los bits de control similares. Pero siendo este reloj el que se usa con regularidad, ya sea para las temporizaciones o para generar ondas PWM, sobrará espacio para familiarizarnos con estas ligeras diferencias.

• Reloj Externo. He aquí la brecha más grande que separa al Timer0 del Timer2. La forma como la señal externa se aplica al microcontrolador depende de cada Timer.

• En el Timer0 la señal externa se conecta al pin T0 del megaAVR. Con esto el programador decide si el Timer0 avanzará con cada flanco de subida o de bajada detectado en dicho pin. Notemos en el diagrama que la señal externa no pasará por su prescaler.

Page 131: Manual Micros 2010

• En el Timer2 su reloj externo puede ser de dos tipos: o es una señal aplicada al pin TOSC1 del megaAVR, en cuyo caso el Timer2 avanzará con cada flanco de bajada de ese pin; o es la señal de un oscilador de XTAL conectado entre los pines TOSC1 y TOSC2 del megaAVR. En ambos casos, la señal de reloj pasará por el prescaler del Timer2.

El modo donde el Timer0/2 trabaja con un reloj externo aplicado al pin T0 (para el Timer0) o TOSC1 (para el Timer2) se conoce como modo Contador porque de alguna forma el Timer contará los pulsos detectados en dicho pin. Sin embargo, el hecho de que el reloj provenga de una fuente externa no le quita sus otras funcionalidades, como por ejemplo, poder generar ondas PWM, interrupciones, etc., claro que sería conveniente que para tal caso la señal fuera periódica.

Page 132: Manual Micros 2010

El prescaler es un circuito contador por el que se puede hacer pasar el reloj del Timer para dividir su frecuencia. De ese modo el Timer avanzará más lento, según las necesidades del diseñador.

El prescaler es parte del reloj del Timer, así que para configurarlo se usan los bits de Selección de Reloj o bits CS (por Clock Select).

Registro TCCR0BTCCR0B FOC0A FOC0B --- --- WGM02 CS02 CS01 CS00

Registro TCCR2BTCCR2B FOC2A FOC2B --- --- WGM22 CS22 CS21 CS20

Como puedes ver, los bits CS se encuentran en los registros TCCRxB de cada Timer, sin embargo, por más que sean casi iguales, tiene efectos diferentes debido a que los prescalers son diferentes. El prescaler del Timer2 es más sencillo y completo, pero empezaremos por explicar el prescaler del Timer0.

El prescaler del Timer0 es compartido con el Timer1 (¿y qué tiene que ver en todo esto el Timer1?). De acuerdo con la figura, es posible que los dos Timers operen simultáneamente con el prescaler y utilizando diferentes factores de división puesto que cada Timer tiene sus propios bits CS (de Clock Select). El único reparo sería que se debe tener cuidado al resetear el prescaler porque para esto se dispone de una única señal PSRSYNC. Es un reset SYNCrono porque el Timers0 y el Timer1 trabajan siempre sincronizados con el reloj del sistema F_CPU, hasta cuando su reloj proviene de los pines T0 o T1, respectivamente. El bit PSRSYNC se encuentra en el registro GTCCR.

figura 61: Arquitectura del Timer 0

figura 62: Prescaladores y relojes del timer0 y timer1

Page 133: Manual Micros 2010

Notemos que el prescaler divide el reloj del sistema por 8, 64, 256 ó 1024. Estos divisores se conocen como factores de prescaler. Observemos además que de usar un reloj proveniente del pin T0, entonces no será posible usar el prescaler.

Registro TCCR0BTCCR0B FOC0A FOC0B --- --- WGM02 CS02 CS01 CS00

Tabla CS02CS02 CS01 CS00 Fuente de reloj del Timer0

0 0 0 Sin fuente de reloj (Timer0 detenido)

0 0 1 F_CPU (Sin prescaler)

0 1 0 F_CPU/8 (con prescaler)

0 1 1 F_CPU/64 (con prescaler)

1 0 0 F_CPU/256 (con prescaler)

1 0 1 F_CPU/1024 (con prescaler)

1 1 0Reloj externo en pin T0. El Timer0 avanza con el flanco de bajada.

1 1 1Reloj externo en pin T0. El Timer0 avanza con el flanco de subida.

Ahora revisemos el prescaler del Timer2. Este prescaler ofrece más factores de división, con lo que las temporizaciones podrán ser más flexibles. A diferencia del Timer0/1, si optamos por un reloj externo aplicado al pin TOSC1, dicha señal sí podrá pasar por el prescaler. Esta vez el prescaler se puede resetear con la señal PSRASY. Su nombre indica que se trata de naturaleza ASYncrona porque si el reloj del Timer2 viene del exterior, no habrá circuito que lo sincronice con el reloj del sistema F_CPU. Los bits AS2 y PSRASY se encuentran en el registro GTCCR.

Page 134: Manual Micros 2010

TCCR2B FOC2A FOC2B --- --- WGM22 CS22 CS21 CS20

En la siguiente tabla la señal clkT2S puede ser F_CPU o el reloj proveniente del exterior.

Tabla CS22CS22 CS21 CS20 Fuente de reloj del Timer2

0 0 0 Sin fuente de reloj (Timer detenido).

0 0 1 clkT2S (Sin prescaler)

0 1 0 clkT2S/8 (Desde el prescaler)

0 1 1 clkT2S/32 (Desde el prescaler)

1 0 0 clkT2S/64 (Desde el prescaler)

1 0 1 clkT2S/128 (Desde el prescaler)

1 1 0 clkT2S/256 (Desde el prescaler)

1 1 1 clkT2S/1024 (Desde el prescaler)

Registro GTCCRGTCCR TSM --- --- --- --- --- PSRASY PSRSYNC

En general existen 3 modos en que pueden trabajar los Timers:

• Modo Normal

figura 63: Preescalador del timer 2

Page 135: Manual Micros 2010

• Modo CTC • Modo PWM

Cada modo tendrá sus variantes dependiendo del Timer. Por ejemplo, en el Timer1 existen hasta 12 modos PWM, pero bueno, de eso nos ocuparemos en su momento.

El timer 0 y el timer 2 en modo normal

Este modo queda seleccionado cuando todos los bits WGM valen 0, es decir, es el modo por defecto del Timer0. De hecho, lo es en todos los Timers.

Tabla WGM02WGM02 WGM01 WGM00 Modo de Operación de Timer0 Inicio del Conteo Tope del Conteo

0 0 0 Normal 0x00 0xFF

En modo Normal el Timer0, habilitado, avanza libre y cíclicamente en todo su rango, es decir, su registro TCNT0 cuenta desde 0x00 hasta 0xFF, luego se desborda para volver a iniciar desde 0x00.

El desbordamiento del Timer activa el flag TOV0 del registro TIFR0 el cual puede programarse para disparar interrupciones. Como el registro TCNT0 es de lectura y escritura podemos en cualquier momento modificar su valor y así recortar los periodos de conteo para calibrar o ajustar las temporizaciones.

Registro TCCR0ATCCR0A COM0A1 COM0A0 COM0B1 COM0B0 --- --- WGM01 WGM00

Registro TCCR0BTCCR0B FOC0A FOC0B --- --- WGM02 CS02 CS01 CS00

Registro TIFR0TIFR0 --- --- --- --- --- OCF0B OCF0A TOV0

El Timer0 siempre inicia detenido, así que para que se cumpla todo lo descrito primero habrá echarlo a andar configurando los bits de reloj CS, según lo estudiado en El Reloj del Timer0 y del Timer2.

Recordemos que los comparadores del Timer0 pueden sacar por los pines OC0A y OC0B unas señales que se pueden configurar con los bits COM. En los modos Normal o CTC esta señal se forma poniendo a cero, a uno, o conmutando el valor de OC0A/OC0B. Todas las opciones posibles se muestran en la siguiente tabla. Para temas de temporización, que es normalmente el propósito del modo Normal o CTC, debemos escoger la primera opción, que es la predeterminada y que nos dejará los pines OC0A/OC0B libres para seguir usándolos como puertos de E/S generales.

Tabla COM0A1COM0A1 COM0A0 Descripción

0 0 Pin OC0A desconectado. Operación normal del pin

0 1 Pin OC0A conmuta en Coincidencia entre TCNT0 y OCR0A

1 0 Pin OC0A se limpia en Coincidencia entre TCNT0 y OCR0A

1 1 Pin OC0A se setea en Coincidencia entre TCNT0 y OCR0A

Page 136: Manual Micros 2010

La tabla solo muestra la configuración de la onda generada para el pin OC0A pero es la misma que se obtiene para el pin OC0B con los bits COM0B1 y COM0B0.

Cálculo de la Temporización en Modo Normal

Temporizar con el Timer0 implica cargar su registro TCNT0 con un valor adecuado y dejar que siga contando hasta que se desborde. Es el tiempo que demora en desbordarse lo que nos interesa conocer para aplicarlo a nuestras necesidades; y son el cálculo y la programación de ese tiempo el objetivo de esta sección.

Bueno, asumo que en este momento ya sabemos cómo configurar el reloj del Timer0 (bits CS), que sabemos cómo programar el Timer0 en modo Normal (bits WGM) y que entendemos su operación en ese modo. Ahora aprenderemos a escoger la opción de reloj más adecuada para nuestras temporizaciones.

Para empezar, debemos usar el reloj interno derivado de F_CPU (cuyo valor es teóricamente igual a la frecuencia del XTAL del megaAVR.), salvo que tengamos una señal externa periódica. Como sabemos, si la fuente de reloj es interna, el Timer0 y el Timer2 se programan igual. Lo único que cambiará serán los factores de prescaler.

Tabla CS02CS02 CS01 CS00 Fuente de reloj del Timer0

0 0 0 Sin fuente de reloj (Timer0 detenido)

0 0 1 F_CPU (Sin prescaler)

0 1 0 F_CPU/8 (con prescaler)

0 1 1 F_CPU/64 (con prescaler)

1 0 0 F_CPU/256 (con prescaler)

1 0 1 F_CPU/1024 (con prescaler)

1 1 0 Reloj externo en pin T0. El Timer0 avanza con el flanco de bajada.

1 1 1 Reloj externo en pin T0. El Timer0 avanza con el flanco de subida.

En primer lugar veamos cómo avanza el Timer0. Por ejemplo, si tenemos un XTAL de 8 MHz y no usamos prescaler, entonces el reloj del Timer0 será de 8 MHz y el registro TCNT0 se incrementará cada 1/8MHz = 128ns, lo mismo que un ciclo de instrucción básica. Pero si usamos el factor de prescaler 8, TCNT0 avanzará cada 1us. Si usamos el factor de prescaler de 256, TCNT0 avanzará cada 32us. Y si cambiamos de XTAL, los tiempos serán otros.

Ahora entonces, suponiendo que seguimos con nuestro XTAL de 8MHz, el registro TCNT0 avanzará desde 0 hasta 255 en 32us (sin prescaler). Pero si cargamos TCNT0 con 200, llegará al desbordamiento después de 7us; y si usamos prescaler de 8, lo hará después de 7×8 = 56us.

Al inicio todos vemos en esto un enredo de números. Parece complejo pero solo es cuestión de encontrar el hilo de la madeja para suspirar diciendo ¡Ah…, era así de fácil! Sin embargo, hay quienes se rinden y prefieren usar fórmulas y cálculos directos como los descritos a continuación.

Bueno, vamos al grano. El Tiempo que pasará el Timer0 contando desde un valor inicial TCNT0 hasta 255 y se produzca el desbordamiento está dado por la fórmula:

Page 137: Manual Micros 2010

Tiempo=N (256−TCNT0 )

FCPU

donde:

• Tiempo = Valor de temporización deseada

• F_CPU = Frecuencia del reloj principal seleccionado del AVR

• N = Factor de división de frecuencia o Prescalamiento (1, 8, 64, 256, 1024)

• TCNT0 = Valor inicial de precarga.

Nota: los factores de prescaler N del Timer2 son 1, 8, 32, 64, 128, 256 y 1024. Eso podría dar otras soluciones para N y TCNT2.

Como ves, ésta es una ecuación con dos incógnitas (N y TCNT0) y es posible encontrar más de una solución para ambas. Sin embargo, no todas serán igualmente adecuadas. Los valores más apropiados serán los que nos permitan realizar un mejor posterior ajuste de precisión.

Pero si no quieres ir tanteando, puedes emplear las siguientes dos fórmulas:

N=tiempo∗FCPU

256

Lo más probable es que el valor obtenido con esta fórmula no esté disponible como factor de prescaler válido (1, 8, 64, 256 ó 1024 para el Timer0 o 1, 8, 32, 64, 128, 256 y 1024 para el Timer2). En tal caso deberemos tomar el factor superior más cercano (“redondear” para arriba). La otra fórmula es:

TCNT0=256−tiempo∗F CPU

N

Como antes, si el resultado no fuera un número entero, habría que redondearlo para arriba.

Si el factor de prescaler obtenido estuviera fuera del rango permitido (más alto que 1024), se puede optar por buscar otro camino, como fragmentar la temporización. Por otro lado, si la temporización es muy fina, puede que sea necesario subir un poquito el valor de inicio del TCNT0 para realizar una calibración añadiendo algunas instrucciones de relleno como nops. Estas dos situaciones las veremos en las prácticas; así que pierde cuidado si no las dejé muy claro.

A modo de ejemplo, hallemos el factor de prescaler N y el valor de inicio de TCNT0 para generar una temporización de 5 ms si el megaAVR trabaja con un XTAL de 10 MHz.

N=5ms∗10 MHz

256=

50000256

=195,31→256 ( factor superior más cercano)

Y el valor de inicio del registro TCNT0 será:

TCNT0=256−5 ms∗10 MHz

256=256−

50000256

=60,67=61(redondear hacia arriba)

La secuencia de conteo resultaría así:

61 – 62 – 63 - ... - 253 – 254 – 255 – 0 – 1 -2 - ...

Desborde

Page 138: Manual Micros 2010

Otro ejemplo. ¿Cuáles son la razón de prescaler y el valor inicial de TCNT0 para conseguir una temporización de 200 µs si nuestro megaAVR tiene un XTAL de 4 MHz?

El factor de prescaler N sería:

N=200μ s∗4 MHz

256=

800256

=3,125→8

Y el valor inicial de TCNT0 será:

TCNT0=256−200μ s∗4MHz

8=256−

8008

=156

Luego, la secuencia de conteo quedaría así:

156 – 157 – 158 - ... - 253 – 254 – 255 – 0 – 1 - 2

Finalmente, ¿cuáles son la razón de prescaler y el valor inicial de TCNT0 para conseguir una temporización de 50 ms si se tiene un megaAVR con un XTAL de 20 MHz?

El factor de prescaler sería:

N=50 ms∗20 MHz

256=

1000000256

=3906,25→? ??

¿Y ahora de dónde vamos a sacar un factor de prescaler mayor que 3906.25 si el máximo es de 1024? ¿Buscamos otro Timer? Bueno, quizá podríamos temporizar 10 veces 5 ms.

Interrupciones del Timer 0 y del timer 2

La real potencia del Timer0 se deja apreciar al emplear su característica más notable: las interrupciones. El Timer0 tiene dos tipos de interrupciones: una por el desbordamiento de su registro TCNT0 y dos en las coincidencias de su registro TCNT0 con los registros OCR0A y OCR0B. Estas interrupciones se controlan por los bits de los registros TIMSK0 y TIFR0:

• TIMSK0 (Timer Interrupt Mask Register 0). Contiene los bits Enable de interrupciones. • TIFR0 (Timer Interrupt Flags Register 0). Contiene los bits de Flag de interrupciones.

Para quienes aún trabajan con los viejos megaAVR, ellos no tienen interrupción en coincidencia B, los bits de la coincidencia A son simplemente OCIE0 y OCF0, y los siguientes registros se llaman TIMSK y TIFR. No llevan el 0 porque también controlan las interrupciones del Timer1 y del Timer2.

Registro TIMSK0TIMSK0 --- --- --- --- --- OCIE0B OCIE0A TOIE0

Registro TIFR0TIFR0 --- --- --- --- --- OCF0B OCF0A TOV0

Interrupción por Desbordamiento del Timer0. El evento que puede disparar esta interrupción es el desbordamiento del registro TCNT0, o sea, la transición de 255 a 0. Esto implica la operación incremental del Timer0, sin importar si está contando en modo Normal, CTC o Fast PWM. En modo PWM de Fase Correcta el Timer0 cuenta en sube y baja sin pasar por la transición 255 a 0, así que en este modo no hay desbordamiento.

El desbordamiento de Timer0 activará el flag TOV0 y si la interrupción está habilitada, se disparará. El bit TOV0 se limpia automáticamente al ejecutarse su función de interrupción ISR, pero también se puede limpiar por software, como de costumbre, escribiéndole un 1 y sin usar instrucciones de lectura-

Page 139: Manual Micros 2010

modificación-escritura como las generadas por las sentencias con el operador OR binario (|).

Para habilitar la interrupción por Desbordamiento del Timer0 se setean los bits TOIE0 y obviamente, el bit enable general de interrupciones I, del registro SREG. La instrucción del ensamblador dedicada a esta operación es SEI y que en lenguaje C se puede incrustar mediante la función macro del mismo nombre sei(). (No sé por qué repito estas cosas.)

Interrupción en Coincidencia del Timer0. Como sabemos, los comparadores del Timer0 son circuitos que en todo momento están comparando los valores del registro TCNT0 con los registros OCR0A y OCR0B. Pues bien, el evento que puede disparar esta interrupción es la coincidencia entre los registros mencionados. Como puede haber dos coincidencias, aquí podemos tener hasta dos interrupciones.

Especificando, cuando se detecte la igualdad entre TCNT0 y OCR0A se activará el flag OCF0A (Output Compare Flag 0 A), y cuando sean iguales TCNT0 y OCR0B se activará el flag OCF0B (Output Compare Flag 0 A). De nuevo, los flags se ponen a 1 independientemente de si sus interrupciones están habilitadas o no. Si lo están, se dispararán sus interrupciones, se ejecutarán las funciones ISR respectivas y los flags OCF0A y/o OCF0B se limpiarán por hardware. Ya sobra decir que también se pueden limpiar por software escribiéndoles un uno.

Ambas interrupciones son gemelas pero no son siamesas, es decir, funcionan exactamente igual pero no necesariamente se tienen que habilitar las dos al mismo tiempo. Se habilitan por separado seteando el bit OCIE0A para una y OCIE0B para la otra.

Una observación: el circuito comparador (llamado Output Compare) trabaja siempre sin importar en qué modo está operando el Timer0 (Normal, CTC o PWM), aunque las implicatorias no serán las mismas. Explico: una coincidencia en modo CTC resetea el registro TCNT0, mientras que en los otros modos el registro TCNT0 sigue su marchar sin hacer caso. Si captaste mi cháchara, habrás descubierto que es posible temporizar con la Interrupción en Coincidencia incluso si el Timer trabaja en modo PWM.

Cálculo en modo CTC del timer 0

La ecuación que permite definir el tiempo que tarda en el modo ctc, esta dado de la siguiente manera

Tiempo=N⋅OCRnx

FCPU

Page 140: Manual Micros 2010

6.3.2 ADCEl Convertidor Analógico Digital del ATmega48 es por Aproximaciones Sucesivas con una resolución de 10 bits. El ADC se conecta a un multiplexor de 8 canales análogos el cual permite 8 voltajes de entrada en una sola terminación construido en los pines delpuerto A. El voltaje de entrada de una sola terminación se refiere a 0 V (GND).

La interrupción por Conversión completa, resulta útil cuando se desea cancelar el ruido en la conversión. Para hacer uso de esta característica, el siguiente procedimiento deberá usarse.

1. Asegúrese que el ADC este habilitado y no se encuentre ocupado en una conversión. En el modo de conversión única debe ser seleccionado y la interrupción de conversión completa del ADC debe ser habilitada.

2. Entre al modo de reducción de ruido del ADC. El ADC iniciará una conversión una vez que el CPU ha sido detenido.

3. Si ninguna interrupción ocurre antes de que la conversión del ADC se complete,la interrupción del ADC despertara al CPU y ejecutara la rutina de interrupción de conversión completa del ADC. Si otra interrupción activa al CPU antes de que la conversión del ADC se complete, esa interrupción será ejecutada, y una solicitud de interrupción de conversión completa del ADC será generada cuando la conversión del ADC se completa. El CPU permanecerá en modo activo hasta que un nuevo comando de sleep se ejecute.

El registro ADCSRA Es el encargado del control y estado del ADC.

ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0

El bit ADIE al ser seteado, permite habilitar la interrupción por conversión completada.

El bit ADIF se pone en estado alto cuando la una conversión analógico a digital ha sido completada y el registro de datos es actualizado.

6.3.3 De la comunicación serial

• El Transmisor/Receptor Universal Síncrono y Asíncrono (USART) es un dispositivo altamente flexible para comunicación serial. Las principales características son:

• Operación Full Duplex (Registros independientes de recepción y transmisión serial).

• Operación Asíncrona y Sincrona.

• Operación sincrona Maestro-Esclavo.

• Generador de alta resolución de Baud rate.

• Soporte de frames con 5, 6, 7, 8 o 9 bits de datos y 1 o 2 bits de stop.

Page 141: Manual Micros 2010

• Generación de paridad Par o Impar y Chequeo soportado por hardware.

• Detección de datos OverRun.

• Detección de framing de error.

• Filtrado de ruido incluid, detección de bit de inicio falso y filtro pasa-bajo ideal.

• Tres interrupciones separadas: Finalización de Tx, Registro de datos vacío Tx,Recepción Completa Rx.

• Modo de comunicación Multiprocesador.

• Modo de comunicación de doble velocidad Asíncrona

Ya que la USART tiene 3 fuentes de interrupción, a continuación se describen los bits de configuración para cada una de ellas:

Transmisión de datos

El transmisor de la USART se habilita mediante la puesta en Alto del bit TXEN en el Registro UCSRnB. Cuando la transmisión es habilitada, la operación normal del puerto donde se ubica la terminal TxDn es controlada por la USART y se configura como salida de transmisión serial.

Banderas de Transmisión e Interrupciones

El transmisor de la USART tiene dos banderas que indican su estado: (UDREn) Registro de Datos de USART vacio y (TXCn) Transmisión completa. Ambas banderas pueden ser utilizadas para generar interrupciones.

La bandera UDREn indica que el buffer para transmisión de datos se encuentra listo para recibir un nuevo dato. Este bit se pone en estado alto cuando el buffer de trasmisión se encuentra vació y se pone en estado bajo cuando el buffer contiene datos a ser transmitido.

Cuando al bit de habilitación de Interrupción por Registro de Datos vacío se le escribe un uno, la interrupción de registro de datos vacío se ejecuta tan pronto como UDREn sea alto. Cuando se usa una transmisión de datos dirigida por interrupción, la rutina de interrupción de registro vacío debe ya sea escribir un nuevo dato a UDRn para limpiar UDREn o deshabilitar lainterrupción de datos de registro vacío, de lo contrario una nueva interrupción puede ocurrir una vez que la rutina de interrupción termine.

El bit de la bandera de la transmisión completada (TXCn) se coloca a uno cuando el frame entero en el registro de corrimiento de transmisión ha sido enviado serialmente y ningún dato actualmente se encuentra en el buffer de transmisión. El bit de la bandera TXCn automáticamente se limpia cuando una interrupción de trasmisión completa se ejecute, o puede ser borrado escribiendo a uno en esa localidad del bit. La bandera TXCn es útil para interfaces de comunicación half-duplex (como el estándar RS485),donde una transmisión debe entrar a modo de recepción y se libere el bus de comunicación inmediatamente después de completar la transmisión.

Cuando el bit de habilitación de interrupción de transmisión completa en el UCSRnB se ponga a uno, la interrupción de

Page 142: Manual Micros 2010

transmisión completa del USART será ejecutada cuando la bandera TXCn llegue a ponerse a uno (siempre y cuando las interrupciones globales estén habilitadas). Cuando la interrupción de transmisión completa se use, la rutina del manejo de interrupción no tiene que limpiar la bandera TXCn, esto se realiza automáticamente cuando la interrupción se ejecute.

Recepción de datos – Receptor de la USART

La recepción inicia se detecta un bit de inicio válido, cada bit que sigue al bit de inicio será muestreado a la velocidad del generador de Baudios, y es desplazado hacia el registro de corrimiento de recepción. Cuando el primer bit de paro es recibido, es decir, cuando el cuadro de recepción serial está completo, el contenido del registro de desplazamiento es movido hacia el registro de recepción, el cual puede ser leído desde la localidad UDRn

Bandera de Recepción completa e Interrupción.

La bandera Recepción Terminada (RXCn) indica la presencia de un dato sin leer en el buffer de recepción

Cuando el bit de habilitación de interrupción de recepción completa (RXCIEn) en el UCSRnB es puesto a uno, la interrupción de recepción completa del USART será ejecutada tan pronto como la bandera RXCn se ponga a uno (siempre y cuando las interrupciones globales estén habilitadas). Cuando se usa la recepción de datos dirigida por interrupción, la rutina de recepción completa debe leer el dato recibido de UDRn para limpiar la bandera de RXC, de lo contrario una nueva interrupción puede ocurrir una vez que la rutina de interrupción termina.

6.3.4 Del comparador analógico.

El comparador analógico permite comparar valores de entrada entre la terminal positiva AIN0 y la terminal negativa AIN1. El usuario puede seleccionar disparo por interrupción en flanco de subida, de bajada o por cambio a la salida.

La interrupción del comparador analógico se habilita mediante el bit ACIE del registro ACSR, al ponerse en estado alto.

El modo de Interrupción se elige mediante los bits ACIS1 y ACIS0

ACIS1 ACIS0 Modo de Interrupción

0 0 Interrupción en cambio a la salida

0 1 Reservado

1 0 Interrupción en flanco de bajada a la salida

1 1 Interrupción en flanco de subida a la salida

Tabla 21: Bits para configuración de Interrupciones del comparador analógico

Page 143: Manual Micros 2010

6.3.5 De la EEPROM

El ATmega48 contiene 256 bytes de memoria de datos EEPROM, la cual se encuentra se organizada como un espacio de datos separado, en el cual, bytes pueden ser leídos o escritos.

La interrupción que genera la EEPROM se habilita mediante el bit EERIE al ponerlo en estado alto, esto en el registro EECR

6.4 Ejemplos de aplicaciones de las interrupciones.Práctica.- Haciendo uso de la interrupción por coincidencia del timer 0, elaborar un reloj digital que muestre segundos, minutos y horas, haga uso del temporizador interno de 8 Mhz prescalado por 8, y agregue dos botones que permitan ajustar los minutos y las horas del reloj.

El código fuente es el que se muestra a continuaciónfigura 64: Reloj Digital Simple

Page 144: Manual Micros 2010

#include <avr/io.h>#define clearbit(sfr,bit) (_SFR_BYTE(sfr) &= ~(_BV(bit)))#define setbit(sfr, bit) (_SFR_BYTE(sfr) |= (_BV(bit)))#define togglebit(sfr,bit) (_SFR_BYTE(sfr)^=(_BV(bit)))#define F_CPU 1000000UL#include <util/delay.h>#include <avr/interrupt.h>

#define SegDataPort PORTB#define SegDataPin PINB#define SegDataDDR DDRB

#define SegCntrlPort PORTC#define SegCntrlPin PINC#define SegCntrlDDR DDRC

unsigned char tick_100ms;unsigned char hora = 0;unsigned char minuto = 0;unsigned char segundo = 0;

#define PinH PD2#define PinM PD3#define pPinH PIND#define rpPinH PORTD#define pPinM PIND#define rpPinM PORTD#define cpPinH DDRD#define cpPinM DDRD/*Función para codificar un decimal a siete segmentos de catodo comun*/unsigned char DigTo7Seg(unsigned char digit, unsigned char comun);

/* * Rutina de servicio de interrupción en coincidencia */

ISR(TIMER0_COMPA_vect){

static unsigned char i;tick_100ms++;if(++i >=10){

segundo++;i=0;

}

if(segundo == 60){

segundo = 0;minuto++;

}

if(minuto == 60){

minuto = 0;hora++;

}

if(hora > 23)hora = 0;

_delay_us(670);//togglebit(PORTB,PB7);

}

int main(void){

Page 145: Manual Micros 2010

SegDataDDR = 0xFF; //Es salidaSegCntrlDDR = 0xFF; // Salidas para encender un solo display a la vezSegCntrlPort = 0xFF;clearbit(cpPinH, PinH);clearbit(cpPinM, PinM);

setbit(rpPinH, PinH); //Se habilitan resistencias de Pull upsetbit(rpPinM, PinM);

setbit(DDRB,PB7);

clearbit(PORTB,PB7);

/* * configuracion del timer 0 * * Modo de operacion: CTC [Clear Timer On Compare Match] * Factor de Preescalamiento: 1024 * Valor de precarga: 96 * Periodo de auto reset: 0.1 s */setbit(TCCR0A, WGM01); //modo ctc pagina 103

setbit(TCCR0B, CS02); // Preescalamiento 1024 --> 101clearbit(TCCR0B, CS01);setbit(TCCR0B, CS00);

OCR0A = 96; //Precarga de comparacion

/*Habilitando la interrupcion por coincidencia del timer*/setbit(TIMSK0, OCIE0A);sei();

while(1){

/*Ajuste de minutos */if(bit_is_clear(pPinM,PinM)){

_delay_ms(200);if(minuto < 59)

minuto++;else

minuto = 0;}/*Ajuste de las horas*/if(bit_is_clear(pPinH,PinH)){

_delay_ms(200);if(hora < 23)

hora++;else

hora = 0;}

SegDataPort = DigTo7Seg(segundo%10,1); //envia unidadesSegCntrlPort = ~0x01;_delay_ms(15);SegDataPort = DigTo7Seg(segundo/10,1); //envia decenas

SegCntrlPort = ~0x02; _delay_ms(15);

SegDataPort = DigTo7Seg(minuto%10,1); //envia unidadesSegCntrlPort = ~0x04;_delay_ms(15);SegDataPort = DigTo7Seg(minuto/10,1); //envia decenas

SegCntrlPort = ~0x08; _delay_ms(15);

SegDataPort = DigTo7Seg(hora%10,1); //envia unidadesSegCntrlPort = ~0x10;

Page 146: Manual Micros 2010

_delay_ms(15);SegDataPort = DigTo7Seg(hora/10,1); //envia decenas

SegCntrlPort = ~0x20; _delay_ms(15);

}}

/** Function Description:* Encode a Decimal Digit 0-9 to its Seven Segment Equivalent.** Function Arguments:* digit - Decimal Digit to be Encoded* common - Common Anode (0), Common Cathode(1)* SegVal - Encoded Seven Segment Value** Connections:* Encoded SegVal is return in the other G-F-E-D-C-B-A that is A is the least* significant bit (bit 0) and G bit 6.*/unsigned char DigTo7Seg(unsigned char digit, unsigned char common){

unsigned char SegVal=0;

switch(digit){

case 0: if(common == 1) SegVal = 0b00111111;else SegVal = ~0b00111111;break;

case 1: if(common == 1) SegVal = 0b00000110;else SegVal = ~0b00000110;break;

case 2: if(common == 1) SegVal = 0b01011011;else SegVal = ~0b01011011;break;

case 3: if(common == 1) SegVal = 0b01001111;else SegVal = ~0b01001111;break;

case 4: if(common == 1) SegVal = 0b01100110;else SegVal = ~0b01100110;break;

case 5: if(common == 1) SegVal = 0b01101101;else SegVal = ~0b01101101;break;

case 6: if(common == 1) SegVal = 0b01111101;else SegVal = ~0b01111101;break;

case 7: if(common == 1) SegVal = 0b00000111;else SegVal = ~0b00000111;break;

case 8: if(common == 1) SegVal = 0b01111111;else SegVal = ~0b01111111;break;

case 9: if(common == 1) SegVal = 0b01101111;else SegVal = ~0b01101111;

}return (SegVal);

}

Tabla 22: Código fuente Reloj digital con display de 7 segmentos basado en ATmega48

El siguiente programa para microcontrolador AVR, muestra la forma en la que se declaran, una interrupción ocasionada por el Timer0 (de 8 bits) y otra por el Timer1 (de 16 bits), por medio de la

Page 147: Manual Micros 2010

implementación de dos librerías, una denominada timer0.h y la otra timer1.c

/**@code #include <timer0.h> @endcode

@briefRutina para la configuración del timer 0 de 8 bitsEste temporizador cuenta con 8 modos de operación clasificados en 4 grupos

* Normal modo{0}* CTC (limpia a la captura) modo{2}* Fast PWM modo{3,7}* PWM de Fase Correcta modo{1,5}**/

#ifndef TIMER0_H_INCLUDED#define TIMER0_H_INCLUDED

/** * @name Definicion para la variable byte * para usar en lugar de unsigned char */#define byte uint8_t /**< definición del tipo de dato byte */

/** * @name Functions */

/** @brief Ajusta los valores del temporizador 0 para sus diferentes modo y activacion de las terminales externas de comparación @param mode Se refiere uno de los siete modos de operacion del timer @param prescale Se refiere al valor de pṕ rescalamiento para el temporizador @param outmode_A Se refiere al comportamiento que pueden tener los bits de comparacion del modulo A @param outmode_B Se refiere al comportamiento que pueden tener los bits de comparacion del modulo B @return none*/void timer0_setup(byte mode, int prescale, byte outmode_A, byte outmode_B);

#endif // TIMER0_H_INCLUDED

Tabla 23: Librería para configuración del timer0 - timer0.h

A continuación se muestra el fuente para esta librería

Page 148: Manual Micros 2010

#include <avr/io.h> #include "timer0.h"

void timer0_setup(byte mode, int prescale, byte outmode_A, byte outmode_B) { mode&=7; outmode_A&=3; outmode_B&=3; byte clock_mode = 0;

switch(prescale) { case 1: clock_mode = 1; break; case 8: clock_mode = 2; break; case 64: clock_mode = 3; break; case 256: clock_mode = 4; break; case 1024: clock_mode = 5; break; default: if(prescale < 0) clock_mode = 7; }

TCCR0A = (outmode_A << 6) | \ (outmode_B << 4) | \ (mode & 0x03); TCCR0B = ((mode & 0x04)<<1) | (clock_mode); }

Tabla 24: Librería para configuración del timer0 - timer0.c

En este apartado se muestra el archivo de cabecera timer1.h

/** @code #include <timer1.h> @endcode

@brief Rutina para la configuración del timer 1 de 16 bits Este temporizador cuenta con 16 modos de operación clasificados en 5 grupos

* Normal modo{0} * CTC (limpia a la captura) modo{4,12} * Fast PWM modo{5,6,7,14,15} * PWM de Fase Correcta modo{1,2,3,10,11} * PWM de fase correcta, frecuencia correcta modo{8,9} */

#ifndef TIMER1_H_INCLUDED #define TIMER1_H_INCLUDED #define byte uint8_t

void timer1_setup(byte mode, int prescale, unsigned char outmode_A, unsigned char outmode_B, unsigned char capture);

#endif // TIMER1_H_INCLUDED

Tabla 25: Librería para configuración del timer1 - timer1.h

y aquí su código fuente

Page 149: Manual Micros 2010

#include <avr/io.h> #include "timer1.h"

void timer1_setup(unsigned char mode, int prescale, unsigned char outmode_A, unsigned char outmode_B, unsigned char capture) { /* *Ajustando el ancho de los campos de bit */ mode &= 15; outmode_A &= 3; outmode_B &= 3; capture &= 3;

unsigned char clock_mode = 0; //El cero significa que el temporizador está apagado

switch(prescale) { case 1: clock_mode = 1; break; case 8: clock_mode = 2; break; case 64: clock_mode = 3; break; case 256: clock_mode = 4; break; case 1024: clock_mode = 5; break; default: if(prescale < 0) //Habilitar conexion por reloj externo clock_mode = 7; } TCCR1A = (outmode_A << 6) | \ (outmode_B << 4) | \ (mode & 3);

TCCR1B = (capture << 6) | ((mode & 0x0C) << 1) | clock_mode; }

Tabla 26: Librería para configuración del timer1 - timer1.c

La forma de usar esta librería se propone en este apartado, en donde dos leds conectados a terminales diferentes encienden y apagan a tiempos determinados de la siguiente manera:

Tiempo=N (OCRxA)

F CPU

en donde OCRxA es el valor (de 16 bits para el timer 1 y 8 bits para el timer0) con el que se va a compara el registro TCNTx, para ser reseteado en modo CTC y que se active la rutina de servicio de interrupción.

La determinación de un tiempo deseado se puede verificar de forma similar a la explicada en la página 135 solo que una vez definido el valor de prescalamiento (que solo puede ser 1,8,64,256 o 1024), se procede a calcular el valor de OCRxA de acuerdo a la siguiente ecuación:

OCRxA=FCPU⋅Tiempo

N

Por ejemplo para un tiempo de 21.68ms a una frecuencia de reloj de 1MHz, los valores de prescalamiento y de carga de comparación (OCR1A) en el temporizador de 16 bits, se tiene que determinar primero el factor de prescalamiento.

N=21.68ms⋅1 MHz

65536=0.333

Al dar un factor de prescalamiento menor a uno, podemos redondearlo hacia arriba a 1, de esta forma el

Page 150: Manual Micros 2010

valor que se debe cargar al OCR1A será determinado como sigue:

OCR1A=(1MHz)(21.68ms)

1=21680=0x54B0

De esta forma, el código fuente queda de la manera siguiente:

/* */

#include <avr/io.h> #include <avr/interrupt.h> #include "timer1.h" #include "timer0.h"

ISR(TIMER1_COMPA_vect) { PORTD^=(1 << PD5); }

ISR(TIMER0_COMPA_vect) { PORTD^=(1 << PD2); }

int main(void) {

// Insert code DDRD|=(1<<DDD5); //salida del Timer 1 DDRD|=(1<<DDD2); //salida del Timer 0 /* configuracion del timer 1 Modo de operacion: CTC (4) Factor de Prescalamiento: 1 Valor de Precarga: 0x54B0 (OCR1A) Periodo de AutoReset: 21.68ms F_CPU = 1MHz Tiempo = N(OCR1A)/F_CPU */ timer1_setup(4,1,0,0,0); OCR1A=0x54B0; TIMSK1|=(1<<OCIE1A); //interrupcion por comparacion en modulo A

/* configuracion del timer 0 Modo de operacion: CTC Factor de Prescalamiento: 1024 Valor de Precarga: 99 (OCR0A) Periodo de AutoReset: 101.3 ms F_CPU: 1MHz Tiempo = N(OCR0A)/F_CPU */ timer0_setup(2,1024,0,0); OCR0A=99; TIMSK0|=(1<<OCIE0A); //interrupcion por comparacion en modulo A

sei();

while(1) ;

return 0; }

Tabla 27: Código fuente para configurar el timer 0 en modo CTC

Page 151: Manual Micros 2010

Para el timer 0, el cálculo es similar, se deja al lector que estime los tiempos que son señalados en el código fuente.

Práctica propuesta

Elaborar de nuevo el reloj, pero usando esta vez una pantalla LCD, en lugar de los cuatros displays de 7 segmentos, tal y como se muestra en la siguiente figura:

Es recomendable también que se haga uso de la libreria de peter Fleury, en conjunto con la libreria clk.h para el manejo de la LCD de esta práctica:

figura 65: Reloj con base en Timer 0

Page 152: Manual Micros 2010

#ifndef LCD_H

#define LCD_H

/*************************************************************************

Title : C include file for the HD44780U LCD library (lcd.c)

Author: Peter Fleury <[email protected]> http://jump.to/fleury

File: $Id: lcd.h,v 1.13.2.2 2006/01/30 19:51:33 peter Exp $

Software: AVR-GCC 3.3

Hardware: any AVR device, memory mapped mode only for AT90S4414/8515/Mega

***************************************************************************/

/**

@defgroup pfleury_lcd LCD library

@code #include <lcd.h> @endcode

@brief Basic routines for interfacing a HD44780U-based text LCD display

Originally based on Volker Oth's LCD library,

changed lcd_init(), added additional constants for lcd_command(),

added 4-bit I/O mode, improved and optimized code.

Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in

4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.

Memory mapped mode compatible with Kanda STK200, but supports also

generation of R/W signal through A8 address line.

@author Peter Fleury [email protected] http://jump.to/fleury

@see The chapter <a href="http://homepage.sunrise.ch/mysunrise/peterfleury/avr-lcd44780.html" target="_blank">Interfacing a HD44780 Based LCD to an AVR</a>

on my home page.

*/

/*@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303

#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !"

#endif

#include <inttypes.h>

#include <avr/pgmspace.h>

Page 153: Manual Micros 2010

/**

* @name Definitions for MCU Clock Frequency

* Adapt the MCU clock frequency in Hz to your target.

*/

#define XTAL F_CPU /**< clock frequency in Hz, used to calculate delay timer */

/**

* @name Definition for LCD controller type

* Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller.

*/

#define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */

/**

* @name Definitions for Display Size

* Change these definitions to adapt setting to your display

*/

#define LCD_LINES 2 /**< number of visible lines of the display */

#define LCD_DISP_LENGTH 16 /**< visibles characters per line of the display */

#define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */

#define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */

#define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */

#define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */

#define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */

#define LCD_WRAP_LINES 0 /**< 0: no wrap, 1: wrap at end of visibile line */

#define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */

#if LCD_IO_MODE

/**

* @name Definitions for 4-bit IO mode

* Change LCD_PORT if you want to use a different port for the LCD pins.

*

* The four LCD data lines and the three control lines RS, RW, E can be on the

* same port or on different ports.

* Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on

* different ports.

*

* Normally the four data lines should be mapped to bit 0..3 on one port, but it

* is possible to connect these data lines in different order or even on different

* ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions.

*

*/

Page 154: Manual Micros 2010

#define LCD_PORT PORTD /**< port for the LCD lines */

#define LCD_DATA0_PORT PORTD /**< port for 4bit data bit 0 */

#define LCD_DATA1_PORT PORTB /**< port for 4bit data bit 1 */

#define LCD_DATA2_PORT PORTB /**< port for 4bit data bit 2 */

#define LCD_DATA3_PORT PORTD /**< port for 4bit data bit 3 */

#define LCD_DATA0_PIN 5 /**< pin for 4bit data bit 0 */

#define LCD_DATA1_PIN 2 /**< pin for 4bit data bit 1 */

#define LCD_DATA2_PIN 3 /**< pin for 4bit data bit 2 */

#define LCD_DATA3_PIN 1 /**< pin for 4bit data bit 3 */

#define LCD_RS_PORT LCD_PORT /**< port for RS line */

#define LCD_RS_PIN 7 /**< pin for RS line */

#define LCD_RW_PORT LCD_PORT /**< port for RW line */

#define LCD_RW_PIN 6 /**< pin for RW line */

#define LCD_E_PORT LCD_PORT /**< port for Enable line */

#define LCD_E_PIN 4 /**< pin for Enable line */

#elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || \

defined(__AVR_ATmega8515__)|| defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || \

defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__)

/*

* memory mapped mode is only supported when the device has an external data memory interface

*/

#define LCD_IO_DATA 0xC000 /* A15=E=1, A14=RS=1 */

#define LCD_IO_FUNCTION 0x8000 /* A15=E=1, A14=RS=0 */

#define LCD_IO_READ 0x0100 /* A8 =R/W=1 (R/W: 1=Read, 0=Write */

#else

#error "external data memory interface not available for this device, use 4-bit IO port mode"

#endif

/**

* @name Definitions for LCD command instructions

* The constants define the various LCD controller instructions which can be passed to the

* function lcd_command(), see HD44780 data sheet for a complete description.

*/

/* instruction register bit positions, see HD44780U data sheet */

#define LCD_CLR 0 /* DB0: clear display */

#define LCD_HOME 1 /* DB1: return to home position */

#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */

#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */

#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */

Page 155: Manual Micros 2010

#define LCD_ON 3 /* DB3: turn lcd/cursor on */

#define LCD_ON_DISPLAY 2 /* DB2: turn display on */

#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */

#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */

#define LCD_MOVE 4 /* DB4: move cursor/display */

#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */

#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */

#define LCD_FUNCTION 5 /* DB5: function set */

#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */

#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */

#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */

#define LCD_CGRAM 6 /* DB6: set CG RAM address */

#define LCD_DDRAM 7 /* DB7: set DD RAM address */

#define LCD_BUSY 7 /* DB7: LCD is busy */

/* set entry mode: display shift on/off, dec/inc cursor move direction */

#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */

#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */

#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */

#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */

/* display on/off, cursor on/off, blinking char at cursor position */

#define LCD_DISP_OFF 0x08 /* display off */

#define LCD_DISP_ON 0x0C /* display on, cursor off */

#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */

#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */

#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */

/* move cursor/shift display */

#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */

#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */

#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */

#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */

/* function set: set interface data length and number of display lines */

#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */

#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */

#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */

#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */

#define LCD_MODE_DEFAULT ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )

Page 156: Manual Micros 2010

/**

* @name Functions

*/

/**

@brief Initialize display and select type of cursor

@param dispAttr \b LCD_DISP_OFF display off \n

\b LCD_DISP_ON display on, cursor off \n

\b LCD_DISP_ON_CURSOR display on, cursor on\n

\b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing

@return none

*/

extern void lcd_init(uint8_t dispAttr);

/**

@brief Clear display and set cursor to home position

@param void

@return none

*/

extern void lcd_clrscr(void);

/**

@brief Set cursor to home position

@param void

@return none

*/

extern void lcd_home(void);

/**

@brief Set cursor to specified position

@param x horizontal position\n (0: left most position)

@param y vertical position\n (0: first line)

@return none

*/

extern void lcd_gotoxy(uint8_t x, uint8_t y);

Page 157: Manual Micros 2010

/**

@brief Display character at current cursor position

@param c character to be displayed

@return none

*/

extern void lcd_putc(char c);

/**

@brief Display string without auto linefeed

@param s string to be displayed

@return none

*/

extern void lcd_puts(const char *s);

/**

@brief Display string from program memory without auto linefeed

@param s string from program memory be be displayed

@return none

@see lcd_puts_P

*/

extern void lcd_puts_p(const char *progmem_s);

/**

@brief Send LCD controller instruction command

@param cmd instruction to send to LCD controller, see HD44780 data sheet

@return none

*/

extern void lcd_command(uint8_t cmd);

/**

@brief Send data byte to LCD controller

Similar to lcd_putc(), but without interpreting LF

@param data byte to send to LCD controller, see HD44780 data sheet

@return none

*/

extern void lcd_data(uint8_t data);

Page 158: Manual Micros 2010

/**

@brief Print a float number in LCD from http://extremeelectronics.co.in/avr-tutorials/using-module-with-avrs/

for example

lcd_writeFloat(68.198,3,2)

will display 068.19

@param val floating data, double type here

@param flbp field length before point

@param flap field length after point

@return none

*/

extern void lcd_writeFloat(double val, unsigned int flbp, unsigned int flap);

/**

@brief macros for automatically storing string constant in program memory

*/

#define lcd_puts_P(__s) lcd_puts_p(PSTR(__s))

/*@}*/

#endif //LCD_H

Tabla 28: Librería lcd.h de Peter Fleury

Archivo lcd.c

Page 159: Manual Micros 2010

/****************************************************************************

Title : HD44780U LCD library

Author: Peter Fleury <[email protected]> http://jump.to/fleury

File: $Id: lcd.c,v 1.14.2.2 2012/02/12 07:51:00 peter Exp $

Software: AVR-GCC 3.3

Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega

DESCRIPTION

Basic routines for interfacing a HD44780U-based text lcd display

Originally based on Volker Oth's lcd library,

changed lcd_init(), added additional constants for lcd_command(),

added 4-bit I/O mode, improved and optimized code.

Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in

4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.

Memory mapped mode compatible with Kanda STK200, but supports also

generation of R/W signal through A8 address line.

USAGE

See the C include lcd.h file for a description of each function

*****************************************************************************/

#include <inttypes.h>

#include <avr/io.h>

#include <avr/pgmspace.h>

#include "lcd.h"

/*

** constants/macros

*/

#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */

#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)

/* on ATmega64/128 PINF is on port 0x00 and not 0x60 */

#define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )

#else

#define PIN(x) (*(&x - 2)) /* address of input register of port x */

#endif

Page 160: Manual Micros 2010

#if LCD_IO_MODE

#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f \n 1:" ); //#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f \n 1: rjmp 2f \n 2:" );

#define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN);

#define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN);

#define lcd_e_toggle() toggle_e()

#define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN)

#define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN)

#define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN)

#define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN)

#endif

#if LCD_IO_MODE

#if LCD_LINES==1

#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE

#else

#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES

#endif

#else

#if LCD_LINES==1

#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE

#else

#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES

#endif

#endif

#if LCD_CONTROLLER_KS0073

#if LCD_LINES==4

#define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x2C /* |0|010|1100 4-bit mode, extension-bit RE = 1 */

#define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x28 /* |0|010|1000 4-bit mode, extension-bit RE = 0 */

#define KS0073_4LINES_MODE 0x09 /* |0|000|1001 4 lines mode */

#endif

#endif

/*

** function prototypes

*/

#if LCD_IO_MODE

static void toggle_e(void);

#endif

/*

Page 161: Manual Micros 2010

** local functions

*/

/*************************************************************************

delay loop for small accurate delays: 16-bit counter, 4 cycles/loop

*************************************************************************/

static inline void _delayFourCycles(unsigned int __count)

{

if ( __count == 0 )

__asm__ __volatile__( "rjmp 1f \n 1:" ); // 2 cycles

else

__asm__ __volatile__ (

"1: sbiw %0,1" "\n\t"

"brne 1b" // 4 cycles/loop

: "=w" (__count)

: "0" (__count)

);

}

/*************************************************************************

delay for a minimum of <us> microseconds

the number of loops is calculated at compile-time from MCU clock frequency

*************************************************************************/

#define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 )

#if LCD_IO_MODE

/* toggle Enable Pin to initiate write */

static void toggle_e(void)

{

lcd_e_high();

lcd_e_delay();

lcd_e_low();

}

#endif

/*************************************************************************

Low-level function to write byte to LCD controller

Input: data byte to write to LCD

Page 162: Manual Micros 2010

rs 1: write data

0: write instruction

Returns: none

*************************************************************************/

#if LCD_IO_MODE

static void lcd_write(uint8_t data,uint8_t rs)

{

unsigned char dataBits ;

if (rs) { /* write data (RS=1, RW=0) */

lcd_rs_high();

} else { /* write instruction (RS=0, RW=0) */

lcd_rs_low();

}

lcd_rw_low();

if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )

&& (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )

{

/* configure data pins as output */

DDR(LCD_DATA0_PORT) |= 0x0F;

/* output high nibble first */

dataBits = LCD_DATA0_PORT & 0xF0;

LCD_DATA0_PORT = dataBits |((data>>4)&0x0F);

lcd_e_toggle();

/* output low nibble */

LCD_DATA0_PORT = dataBits | (data&0x0F);

lcd_e_toggle();

/* all data pins high (inactive) */

LCD_DATA0_PORT = dataBits | 0x0F;

}

else

{

/* configure data pins as output */

DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);

DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);

DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);

DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);

Page 163: Manual Micros 2010

/* output high nibble first */

LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);

LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);

LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);

LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);

if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);

if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);

if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);

if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);

lcd_e_toggle();

/* output low nibble */

LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);

LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);

LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);

LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);

if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);

if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);

if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);

if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);

lcd_e_toggle();

/* all data pins high (inactive) */

LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);

LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);

LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);

LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);

}

}

#else

#define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;

/* rs==0 -> write instruction to LCD_IO_FUNCTION */

/* rs==1 -> write data to LCD_IO_DATA */

#endif

/*************************************************************************

Low-level function to read byte from LCD controller

Input: rs 1: read data

0: read busy flag / address counter

Returns: byte read from LCD controller

*************************************************************************/

Page 164: Manual Micros 2010

#if LCD_IO_MODE

static uint8_t lcd_read(uint8_t rs)

{

uint8_t data;

if (rs)

lcd_rs_high(); /* RS=1: read data */

else

lcd_rs_low(); /* RS=0: read busy flag */

lcd_rw_high(); /* RW=1 read mode */

if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )

&& ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )

{

DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */

lcd_e_high();

lcd_e_delay();

data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */

lcd_e_low();

lcd_e_delay(); /* Enable 500ns low */

lcd_e_high();

lcd_e_delay();

data |= PIN(LCD_DATA0_PORT)&0x0F; /* read low nibble */

lcd_e_low();

}

else

{

/* configure data pins as input */

DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);

DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);

DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);

DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);

/* read high nibble first */

lcd_e_high();

lcd_e_delay();

data = 0;

if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10;

Page 165: Manual Micros 2010

if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20;

if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40;

if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80;

lcd_e_low();

lcd_e_delay(); /* Enable 500ns low */

/* read low nibble */

lcd_e_high();

lcd_e_delay();

if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01;

if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02;

if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04;

if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08;

lcd_e_low();

}

return data;

}

#else

#define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)

/* rs==0 -> read instruction from LCD_IO_FUNCTION */

/* rs==1 -> read data from LCD_IO_DATA */

#endif

/*************************************************************************

loops while lcd is busy, returns address counter

*************************************************************************/

static uint8_t lcd_waitbusy(void)

{

register uint8_t c;

/* wait until busy flag is cleared */

while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {}

/* the address counter is updated 4us after the busy flag is cleared */

delay(2);

/* now read the address counter */

return (lcd_read(0)); // return address counter

}/* lcd_waitbusy */

Page 166: Manual Micros 2010

/*************************************************************************

Move cursor to the start of next line or to the first line if the cursor

is already on the last line.

*************************************************************************/

static inline void lcd_newline(uint8_t pos)

{

register uint8_t addressCounter;

#if LCD_LINES==1

addressCounter = 0;

#endif

#if LCD_LINES==2

if ( pos < (LCD_START_LINE2) )

addressCounter = LCD_START_LINE2;

else

addressCounter = LCD_START_LINE1;

#endif

#if LCD_LINES==4

#if KS0073_4LINES_MODE

if ( pos < LCD_START_LINE2 )

addressCounter = LCD_START_LINE2;

else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) )

addressCounter = LCD_START_LINE3;

else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) )

addressCounter = LCD_START_LINE4;

else

addressCounter = LCD_START_LINE1;

#else

if ( pos < LCD_START_LINE3 )

addressCounter = LCD_START_LINE2;

else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) )

addressCounter = LCD_START_LINE3;

else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) )

addressCounter = LCD_START_LINE4;

else

addressCounter = LCD_START_LINE1;

#endif

#endif

lcd_command((1<<LCD_DDRAM)+addressCounter);

Page 167: Manual Micros 2010

}/* lcd_newline */

/*

** PUBLIC FUNCTIONS

*/

/*************************************************************************

Send LCD controller instruction command

Input: instruction to send to LCD controller, see HD44780 data sheet

Returns: none

*************************************************************************/

void lcd_command(uint8_t cmd)

{

lcd_waitbusy();

lcd_write(cmd,0);

}

/*************************************************************************

Send data byte to LCD controller

Input: data to send to LCD controller, see HD44780 data sheet

Returns: none

*************************************************************************/

void lcd_data(uint8_t data)

{

lcd_waitbusy();

lcd_write(data,1);

}

/*************************************************************************

Set cursor to specified position

Input: x horizontal position (0: left most position)

y vertical position (0: first line)

Returns: none

*************************************************************************/

void lcd_gotoxy(uint8_t x, uint8_t y)

{

#if LCD_LINES==1

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);

#endif

Page 168: Manual Micros 2010

#if LCD_LINES==2

if ( y==0 )

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);

else

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);

#endif

#if LCD_LINES==4

if ( y==0 )

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);

else if ( y==1)

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);

else if ( y==2)

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);

else /* y==3 */

lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);

#endif

}/* lcd_gotoxy */

/*************************************************************************

*************************************************************************/

int lcd_getxy(void)

{

return lcd_waitbusy();

}

/*************************************************************************

Clear display and set cursor to home position

*************************************************************************/

void lcd_clrscr(void)

{

lcd_command(1<<LCD_CLR);

}

/*************************************************************************

Set cursor to home position

*************************************************************************/

void lcd_home(void)

{

lcd_command(1<<LCD_HOME);

Page 169: Manual Micros 2010

}

/*************************************************************************

Display character at current cursor position

Input: character to be displayed

Returns: none

*************************************************************************/

void lcd_putc(char c)

{

uint8_t pos;

pos = lcd_waitbusy(); // read busy-flag and address counter

if (c=='\n')

{

lcd_newline(pos);

}

else

{

#if LCD_WRAP_LINES==1

#if LCD_LINES==1

if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);

}

#elif LCD_LINES==2

if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);

}else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);

}

#elif LCD_LINES==4

if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);

}else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0);

}else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0);

}else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) {

lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);

}

#endif

lcd_waitbusy();

Page 170: Manual Micros 2010

#endif

lcd_write(c, 1);

}

}/* lcd_putc */

/*************************************************************************

Display string without auto linefeed

Input: string to be displayed

Returns: none

*************************************************************************/

void lcd_puts(const char *s)

/* print string on lcd (no auto linefeed) */

{

register char c;

while ( (c = *s++) ) {

lcd_putc(c);

}

}/* lcd_puts */

/*************************************************************************

Display string from program memory without auto linefeed

Input: string from program memory be be displayed

Returns: none

*************************************************************************/

void lcd_puts_p(const char *progmem_s)

/* print string from program memory on lcd (no auto linefeed) */

{

register char c;

while ( (c = pgm_read_byte(progmem_s++)) ) {

lcd_putc(c);

}

}/* lcd_puts_p */

/*************************************************************************

Initialize display and select type of cursor

Page 171: Manual Micros 2010

Input: dispAttr LCD_DISP_OFF display off

LCD_DISP_ON display on, cursor off

LCD_DISP_ON_CURSOR display on, cursor on

LCD_DISP_CURSOR_BLINK display on, cursor on flashing

Returns: none

*************************************************************************/

void lcd_init(uint8_t dispAttr)

{

#if LCD_IO_MODE

/*

* Initialize LCD to 4 bit I/O mode

*/

if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )

&& ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT)

&& (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)

&& (LCD_RS_PIN == 4 ) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6 ) )

{

/* configure all port bits as output (all LCD lines on same port) */

DDR(LCD_DATA0_PORT) |= 0x7F;

}

else if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )

&& (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )

{

/* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */

DDR(LCD_DATA0_PORT) |= 0x0F;

DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);

DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);

DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);

}

else

{

/* configure all port bits as output (LCD data and control lines on different ports */

DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);

DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);

DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);

DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);

DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);

DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);

DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);

}

delay(16000); /* wait 16ms or more after power-on */

Page 172: Manual Micros 2010

/* initial write to lcd is 8bit */

LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4;

LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4;

lcd_e_toggle();

delay(4992); /* delay, busy flag can't be checked here */

/* repeat last command */

lcd_e_toggle();

delay(64); /* delay, busy flag can't be checked here */

/* repeat last command a third time */

lcd_e_toggle();

delay(64); /* delay, busy flag can't be checked here */

/* now configure for 4bit mode */

LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4

lcd_e_toggle();

delay(64); /* some displays need this additional delay */

/* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */

#else

/*

* Initialize LCD to 8 bit memory mapped mode

*/

/* enable external SRAM (memory mapped lcd) and one wait state */

MCUCR = _BV(SRE) | _BV(SRW);

/* reset LCD */

delay(16000); /* wait 16ms after power-on */

lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */

delay(4992); /* wait 5ms */

lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */

delay(64); /* wait 64us */

lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */

delay(64); /* wait 64us */

#endif

#if KS0073_4LINES_MODE

/* Display with KS0073 controller requires special commands for enabling 4 line mode */

lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);

lcd_command(KS0073_4LINES_MODE);

Page 173: Manual Micros 2010

lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);

#else

lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */

#endif

lcd_command(LCD_DISP_OFF); /* display off */

lcd_clrscr(); /* display clear */

lcd_command(LCD_MODE_DEFAULT); /* set entry mode */

lcd_command(dispAttr); /* display/cursor control */

}/* lcd_init */

Tabla 29: Librería lcd.c de Peter Fleury

La librería clk funciona como un medio para inicializar el preescalamiento del reloj de Sistema del ATMega32u4, así como para ajustar el uso de la función _delay_ms(x), además provee macros que permiten la declaración y uso de un puerto, tanto como para configurarlo, como para leerlo o escribirlo.

Page 174: Manual Micros 2010

#ifndef CLK_H

#define CLK_H

/**

@defgroup atmega32u4_clk Prescaler_Macros

@code #include <clk.h> @endcode

@brief Macros para definir la frecuencia de oscilacion del reloj

principal

*/

/*@{*/

/**

* @name Definitions for MCU Clock Frequency

* Adapt the MCU clock frequency in Hz to your target.

* Revisa las paginas 37-39

*/

#define F_CPU 16000000L

#if F_CPU == 16000000L

#define ADC_PRESCALER 0x07 /**<Factor de division 128 F_ADC = 125kHz*/

#define CPU_PRESCALER 0x00

#elif F_CPU == 8000000L

#define ADC_PRESCALER 0x06 /**<Factor de division 64 F_ADC = 125kHz*/

#define CPU_PRESCALER 0x01

#elif F_CPU == 4000000L

#define ADC_PRESCALER 0x05 /**<Factor de division 32*/

#define CPU_PRESCALER 0x02

#elif F_CPU == 2000000L

#define ADC_PRESCALER 0x04 /**<Factor de division 16*/

#define CPU_PRESCALER 0x03

#elif F_CPU == 1000000L

#define ADC_PRESCALER 0x03 /**<Factor de division 8*/

#define CPU_PRESCALER 0x04

#else

#error "Teensyduino only supports 16, 8, 4, 2, 1 MHz. Please edit boards.txt"

#endif

/**

* @name Macros para sustituir el seteo de bits individuales

*/

Page 175: Manual Micros 2010

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=_BV(bit)) /**<Pone en set un bit*/

#define clrbit(sfr,bit) (_SFR_BYTE(sfr)&=~_BV(bit)) /**<Pone en clear un bit*/

#define togglebit(sfr,bit) (_SFR_BYTE(sfr)^=_BV(bit)) /**<Cambia el estado de bit*/

#define DDR(x) (*(&x -1))

#define PIN(x) (*(&x -2))

/**

* @name Functions

*/

/**

@brief Funcion para inicializar los tiempos en el ATMega32U4

@param none

@return none

*/

void _init_Teensyduino_internal_(void);

void delay_ms(unsigned int time_ms);

/*@}*/

#endif //end clk.h

Tabla 30: Librería clk.h

Page 176: Manual Micros 2010

#include "clk.h"

#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>

//#include "clk.h"

void _init_Teensyduino_internal_(void)

{

cli();

CLKPR = 0x80;

CLKPR = CPU_PRESCALER;

}

void delay_ms(unsigned int time_ms)

{

unsigned int i;

for(i=0; i<time_ms; i++)

_delay_ms(1);

}

Tabla 31: Librería clk.c

Page 177: Manual Micros 2010

Unidad 7

Programación del microcontrolador con aplicaciones

Page 178: Manual Micros 2010

Unidad 7 Programación del microcontrolador con aplicaciones

7.1 Técnicas de control de motores usando:

7.1.1 PWM

7.1.2 Encoders incrementales como sensor de velocidad, posición y sentido de giro.

7.2 Control de sentido de giro, de posición de velocidad en:

7.2.1 Motores de DC

7.2.2 Motores de pasos

Competencia específica

Resolver problemas mediante la programación del microcontrolador.

Conocer y conectar motores con microcontroladores.

Actividades de aprendizaje:

• Mapa Conceptual: Catalogar mediante un mapa conceptual los usos de los puertos para manejo de potencia con interfaces de transistores, Darlington, MOSFETS, relevadores, Optoacopladores, puentes H discretos y de Circuito Integrado.

Page 179: Manual Micros 2010

7.1 Técnicas de control de motores usando:

7.1.1 PWM

Las notas que se presentan en esta sección corresponden a NeoTeo (Mario, 2010)

Cuando trabajamos con motores de corriente continua no siempre las aplicaciones se limitan a una función de marcha plena en alguno de los dos sentidos posibles (CW y CCW). En la mayoría de los diseños debemos controlar las revoluciones por minuto de los motores de acuerdo al desarrollo efectuado y el sentido de giro que esta rotación debe tener. Es por esto que, cuando necesitamos invertir el movimiento mecánico del sistema debemos apelar a utilizar un puente H.

Una de las técnicas más efectivas para conectar o desconectar una carga a una fuente de energía eléctrica ha sido siempre la utilización de simples llaves interruptoras manuales, o un relé activado por un circuito de control muy sencillo. Utilizar otros elementos para este trabajo (por ejemplo, transistores), acarrean necesidades de cálculos de corrientes a conmutar, tensiones de trabajo, y otras variables que una llave o un relé resuelven sin inconvenientes ni consecuencias. Sin embargo, cuando la aplicación requiere el control variable de una carga, comenzamos a imaginar un reóstato enorme y gigante, capaz de manejar muchos amperios y con la capacidad de disipar grandes cantidades de temperatura. Por supuesto que así no se resuelve la situación sino que se emplea una técnica muy sencilla y práctica llamada PWM.

ongamos como ejemplo que queremos hacer trabajar a un motor de 12Volts a la mitad de su régimen nominal. Lo primero que a muchos se le viene a la mente es aplicarle 6Volts de alimentación. Sin embargo, en la vida real, un motor de levalunas de coche, o un motor que impulsa una bomba de líquido refrigerante en una maquinaria, que debe tener su temperatura de trabajo controlada, no serían capaces de moverse del modo esperado al actuar de este modo. Muy por el contrario, quedarían inmóviles sufriendo un incremento notable de temperatura al ser atravesados por una corriente que no logra movilizar el eje en rotación debido a la carga que el motor tiene acoplada y debe impulsar. Si en cambio aplicamos por un pequeño lapso de tiempo la tensión de alimentación de 12Volts (la nominal de trabajo del motor del ejemplo), éste comenzaría a girar, o haría el intento de hacerlo, hasta volver a detenerse.

Si aplicamos muchos impulsos en forma reiterada, es decir, conectar – desconectar la alimentación varias veces en un segundo, el motor comenzaría a girar y por la propia inercia del sistema acoplado a su eje, se mantendría en marcha según el régimen de eventos de conexión – desconexión que le apliquemos durante un segundo. El método PWM basa su funcionamiento en este principio. En conectar de manera controlada y durante tiempos ajustables la alimentación, en este ejemplo a un motor, para de este modo poder variar la velocidad sin perder capacidad de tracción, o fuerza. También encontraremos algunos textos que utilicen el término “torque” para esta propiedad motriz. La mejor manera entonces es disponer de una llave o relé controlados de manera inteligente y que conecten – desconecten la carga muchas veces en un segundo. Pero, ¿cuántas veces es lo aconsejable?

Si aplicamos muchos impulsos en forma reiterada, es decir, conectar – desconectar la alimentación varias veces en un segundo, el motor comenzaría a girar y por la propia inercia del sistema acoplado a su eje, se mantendría en marcha según el régimen de eventos de conexión – desconexión que le apliquemos durante un segundo. El método PWM basa su funcionamiento en este principio. En conectar de manera controlada y durante tiempos ajustables la alimentación, en este ejemplo a un motor, para de este modo poder variar la velocidad sin perder capacidad de

Page 180: Manual Micros 2010

tracción, o fuerza. También encontraremos algunos textos que utilicen el término “torque” para esta propiedad motriz. La mejor manera entonces es disponer de una llave o relé controlados de manera inteligente y que conecten – desconecten la carga muchas veces en un segundo. Pero, ¿cuántas veces es lo aconsejable?

figura 66: Conmutando la alimentación de una carga podemos lograr un régimen de trabajo variable

En una aplicación de iluminación, si conmutamos (conectamos - desconectamos) la tensión de alimentación menos de 20 veces por segundo, podemos llegar a notar parpadeos molestos a la vista y en el caso de un motor quizás podamos observar o percibir, un accionar muy irregular cual si fuese a los golpes o con impulsos que pueden generar problemas mecánicos a largo plazo, además de entregar una marcha desagradable e incorrecta. Si en cambio elevamos la frecuencia de conmutación por encima de las 50 activaciones por segundo para lograr una marcha estable, caeremos en el problema de comenzar a generar sonidos audibles provocados por el bobinado del motor. Recuerda que el espectro de audición humana se establece entre los 20 ciclos por segundo y los 20 mil. (20Hz. – 20.000Hz.) Por supuesto que el bobinado de un motor no se comportará como un parlante o altavoz tan efectivo como para abarcar toda esta gama de frecuencias con absoluta fidelidad, pero existirán segmentos de resonancia donde algunas frecuencias hagan vibrar los bobinados más que otras, provocando un desagradable sonido que no debiera existir.

Si analizamos este razonamiento, llegamos a la conclusión que para obtener un funcionamiento suave, sin golpes, parpadeos ni sonidos extraños, debemos trabajar con frecuencias superiores a las que un bobinado de motor pueda “resonar”. Estas frecuencias se ubican, en la mayoría de los casos, por encima de los 10Khz. Una vez encontrada la frecuencia apropiada de funcionamiento para nuestro sistema, observaremos que quizás sean demasiadas conexiones en un segundo para la velocidad mínima deseada. Digámoslo de este modo: es probable que el motor gire demasiado rápido y nosotros necesitemos una velocidad menor. Bajar la frecuencia de conmutación es impracticable porque comenzarían los ruidos, entonces, ¿qué opción nos queda?: El PWM. Variar el ciclo de trabajo de la señal conmutada que sirve de activación del sistema. Manipular el ancho del impulso de conexión a la carga.

De este modo, podemos trabajar con frecuencias tan altas como 10Khz. y obtener un ancho de impulso

Page 181: Manual Micros 2010

del 1% (o menor) de la señal. A medida que este ancho del impulso comienza a aumentar, la energía promedio que se entrega a la carga también lo hace, pudiendo ser calculada y controlada de manera muy precisa. En el caso de utilizar un microcontrolador, obtendremos mediante su programación, una secuencia de “unos” y “ceros” que respetarán una frecuencia fija pero que pueden tener un ciclo de trabajo variable. Este término, también conocido como Duty, hará variar el ancho del impulso de conexión para obtener así un funcionamiento controlado desde la detención absoluta hasta la marcha a máxima potencia. Para esto, dentro de la programación del microcontrolador, asignaremos una variable al ciclo de trabajo o duty, que será del tipo BYTE y podrá adquirir valores entre 0 y 255. Para un duty igual a cero, el motor estará detenido. Lo mismo que para un valor de 1 o 2. A pesar de ser impulsos enviados al motor que poseen su tensión nominal de trabajo y que se ejecutan a una frecuencia de más de 10Khz., no tendrán el ancho suficiente para entregar la energía necesaria que el motor necesitaría para comenzar a girar, o la luminaria comenzar a encender.

figura 67: Acumulación de tiempos controlable por microcontrolador

Si en cambio incrementamos el valor de la variable duty a 100, la relación será 100/255 = 0,392 = 39%. Con este nivel de energía aplicada al motor podemos llegar a alcanzar el esfuerzo suficiente como para movilizarlo y mantenerlo funcionando en un régimen aproximado al 40% de la velocidad máxima. Por otro lado, debemos tener en claro que al momento de realizar un programa dentro de un microcontrolador, el desarrollador puede dar marcha al sistema con un duty máximo (255) durante algunos instantes para obtener un arranque a máxima potencia para luego descender de manera suave y progresiva al 40% antes elegido, o también puede hacerlo de manera abrupta, de un instante a otro, aprovechando que no se notará una disminución brusca en la velocidad gracias a la inercia mecánica del sistema acoplado al eje del motor. Para el caso de una luminaria, esta variación brusca no podrá disimularse, pero si el arranque a un duty máximo es lo suficientemente corto, el fenómeno no alcanzará a notarse. De todos modos, en el caso de las luminarias siempre será deseable iniciar con baja potencia para luego incrementarla, es decir, a la inversa de los motores eléctricos. Por lo tanto, el PWM es una herramienta que posee el desarrollador/programador para variar el régimen de trabajo de motores o luminarias con la mayor eficiencia posible.

Para el tipo de conmutación mencionado hasta aquí y para obtener un funcionamiento satisfactorio a una frecuencia tan elevada, una llave mecánica o un relé se vuelven imposibles de utilizar. Es aquí donde hace su presentación el IRFZ44N. ¿Qué es el IRFZ44N? Es un transistor de tecnología MOS-FET (Metal–Oxide–Semiconductor – Field Effect Transistor) que posee destacadas características que lo hacen ideal para este tipo de aplicaciones. Queremos también aclarar que PWM se puede realizar

Page 182: Manual Micros 2010

con transistores bipolares (NPN - PNP), con tiristores, triacs, o IGBT según la conveniencia de la aplicación, es decir, el PWM no se hace sólo con un transistor MOS-FET como veremos ahora sino que puedes encontrar aplicaciones que utilizan sistemas electrónicos de conmutación muy variados y como mencionamos antes, ajustables a las necesidades de la aplicación.

figura 68: El IRFZ44N en su hoja de datos

Entre las características más destacadas de este transistor encontramos que es capaz de manejar corrientes de hasta 50 Amperes ofreciendo una resistencia tan baja como 0,017 Ohms. Esto permite un régimen de trabajo extraordinario ya que trabajando al máximo de sus posibilidades no desarrollará una potencia mayor a los 45 Watts. Nada extraordinario para un generoso disipador que pueda irradiar el calor generado por semejante corriente circulando a través del dispositivo. Para que tengas una idea, trabajando con 12 Volts, una lámpara incandescente de 100W consumirá 8,33 Amperes. Es decir, la sexta parte de sus posibilidades extremas y claro está, a 100W, es decir, a la potencia máxima o a un duty de 255.

Una sencilla y práctica explicación del funcionamiento de un transistor MOS-FET puede resumirse a comprender el comportamiento de la circulación de corriente dentro del transistor. Al aplicar una determinada tensión sobre la compuerta, puerta o Gate (positiva respecto a GND), se genera dentro del transistor un campo eléctrico que permite la circulación de corriente entre el terminal identificado como Drain y el terminal Source. Tan simple como eso. Al aplicar tensión al Gate, el campo eléctrico aporta huecos o lagunas, hecho que favorece y activa la circulación de electrones entre Drain y Source. Cuando la tensión en Gate se interrumpe o se coloca a un bajo potencial, la corriente entre Drain y Source se interrumpe. Tenemos de este modo una llave electrónica comandada por tensión (no por corriente, atentos a este punto) que no tendrá inconvenientes en conmutar a frecuencias tan altas como las que necesitamos para controlar una carga.

Page 183: Manual Micros 2010

figura 69: Efecto del voltaje Vgs en un MOSFET

La tensión mínima de Gate para que el transistor comience a conducir (según su hoja de datos que encontrarás al final del artículo) está ubicada entre 2 y 4 Volts mientras que la máxima tensión aplicable respecto al terminal Source, es de 20 Volts. Con 10 Volts de tensión sobre el Gate el transistor alcanza la mínima resistencia entre Drain y Source. Si se sobrepasa la tensión Vgs (tensión de Gate respecto a Source) máxima de 20 Volts el transistor se rompe y si no se alcanza la tensión mínima de 2 a 4 Volts, el transistor no entra en conducción. Una situación a destacar es que si trabajamos siempre con 5 Volts, estaremos sobre el límite de activación del transistor, mientras que si trabajamos con mayor tensión sobre el Gate lograremos un mejor desempeño con menor disipación de calor al ofrecer menor resistencia a la circulación de corriente entre Drain y Source.

figura 70: Fotografía de IRFZ44N

Otro de los detalles importantes a considerar en un diseño que utilice PWM con un MOS-FET es el manejo de los tiempos y las formas de los flancos de subida y bajada de la señal aplicada al Gate. No respetar con fidelidad la forma de onda con la que se debe activar el Gate de un MOS-FET puede llevarte a disipaciones anormales de temperatura y funcionamientos al límite de los márgenes de seguridad térmica. El circuito mostrado permite un óptimo trabajo del transistor. En cambio, si la alimentación desciende a 5 Volts (puede suceder por diseño) la resistencia de Gate debe bajar a valores entre 2,2 y 5 Ohm ya que la tensión de activación del Gate estará al límite de los valores

Page 184: Manual Micros 2010

mínimos de operación. Recuerda observar siempre la hoja de datos para lograr un diseño apropiado.

figura 71: Circuito de Aplicación

Con esta sencilla aplicación puedes controlar la intensidad de iluminación, la velocidad de motores para tu robot o tu próxima CNC sin mayores inconvenientes. Cambiando los valores de una simple variable BYTE dentro de un microcontrolador, tienes el problema resuelto. Tu genialidad, creatividad e imaginación, determinarán el método a aplicar para realizar la tarea de control dentro del programa. Mientras tanto, ya tienes algo muy importante: El hardware y la explicación de su funcionamiento aplicando el IRFZ44N, un transistor que puede brindarte infinitas satisfacciones si lo utilizas de manera correcta como hemos visto en este artículo. ¿Ya has pensado en que aplicarás el PWM? ¿En iluminación? ¿En motores?

7.1.1.1 Configurando el PWM en el ATMega32U4 con el Timer 0

El modo Fast PWM (3 o 7) es una opción para generar una forma de onda PWM de alta frecuencia, esta opción difiere de otras formas de generar ondas PWMya que es una operación de una sola rampa. En este modo el contador va de BOTTOM hacia TOP, quedando de la siguiente forma:

TOP = 0xFF cuando WGM3:0 = 3

TOP = OCRX cuando WMG3:0 = 7

En el modo de comparación a la salida no Inversora, el pin de salida OCx es igual a cero cuando son iguales los registros TCNT0 y OCRX y puesto en uno cuando se llega al valor BOTTOM.

Se considera importante mencionar que la frecuencia de funcionamiento pueda ser el doble de la frecuencia generada por el modo PWM de fase correcta.

La alta frecuencia de operación de este modo, permite su uso eficaz en aplicaciones tales como:

• Regulación de potencia

Page 185: Manual Micros 2010

• Rectificación

• Conversión Digital a analógica

De la gráfica siguiente, en el modo complemento, si OCRx = TOP, los bits de salida estarán en estado bajo. Conforme decrece el valor de OCRx, el tiempo de permanencia en alto del pin OCn será mayor. Todo lo contrario sucederá para el modo no complementario.

La frecuencia PWM de salida puede ser calculada de la siguiente manera

f OCnxPWM=

f clk I /O

N⋅256

Ejemplo: Usando el modo PWM FAST generar una señal pwm cuya frecuencia sea superior a 20kHz, suponga que el reloj del sistema está 8 Mhz

Primero determinamos el valor del preescalador que se utilizará para un valor supuesto de frecuencia deseada, este valor se puede determinar a partir de la expresión siguiente:

N=f clk I /O

f deseada⋅256=

8 MHz(22kHz)(256)

≈1.42

Para este caso, se debe redondear N = 1, con lo cual se obtiene una frecuencia de salida de

f OC N xPWM=8 MHz

256=31.25 kHz

En el siguiente ejemplo se muestra la codificación para generar señales de tipo PWM con el Timer 0 y el Timer 1

Page 186: Manual Micros 2010

/*

*/

#include "clk.h"

#include <avr/io.h>

#include <avr/interrupt.h>

#include "timer0/timer0.h"

#include "timer1/timer1.h"

int main(void)

{

_init_Teensyduino_internal_();

// Insert code

delay_ms(100);

setbit(DDRB,0); //led verde

setbit(DDRD,0); //OC0B

setbit(DDRB,6); //OC1B

setbit(DDRB,5); //OC1A

/*

configuracion del timer 1

Modo de operacion: FAST PWM (5)

Resolucion: 8 bits

Factor de prescalamiento: 1024

Comportamiento de OC1A: No inversor

Frecuencia de PWM = F_CPU/(N(1+TOP)) = 1Mhz/(1024(1+255) = 3.81Hz

Periodo de PWM = 1/Freq de PWM = 262.14ms

Ciclo de trabajo = 39% = OCR1A*100/TOP

timer1_setup(5,1024,3,3,0);

OCR1A = 100;

*/

timer1_setup(5,1024,2,2,0); //modo PWM de 8 bit frecuencia de 3906.25Hz PB5

OCR1A = 100;

OCR1B = 255;

/*

configuracion del timer 0 (2)

Modo de operacion: CTC

Factor de Prescalamiento: 1024

Valor de Precarga: 99 (OCR0A)

Page 187: Manual Micros 2010

Periodo de AutoReset: 101.3 ms

F_CPU: 1MHz

Tiempo = N(OCR0B+1)/F_CPU

COM0A = 0 (SE DESCONECTA LA SALIDA DEL WMG AL PIN OC0A)

COM0B = 1 (CAMBIA DE ESTADO CADA VEZ QUE DESBORDA)

*/

timer0_setup(2,1,0,1); //modo CTC interrupcion en PD0

OCR0A = 99;

while(1)

{

togglebit(PORTB,0);

delay_ms(1000);

}

return 0;

}

Tabla 32: Código configuración de timers con PWM

Page 188: Manual Micros 2010

7.1.2 Encoders incrementales como sensor de velocidad y sentido de giroscopio

Un elemento imprescindible a la hora de controlar un servosistema es el la realimentación de posición y velocidad (Motion Control, 2010).

Cierto es que existen sistemas (variadores pricipalmente) que funcionan sin realimentación de posición (lazo abierto) , pero dichos variadores se utilizan básicamente para control de velocidad o par. Para un control preciso de velocidad y posición, la realimentación del motor o la carga hacia el dispositivo de control, es absolutamente necesaria.

¿Encoder o Resolver?

Generalmente utilizamos el término inglés ‘encoder’ para referirnos al sistema de realimentación.

Cabe decir, que existen gran variedad de encoders: rotativos, llineales, incrementales, absolutos, semi-absolutos, y… de hecho en muchas ocasiones hablamos de ‘encoder’ cuando en realidad lo que tenemos es un resolver.

La diferencia fundamental entre encoder y resolver estriba en que el primero es un sistema digital y el segundo un sistema analógico.

-El encoder rotativo normalmente consta de un disco fijado al eje del motor, con una serie de marcas (normalmente codificadas en gray para minimizar errores), y un dispositivo optico capaz de leer dichas marcas. La combinación binaria de la lectura de dichas marcas nos dará como resultado la posición del rotor respecto al estator. Posteriormente y según el tipo de encoger, esta información será codificada y transmitida al servoamplificador o controlador de movimiento.

En su versión más ‘simple’ el encoder nos enviará dos trenes de pulsos con un desfase conocido, contando los pulsos podremos saber la posición del motor y examinando qué fase es la primera, podremos saber la dirección, es el tipico encoder de cuadratura A,/A, B, /B. Normalmente una señal adicional Z,/Z nos informará de una marca única en el disco que servirá para definir el origen (Homing)

-El resolver (rotativo), es un sistema analógico, grosso modo lo que nos está enviando es el voltaje inducido de dos espiras, que por razones constructivas daran como resultado dos senoides (en lugar de pulsos digitales aquí tenemos una senoide), examinando la senoide podremos conocer la posición, y examinando el desfase la dirección.

Hoy en día se utilizan tanto resolvers como encoders. Tradicionalmente el resolver se ha considerado más robusto desde el punto de vista mecánico, pero al tratarse de una señal analógica es más sensible desde el punto de vista electromagnético. El encoder a su vez es más sensible desde el punto de vista mecánico: fuerzas excesivas perpendiculares al eje pueden dañar el disco lector, pero en sus versiones más avanzadas codifica los datos digitalmente por lo que la detección y corrección de errores de comunicación es posible a nivel de protocolo.

Creo que existe ifinidad de literatura respecto al ‘encoder’ de cuadratura y el resolver, por lo que no me extenderé más y os referencio a : http://es.wikipedia.org/wiki/Codificador_rotatorio para más información.

En este artículo mi intención es no tanto explicar qué es un encoder o un resolver (para eso está la Wiki), sinó hacer un pequeño repaso de los diferentes tipos de encoders y protocolos y su campo de aplicación.

¿Encoder incremental o absoluto?

La respuesta está clara: Absoluto ! Siempre que el presupuesto nos lo permita.

Page 189: Manual Micros 2010

El encoder incremental nos informa de los incrementos de posición y a cada vuelta nos envía una marca especial “Z” que utilizaremos para referenciar o hacer el Homing de una máquina.

¿Qué es el Homing?

Lo razonable es dedicar uno o más artículos al Homing, aquí sólo mencionaré que el homing es una secuencia inicial para cualquier sistema de posicionado en el que el controlador necesita conocer la posición absoluta del motor respecto a la máquina.

Imaginemos una mesa rotativa, con posiciones de trabajo situadas a 90, y 180 grados respectivamente respecto al punto en el que depositamos la pieza que queremos manipular (Posición 0º)

Al poner en marcha la máquina, el controlador de movimiento necesita saber, cual es la posición actual del eje del motor, respecto de la posición 0º de la máquina, para ello, si no se dispone de un encoder absoluto el controlador comandará uno o varios movimientos al eje, hasta que pueda detectar la marca “Z”.

Posiblemente la marca “Z” no estará en la posición 0º de la máquina, pero una vez detectada la señal “Z” del encoder motor solidario a la mesa (imaginemos que se ha pasado 37º del ‘cero’ de máquina) , podremos podremos referenciar el sistema y decirle al motor, muévase 37º en sentido contratio, pues ese es el ‘cero’ de la máquina y donde debe colocarse usted para recibir la primera pieza a trabajar.

El ejemplo que he expuesto es muy simplificado (sería el caso de un direct-drive) sin transmisión alguna entre motor y mesa, por tanto una revolución de motor, correspondería con una revolución de la mesa. En la mayoría de los casos nos encontraremos con transmisiones intermedias, por lo que una revolución de motor no corresponderá con una revolución de mesa, en este caso, se utilizan señales adicionales (sensor de proximidad) para determinar la posición.

Encoder IncrementalLos encoders incrementales son probablemente el tipo más común de encoder utilizado en la industria, por la gran variedad de aplicaciones que su uso abarcan.Cada encoder incremental tiene en su interior un disco, marcado con una serie de líneas uniformes a

Page 190: Manual Micros 2010

través de una única pista alrededor de su perímetro, las líneas impermeables a la luz de anchura igual a los huecos transparentes, trabajando con una unidad emisora de luz y una unidad de captación de la misma, al girar el disco, generan unas señales que debidamente tratadas proporcionan las señales de salida de un encoder incremental.

Las señales de salida de un encoder pueden ser un tren de impulsos, en forma de señal cuadrada, donde el número de impulsos que se generarán en una vuelta coincidirá con el número de impulsos del disco en el interior del encoder, nos referimos a encoders de un solo canal (señal A).Una segunda señal (señal B) suministra un tren de impulsos idéntico al que suministra la señal A pero desfasada 90º respecto de esta, nos referimos al encoder de dos canales. También cabe la posibilidad de una señal de referencia o cero que proporciona un pulso a cada vuelta, esta señal puede sincronizarse respecto de la señal A (A+0), respecto la señal B (A+B+0) o respecto a ambas.

Encoder Absoluto, y Absoluto multi-vuelta

En un sistema con encoder absoluto, no es necesario realizar la secuencia de Homing, puesto que al poner en marcha la máquina y sin necesidad de movimiento alguno, el encoder del motor informará al controlador de su posición: “Estoy en la posición 37º”.

El encoder absoluto necesita de algún mecanismo mecánico o electrónico para memorizar su posición: dentro de una revolución del motor. Muy habitualmente cuando hablamos de un encoder absoluto, en realidad se trata de un encoder absoluto-multivuelta, pues en muchas aplicaciones necesitamos conocer no sólo la posición absoluta dentro de una vuelta, también en número de vueltas que ha dado el motor, para poder determinar la posición absoluta.

Tradicionalmente existen dos enfoques a la hora de implementar un encoder absoluto multivuelta:

-Un sistema mecánico de discos (algo así como un reloj suizo…)-Una batería capaz de mantener la posición durante varios años

La ventaja está clara: con un encoder absoluto no es necesario ningún movimiento para determinar la posición del motor, por lo que se gana tiempo en el arranque de la máquina y se evitan movimientos inconvenientes para algunas máquinas.

Contrapartida: Un encoder incremental resulta más económico.

En el caso de encoders absolutos multivuelta con batería, debemos ser conscientes de que desconectar la batería implicará perder la posición absoluta…

Full-close loop encoder

El encoder en sí mismo, lo que nos da es una realimentación de posición.

El servoamplificador derivará la posición respecto al tiempo para calcular la velocidad.

Como ya se comentó en artículos anteriores, el amplificador necesita la realimentación del encoder para poder cerrar el lazo de velocidad y efectuar un buen control vectorial.

Normalmente la misma señal de encoder es retransmitida al controlador de posición para cerrar el lazo de posición y/o controlar la desviación (error).

En ocasiones será necesario utilizar un encoder adicional para cerrar el lazo de posición e ignorar el encoder del motor.

Típicamente esto ocurre cuando:

-La mecánica entre el motor y la carga es ‘mala’ o ‘complicada’ (resulta más sencillo utilizar un

Page 191: Manual Micros 2010

encoder adicional cerca de la carga, y evitar toda la cadena cinemática entre motor y carga-Aplicaciones en las que positivamente sabemos que existen variaciones difícilmente controlables entre la posición del motor y la carga: p.e. cuando la carga desliza sobre rodillos, a veces es mejor leer la posición con una encoder en contacto directo con la carga.

La utilización de este tipo de encoder adicional, se conoce como full-close loop feedback, aunque dependiendo del fabricante puede tener nombres comerciales diferentes.

Encoder rotativo y encoder lineal

En gran numero de ocasiones el movimiento rotativo del motor se traduce en un movimiento lineal.

A raíz de que que los ciclos de trabajo se han vuelto más exigentes (mayor productividad) y la demanda de precisión (mayor calidad), cada vez són más las aplicaciones que integran motores lineales en lugar de utilizar motores rotativos que posteriormente pirden eficiencia y precisión al transformarse en un movimiento lineal, p.e. tornillo sin fin.

Cabe decir que hay dos grandes familias de motores lineales:

-Motores lineales montados sobre guías : El motor (o los imanes) se desliza sobre guías (sliders) a gran velocidad varios m/s, con aceleraciones de varios ‘g’ y con una precisión sub-micra. (No se trata de ciéncia ficción…, esta tecnología existe y ha evolucionado mucho en los últimos años: Si teneis alguna de TV pantalla plana 32” o más… en casa, con toda seguridad os digo que se han utilizado este tipo de motores tanto en su fabricación como en su control de calidad, demasiados píxels y demasiada precisión para un motor convencional), otro mercado habitual para este tipo de motor es el del semi-conductor y, en los últimos años está generalizando su uso en la fabricación de paneles fotovoltaicos. En los últimos tiempos se están empezando a utilizar este tipo de motores en otros sectores, como el embalage, la manipulación y conformación de objetos, etc…, el motivo es claro: calidad y velocidad!

En configuraciones más avanzada estos motores pueden trabajar cooperando sobre la misma guía, o en tandem paralelo p.e. puentes grua, o en conformaciones cartesianas XY, XYZ, XYZ+R (R=motor rotativo)

-Motores lineales con eje cilíndico (motores lineales de fuerza): Existen varios nombres comerciales para este tipo de motor, pero en mi opinión la característica común a todos estos motores es que reemplazan la función de un cilíndro pneumático. Este tipo de motor acostumbra a tener un eje cilíndico en su interior, se trata efectivamente de un motor lineal, y su característica principal no es tanto la precisión como la fuerza que pueden desarrollar. Este tipo de motores tiene un recorrido (strocke) limitado comparado con el primer tipo de motores que pueden alcanzar varios metros de longitud.

Los encoders lineales son la evolución de las escalas lineales, ahora ya no hablamos de milímetros sinó de sub-micras de precisión, este tipo de encoders són utilizados en motores con guías, (los motores lineales cilíndicos acostumbran a tener su propio encoder integrado).

Estos encoders tienen una serie de marcas equidistantes que un sensor óptico o magnético puede leer.

Resulta interesante el caso de los encoders lineales semi-absolutos o de marcas codificadas. Este tipo de encoder es muy ingenioso, ya que utiliza marcas no equidistantes, estas están separadas siguiendo un patron numérico (generalmente dos series numéricas superpuestas), de manera que la distancia entre dos marcas es única, por tanto leyendo dos marcas consecutivas podemos saber la posición absoluta. Su utilización resulta muy interesante en guías lineales de varios metros, o p.e, cuando varios motores colaboran en una misma guía lineal.

En pocas palabras, tenemos sistemas de realimentación de posición (velocidad) que en función de :

Page 192: Manual Micros 2010

Su principio físico de funcionamiento serán:

-Resolvers (analógicos)-Encoders (digitales)

Su capacidad de reverenciarse:

-Incrementales-Absolutos (Absolutos multi-vuelta) ya sea mediante mecánica o electrónica con batería.

La naturaleza del motor a utilizar:

-Rotativos-Incrementales

Page 193: Manual Micros 2010

7.2 Control de sentido de giro, de posición y de velocidadPara iniciar este tema, se colocará un ejemplo de control de los timers 0 y 1 del un microcontrolador ATMega48 para generar señales PWM y de temporizado, que mas adelante podrán ser usadas para el control de sentido de giro, posición y de velocidad de motores

El circuito es el siguiente

El código fuente se coloca a continuación

figura 72: Circuito para generar PWM en ATMega48

Page 194: Manual Micros 2010

#include <avr/io.h> #include <avr/interrupt.h> #include "timer1.h" #include "timer0.h"

ISR(TIMER1_COMPA_vect) { PORTD^=(1 << PD5); }

ISR(TIMER0_COMPA_vect) { PORTD^=(1 << PD2); }

int main(void) {

// Insert code DDRD|=(1<<DDD5); //salida del Timer 1 DDRD|=(1<<DDD2); //salida del Timer 0 DDRB|=(1<<DDB1); //salida OC1A /* configuracion del timer 1 Modo de operacion: CTC (4) Factor de Prescalamiento: 1 Valor de Precarga: 0x54B0 (OCR1A) Periodo de AutoReset: 21.68ms F_CPU = 1MHz Tiempo = N(OCR1A+1)/F_CPU Se habilita salida del OC1A */ timer1_setup(4,1,3,0,0); /* configuracion del timer 1 Modo de operacion: FAST PWM (5) Factor de prescalamiento: 1 Comportamiento de OC1A: No inversor Frecuencia de PWM = F_CPU/(N(1+TOP)) = 1Mhz/(1(1+255) = 3.9kHz Periodo de PWM = 1/Freq de PWM = 256 us Ciclo de trabajo = 39% = OCR1A*100/TOP timer1_setup(5,1,2,0,0); OCR1A = 100; */ OCR1A=100; TIMSK1|=(1<<OCIE1A); //interrupcion por comparacion en modulo A

/* configuracion del timer 0 Modo de operacion: CTC Factor de Prescalamiento: 1024 Valor de Precarga: 99 (OCR0A) Periodo de AutoReset: 101.3 ms F_CPU: 1MHz Tiempo = N(OCR0A+1)/F_CPU */ timer0_setup(4,64,0,0); OCR0A=99; TIMSK0|=(1<<OCIE0A); //interrupcion por comparacion en modulo A

sei();

while(1) ;

Page 195: Manual Micros 2010

return 0; }

Tabla 33: Código para la configuración de timers

Page 196: Manual Micros 2010

7.2.1 Motores de corriente directamente

Ejemplo.- Elabora un programa para el microcontrolador ATMega32U4 permita el control de paro y arranque de un motor de corriente directa (usando interrupciones), a través de un circuito L293, ademas de que tenga control sobre la rotación y sobre la velocidad del motor (con modo FAST PWM del temporizador 0). Siga el diagrama de conexiones que se muestra a continuación

figura 73: circuito para control PWM de motor DC con L293D

Page 197: Manual Micros 2010

Código fuente de ejemplo/*

*/

#define F_CPU 8000000L

#include <avr/io.h>

#include <avr/interrupt.h>

#include <util/delay.h>

#include <clk.h>

#include <timer0/timer0.h>

#define start 0

#define pstart PORTB

#define stop 1

#define pstop PORTB

#define Vplus 4

#define pVplus PORTD

#define Vminus 6

#define pVminus PORTD

typedef enum {FALSE, TRUE} boolean ;

boolean Derecha = TRUE;

unsigned char velocidad=0;

ISR(INT0_vect)

{

Derecha = FALSE;

}

ISR(INT1_vect)

{

Derecha = TRUE;

}

void M_adelante(unsigned char pwm);

void M_reversa(unsigned char pwm);

void motor_init(void);

void setVelocidad(void);

void board_init(void);

Page 198: Manual Micros 2010

int main(void)

{

// Insert code

_init_Teensyduino_internal_();

delay_ms(100);

velocidad = 0;

motor_init();

board_init();

while(1)

{

if((bit_is_clear(pstart,start) && bit_is_set(pstop,stop))== TRUE)

{

while(bit_is_set(pstop,stop))

{

while(Derecha == FALSE && bit_is_set(pstop,stop))

{

setVelocidad();

}

while(Derecha == TRUE && bit_is_set(pstop,stop))

{

setVelocidad();

}

}

}

}

return 0;

}

void M_adelante(unsigned char pwm)

{

OCR0A = 0;

OCR0B = pwm;

}

void M_reversa(unsigned char pwm)

{

OCR0A = pwm;

OCR0B = 0;

Page 199: Manual Micros 2010

}

void motor_init()

{

//Configure para salida PWM Inversa

//Ajuste OCxx en Comparacion, limpia el timer en sobreflujo

//Contador desde 0 hasta 255

//Ciclo de reloj 8MHz Prescalamiento = 1

timer0_setup(3,1,3,3);

//inicializa todos los PWM al 0% de ciclo de trabajo

OCR0A = OCR0B = 0;

//Ajusta los pines PWM como salidas digitales

DDRD |= (1<<DDD0);

DDRB |= (1<<DDB7);

}

void setVelocidad(void)

{

if(bit_is_clear(pVplus,Vplus) == TRUE)

{

delay_ms(20);

velocidad++;

}

if(bit_is_clear(pVminus,Vminus)== TRUE)

{

delay_ms(20);

velocidad--;

}

}

void board_init(void)

{

DDRB &= ~(1<<PB0);

DDRB &= ~(1<<PB1);

DDRD &= ~(1<<PD4);

DDRD &= ~(1<<PD6);

DDRD &= ~(1<<PD1);

DDRD &= ~(1<<PD2);

//Habilitando las pullups

PORTB |= (1<<PB0); //start

Page 200: Manual Micros 2010

PORTB |= (1<<PB1); //stop

PORTD |= (1<<PD4); //Vplus

PORTD |= (1<<PD6); //Vminus

PORTD |= (1<<PD1); //Derecha

PORTD |= (1<<PD2); //Izquierda

}

Tabla 34: Código control PWM de puente H

Ejercicio.- Agregue al diagrama una pantalla LCD y que en ella se muestre la velocidad del motor en términos de porcentaje, considere el siguiente diagrama de estados:

En la siguiente figura se muestra una fotografía del circuito funcionando

figura 74: Diagrama de estados para práctica con PWM

Page 201: Manual Micros 2010

figura 75: Funcionamiento de PWM con motor DC

Page 202: Manual Micros 2010

7.2.2 Motores de pasos

Una descripción de los motores a pasos podrá encontrarse en la sección 5.5.2 Motores a pasos donde se describen a grosso modo las características de los motores a pasos.

7.2.2.1 Cálculo de la potencia disipada en un controlador MOSFET para un motor a pasos usando la técnica de medios pasos

Resumen

En el presente trabajo se muestra el cálculo de disipación de potencia en los transistores de las ramas superiores de un puente H cuando se controla un motor a pasos, desde un enfoque de disipación de la energía.

Desarrollo. Considere un motor a pasos cuyas características se encuentran definidas por:

Características del motor a pasos

Rfase = 0.29 Ω

MMOTOR = 3.2 Nm

Lfase = 1.7 mH

Ifase = 6 A

Paso = 1.8º

Inercia = 1000 gcm2

VNOM = 1.74 V

Para determinar la potencia disipada en el motor por sobre-Tensión, primero se debe considerar la siguiente forma de onda de corriente, en la cual se describen los tiempos donde se suministra energía a los embobinados del motor a pasos:

donde

Tr.- Corresponde al tiempo que tarda la bobina del motor en alcanzar la corriente máxima (IL).

TLD.- Tiempo en el que la bobina permanece en el valor máximo de corriente.

Nota.- Si se usan medios pasos. Cada bobina está excitada 3 pasos y un cuarto descansa. La duración de cada paso viene dada por la ecuación:

T LD=3⋅T (paso)−T r

Para ser mas claro en cuanto a este término observe la tabla Tabla 35: Secuencia de energización de bobinas de motor bipolar en medios pasos, en la cual las letras de A,..D corresponden a las bobinas y el número uno, corresponde a su estado excitado:

Page 203: Manual Micros 2010

A B C D PASO

0 1 0 1 1

0 0 0 1 2

1 0 0 1 3

1 0 0 0 4

1 0 1 0 5

0 0 1 0 6

0 1 1 0 7

0 1 0 0 8

Tabla 35: Secuencia de energización de bobinas de motor bipolar en medios pasos

Las áreas en gris de la tabla corresponden a la energización de las bobinas del motor a pasos bipolar. Otra forma de visualizar la tabla anterior, refiérase a la figura 76: Secuencia de activación en bobina:

Tf y Td.- Corresponden al tiempo de caída y de carga nula. Considera que Tf +Td es el tiempo donde la bobina no está excitada.

Chopping Period.- Es el periodo de troceo que genera el driver para limitar la corriente en las bobinas, de acuerdo a la hoja de datos del circuito L297, la frecuencia del troceo (chopping) de la corriente es:

f switch=1

0.7 RC

Un término más a considerar es el del tiempo de conmutación del MOSFET controlador del motor, la cual se define como TCOM

7.4.2.2 Cálculo de la energía disipada durante el tiempo Tr

La ecuación siguiente define la energía que disipa un transistor MOSFET que se encuentra conectado a una bobina:

figura 76: Secuencia de activación en bobina

Page 204: Manual Micros 2010

EOFF /ON=[RDS (ON )⋅I L2⋅Tr ]⋅2/3 [Joules]1

a saber que la potencia se puede expresar como el producto de la corriente al cuadrado por la Resistencia del total del sistema y que la potencia al multiplicarse por el tiempo, se obtiene la energía.

Luego se considera que la constante de tiempo del motor se define mediante

τ=Lfase / Rmotor

Si consideramos en esta ecuación el valor de las resistencias de los MOSFET cuando están saturados, se tiene entonces que, para que este circuito alcance el estado estable, el tiempo queda determinado por la ecuación:

T estable≈3τ≈3⋅( L fase

RFASE+2RDS (ON))

considera la siguiente imagen en la figura 77: Circuito equivalente de bobina en Tr, que corresponde al modelo eléctrico de las ecuaciones anteriormente descritas.

Este sistema, debido a sus características debe ser alimentado por una fuente de alimentación cuyo valor,es mayor que el definido por el parámetro VNOM. Elaborando una aproximación y considerando que el embobinado se comporta como un cortocircuito en DC (Referencia de libro fundamentos de analisis de circuitos electricos de Alexander) entonces se tiene que

Ldidt

+R i=V alimentación como el voltaje aplicado a las terminales de la bobina energizada del motor de

pasos, y argumentando la referencia antes mencionada, entonces la ecuación se ve reducida a la forma

Ldidt

≈V despejando y agrupando términos, se tiene entonces que

V alimentación

Lfase

≈didt

La ecuación anterior, por sus unidades de medición, establece que el voltaje dividido entre la inductancia tiene una “equivalencia” a la relación de Amperes sobre segundo. De tal modo que a partir de esta ecuación el tiempo Tr se puede definir a partir de la corriente que se desea pasar a través de la bobina de acuerdo a la ecuación siguiente:

1 El factor 2/3 es una aproximación, ya que en el circuito equivalente del puente H cuando la bobina se encuentra energizada, se va a dividir en 2 Resistencias Rds(on) de los mosfet y una Rmotor del embobinado.

figura 77: Circuito equivalente de bobina en Tr

Page 205: Manual Micros 2010

T r≈I deseada

V alimentación/ Lfase

≈I deseada⋅L fase

V alimentación

con este ultimo valor se obtiene la energía disipada por el sistema

al encendido.

Para fines de practicidad, es posible considerar que esta misma cantidad de energía es la que el sistema disipa al apagado, es decir

EOFF /ON=EON /OFF

7.2.2.3 Determinación de la energía disipada en TLD

La energía disipada durante el tiempo TLD se encuentra definida por la ecuación

ELD=I L2⋅RDS (ON )⋅2⋅T LD Recuerde que aquí solo se considera la resistencia del MOSFET en

conducción a consecuencia de que ya la bobina del motor a pasos está en un estado estable y por lo tanto, la resistencia de la misma se considera cero y que el número 2 es un factor de seguridad.

Considerando además que el TLD se encuentra definido a través de T LD=3⋅T (paso)−T r , entonces para una frecuencia de paso dada, la ecuación anterior se define como

ELD=I L2⋅RDS (ON )⋅6⋅T ( paso)−( I deseada⋅L fase

V alimentación)

siendo

T ( paso)=1

f paso

Además de la energía disipada en TLD haciendo referencia al estado estable, es importante considerar la energía que ocasiona el rizo generado por el conmutador que se encarga de mantener una corriente constante sobre las bobinas del motor a pasos durante el estado de activación. Para determinar esa energía disipada en los mosfet de conmutación, considere la siguiente ecuación:

ECOM=V S⋅I L⋅T com⋅f switch⋅T LD

Por lo tanto la energía que se disipa en los MOSFET de conmutación a durante el intervalo de tiempo TLD es la suma de estas dos energías, por lo tanto la expresión de ambas se define por medio de

ELD(Total)=ELD+ECOM

7.2.2.4 Determinación de la energía disipada en el tiempo de espera

Podría considerarse que cuando las bobinas no se encuentran energizadas, habrá una disipación nula de energía en el controlador MOSFET, sin embargo, si consideramos la corriente “quiscent” que está definida por lo portadores minoritarios en cualquier dispositivo semiconductor, tal energía disipada durante el periodo de espera se encuentra definido por:

Page 206: Manual Micros 2010

Equiescent=I quiescent⋅V alimentación⋅T D

7.2.2.5 Determinación de la energía total disipada y potencia total disipada en el mosfet de conmutación

La energía total disipada, se determina por la sumatoria de todas las energías anteriormente calculadas, en consecuencia, la ecuación para realizar tal cálculo queda definido de la siguiente manera

ETOTAL=EOFF /ON+ELD(Total)+EON /OFF+ Equiescent

En conformidad con el valor obtenido, la potencia disipada, por definición se puede calcular de la forma siguiente:

PDISIPADA=ETOT

T CICLO

Page 207: Manual Micros 2010
Page 208: Manual Micros 2010

Unidad 8

El convertidor ADC y DAC

Page 209: Manual Micros 2010

Unidad 8 El convertidor ADC y DAC

8.1 Arquitectura Interna.

8.2 Configuración y programación.

Competencia específica

Utilizar el convertidor ADC y DAC para fines de control.

Actividades de aprendizaje:

• Mapa Conceptual: Elaborar un mapa conceptual a partir de los componentes relevantes del convertidor, su configuración y su programación.

Page 210: Manual Micros 2010

8.1 Arquitectura Interna.Los Convertidores Analógicos Digitales permiten una comunicación eficaz entre los sistemas

analógicos y los sistemas digitales, tomando muestras del mundo real para generar datos que puedan ser manipulados por un microcontrolador por ejemplo, obteniendo de ésta manera cualquier tipo de señal física en tensiones eléctricas cuyos datos podrán ser procesados por el dispositivo electrónico.

Además fueron creados para poder aumentar la velocidad del procesamiento de las señales logrando así acoplar los sistemas analógicos con los sistemas digitales.

Actividad de aprendizaje.- realiza la lectura de las páginas 244-259 Analog-to-Digital converter y elabora:

Mapa Conceptual: Elaborar un mapa conceptual a partir de los componentes relevantes del convertidor.

8.2 Configuración y programación.El ADC convierte un voltaje analógico de entrada en un valor digital de 10 bits a través de aproximaciones sucesivas. El valor mínimo representa a GND y el valor máximo representa al voltaje en el pin AREF menos 1 LSB. Opcionalmente, AVCC o un voltaje de referencia interna de 1.1V puede conectarse al pin AREF escribiendo en los bits REFSn en el Registro ADMUX. La referencia de voltaje interna puede ser desacoplada por un condensador externo en el pin AREF para mejorar la inmunidad al ruido.

El ADC genera un resultado de 10 bits que se presenta en los Registros de Datos del ADC (ADC Data Registers), ADCH y ADCL. Por defecto, el resultado se presenta ajustado hacia la derecha, pero opcionalmente puede presentarse ajustado hacia la izquierda configurando el bit ADLAR en el ADMUX.

Si el resultado está ajustado hacia la izquierda y no se requiere más que 8 bits, es suficiente leer el ADCH. De otro modo, ADCL debe leerse primero, luego ADCH, para asegurarse de que el contenido de los Registros de Datos correspondan a la misma conversión. Una vez que el ADCL es leído, se bloquea el acceso del ADC a los Registros de Datos. Esto significa que si se ha leído el ADCL, y una conversión se completa antes de que se lea el ADCH, ni el registro es actualizado ni el resultado de la conversión se pierde. Cuando el ADCH es leído, el acceso del ADC a los Registros ADCH y ADCL se habilita nuevamente.

El ADC tiene su propia interrupción que puede activarse cuando una conversión se ha completado. Cuando se prohíbe el acceso del ADC a los Registros de Datos en medio de la lectura del ADCH y del ADCL, la interrupción se activará aún si el resultado se pierde.

Page 211: Manual Micros 2010

Ejemplo de diagramas de flujo para el uso del ADC

Diagrama de flujo para lectura de temperatura con promedios

figura 78: diagrama de flujo para promediado de lecturas de ADC

Page 212: Manual Micros 2010
Page 213: Manual Micros 2010

Práctica. Programar un microcontrolador ATmega48 para leer el ADC conectado en el canal cero, usando formato de 8 bits, y mostrar el resultado en una pantalla LCD. De acuerdo a los siguientes diagramas:

figura 79: Lectura de ADC ATmega48

Page 214: Manual Micros 2010

Paso 1. Seleccionar el valor de preescalamiento del ADC para elegir una frecuencia de operación del ADC a 125kHz (aprox 14kSps) usando los bits (ADPS2:ADPS0) del registro ADCSRA. Considerando que la frecuencia del sistema es de 1MHz (El circuito no tiene oscilador externo o cristal, por lo que se referirá al oscilador interno RC)

PRE=FCPU

Fadc

=1MHz

125kHz=8 .

ADPS2 ADPS1 ADPS0 Preescalamiento

0 0 0 2

0 0 1 2

0 1 0 4

0 1 1 8

1 0 0 16

1 0 1 32

1 1 0 64

1 1 1 128

Paso 2. Seleccionar los voltajes de referencia del ADC usando los bits (REFS1:REFS0) del registro ADMUX. Para el caso especificado, se requiere que la referencia sea igual al valor de alimentación

Page 215: Manual Micros 2010

Vcc.

REFS1 REFS0 Descripción

0 0 Aref, Vref interna OFF

0 1 Avcc, Vref externa

1 0 Reservado

1 1 Interna de 1.1V con capacitor en pin Aref

Paso 3. Establecer la justificación de resultado con el bit ADLAR (ADMUX). Si ADLAR = 0 (por defecto) realiza la justificación a la derecha.(conversión de 10bits)

15 14 13 12 11 10 9 8

MSB(9) X ADCH

X X X X X X X LSB(0) ADCL

7 6 5 4 3 2 1 0

Page 216: Manual Micros 2010

Si ADLAR= 1, se realiza la justificación a la izquierda (Para conversión de 8 bits)

15 14 13 12 11 10 9 8

MSB(7) X X X X X X LSB(0) ADCH

X lsb ADCL

7 6 5 4 3 2 1 0

Paso 4. Seleccionar el canal o canales de entrada del ADC con los bits MUX3:MUX0. Para este caso el canal 0, es mediante el valor MUX3:MUX0 = 0000.

MUX3:MUX0 Descripción MUX3:MUX0 Descripción

0000 ADC0 1000 reservado

0001 ADC1 1001 reservado

0010 ADC2 1010 reservado

0011 ADC3 1011 reservado

0100 ADC4 1100 reservado

0101 ADC5 1101 reservado

0110 reservado 1110 1.1V (VBG)

0111 reservado 1111 0V GND

Paso 5. Encender el módulo del ADC al setear el bit ADEN del registro ADCSRA

Paso 6. Iniciar la conversión seteando el bit ADSC en el registro ADCSRA

Paso 7. Esperar a que termine la conversión. Cuando esto sucede, el flag ADIF se pondrá a uno y si la conversión es normal y el bit ADSC se limpiará automáticamente.

Paso 8. Leer el resultado de la conversión del par de registros ADCH:ADCL. Para el caso de la práctica, solo se leerá el registro ADCH en una variable tipo char, si se requiere de una lectura de 10bits, habrá que justificar a la derecha y la variable receptora es de tipo int.

Paso 9. Escribir el código que a continuación se presenta:

Page 217: Manual Micros 2010

#include <avr/io.h>

#define F_CPU 1000000UL

#include <util/delay.h>

#include "lcd.h"

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=(_BV(bit)))

#define clearbit(sfr,bit) (_SFR_BYTE(sfr)&=~(_BV(bit)))

void adc_setup(void);

unsigned char adc_read(char channel);

int main(void)

{

unsigned char n; // variable que recibira la lectura de 8 bits

char buff[4]; //Buffer para lectura de ADC

lcd_init();

adc_setup();

lcd_gotorc(1,5);

lcd_puts("ADC0");

while(1)

{

n = adc_read(0);

sprintf(buff,"%3d",n); //campo de numeros

lcd_gotorc(2,1);

lcd_puts("val: ");

lcd_gotorc(2,5);

lcd_puts(buff);

}

}

void adc_setup(void)

{

//vref+ y Vref-: Vcc y GND

//Justificación: Izquierda (Para lectura de 8 bits)

clearbit(ADMUX,REFS1); //Referencia a AVcc

setbit(ADMUX,REFS0);

Page 218: Manual Micros 2010

setbit(ADMUX,ADLAR);

// Reloj del ADC0: F_CPU/8 = 125kHz

// Estado del convertidor: ON

// Modo: Manual

setbit(ADCSRA,ADEN); //ADC habilitado

clearbit(ADCSRA,ADATE); //Modo manual (Normal)

clearbit(ADCSRA,ADPS2); //Seleccion del Prescalador reloj

setbit(ADCSRA,ADPS1); // n = 8

setbit(ADCSRA,ADPS0);

}

unsigned char adc_read(char channel)

{

ADMUX&=0xFF;

ADMUX|=channel;

_delay_us(10); //delay para estabilizar el voltaje de entrada del ADC

setbit(ADCSRA,ADSC); //se inicia la conversion

while(bit_is_clear(ADCSRA,ADIF)); //Espera a que termine la conversion

return ADCH;

}

Tabla 36: Lectura del ADC en ATmega48

Page 219: Manual Micros 2010

Unidad 9

Puertos Seriales y memoria EEPROM

Page 220: Manual Micros 2010

Unidad 9 Puertos seriales y memoria EEPROM

9.1 USART

9.2 TWI (I2C)

9.3 Leer y escribir sobre EEPROM

Competencia específica

Comunicar dispositivos usando los puertos seriales

Utilizar la memoria EEPROM

Actividades de aprendizaje:

Mapa Conceptual: Distinguir mediante un mapa conceptual la comunicación de dispositivos a través de los puertos seriales como el USART, TWI y otros protocolos.

Page 221: Manual Micros 2010

9.1 El USART

9.1.1 Librerías para el control del puerto serial

La librería para el control del puerto serial es una modificación de la librería ofrecida por Peter Fleury, este código permite al programador enviar caracteres en formato ASCII a través de la USART del microcontrolador ATMega32u4, pero además de ello, se caracteriza por el hecho de que cuenta con la creación de un buffer, el cual puede ser modificado a voluntad del usuario.

Tal buffer puede ser usado con el fin de recibir datos complejos desde una aplicación o desde otro microcontrolador.

Anexo a esto, la misma rutina permite la recepción de tres caracteres especiales, tales como

Escape.- La funcionalidad de esta tecla es que permite el borrado completo del buffer temporal del microcontrolador

INTRO (Enter).- Permite la aceptación del buffer, con el fin establecer que se ha recibido un comando.

BACKSPACE (Tecla de retroceso).- En caso de que el comando enviado por el puerto serial contenga un error, con esta tecla es posible eliminar el último caracter insertado en la cola del buffer (RedRaven, 2010).

Es importante señalar que la velocidad de comunicación inicial es de 9600 bauds, sin embargo, el usuario puede cambiar esta velocidad con tan solo modificar el valor de la línea

#define USART_BAUDRATE 9600L por el valor que se desee:

Page 222: Manual Micros 2010

#ifndef __UART_H

#define __UART_H

#include "clk.h"

# define USART_BAUDRATE 9600UL

# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16UL))) - 1)

//definicion de teclas

#define INTRO 0x0D

#define RETROCESO 0x08

#define ESCAPE 0x1B

//define el tamano del buffer

#define lenbuff 10

void uart_transmit( unsigned char data );

unsigned char uart_receive(void);

void uart_init(void);

int uart_dataAvailable(void);

void uart_print(const char *s);

/**

* funcion que limpia el buffer de caracteres para la comunicacion serial

*/

void initBuff(void);

/**

* funcion para agregar un caracter al buffer de comunicacion serial

*/

void add2cbuff(unsigned char c);

/**

* funcion que imprime un echo a la terminal, solo caracteres imprimibles

*/

void echosel(unsigned char c);

#endif

Tabla 37: librería usart.h

Page 223: Manual Micros 2010

// uart.c

// Originally for NerdKits with ATmega168, 14.7456 MHz clock

// [email protected]

// Modified for Adafruit ATMega32u4 Breakout, with 16.0000Mhz clock

// Note, this references serial 1, not 0, since the micro does not have 0.

// At least for the above breakout, D3 is TX, and D2 RX

// https://github.com/tomvdb/avr_arduino_leonardo/blob/master/examples/uart/main.c

#include "clk.h"

#include <avr/io.h>

#include <string.h>

#include "uart.h"

#include <util/delay.h>

//variables para el manejo de comunicacion serial

typedef enum{false, true} boolean;

boolean flagcommand= false;

unsigned char xbuff=0x00;

unsigned char cbuff[lenbuff];

char rcvchar=0x00;

// transmit a char to uart

void uart_transmit( unsigned char data )

{

// wait for empty transmit buffer

while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) )

;

// put data into buffer, sends data

UDR1 = data;

}

// read a char from uart

unsigned char uart_receive(void)

{

while (!( UCSR1A & ( 1 << RXC1) ))

;

return UDR1;

}

// init uart

Page 224: Manual Micros 2010

void uart_init(void)

{

// set baud rate

unsigned int baud = BAUD_PRESCALE;

UBRR1H = (unsigned char)(baud >> 8 );

UBRR1L = (unsigned char)baud;

//UBRR1H = 0;

//UBRR1L = 0x34;

// enable received and transmitter

UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 );

// set frame format ( 8data, 2stop )

UCSR1C = ( 1 << USBS1 ) | ( 1 << UCSZ11 ) | (1 << UCSZ10);

}

// check if there are any chars to be read

int uart_dataAvailable(void)

{

if ( UCSR1A & ( 1 << RXC1) )

return 1;

return 0;

}

// write a string to the uart

void uart_print(const char *s)

{

register char c;

while((c=*s++)){

uart_transmit(c);

}

}

/*

void uart_print( char data[] )

{

int c = 0;

for ( c = 0; c < strlen(data); c++ )

uart_transmit(data[c]);

}

*/

Page 225: Manual Micros 2010

void initBuff(void)

{

int i;

for(i=0;i<lenbuff; i++)

{

cbuff[i]=0x00;

}xbuff=0x00;

}

void add2cbuff(unsigned char c)

{

if(xbuff<lenbuff)

{

switch(c)

{

case INTRO:

flagcommand = true;

break;

case RETROCESO:

if(xbuff>0) cbuff[--xbuff] = 0x00;

break;

case ESCAPE:

initBuff();

break;

default:

cbuff[xbuff++]=c;

}

}

else

{

initBuff();

uart_print("ERROR\r\n");

}

}

void echosel(unsigned char c)

{

switch(c)

{

case INTRO:

uart_print("\r\n");

break;

Page 226: Manual Micros 2010

case RETROCESO:

uart_transmit(RETROCESO);

break;

case ESCAPE:

uart_transmit(ESCAPE);

break;

default:

uart_transmit(c);

}

}

Tabla 38: librería usart.c

9.1.2 Ejemplo de recepción de datos desde una terminal de comunicación serial GtkTerm o CuteCom hacia el microcontrolador ATmega32U4.

En el siguiente ejemplo, desde el teclado de una PC o laptop, se envia hacia el microcontrolador ATMega32u4, los caracteres 0,1,2,3, los cuales tienen la función que en la tabla siguiente se muestra:

Caracter Acción a realizar

0 Apagar LED Amarillo

1 Encender LED Amarillo

2 Apagar LED Rojo

3 Encender LED Rojo

El circuito de conexión se muestra a continuación

Código fuente Principal

Page 227: Manual Micros 2010

#include "clk.h"

#include <avr/io.h>

#include "uart.h"

#define LED_R 0

#define PLED_R PORTB

#define LED_A 6

#define PLED_A PORTB

//variable que recibe el comando de entrada

unsigned int Byte_entrada = 0;

int main(void)

{

_init_Teensyduino_internal_();

uart_init(); //9600 8 2 bits de paro, sin paridad

setbit(DDR(PLED_A), LED_A);

setbit(DDR(PLED_R), LED_R);

clrbit(PLED_A,LED_A); //apagar los leds

clrbit(PLED_R,LED_R);

// Insert code

while(1)

{

if(uart_dataAvailable())

{

Byte_entrada = uart_receive();

if(Byte_entrada == '0')

{

clrbit(PLED_A, LED_A);

uart_print("LED Amarillo OFF");

}

else if(Byte_entrada == '1')

{

setbit(PLED_A, LED_A);

uart_print("LED Amarillo ON");

}

else if(Byte_entrada == '2')

{

clrbit(PLED_R, LED_R);

uart_print("LED Rojo OFF");

}

Page 228: Manual Micros 2010

else if(Byte_entrada == '3')

{

setbit(PLED_R, LED_R);

uart_print("LED Rojo ON");

}

}

}

return 0;

}

Tabla 39: Encendido de leds a través de puerto serie en microcontrolador

Si el usuario así lo desea, puede ejecutar un programa diseñado en languaje Java, para interactuar con el microcontrolador, pero para ello deberá seguir las reglas que se muestran en el apartado siguiente:

9.1.3 Acceso como usuario normal al puerto serial e instalación de RxTx

Rxtx en Manjaro Linux2

Como primer punto hay que hacer mención que al día de hoy se encuentra caido el site de qbang el cual nos ha facilitado las librerias de comunicacion serial de Java, por lo cual es posible acudir a pacman para instalarles

sudo pacman -Ss rxtx

listando lo siguiente (a mi me marca que ya está instalado)

community/java-rxtx 2.2pre2-2 [instalado]

Java library for serial IO

posteriormente se instalado

$sudo pacman -S java-rxtx

Al finalizar la instalación indicará lo siguiente:

Users need to be in 'lock' and 'uucp' groups to connect to devices

Operación finalizada con éxito

3Lo que significa que, para que un usuario normal sin privilegios de root pueda acceder a los puertos de

2 Las pruebas fueron realizadas sobre una laptop Gateway NV55C con Manjaro Linux 0.8.9 x64 con RAM de 6 GB

3 Estos pasos sirven tambien para comunicar a Scilab con un microcontrolador por medio de los comandos que a continuación se presentan:

-->h=openserial("/dev/ttyUSB0","9600,n,8,2")

h =

file77

Page 229: Manual Micros 2010

comunicación serial, éste debe pertenecer a los grupoas lock y uucp, para ello desde la consola escriba los siguientes comandos:

$ sudo usermod -aG uucp “TunombredeUsuario”

$sudo usermod -aG lock “TunombredeUsuario”

Preguntar sobre el estado de jdk7

[miguel@manjaro opt]$ sudo pacman -Ss jdk7

extra/jdk7-openjdk 7.u51_2.4.6-1

Free Java environment based on OpenJDK 7.0 with IcedTea7 replacing binary

plugs – SDK

E instalar con:

[miguel@manjaro opt]$ sudo pacman -S extra/jdk7-openjdk

9.1.4 Construir una clase de Java para mostrar los puertos detectados en Manjaro

Para usar las librerias en Netbeans de comunicación serial instaladas desde el repositorio se tiene que agregar la libreria desde las propiedades del proyecto y dando clic en la opción “Libraries”, en el Tab “Compile” dar clic en el botón Add JAR/Folder

-->result=closeserial(h)

result =

0.

Page 230: Manual Micros 2010

Si se compila solo con esta opción, entonces al tratar de correr la aplicación, marcará el siguiente error4

java.lang.UnsatisfiedLinkError: no rxtxSerial in java.library.path thrown while loading gnu.io.RXTXCommDriver

esto se debe a que el Linker no apunta a la libreria dinámica “librxtxSerial.so”, en este caso, la libreria instalada, se encuentra en “/usr/lib/”, por lo tanto se debe indicar esta dirección en el IDE, haciendo esto de la siguiente manera:

Agregar la línea -Djava.library.path=”/usr/lib” en las opciones de máquina virtual (click derecho sobre el proyecto -> Propiedades -> Run)

4 La ruta donde se encuentra ubicado la librería dinámica depende de la distribución usada, este apartado se consultó el 19 de abril de 2014 desde la página http://ubuntuforums.org/archive/index.php/t-1747382.html

figura 80: Configuración de libreria RxTx en Netbeans agregando JAR

Page 231: Manual Micros 2010

el código fuente es el siguiente:

figura 81: Configuración de librerias RxTx en netbeans

Page 232: Manual Micros 2010

/*

* To change this license header, choose License Headers in Project Properties.

* To change this template file, choose Tools | Templates

* and open the template in the editor.

*/

package detectarpuertos;

import java.util.*;

import gnu.io.*;

/**

*

* @author miguel

*/

public class DetectarPuertos {

CommPortIdentifier ports;

void mirar()

{

Enumeration<?> puertos = CommPortIdentifier.getPortIdentifiers();

while(puertos.hasMoreElements()){

ports = (CommPortIdentifier) puertos.nextElement();

System.out.println("********\n"+ports.getName());

}

}

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

// TODO code application logic here

DetectarPuertos ini = new DetectarPuertos();

ini.mirar();

}

}

Tabla 40: Código fuente de Java para verificar puertos seriales habilitados

Al dar clic en run este proyecto, la salida es la siguiente, siempre y cuando se disponga de un cable de conversión serial a USB conectado en el equipo:

run:

********

/dev/ttyUSB0

BUILD SUCCESSFUL (total time: 0 seconds)

Page 233: Manual Micros 2010

9.1.5 Envío de Datos del microcontrolador hacia el PC usando Scilab 5.x

El ejemplo que se muestra a continuación permite el envio de datos desde el microcontrolador hacia el PC para mostrarse, tanto en formato ASCII (código fuente comentado) como en formato Binario, esto con el fin de mostrar en una gráfica obtenida a partir de la adquisición de datos usando el Toolbox de comunicación serial de SCILAB.

El propósito es de leer una variable analógica con el microcontrolador y que éste a su vez se comunique con el Toolbox de Scilab a fin de graficar la señal adquirida.

El circuito eléctrico se muestra a continuación

La tabla de conexiones del microcontrolador y el código fuente del proyecto se colocan

Page 234: Manual Micros 2010

/*

Debe agregarse a las opciones del linker las siguientes lineas

-lm

-u

vfprintf -lprintf_flt

Con CodeBlocks

Para agregarlas solo da clic derecho en el nombre del proyecto

elige la opcion que dice Properties....

En la ventana que se abre, da clic en el boton Project's Build options...

Te abre una nueva ventana

Da clic en el Tab Linker Setting

y del lado izquierdo encuentras las opciones del linker, ahora

solo resta agregar las librerias para que puedas hacer uso de sprintf

para imprimir numeros con punto decimal

*/

#include "clk.h"

#include <avr/io.h>

#include <avr/interrupt.h>

#include <stdlib.h>

#include <stdio.h>

#include "adc.h"

#include "timer0.h"

#include "timer1.h"

#include "lcd.h"

#include "uart.h"

//void _init_Teensyduino_internal_(void);

//ISR(TIMER0_COMPA_vect)

//{

// //togglebit(PORTD,PD0);

//}

//

//ISR(TIMER1_COMPA_vect)

//{

// // togglebit(PORTB,5);

//}

int main(void)

Page 235: Manual Micros 2010

{

unsigned int valor;

unsigned long reloj;

double mostrar;

char buffer[10];

char bufferfloat[10];

char lcdbuffer[10];

//char rxByte;

_init_Teensyduino_internal_();

// Insert code

delay_ms(1000);

lcd_init(LCD_DISP_ON);

setbit(DDRB,0); //led verde

setbit(DDRD,0); //OC0B

setbit(DDRB,6); //OC1B

setbit(DDRB,5); //OC1A

/*Inicializando la UART*/

uart_init();

lcd_puts("probando LCD");

if(uart_dataAvailable())

{

uart_transmit(0x00);

lcd_puts("serial dataAvalible");

delay_ms(1000);

}

uart_print("Hola :)");

lcd_gotoxy(1,2);

lcd_puts("enviando serie");

delay_ms(1000);

/*

configuracion del timer 1

Modo de operacion: FAST PWM (5)

Resolucion: 8 bits

Factor de prescalamiento: 1024

Page 236: Manual Micros 2010

Comportamiento de OC1A: No inversor

Frecuencia de PWM = F_CPU/(N(1+TOP)) = 1Mhz/(1024(1+255) = 3.81Hz

Periodo de PWM = 1/Freq de PWM = 262.14ms

Ciclo de trabajo = 39% = OCR1A*100/TOP

timer1_setup(5,1024,3,3,0);

OCR1A = 100;

*/

timer1_setup(5,1024,3,3,0); //modo PWM de 8 bit frecuencia de 3906.25Hz PB5

OCR1A = 255;

OCR1B = 255;

//comparacion no inversa

//adc_setup(2,0,0,0);

//Prescalamiento de 2

//referencia: AREF

//justificacion: 1 (Izquierda- 8 bits de resolucion)

//canal: Leer canal 0

adc_setup(0,1,ADC0);

/*

configuracion del timer 0 (2)

Modo de operacion: CTC

Factor de Prescalamiento: 1024

Valor de Precarga: 99 (OCR0A)

Periodo de AutoReset: 101.3 ms

F_CPU: 1MHz

Tiempo = N(OCR0B+1)/F_CPU

COM0A = 0 (SE DESCONECTA LA SALIDA DEL WMG AL PIN OC0A)

COM0B = 1 (CAMBIA DE ESTADO CADA VEZ QUE DESBORDA)

*/

timer0_setup(2,1024,0,1); //modo CTC interrupcion en PD0

OCR0A = 99;

//setbit(TIMSK0,OCIE0A); //habilita la interrupcion del T0 CTC

//setbit(TIMSK1, OCIE1A);

lcd_clrscr();

lcd_puts("Medicion ADC");

//sei();

while(1)

{

Page 237: Manual Micros 2010

valor = adc_read(ADC0);

//itoa(valor,buffer,16);

//si es utilizada la base 10

//entonces mas alla del valor medio

//el resultado dara un signo (bit de signo)

//para cualquier otra base, el valor es

// considerado como numero sin signo

//Si se desean leer solo 8 bits entonces

//recorre el numero

valor = (valor >>8);

mostrar = (valor*100.0)/256.0;

reloj = F_CPU;

sprintf(lcdbuffer,"%ld",reloj);

//itoa(valor,buffer,16);

sprintf(buffer,"%d",valor);

//mostrar = 3.14;

lcd_gotoxy(4,1);

lcd_puts(" ");

lcd_gotoxy(4,1);

lcd_puts(buffer);

sprintf(bufferfloat,"%1.2f",mostrar);

lcd_gotoxy(13,0);

lcd_puts(" ");

lcd_gotoxy(13,0);

lcd_puts(bufferfloat);

setbit(PORTB,0);

delay_ms(5);

//valor++;

clrbit(PORTB,0);

delay_ms(5);

//Para adquirir el dato con scilab

//el dato convertido se debe enviar como numero

//no como caracter

uart_transmit(valor);

// uart_print("\r");

// uart_print("Valor de Conversion AD:");

// uart_print(bufferfloat);

// uart_print("\n\r");

// uart_print("Valor de F CPU:");

// uart_print(lcdbuffer);

// uart_print("\n\r");

Page 238: Manual Micros 2010

}

return 0;

}

Tabla 41: Código para envío de datos binarios adquiridos por el ADC a través del puerto serial

El código fuente del script de Scilab para la conexión entre el microcontrolador y el software queda definido en el marco siguiente:

clf;

//Inicializaciones

EOC = ascii([13 10])

LF = ascii(10)

dt = 20 //temporizacion ms

dtc = 1/1.2 //tiempo de caracter ms

n=500; //numero de muestras

y=ones(1,n); //vector acumulador

h=openserial("/dev/ttyUSB0","9600,n,8,2");

sleep(50);

i=1;

x=[0:1:n-1];//dominio a graficar

pot=" ";

while i<=n

pot=ascii(readserial(h))//lee lo que hay en el buffer

y(i) = pot(1)

xpause(25000) //delay en microsegundos

i=i+1;

end

k=(100/256).*y;

xx=1:length(k);

plot2d2(xx,y);

closeserial(h);

Tabla 42: Script de scilab para comunicación con el puerto serial

9.2 TWI (I2C)Las notas que están a continuación se obtuvieron del sitio web Quadruino (2014).

¿Qué es I2C?

I2C es un protocolo de comunicación serie diseñado por Philips que se utiliza esencialmente entre

Page 239: Manual Micros 2010

dispositivos que pertenecen al mismo circuito, por ejemplo, sensores con un microcontrolador.

¿Qué es TWI?

Aunque las patentes de I2C ya han expirado, algunos vendedores utilizan los nombres TWI y TWSI para referirse a I2C. Es exactamente lo mismo.

Características del protocolo:

• Velocidad standard de 100Kbit/s (100kbaudios). Se puede cambiar al modo de alta velocidad (400Kbit/s)

• Configuración maestro/esclavo. La direccion del esclavo se configura con software • Solo se necesitan dos lineas:

• SDA (Serial Data Line): Linea de datos. • SCL/CLK (Serial Clock Line): Linea de reloj, será el que marque el tiempo de RW

(Lectura/Escritura) • Nota: Suponemos que todos los dispositivos tienen masa común, si no fuera así hay que

uncluir una linea de masa. • Los comunicación siempre tiene la estructura siguiente:

• Transmisor: Byte de datos (8 Bits) • Receptor: Bit llamado ACK de confirmación.

¿Cómo se realizan las conexiones?SDA y SCL van a su pin correspondiente en cada dispositivo, de manera que todos quedan en paralelo.Las lineas SDA y SCL estan independientemente conectadas a dos resistores Pull-Up que se encargaran de que el valor logico siempre sea alto a no ser que un dispositivo lo ponga a valor lógico bajo.

¿Qué tipo de comunicación es?

Es una comunicación de tipo half duplex. Comunicación bidireccional por la misma linea pero no simultáneamente bidireccional.

¿Cual es la estructura de la comunicación?

La estructura de la comunicación básica es la siguiente:

1. START condition (Master) 2. 7 Bits de direccion de esclavo (Master) 3. 1 Bit de RW, 0 es Leer y 1 Escribir. (Master) 4. 1 Bit de Acknowledge (Slave) 5. Byte de dirección de memoria (Master) 6. 1 Bit de Acknowledge (Slave) 7. Byte de datos (Master/Slave (Escritura/Lectura)) 8. 1 Bit de Acknowledge (Slave/Master (Escritura/Lectura)) 9. STOP condition (Master)

Esta es la base de la comunicación pero para leer o escribir, según el dispositivo con el que se comunica el Master la comunicación tendrá una estructura específica.

Page 240: Manual Micros 2010

¿Qué es el bit de Acknowledge (ACK)?

Este bit es una respuesta del receptor al transmisor. Es una parte básica de la comunicación y tiene diferentes sentidos según el contexto.

Se utiliza principalmente con dos propósitos:

1. Conocer si el transmisor ha sido escuchado 2. Lecturas multidatos:

Cuando se esta leyendo de un esclavo, si el master realiza un ACK, es decir, que responde; el esclavo pasa al siguiente valor de registro y lo envía también, hasta recibir un NACK (Not Acknowledge), es decir, ninguna respuesta del master. Esto sirve para hacer múltiples lecturas. Por ejemplo, nuestro acelerómetro o giroscopio, que tienen valores de X, Y y Z.

En esencia este es el funcionamiento del protocolo de comunicación con el que nos comunicaremos con múltiples sensores

Ejemplos de uso de TWI

A continuación se colocan las librerias para la comunicación TWI para AVR

Page 241: Manual Micros 2010

/*************************************************************************

* Title: I2C master library using hardware TWI interface

* Author: Peter Fleury <[email protected]> http://jump.to/fleury

* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $

* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3

* Target: any AVR device with hardware TWI

* Usage: API compatible with I2C Software Library i2cmaster.h

**************************************************************************/

#include <inttypes.h>

#include <compat/twi.h>

#include <i2cmaster.h>

/* define CPU frequency in Mhz here if not defined in Makefile */

#ifndef F_CPU

#define F_CPU 4000000UL //puede cambiarse por F_CPU pero incluir a clk.h

#endif

/* I2C clock in Hz */

#define SCL_CLOCK 100000L

/*************************************************************************

Initialization of the I2C bus interface. Need to be called only once

*************************************************************************/

void i2c_init(void)

{

/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

TWSR = 0; /* no prescaler */

TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */

}/* i2c_init */

/*************************************************************************

Issues a start condition and sends address and transfer direction.

return 0 = device accessible, 1= failed to access device

*************************************************************************/

unsigned char i2c_start(unsigned char address)

{

uint8_t twst;

// send START condition

Page 242: Manual Micros 2010

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

// send device address

TWDR = address;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed and ACK/NACK has been received

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

return 0;

}/* i2c_start */

/*************************************************************************

Issues a start condition and sends address and transfer direction.

If device is busy, use ack polling to wait until device is ready

Input: address and transfer direction of I2C device

*************************************************************************/

void i2c_start_wait(unsigned char address)

{

uint8_t twst;

while ( 1 )

{

// send START condition

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

Page 243: Manual Micros 2010

twst = TW_STATUS & 0xF8;

if ( (twst != TW_START) && (twst != TW_REP_START)) continue;

// send device address

TWDR = address;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )

{

/* device busy, send stop condition to terminate write operation */

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released

while(TWCR & (1<<TWSTO));

continue;

}

//if( twst != TW_MT_SLA_ACK) return 1;

break;

}

}/* i2c_start_wait */

/*************************************************************************

Issues a repeated start condition and sends address and transfer direction

Input: address and transfer direction of I2C device

Return: 0 device accessible

1 failed to access device

*************************************************************************/

unsigned char i2c_rep_start(unsigned char address)

{

return i2c_start( address );

}/* i2c_rep_start */

/*************************************************************************

Page 244: Manual Micros 2010

Terminates the data transfer and releases the I2C bus

*************************************************************************/

void i2c_stop(void)

{

/* send stop condition */

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released

while(TWCR & (1<<TWSTO));

}/* i2c_stop */

/*************************************************************************

Send one byte to I2C device

Input: byte to be transfered

Return: 0 write successful

1 write failed

*************************************************************************/

unsigned char i2c_write( unsigned char data )

{

uint8_t twst;

// send data to the previously addressed device

TWDR = data;

TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits

twst = TW_STATUS & 0xF8;

if( twst != TW_MT_DATA_ACK) return 1;

return 0;

}/* i2c_write */

/*************************************************************************

Read one byte from the I2C device, request more data from device

Return: byte read from I2C device

*************************************************************************/

unsigned char i2c_readAck(void)

Page 245: Manual Micros 2010

{

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);

while(!(TWCR & (1<<TWINT)));

return TWDR;

}/* i2c_readAck */

/*************************************************************************

Read one byte from the I2C device, read is followed by a stop condition

Return: byte read from I2C device

*************************************************************************/

unsigned char i2c_readNak(void)

{

TWCR = (1<<TWINT) | (1<<TWEN);

while(!(TWCR & (1<<TWINT)));

return TWDR;

}/* i2c_readNak */

Tabla 43: Librería Peter Fleury twimaster.c

Ahora se enlista el archivo de cabecera

Page 246: Manual Micros 2010

#ifndef _I2CMASTER_H

#define _I2CMASTER_H 1

/*************************************************************************

* Title: C include file for the I2C master interface

* (i2cmaster.S or twimaster.c)

* Author: Peter Fleury <[email protected]> http://jump.to/fleury

* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $

* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3

* Target: any AVR device

* Usage: see Doxygen manual

**************************************************************************/

#ifdef DOXYGEN

/**

@defgroup pfleury_ic2master I2C Master library

@code #include <i2cmaster.h> @endcode

@brief I2C (TWI) Master Software Library

Basic routines for communicating with I2C slave devices. This single master

implementation is limited to one bus master on the I2C bus.

This I2c library is implemented as a compact assembler software implementation of the I2C protocol

which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).

Since the API for these two implementations is exactly the same, an application can be linked either against the

software I2C implementation or the hardware I2C implementation.

Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module

i2cmaster.S to your target when using the software I2C implementation !

Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

@note

The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted

to GNU assembler and AVR-GCC C call interface.

Replaced the incorrect quarter period delays found in AVR300 with

half period delays.

@author Peter Fleury [email protected] http://jump.to/fleury

@par API Usage Example

Page 247: Manual Micros 2010

The following code shows typical usage of this library, see example test_i2cmaster.c

@code

#include <i2cmaster.h>

#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet

int main(void)

{

unsigned char ret;

i2c_init(); // initialize I2C library

// write 0x75 to EEPROM address 5 (Byte Write)

i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode

i2c_write(0x05); // write address = 5

i2c_write(0x75); // write value 0x75 to EEPROM

i2c_stop(); // set stop conditon = release bus

// read previously written value back from EEPROM address 5

i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode

i2c_write(0x05); // write address = 5

i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode

ret = i2c_readNak(); // read one byte from EEPROM

i2c_stop();

for(;;);

}

@endcode

*/

#endif /* DOXYGEN */

/**@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304

#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"

#endif

#include <avr/io.h>

Page 248: Manual Micros 2010

/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */

#define I2C_READ 1

/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */

#define I2C_WRITE 0

/**

@brief initialize the I2C master interace. Need to be called only once

@param void

@return none

*/

extern void i2c_init(void);

/**

@brief Terminates the data transfer and releases the I2C bus

@param void

@return none

*/

extern void i2c_stop(void);

/**

@brief Issues a start condition and sends address and transfer direction

@param addr address and transfer direction of I2C device

@retval 0 device accessible

@retval 1 failed to access device

*/

extern unsigned char i2c_start(unsigned char addr);

/**

@brief Issues a repeated start condition and sends address and transfer direction

@param addr address and transfer direction of I2C device

@retval 0 device accessible

@retval 1 failed to access device

*/

extern unsigned char i2c_rep_start(unsigned char addr);

/**

Page 249: Manual Micros 2010

@brief Issues a start condition and sends address and transfer direction

If device is busy, use ack polling to wait until device ready

@param addr address and transfer direction of I2C device

@return none

*/

extern void i2c_start_wait(unsigned char addr);

/**

@brief Send one byte to I2C device

@param data byte to be transfered

@retval 0 write successful

@retval 1 write failed

*/

extern unsigned char i2c_write(unsigned char data);

/**

@brief read one byte from the I2C device, request more data from device

@return byte read from I2C device

*/

extern unsigned char i2c_readAck(void);

/**

@brief read one byte from the I2C device, read is followed by a stop condition

@return byte read from I2C device

*/

extern unsigned char i2c_readNak(void);

/**

@brief read one byte from the I2C device

Implemented as a macro, which calls either i2c_readAck or i2c_readNak

@param ack 1 send ack, request more data from device<br>

0 send nak, read is followed by a stop condition

@return byte read from I2C device

*/

extern unsigned char i2c_read(unsigned char ack);

#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();

/**@}*/

#endif

Page 250: Manual Micros 2010

Tabla 44: Libreria Peter Fleury i2cmaster.h

Y Finalmente un ejemplo de uso de la librería

#include <i2cmaster.h>

#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet

int main(void) { unsigned char ret;

i2c_init(); // initialize I2C library

// write 0x75 to EEPROM address 5 (Byte Write) i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode i2c_write(0x05); // write address = 5 i2c_write(0x75); // write value 0x75 to EEPROM i2c_stop(); // set stop conditon = release bus

// read previously written value back from EEPROM address 5 i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode

i2c_write(0x05); // write address = 5 i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode

ret = i2c_readNak(); // read one byte from EEPROM i2c_stop();

for(;;); }

Tabla 45: Ejemplo de uso de libreria i2c

9.3 Leer y escribir sobre EEPROM I2CUna memoria EEPROM I2C tiene una dirección físicamente modificable en sus últimos tres bits, siendo los cuatro más significativos valores ya dados de fabrica. El formato de una dirección para una EEPROM I2C es la siguientes

1 0 1 0 A2 A1 A0 R/~W

Tabla 46: Estructura de dirección de una memoria EEPROM I2C

Donde los bits A2..A0 se cablean de forma física ya sea con conexión a tierra o Vcc, tal y como se muestra en la siguiente figura

Page 251: Manual Micros 2010

La memoria que se muestra en figura 82: Conexión memoria 24C512 tiene una capacidad de almacenamiento de 512kilo bits, los cuales se encuentran agrupados en palabras cuya longitud es 8, lo cual nos da una capacidad total de 64kBytes. Cabe aclarar esto, ya que existen diversas memorias de este tipo, pero con diferentes terminaciones, como por ejemplo la 24C128, la cual tiene una capacidad de almacenamiento en bytes de 16k, o la 24C02 que solo puede almacenar 256 bytes.

Cabe señalar que la memoria que se muestra en la figura cuenta con “jumpers” los cuales permiten modificar la dirección de la memoria a voluntad del usuario, de igual forma el pin 7 (WP) permite la habilitación de la protección contra escritura de la EEPROM si el jumper se retira.

9.3.1 Lectura y escritura simple de sobre una EEPROM I2C

Los procesos de lectura y escritura se resumen en el siguiente diagrama:

figura 82: Conexión memoria 24C512

Page 252: Manual Micros 2010

Las funciones que se muestran a continuación sirven para memorias cuya longitud de direccionamiento requiere mas de un byte; como podrá apreciarse en la función descrita en la Tabla 47: función deescritura de una EEPROM I2C la dirección es de dos bytes (tipo int) y se usa un casting para transformar la variable a dos de tipo char, esto con el fin de posibilitar su envío por el bus I2C.

void write2EEPROM(unsigned char data, unsigned int dir)

{

unsigned char dirl, dirh;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

i2c_write(data);

i2c_stop();

_delay_ms(10);

}

Tabla 47: función de escritura de una EEPROM I2C

De igual forma, se contempla a continuación una función que permite la lectura de un byte de una memoria EEPROM con tan solo indicar la dirección que desea ser leída

figura 83: Diagrama de lectura - escritura de una eeprom i2c

Enviar START

Escritura

Enviar direcciónDel esclavoMás bit deEscritura

Enviar datoA escribir

Enviar STOP

Esperar 6ms

Fin escritura

Lectura

Enviar START

Enviar direcciónA escribir en la

EEPROM

Enviar direcciónDel esclavoMás bit deEscritura

Enviar direcciónA Leer en laEEPROM

Enviar direcciónDel esclavoMás bit de

Lectura

¿nAK recibido?Guardar dato

De la EEPROM Enviar STOP

Fin de lectura

Procesos para la lecturaY escritura simple de unaEEPROM I2C

NoSi

Page 253: Manual Micros 2010

unsigned char read2EEPROM(unsigned int dir)

{

unsigned char leido, dirh, dirl;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

i2c_rep_start(devAA512+I2C_READ);

leido=i2c_readNak();

i2c_stop();

return leido;

}

Tabla 48: función de lectura de una EEPROM I2C

Notesé el uso de la macro devAA512, la cual va a indicar la dirección de la memoria que se desea escribir o leer. Como siguiente punto se muestra un código fuente de ejemplo que permite la escritura y lectura simple de una eeprom 24AA512

Page 254: Manual Micros 2010

/*

*/

#include <avr/io.h>

#include <util/delay.h>

#include "i2cmaster.h"

#define devAA512 0xA6

void write2EEPROM(unsigned char data, unsigned int dir);

unsigned char read2EEPROM(unsigned int dir);

int main(void)

{

unsigned char ret;

unsigned int dir;

// Insert code

i2c_init();

while(1){

for(dir=0;dir<0x10000;dir++)

{

write2EEPROM(0x75,dir);

ret=read2EEPROM(dir);

}

}

return 0;

}

void write2EEPROM(unsigned char data, unsigned int dir)

{

unsigned char dirl, dirh;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

Page 255: Manual Micros 2010

i2c_write(data);

i2c_stop();

_delay_ms(10);

}

unsigned char read2EEPROM(unsigned int dir)

{

unsigned char leido, dirh, dirl;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

i2c_rep_start(devAA512+I2C_READ);

leido=i2c_readNak();

i2c_stop();

return leido;

}

Tabla 49: Lectura escritura simple de una eeprom

Como ejercicio para el lector se propone que modifique el programa anterior a fin de que en una pantalla LCD se vaya mostrando la dirección que se escribe y su posterior lectura, así como el contenido de tal valor de memoria.

9.3.2 Lectura escritura controlada por el puerto de comunicación serial

Con este experimento se va a mostrar la forma de comunicar una EEPROM externa a un MCU y

figura 84: Escritura y lectura simple de una EEPROM sobre I2C

Page 256: Manual Micros 2010

conectada a él vía I2C. Con estos comandos se va a poder enviar datos (un texto) al MCU para ser grabados en la EEPROM y sea posible leer el contenido de la misma para ser presentado en al PC, bajo las siguientes señalizaciones:

• El programa del microcontrolador va guardando lo recibido vía RS232 en un buffer. Con la tecla ENTER se envía a procesar el contenido. Con RETROCESO o ESC se puede borrar el último caracteres o el contenido de todo el buffer.

• Con “/r” se lee todo el contenido de la EEPROM, con “/i dir” se escribe un índice en la posición de memoria 0x00 y 0x01 de la EEPROM a partir de la cual con “/w data” se puede escribir los datos enviados.

• Con “/B” podemos dar formato al contenido de la EEPROM e inicializar el valor del índice, considere la siguiente figura como un mapeo de la memoria:

0x0 0x1 0x2 0x3 ..... 0xE 0xF

0x000 DIRH DIRL 0x00 0x00 ..... 0x00 0x00

0x010 0x00 0x00 0x00 0x00 ..... 0x00 0x00

*

*

*

..... *

*

*.....

0xFFE 0x00 0x00 0x00 0x00 ..... 0x00 0x00

0xFFF 0x00 0x00 0x00 0x00 ..... 0x00 0x00

Código fuente

/*

* Este código permite comunicar un AVR con una PC por medio del puerto Serie

* a fin de controlar la escritura y lectura de una memoria EEPROM por medio del

* protocolo I2C

*/

#include "clk.h"

#include <avr/io.h>

#include <avr/interrupt.h>

#include <stdlib.h>

#include <stdio.h>

#include "uart.h"

#include "i2cmaster.h"

Page 257: Manual Micros 2010

#define devAA512 0xA6

//define el tamano del buffer

#define lenbuff 10

//variables para el manejo de comunicacion serial

typedef enum{false, true} boolean;

boolean flagcommand= false;

unsigned char xbuff=0x00;

unsigned char cbuff[lenbuff];

//funciones para la comunicacion PC - AVR

void presmenu(void); //presenta el menu

void comando(void); //procesa el comando recibido

/**

* funcion que limpia el buffer de caracteres para la comunicacion serial

*/

void initBuff(void);

/**

* funcion para agregar un caracter al buffer de comunicacion serial

*/

void add2cbuff(unsigned char c);

/**

* funcion que imprime un echo a la terminal, solo caracteres imprimibles

*/

void echosel(unsigned char c);

//funciones para lectura/escritura de la eeprom

void write2EEPROM(unsigned char data, unsigned int dir);

unsigned char read2EEPROM(unsigned int dir);

volatile unsigned char rcvchar;

//interrupciones

ISR(USART1_RX_vect)

{

rcvchar = 0x00; //Se inicializa el caracter recibido

if(uart_dataAvailable()) //Existe algun dato disponible

{

rcvchar = uart_receive();//Se lee el buffer de recepcion

add2cbuff(rcvchar); //se agrega al buffer de comando

echosel(rcvchar); //Se envia un eco hacia la PC

Page 258: Manual Micros 2010

}

}

int main(void)

{

//unsigned int dir;

// Insert code

i2c_init();

uart_init();

// Insert code

initBuff();

presmenu();

while(1)

{

if(flagcommand) comando();

}

return 0;

}

void comando()

{

int i,j,u,h;

unsigned char hh,hl; //variables para extraer la dir de memoria

boolean flagValido = false;

char buffer[5];

char buf[lenbuff];

char arg[lenbuff];

clrbit(UCSR1B, RXCIE1); //deshabilitar la recepcion de datos

for(i=0; i< lenbuff; i++){

arg[i]= 0x00;

}

//Código para procesar /?

if(cbuff[0]=='/' && cbuff[1]=='?'){

Page 259: Manual Micros 2010

flagValido = true;

presmenu();

}

//Codigo para procesar /B

if(cbuff[0]=='/' && cbuff[1]=='B'){

flagValido = true;

uart_print("\r\nFormateando");

j=0;

for( j=0;j<0x10000;j++){

write2EEPROM(0x00,i);

}

//Escribiendo la direccion indice

write2EEPROM(0x00,0);

write2EEPROM(0x02,1);

}

//Codigo para procesar /r

if(cbuff[0]=='/' && cbuff[1]=='r'){

flagValido = true;

for(i=0; i<16;i++){

sprintf(buffer,"%X",i);

uart_print(buffer);

}

uart_print("\r\n");

for( j=0; j<16;j++)

uart_print("==");

uart_print("\r\n");

for(i=0;i<0x10000;i++){

u = read2EEPROM(i);

sprintf(buffer,"%X",u);

uart_print(buffer);

}

uart_print("\r\n\r\n");

}

//Procesar comando /w dat

if(cbuff[0]=='/' && cbuff[1]=='w'){

flagValido = true;

i=3;//Se estrae la cadena a escribir n la eeprom

do{

Page 260: Manual Micros 2010

arg[i-3] = cbuff[i];

}while(cbuff[++i]!=0x00);

hh = read2EEPROM(0x0000);

hl = read2EEPROM(0x0001);

h = hh<<8;

h = h|hl;

uart_print("Escribir ");

uart_print(arg);

uart_print(" a partir de ");

sprintf(buffer,"%X",h);

uart_print(buffer);

uart_print("\r\n\r\n");

i=0;

do{

write2EEPROM(arg[i],h);

++h;//colocate en la siguinte direccion

++i;//escribe el siguiente caracter en dat

}while(arg[i]!=0x00);

//actualizar el indice

--h;

hh=(unsigned char) (h>>8);

hl=(unsigned char) (h);

write2EEPROM(hh,0x0000);

write2EEPROM(hl,0x0001);

uart_print("Buffer escrito\r\n\r\n");

}

//procesando comando /i dir

//la direccion se procesa como hexadecimal

if(cbuff[0]=='/' && cbuff[1]=='i'){

flagValido = true;

i=3;

do{

arg[i-3] = cbuff[i];

}while(cbuff[++i]!=0x00);

h= (16*ascii2hex(arg[1]) + (ascii2hex(arg[0])) +

(16*16*ascii2hex(arg[2])) +

(16*16*16*ascii2hex(arg[3])));

Page 261: Manual Micros 2010

//Se calcula la direccion a partir de lo recibido

//Se escribe el nuevo indice

hh=(unsigned char) (h>>8);

hl=(unsigned char) (h);

write2EEPROM(hh,0x0000);

write2EEPROM(hl,0x0001);

}

if(flagValido == false){

uart_print("¿");

sprintf(buf,"%uc",cbuff);

uart_print(buf );

uart_print("?");

}

initBuff();

setbit(UCSR1B,RXCIE1);

}

void presmenu()

{

delay_ms(25);

uart_print("\n\r");

uart_print("EEPROM Lectura Escritura por PC\n\r");

uart_print("control por buffer\n\r");

uart_print("[ENTER] procesa el comando\n\r");

uart_print("[ESC] Borra todo el buffer\n\r");

uart_print("[DEL] Borra el ultimo caracter del buffer\n\r");

uart_print("\n\r\n\r");

uart_print("Comando EEPROM\n\r");

uart_print("/? ------- Presenta menu nuevamente\n\r");

uart_print("/B ------- Formatea la memoria EEPROM\n\r");

uart_print("/r ------- lee el contenido completo de la EEPROM y lo vuelca por RS232\n\r");

uart_print("/w <dat> - Escribe la cadena <dat> en la EEPROM a partir de la direccion indice\n\r");

uart_print("/i <dir> - Coloca el indice de la EEPROM en 0x<dir> sin borrar contenido\n\r");

uart_print("\n\r");

delay_ms(25);

}

void initBuff(void)

Page 262: Manual Micros 2010

{

int i;

for(i=0;i<lenbuff; i++)

{

cbuff[i]=0x00;

}xbuff=0x00;

}

void add2cbuff(unsigned char c)

{

if(xbuff<lenbuff)

{

switch(c)

{

case INTRO:

flagcommand = true;

break;

case RETROCESO:

if(xbuff>0) cbuff[--xbuff] = 0x00;

break;

case ESCAPE:

initBuff();

break;

default:

cbuff[xbuff++]=c;

}

}

else

{

initBuff();

uart_print("ERROR\r\n");

}

}

void echosel(unsigned char c)

{

switch(c)

{

case INTRO:

uart_print("\r\n");

Page 263: Manual Micros 2010

break;

case RETROCESO:

uart_transmit(RETROCESO);

break;

case ESCAPE:

uart_transmit(ESCAPE);

break;

default:

uart_transmit(c);

}

}

void write2EEPROM(unsigned char data, unsigned int dir)

{

unsigned char dirl, dirh;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

i2c_write(data);

i2c_stop();

delay_ms(10);

}

unsigned char read2EEPROM(unsigned int dir)

{

unsigned char leido, dirh, dirl;

dirh = (unsigned char) (dir >> 8);

dirl = (unsigned char) (dir);

i2c_start_wait(devAA512+I2C_WRITE);

i2c_write(dirh);

i2c_write(dirl);

i2c_rep_start(devAA512+I2C_READ);

leido=i2c_readNak();

i2c_stop();

return leido;

}

Page 264: Manual Micros 2010

Librería de comunicación serial, cabecera y fuentes

#ifndef __UART_H

#define __UART_H

//#define F_CPU 16000000L

#include "clk.h"

# define USART_BAUDRATE 9600UL

# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16UL))) - 1)

//definicion de teclas

#define INTRO 0x0D

#define RETROCESO 0x08

#define ESCAPE 0x1B

void uart_transmit( unsigned char data );

unsigned char uart_receive(void);

void uart_init(void);

int uart_dataAvailable(void);

void uart_print(const char *s);

/**

* funcion para convertir un caracter ascii a hexadecimal

*/

int ascii2hex(char d);

#endif

// uart.c

// Originally for NerdKits with ATmega168, 14.7456 MHz clock

// [email protected]

// Modified for Adafruit ATMega32u4 Breakout, with 16.0000Mhz clock

// Note, this references serial 1, not 0, since the micro does not have 0.

// At least for the above breakout, D3 is TX, and D2 RX

// https://github.com/tomvdb/avr_arduino_leonardo/blob/master/examples/uart/main.c

#include "clk.h"

#include <avr/io.h>

#include <string.h>

#include "uart.h"

Page 265: Manual Micros 2010

#include <util/delay.h>

#include <ctype.h>

// transmit a char to uart

void uart_transmit( unsigned char data )

{

// wait for empty transmit buffer

while ( ! ( UCSR1A & ( 1 << UDRE1 ) ) )

;

// put data into buffer, sends data

UDR1 = data;

}

// read a char from uart

unsigned char uart_receive(void)

{

while (!( UCSR1A & ( 1 << RXC1) ))

;

return UDR1;

}

// init uart

void uart_init(void)

{

// set baud rate

unsigned int baud = BAUD_PRESCALE;

UBRR1H = (unsigned char)(baud >> 8 );

UBRR1L = (unsigned char)baud;

//UBRR1H = 0;

//UBRR1L = 0x34;

// enable received and transmitter

UCSR1B = ( 1 << RXEN1 ) | ( 1 << TXEN1 );

// set frame format ( 8data, 2stop )

UCSR1C = ( 1 << USBS1 ) | ( 1 << UCSZ11 ) | (1 << UCSZ10);

Page 266: Manual Micros 2010

}

// check if there are any chars to be read

int uart_dataAvailable(void)

{

if ( UCSR1A & ( 1 << RXC1) )

return 1;

return 0;

}

// write a string to the uart

void uart_print(const char *s)

{

register char c;

while((c=*s++)){

uart_transmit(c);

}

}

/*

void uart_print( char data[] )

{

int c = 0;

for ( c = 0; c < strlen(data); c++ )

uart_transmit(data[c]);

}

*/

int ascii2hex(char d)

{

int r = 0x00;

if(isxdigit(d))

{

if(isdigit(d))

{

r = d-'0';

}

if(isalpha(d))

{

d = toupper(d);

r = 10+(d-'A');

Page 267: Manual Micros 2010

}

}

return(r);

}

Librería para la comunicación I2C cabecera y fuentes

#ifndef _I2CMASTER_H

#define _I2CMASTER_H 1

/*************************************************************************

* Title: C include file for the I2C master interface

* (i2cmaster.S or twimaster.c)

* Author: Peter Fleury <[email protected]> http://jump.to/fleury

* File: $Id: i2cmaster.h,v 1.10 2005/03/06 22:39:57 Peter Exp $

* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3

* Target: any AVR device

* Usage: see Doxygen manual

**************************************************************************/

#ifdef DOXYGEN

/**

@defgroup pfleury_ic2master I2C Master library

@code #include <i2cmaster.h> @endcode

@brief I2C (TWI) Master Software Library

Basic routines for communicating with I2C slave devices. This single master

implementation is limited to one bus master on the I2C bus.

This I2c library is implemented as a compact assembler software implementation of the I2C protocol

which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).

Since the API for these two implementations is exactly the same, an application can be linked either against the

software I2C implementation or the hardware I2C implementation.

Use 4.7k pull-up resistor on the SDA and SCL pin.

Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module

i2cmaster.S to your target when using the software I2C implementation !

Adjust the CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

@note

The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted

to GNU assembler and AVR-GCC C call interface.

Page 268: Manual Micros 2010

Replaced the incorrect quarter period delays found in AVR300 with

half period delays.

@author Peter Fleury [email protected] http://jump.to/fleury

@par API Usage Example

The following code shows typical usage of this library, see example test_i2cmaster.c

@code

#include <i2cmaster.h>

#define Dev24C02 0xA2 // device address of EEPROM 24C02, see datasheet

int main(void)

{

unsigned char ret;

i2c_init(); // initialize I2C library

// write 0x75 to EEPROM address 5 (Byte Write)

i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode

i2c_write(0x05); // write address = 5

i2c_write(0x75); // write value 0x75 to EEPROM

i2c_stop(); // set stop conditon = release bus

// read previously written value back from EEPROM address 5

i2c_start_wait(Dev24C02+I2C_WRITE); // set device address and write mode

i2c_write(0x05); // write address = 5

i2c_rep_start(Dev24C02+I2C_READ); // set device address and read mode

ret = i2c_readNak(); // read one byte from EEPROM

i2c_stop();

for(;;);

}

@endcode

*/

#endif /* DOXYGEN */

Page 269: Manual Micros 2010

/**@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304

#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"

#endif

#include <avr/io.h>

/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */

#define I2C_READ 1

/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */

#define I2C_WRITE 0

/**

@brief initialize the I2C master interace. Need to be called only once

@param void

@return none

*/

extern void i2c_init(void);

/**

@brief Terminates the data transfer and releases the I2C bus

@param void

@return none

*/

extern void i2c_stop(void);

/**

@brief Issues a start condition and sends address and transfer direction

@param addr address and transfer direction of I2C device

@retval 0 device accessible

@retval 1 failed to access device

*/

extern unsigned char i2c_start(unsigned char addr);

/**

Page 270: Manual Micros 2010

@brief Issues a repeated start condition and sends address and transfer direction

@param addr address and transfer direction of I2C device

@retval 0 device accessible

@retval 1 failed to access device

*/

extern unsigned char i2c_rep_start(unsigned char addr);

/**

@brief Issues a start condition and sends address and transfer direction

If device is busy, use ack polling to wait until device ready

@param addr address and transfer direction of I2C device

@return none

*/

extern void i2c_start_wait(unsigned char addr);

/**

@brief Send one byte to I2C device

@param data byte to be transfered

@retval 0 write successful

@retval 1 write failed

*/

extern unsigned char i2c_write(unsigned char data);

/**

@brief read one byte from the I2C device, request more data from device

@return byte read from I2C device

*/

extern unsigned char i2c_readAck(void);

/**

@brief read one byte from the I2C device, read is followed by a stop condition

@return byte read from I2C device

*/

extern unsigned char i2c_readNak(void);

/**

@brief read one byte from the I2C device

Page 271: Manual Micros 2010

Implemented as a macro, which calls either i2c_readAck or i2c_readNak

@param ack 1 send ack, request more data from device<br>

0 send nak, read is followed by a stop condition

@return byte read from I2C device

*/

extern unsigned char i2c_read(unsigned char ack);

#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();

/**@}*/

#endif

/*************************************************************************

* Title: I2C master library using hardware TWI interface

* Author: Peter Fleury <[email protected]> http://jump.to/fleury

* File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $

* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3

* Target: any AVR device with hardware TWI

* Usage: API compatible with I2C Software Library i2cmaster.h

**************************************************************************/

#include <inttypes.h>

#include <compat/twi.h>

#include "i2cmaster.h"

/* define CPU frequency in Mhz here if not defined in Makefile */

#ifndef F_CPU

#define F_CPU 4000000UL

#endif

/* I2C clock in Hz */

#define SCL_CLOCK 200000L //Velocidad de comunicacion para la memoria 24AA512

/*************************************************************************

Initialization of the I2C bus interface. Need to be called only once

*************************************************************************/

void i2c_init(void)

{

/* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */

Page 272: Manual Micros 2010

TWSR = 0; /* no prescaler */

TWBR = ((F_CPU/SCL_CLOCK)-16)/2; /* must be > 10 for stable operation */

}/* i2c_init */

/*************************************************************************

Issues a start condition and sends address and transfer direction.

return 0 = device accessible, 1= failed to access device

*************************************************************************/

unsigned char i2c_start(unsigned char address)

{

uint8_t twst;

// send START condition

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

// send device address

TWDR = address;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed and ACK/NACK has been received

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

return 0;

}/* i2c_start */

/*************************************************************************

Issues a start condition and sends address and transfer direction.

Page 273: Manual Micros 2010

If device is busy, use ack polling to wait until device is ready

Input: address and transfer direction of I2C device

*************************************************************************/

void i2c_start_wait(unsigned char address)

{

uint8_t twst;

while ( 1 )

{

// send START condition

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst != TW_START) && (twst != TW_REP_START)) continue;

// send device address

TWDR = address;

TWCR = (1<<TWINT) | (1<<TWEN);

// wail until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits.

twst = TW_STATUS & 0xF8;

if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )

{

/* device busy, send stop condition to terminate write operation */

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released

while(TWCR & (1<<TWSTO));

continue;

}

//if( twst != TW_MT_SLA_ACK) return 1;

break;

}

Page 274: Manual Micros 2010

}/* i2c_start_wait */

/*************************************************************************

Issues a repeated start condition and sends address and transfer direction

Input: address and transfer direction of I2C device

Return: 0 device accessible

1 failed to access device

*************************************************************************/

unsigned char i2c_rep_start(unsigned char address)

{

return i2c_start( address );

}/* i2c_rep_start */

/*************************************************************************

Terminates the data transfer and releases the I2C bus

*************************************************************************/

void i2c_stop(void)

{

/* send stop condition */

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);

// wait until stop condition is executed and bus released

while(TWCR & (1<<TWSTO));

}/* i2c_stop */

/*************************************************************************

Send one byte to I2C device

Input: byte to be transfered

Return: 0 write successful

1 write failed

*************************************************************************/

unsigned char i2c_write( unsigned char data )

{

uint8_t twst;

Page 275: Manual Micros 2010

// send data to the previously addressed device

TWDR = data;

TWCR = (1<<TWINT) | (1<<TWEN);

// wait until transmission completed

while(!(TWCR & (1<<TWINT)));

// check value of TWI Status Register. Mask prescaler bits

twst = TW_STATUS & 0xF8;

if( twst != TW_MT_DATA_ACK) return 1;

return 0;

}/* i2c_write */

/*************************************************************************

Read one byte from the I2C device, request more data from device

Return: byte read from I2C device

*************************************************************************/

unsigned char i2c_readAck(void)

{

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);

while(!(TWCR & (1<<TWINT)));

return TWDR;

}/* i2c_readAck */

/*************************************************************************

Read one byte from the I2C device, read is followed by a stop condition

Return: byte read from I2C device

*************************************************************************/

unsigned char i2c_readNak(void)

{

TWCR = (1<<TWINT) | (1<<TWEN);

while(!(TWCR & (1<<TWINT)));

return TWDR;

Page 276: Manual Micros 2010

}/* i2c_readNak */

Librería de ajustes generales para el ATMega32u4

#ifndef CLK_H

#define CLK_H

/**

@defgroup atmega32u4_clk Prescaler_Macros

@code #include <clk.h> @endcode

@brief Macros para definir la frecuencia de oscilacion del reloj

principal

*/

/*@{*/

/**

* @name Definitions for MCU Clock Frequency

* Adapt the MCU clock frequency in Hz to your target.

* Revisa las paginas 37-39

*/

#define F_CPU 1000000L

#if F_CPU == 16000000L

#define ADC_PRESCALER 0x07 /**<Factor de division 128 F_ADC = 125kHz*/

#define CPU_PRESCALER 0x00

#elif F_CPU == 8000000L

#define ADC_PRESCALER 0x06 /**<Factor de division 64 F_ADC = 125kHz*/

#define CPU_PRESCALER 0x01

#elif F_CPU == 4000000L

#define ADC_PRESCALER 0x05 /**<Factor de division 32*/

#define CPU_PRESCALER 0x02

#elif F_CPU == 2000000L

#define ADC_PRESCALER 0x04 /**<Factor de division 16*/

#define CPU_PRESCALER 0x03

#elif F_CPU == 1000000L

#define ADC_PRESCALER 0x03 /**<Factor de division 8*/

#define CPU_PRESCALER 0x04

#else

#error "Teensyduino only supports 16, 8, 4, 2, 1 MHz. Please edit boards.txt"

#endif

Page 277: Manual Micros 2010

/**

* @name Macros para sustituir el seteo de bits individuales

*/

#define setbit(sfr,bit) (_SFR_BYTE(sfr)|=_BV(bit)) /**<Pone en set un bit*/

#define clrbit(sfr,bit) (_SFR_BYTE(sfr)&=~_BV(bit)) /**<Pone en clear un bit*/

#define togglebit(sfr,bit) (_SFR_BYTE(sfr)^=_BV(bit)) /**<Cambia el estado de bit*/

/**

* @name Functions

*/

/**

@brief Funcion para inicializar los tiempos en el ATMega32U4

@param none

@return none

*/

void _init_Teensyduino_internal_(void);

void delay_ms(unsigned int time_ms);

/*@}*/

#endif //end clk.h

#include "clk.h"

#include <avr/io.h>

#include <util/delay.h>

#include <avr/interrupt.h>

//#include "clk.h"

void _init_Teensyduino_internal_(void)

{

cli();

CLKPR = 0x80;

CLKPR = CPU_PRESCALER;

}

void delay_ms(unsigned int time_ms)

Page 278: Manual Micros 2010

{

unsigned int i;

for(i=0; i<time_ms; i++)

_delay_ms(1);

}

Page 279: Manual Micros 2010

Índice de figurasfigura 1: MCU, MPU, microcomputadora.................................................................................................8

figura 2: Partes e interfaces de un microcontrolador.................................................................................9

figura 3: Definiciones de arquitectura de computadoras..........................................................................13

figura 4: Arquitectura Memoria Unificada...............................................................................................14

figura 5: Arquitectura Memoria Separada................................................................................................14

figura 6: Cuadro comparativo entre microcontroladores.........................................................................20

figura 7: Arquitectura AVR......................................................................................................................21

figura 8: Mapeo de memoria del ATMega32U4......................................................................................22

figura 9: Pinout del microcontrolador ATMega32U4..............................................................................26

figura 10: Sistema de reloj del ATMega32U4..........................................................................................35

figura 11: Formas de onda de reloj...........................................................................................................36

figura 12: Opciones para configurar el reloj............................................................................................37

figura 13: Conexión de cristal de bajo consumo......................................................................................37

figura 14: Palabra en FUSES para la conexión de oscilador de bajo consumo.......................................38

figura 15: Palabra para seleccionar el reloj interno..................................................................................38

figura 16: Conexión de Reloj externo......................................................................................................38

figura 17: Sistema de reloj de PLL..........................................................................................................39

figura 18: fuentes de reset........................................................................................................................40

figura 19: Relación entre velocidad y alimentación.................................................................................42

figura 20: Tarjeta para prácticas...............................................................................................................53

figura 21: Esquema eléctrico de protección de una terminal E/S............................................................63

figura 22: Teclado matricial 4 x 4............................................................................................................64

figura 23: Lectura de un teclado matricial...............................................................................................65

figura 24: Conexiones display de 7 segmentos........................................................................................72

figura 25: Pinout display de 7 segmentos................................................................................................72

figura 26: Diagrama de funcionamiento de sensor ultrasónico................................................................79

figura 27: Terminales del SRF-04............................................................................................................79

figura 28: rango de detección...................................................................................................................80

figura 29: Transistor inversor...................................................................................................................81

figura 30: seguidor emisivo......................................................................................................................81

figura 31: Acoplamiento con transistor PNP............................................................................................82

figura 32: Conexión básica de relevador..................................................................................................82

figura 33: Montaje Darlington.................................................................................................................83

Page 280: Manual Micros 2010

figura 34: Doble transistor de activación.................................................................................................83

figura 35: Cálculo de conexión a Relevador............................................................................................84

figura 36: circuito saturación...................................................................................................................85

figura 37: curva característica..................................................................................................................85

figura 38: Saturación de un MOSFET.....................................................................................................85

figura 39: Circuito equivalente en saturación..........................................................................................86

figura 40: Circuito equivalente en corte...................................................................................................86

figura 41: Ejemplos de optoacopladores..................................................................................................87

figura 42: Optoacoplador de herradura....................................................................................................87

figura 43: Optoacoplador de reflexión.....................................................................................................87

figura 44: Empaquetados de optoacopladores..........................................................................................88

figura 45: Características mecánicas de empaquetados...........................................................................89

figura 46: pinout del ULN2803................................................................................................................90

figura 47: Pinout del L293.......................................................................................................................91

figura 48: Diagrama de estados propuesto...............................................................................................92

figura 49: circuito estados lógicos..........................................................................................................100

figura 50: motor a pasos unipolar..........................................................................................................101

figura 51: Motor a pasos bipolar............................................................................................................101

figura 52: Servomotor DC aeromodelismo............................................................................................102

figura 53: Desensamble de un servo......................................................................................................103

figura 54: Cables de un servo estándar..................................................................................................103

figura 55: Señales y posiciones de un servo...........................................................................................104

figura 56: Secuencia para leer el sensor ultrasónico..............................................................................104

figura 57: Práctica sensor ultrasónico....................................................................................................105

figura 58: circuito medidor de distancia ultrasónico..............................................................................105

figura 59: circuito con LCD e interrupciones........................................................................................123

figura 60: Arquitectura del Temporizador 0...........................................................................................128

figura 61: Arquitectura del Timer 0........................................................................................................131

figura 62: Prescaladores y relojes del timer0 y timer1...........................................................................131

figura 63: Preescalador del timer 2........................................................................................................133

figura 64: Reloj Digital Simple..............................................................................................................142

figura 65: Reloj con base en Timer 0.....................................................................................................150

figura 66: Conmutando la alimentación de una carga podemos lograr un régimen de trabajo variable179

figura 67: Acumulación de tiempos controlable por microcontrolador.................................................180

figura 68: El IRFZ44N en su hoja de datos...........................................................................................181

Page 281: Manual Micros 2010

figura 69: Efecto del voltaje Vgs en un MOSFET.................................................................................182

figura 70: Fotografía de IRFZ44N.........................................................................................................182

figura 71: Circuito de Aplicación...........................................................................................................183

figura 72: Circuito para generar PWM en ATMega48...........................................................................192

figura 73: circuito para control PWM de motor DC con L293D...........................................................195

figura 74: Diagrama de estados para práctica con PWM.......................................................................199

figura 75: Funcionamiento de PWM con motor DC..............................................................................200

figura 76: Secuencia de activación en bobina........................................................................................202

figura 77: Circuito equivalente de bobina en Tr.....................................................................................203

figura 78: diagrama de flujo para promediado de lecturas de ADC.......................................................210

figura 79: Lectura de ADC ATmega48...................................................................................................212

figura 80: Configuración de libreria RxTx en Netbeans agregando JAR..............................................229

figura 81: Configuración de librerias RxTx en netbeans.......................................................................230

figura 82: Conexión memoria 24C512...................................................................................................250

figura 83: Diagrama de lectura - escritura de una eeprom i2c...............................................................251

figura 84: Escritura y lectura simple de una EEPROM sobre I2C.........................................................254

Page 282: Manual Micros 2010

Índice de tablasTabla 1: Características especiales del Puerto B en el ATMega32U4......................................................28

Tabla 2: Características especiales del Puerto C en el ATMega32U4......................................................29

Tabla 3: Características especiales del Puerto D en el ATMega32U4.....................................................30

Tabla 4: Características especiales del Puerto E en el ATMega32U4......................................................31

Tabla 5: Código máquina.........................................................................................................................47

Tabla 6: Ejemplo de código fuente en ensamblador................................................................................48

Tabla 7: Ejemplo de código fuente en C..................................................................................................49

Tabla 8: Código de ejemplo de teclado matricial.....................................................................................69

Tabla 9: Código de ejemplo para display de siete segmentos..................................................................75

Tabla 10: Código de AHDL para control por FSM..................................................................................92

Tabla 11: Código para control por FSM...................................................................................................97

Tabla 12: Vectores de Interrupción.........................................................................................................108

Tabla 13: Equivalencias entre vectores del datasheet y AVRGCC........................................................109

Tabla 14: Control de sensado de Interrupción externa...........................................................................110

Tabla 15: Código para configuración de interrupciones externas - Shawn Johnson..............................111

Tabla 16: Ejemplo de uso de librerías LCD de Shawn Johnson............................................................113

Tabla 17: Librería LCD de Shawn Johnson - lcd.h................................................................................115

Tabla 18: Librería lcd de Shawn Johnson -lcd.c....................................................................................119

Tabla 19: Código para control de puente H...........................................................................................125

Tabla 20: Bits para configuración de Interrupciones del comparador analógico...................................139

Tabla 21: Código fuente Reloj digital con display de 7 segmentos basado en ATmega48....................143

Tabla 22: Librería para configuración del timer0 - timer0.h..................................................................144

Tabla 23: Librería para configuración del timer0 - timer0.c..................................................................145

Tabla 24: Librería para configuración del timer1 - timer1.h..................................................................145

Tabla 25: Librería para configuración del timer1 - timer1.c..................................................................146

Tabla 26: Código fuente para configurar el timer 0 en modo CTC.......................................................147

Tabla 27: Librería lcd.h de Peter Fleury.................................................................................................155

Tabla 28: Librería lcd.c de Peter Fleury.................................................................................................170

Tabla 29: Librería clk.h..........................................................................................................................172

Tabla 30: Librería clk.c..........................................................................................................................173

Tabla 31: Código configuración de timers con PWM............................................................................186

Tabla 32: Código para la configuración de timers.................................................................................194

Tabla 33: Código control PWM de puente H.........................................................................................199

Page 283: Manual Micros 2010

Tabla 34: Secuencia de energización de bobinas de motor bipolar en medios pasos............................202

Tabla 35: Lectura del ADC en ATmega48.............................................................................................217

Tabla 36: librería usart.h........................................................................................................................225

Tabla 37: librería usart.c.........................................................................................................................229

Tabla 38: Encendido de leds a través de puerto serie en microcontrolador...........................................231

Tabla 39: Código fuente de Java para verificar puertos seriales habilitados.........................................235

Tabla 40: Código para envío de datos binarios adquiridos por el ADC a través del puerto serial.........241

Tabla 41: Script de scilab para comunicación con el puerto serial........................................................241

Tabla 42: Librería Peter Fleury twimaster.c...........................................................................................248

Tabla 43: Libreria Peter Fleury i2cmaster.h...........................................................................................253

Tabla 44: Ejemplo de uso de libreria i2c................................................................................................253

Tabla 45: Estructura de dirección de una memoria EEPROM I2C........................................................253

Tabla 46: función de escritura de una EEPROM I2C............................................................................255

Tabla 47: función de lectura de una EEPROM I2C...............................................................................256

Tabla 48: Lectura escritura simple de una eeprom.................................................................................258

Page 284: Manual Micros 2010

Referencias

Biblioman. (2013). Implementación de una Máquina de Estados Finita en un PIC. AquiHayApuntes.

Retrieved June 6, 2014, from http://www.aquihayapuntes.com/indice-practicas-pic-en-

c/implementacion-de-una-maquina-de-estados-finita-en-un-pic.html

Carletti, E. (2007). Servos - Características básicas. Robots Argentina pasión por la robótica en

Argentina. Retrieved June 6, 2014, from http://robots-argentina.com.ar/MotorServo_basico.htm

Chavarrea, G., & Chiluisa, A. (2013). construcción e implementación de un circuito electrónico

mediante un sensor de huellas dactilares para el control de ingreso y salida del personal

autorizado al cuarto de equipos de computación ubicado en el Instituto de Estudios del Petrolo

- Quito (Proyecto previo a la obtención del título de Tecnologo en Electrónica y

Telecomunicaciones). Quito Ecuador: Escuela Politecnica Nacional, Escuela de formación de

Tecnológos. Retrieved from http://bibdigital.epn.edu.ec/bitstream/15000/6359/1/CD-4882.pdf

Devantech Ltd. (2003). SRF04 Technical Documentation. Robot electronics. Retrieved March 10,

2014, from http://www.robot-electronics.co.uk/htm/srf04tech.htm

EPSA. (2001). Optoelectrónica. Laboratorio de electrónica - Escuela Politecnica Superior de

Albacete. Retrieved June 6, 2014, from http://www.info-

ab.uclm.es/labelec/solar/Componentes/OPTOELECTRONICA.html

Gadre, D. (2000). Programming and Customizing the AVR Microcontroller (1 edition.). New York:

McGraw-Hill/TAB Electronics.

Mario. (2010). IRFZ44N: El MOS-FET de batalla para PWM. NeoTeo. Retrieved June 6, 2014, from

http://www.neoteo.com/irfz44n-el-mos-fet-de-batalla-para-pwm/

Motion Control. (2010). Sistema de realimentación de posición (I): encoder o resolver :Motion Control.

Motion Control - Control de movimiento y accionamientos eléctricos. Retrieved June 6, 2014,

from http://www.infoplc.net/blog4/2010/12/03/sistema-de-realimentacion-de-posicion-i-

encoder-o-resolver/

Pablin. (2008). Detector Infrarrojo de proximidad. PABLIN Portal de tecnología de habla hispana.

Retrieved June 6, 2014, from http://www.pablin.com.ar/electron/circuito/varios/proximid/

Page 285: Manual Micros 2010

Quadruino. (2014). Protocolo I2C / TWI - Quadruino. Quadruino A free software and hardware

Quadracopter. Retrieved June 6, 2014, from http://www.quadruino.com/guia-

2/sensores/protocolo-i2c-twi

RedRaven. (2010). Procesador de comandos via RS232 (con buffer de recepción). PicMania by

RedRaven. Retrieved June 6, 2014, from http://picmania.garcia-

cuervo.net/picc.php#COMBUF232

UNLP. (2010). Instrumentación y Comunicaciones Industriales - Facultad de Ingeniería - UNLP.

Apuntes de Cátedra. Retrieved June 6, 2014, from

http://www.ing.unlp.edu.ar/electrotecnia/procesos/

Page 286: Manual Micros 2010

Índice alfabéticoA

arquitectura.............................................................................................................6, 13 ss., 19, 58, 80, 82

Arquitectura..........................................................................................................................13, 18 s., 58 s.

C

CPU............................................................................................................................................................9

Cristal oscilador de baja frecuencia.........................................................................................................34

Cristal oscilador de bajo consumo...........................................................................................................33

F

Fuentes de Reloj.......................................................................................................................................33

M

MEMORIA de PROGRAMA....................................................................................................................9

microcomputadora..................................................................................................................................6 s.

Microcomputadora................................................................................................................................6 ss.

Microcontrolador.......................................................................................................................................7

Microprocesador........................................................................................................................................7

Modelo Acumulador................................................................................................................................14

Modelo Registro-memoria.......................................................................................................................15

Modelo Registro-registro.........................................................................................................................15

Modo Idle.................................................................................................................................................37

Modo Power-down...................................................................................................................................37

Modo Power-save.....................................................................................................................................37

Modo Reducción de ruido en ADC..........................................................................................................37

Modo Standby..........................................................................................................................................38

O

Oscilador interno RC calibrado................................................................................................................34

P

perro guardián........................................................................................................................16, 31, 34, 37

Perro guardián..........................................................................................................................................37

Perro Guardián.........................................................................................................................................37

PERRO GUARDIÁN..............................................................................................................................10

PLL...........................................................................................................................................................35

PORTB.....................................................................................................................................................24

Puerto C....................................................................................................................................................25

Page 287: Manual Micros 2010

Puerto D...................................................................................................................................................26

Puerto E....................................................................................................................................................27

Puerto F....................................................................................................................................................28

puerto serial..............................................................................................................................10, 211, 214

PUERTO SERIAL...................................................................................................................................10

PUERTOS ANALÓGICOS.....................................................................................................................10

PUERTOS DIGITALES...........................................................................................................................10

R

ram....................................................................................................................................13, 16, 60 ss., 66

RAM...............................................................................................................................................7, 10, 16

reloj.............................................................10, 16, 22, 24, 26 ss., 37 s., 119 s., 122 s., 132, 173, 178, 186

Reloj...........................................................................................................................11, 25 ss., 32 ss., 120

RELOJ......................................................................................................................................................10

Reloj de entradas/salidas..........................................................................................................................32

Reloj del convertidor analógico-digital....................................................................................................32

Reloj del CPU..........................................................................................................................................32

Reloj del prescalador PLL........................................................................................................................33

Reloj del timer de alta velocidad..............................................................................................................33

Reloj del USB..........................................................................................................................................33

Reloj externo............................................................................................................................................34

Reloj flash................................................................................................................................................32

reset.......................................................................................................10, 24 ss., 34, 37, 86, 88, 128, 134

Reset.......................................................................................................16, 22, 29, 36, 42, 45, 100 s., 138

RESET........................................................................................................................10, 22, 29, 37, 100 s.

RTC.................................................................................................................................11, 88, 114 s., 132

T

timer..................................................10, 16, 32 ss., 99, 118, 124, 127, 132, 134 s., 137 ss., 174, 181, 185

Timer...........................................................16, 26 s., 32, 100 ss., 118 s., 122 ss., 126, 128, 134, 138, 172

TIMER.....................................................................................................................10, 101 ss., 133, 136 s.

V

Velocidad máxima vs velocidad...............................................................................................................38