03 - Cap 1 - 2 - 3
03 - Cap 1 - 2 - 3
03 - Cap 1 - 2 - 3
Un sistema electrónico puede ser representado con el diagrama de la figura 1.1, sin
importar la funcionalidad para la cual haya sido diseñado.
El sistema recibe las peticiones de los usuarios o conoce lo que ocurre en su entorno por
medio de los sensores. Los sensores son dispositivos electrónicos que se encargan de
acondicionar diferentes tipos de información a un formato reconocido por los elementos
de procesamiento. Un sensor puede ser tan simple como un botón o tan complejo como
un reconocedor de huella digital, pero si los elementos de procesamiento son digitales,
en ambos casos la salida va a estar codificada en 1’s y 0’s. Con los sensores se pueden
monitorear diferentes parámetros, como: temperatura, humedad, velocidad, intensidad
luminosa, etc.
Los elementos de visualización son dispositivos electrónicos que muestran el estado actual del
sistema, notificando al usuario si debe tomar acciones. Los elementos de visualización típicos
son: LEDs individuales o matrices de LEDs, displays de 7 segmentos o de cristal líquido.
15
Los actuadores son dispositivos electrónicos o electromecánicos que también forman parte
de las salidas de un sistema, pero con la capacidad de modificar el entorno, es decir, van más
allá de la visualización, algunos ejemplos son: motores, electroválvulas, relevadores, etc.
16
Un microcontrolador es un Circuito Integrado con una escala de integración muy grande
(VLSI1, very large scale integration) que internamente contiene una Unidad Central
de Procesamiento (CPU, Cental Processing Unit), memoria para código, memoria
para datos, temporizadores, fuentes de interrupción y otros recursos necesarios para el
desarrollo de aplicaciones, por lo general con un propósito específico.
Si bien, un MCU incluye prácticamente los elementos necesarios para ser considerado
como una computadora en un circuito integrado, frecuentemente no es tratado como tal,
ya que su uso típico consiste en el desempeño de funciones de “control” interactuando
con el “mundo real” para monitorear condiciones (a través de sensores) y en respuesta
a ello, encender o apagar dispositivos (por medio de actuadores).
17
computadora, una computadora es un Sistema de Propósito General, es decir, un
sistema de procesamiento intensivo capaz de realizar cualquier tarea que se le solicite
por programación.
• Las aplicaciones por lo general utilizan pocas entradas, algunas son directamente
de 1 bit y otras pueden ser agrupadas en un puerto de 8 bits, para su procesamiento
es suficiente con una CPU que trabaje por bytes. De manera poco frecuente estas
aplicaciones requieren datos de 16 bits, por ello, algunos microcontroladores
incluyen instrucciones que operan directamente sobre 16 bits, o bien, puede buscarse
un microcontrolador con una CPU de 16 bits. Para las salidas, es muy común que se
requiera la manipulación directa de 1 bit. El encendido o apagado de un motor, un
relevador, una lámpara, etc., no requiere más de 1 bit. Si fuera necesario algún tipo
de variación en la intensidad de la salida, puede utilizarse modulación por ancho de
pulso (PWM, pulse width modulation).
Puede observarse que un MCU efectivamente contiene los elementos suficientes para
ser considerado como una computadora en un CI. Aunque sería una computadora con
una capacidad de procesamiento limitada. No obstante, los recursos incluidos en un
MCU son suficientes para aplicaciones de propósito específico, que no demanden
un alto rendimiento y que no requieran manejar un conjunto masivo de datos.
Aplicaciones como procesamiento de imágenes o video, están fuera del alcance de un
microcontrolador.
18
1.4 FPGAs y Microcontroladores
Los FPGAs son dispositivos electrónicos programables que también pueden emplearse como
elementos de procesamiento en sistemas electrónicos. La sigla FPGA (Field Programmable
Gate Array) hace referencia a un Arreglo de Compuertas Programable en Campo. En la
figura 1.3 se muestra la organización general de un FPGA, en donde puede notarse una
disposición matricial de Bloques Lógicos Configurables (CLB, Configurable Logic Block)
rodeados por Bloques de Entrada/ Salida (IOB, Input/Output Block), además de los recursos
necesarios para la conexión de CLBs con IOBs o entre CLBs.
Un aspecto común entre FPGAs y MCUs es que ambos son dispositivos configurables,
con ambos se pueden construir sistemas flexibles, cuyo comportamiento se puede
alterar al reprogramar al dispositivo. Con todo, debe distinguirse el papel del programa
en cada caso, en un FPGA el programa determina cómo se van a conectar sus elementos
internos, es decir, el programa define al hardware y de esta manera determina el
comportamiento del sistema. En cambio, en un MCU el hardware es fijo y el programa
establece la operación de ese hardware.
19
La organización de los FPGAs hace que el proceso de desarrollo de un sistema sea más
complejo y tardado, con respecto al uso de microcontroladores. La ventaja de su uso es
que la tecnología actual empleada en su fabricación y el hecho de trabajar directamente
en hardware hacen que se alcance una velocidad de procesamiento muy alta (100 MHz
o más) en relación a la velocidad de un MCU promedio.
20
1.5.1 La Unidad Central de Procesamiento (CPU)
Este bloque administra todas las actividades en el sistema y ejecuta todas las
operaciones sobre los datos. Esto mediante la ejecución de las instrucciones
ubicadas en la memoria de código, con las cuales se determina el comportamiento
del sistema. Un programa se define como una serie de instrucciones, combinada
para realizar algún trabajo específico. El grado en el cual los trabajos son realizados
eficiente y correctamente depende muchas veces del software y no de qué tan
sofisticada es la CPU.
b) Decodificación de la misma.
c) Ejecución.
Trabajo que realiza a altas velocidades, por lo que el usuario observa el efecto de un
programa completo y no de instrucciones individuales.
c) Transferencias de datos.
21
Una instrucción es una cadena de 1’s y 0’s que la computadora reconoce e interpreta,
en esa cadena existen diferentes grupos de bits que se conocen como campos de
la instrucción. Una instrucción incluye un campo para el código de operación
(opcode), éste determina la operación a realizar, y típicamente uno o dos campos para
los operandos, que corresponden a los datos sobre los cuales se aplica la operación.
Las CPUs se clasifican como CISC o RISC, esto de acuerdo con su organización
interna. Con CISC se hace referencia a computadoras con un Repertorio de
Instrucciones Complejo (CISC, Complex Instruction Set Computers) y RISC es para
referir a computadoras con un Repertorio de Instrucciones Reducido (RISC, Reduced
Instruction Set Computers).
Una arquitectura RISC tiene pocas instrucciones y generalmente éstas son del mismo
tamaño; en la CISC hay demasiadas instrucciones con diferentes tamaños y formatos,
que pueden ocupar varios bytes, uno para el opcode y los demás para los operandos.
La tarea realizada por una instrucción CISC puede requerir de varias instrucciones
RISC. En contraste, el hardware de un procesador RISC es tan simple, que se puede
implementar en una fracción de la superficie ocupada en un circuito integrado por un
procesador CISC.
22
El Contador de Programa (PC, Program Counter), el Registro de Instrucción (IR,
Instruction Register) y el Apuntador de Pila (SP, Stack Pointer), son registros con una
función específica en una CPU.
Los registros de propósito general son los elementos más rápidos para el almacenamiento
de variables. Dado que el número de registros en una CPU es limitado, si éste no es
suficiente para todas las variables requeridas, debe utilizarse la memoria de datos para
su almacenamiento.
23
1.5.1.2 Tareas de la CPU
Con cada instrucción, la CPU realiza tres tareas fundamentales: Captura, Decodificación
y Ejecución.
La Captura de una Instrucción es una tarea que involucra los siguientes pasos:
b. La CPU genera una señal de control, para habilitar la lectura de memoria de código.
Una vez que la instrucción está en el IR, el procesador continúa con la decodificación
de la instrucción. Decodificar una instrucción consiste en descifrar el opcode para
generar las señales de control necesarias, dependiendo del tipo de instrucción.
Figura 1.6 Modelos de computadoras respecto a la organización de la memoria (a) Arquitectura von Neumann y (b)
Arquitectura Harvard
24
John von Neumann2 propuso el concepto de programa almacenado, el cual establece que
las instrucciones se lleven a memoria como si fueran datos, para que posteriormente se
ejecuten sin tener que escribirlas nuevamente, por lo tanto, se requiere de un solo espacio
de memoria para almacenar instrucciones y datos. Este concepto fue primeramente
aplicado en la Computadora Automática Electrónica de Variable Discreta (EDVAC,
Electronic Discrete-Variable Automatic Computer), desarrollada por Von Neumann,
Eckert y Mauchly. Actualmente ha sido adoptado por los diseñadores de computadoras
porque proporciona flexibilidad a los sistemas. Si una computadora se basa en este
concepto, se dice que tiene una Arquitectura tipo Von Neumann.
1.5.3 Oscilador
25
microcontroladores ya incluyen un oscilador RC calibrado interno. Tan pronto como se
suministra la alimentación eléctrica, el oscilador empieza con su operación.
1.5.4 Temporizador/Contador
Figura 1.7 Organización básica de un Temporizador/Contador, en (a) el registro ha alcanzado su valor máximo y en (b)
al reiniciar la cuenta se genera una señalización
26
En algunos microcontroladores la entrada del temporizador es precedida por un pre-
escalador, el cual básicamente es un divisor de frecuencia configurable, con el que se
puede contar un número más grande de eventos y por lo tanto, alcanzar intervalos de
tiempo mayores.
• Asíncrona: Sólo hay líneas para los datos, el transmisor y el receptor se deben
configurar con la misma velocidad de transferencia (bits/segundo, Baud Rate),
además de definir el mismo formato para cada trama.
27
microcontroladores o un microcontrolador con otros sistemas que incluyan un puerto de
comunicación serial. En la figura 1.8 se muestra la diferencia entre una comunicación
síncrona y asíncrona.
28
1.6 Clasificación de los Microcontroladores
Existen diferentes formas de clasificar a los microcontroladores y no son excluyentes
unas de otras. A continuación se describen las formas típicas de clasificaciones.
La última clasificación tiene que ver con la forma en que los datos son almacenados y
manipulados internamente dentro de la CPU. Los microcontroladores manipulan datos
por medio de un programa de usuario, en este esquema de clasificación se distingue a
las arquitecturas de acuerdo a como la CPU ejecuta las instrucciones y tiene acceso a
los datos que involucra cada instrucción. Bajo este esquema, se tienen los siguientes
cuatro modelos: Pila, Acumulador, Registro-Memoria y Registro-Registro.
En una arquitectura tipo Pila, una pila es la base para el procesamiento, los datos a
operar deben ingresarse en la pila, las operaciones se realizan sobre los últimos datos de
la pila y dejan el resultado en el tope de la pila. Por ejemplo, para realizar la operación
de alto nivel:
A=B–C
29
requieren un operando se aplican sobre el acumulador y en la ALU, necesariamente un
operando debe ser el acumulador.
Finalmente, en una arquitectura del tipo Registro-Registro, los dos operandos que
llegan a la ALU deben estar en los registros de propósito general. Las arquitecturas de
este estilo también son conocidas como Arquitecturas tipo Carga-Almacenamiento,
esto porque cuando se van a operar variables que están en memoria, primeramente
deben ser cargadas en registros, el resultado queda en un registro y, por lo tanto, se
requiere de un almacenamiento para llevarlo a una variable de memoria. Para el mismo
ejemplo se tendrían las instrucciones siguientes:
LOAD R1, B ; Carga la variable B en un registro
LOAD R2, C ; Carga la variable C en otro registro
SUB R1, R2 ; La ALU opera sobre registros
MOV A, R1 ; Almacena el resultado en la variable A
La primera consideración son las prestaciones del dispositivo, las cuales se deben
vincular con los requerimientos de procesamiento que debe realizar el sistema.
30
Considerando la capacidad de procesamiento, los dispositivos se pueden agrupar en 3
clases diferentes:
• Gama media: Dispositivos de 16 y 32 bits. Para tareas de control con cierto grado
de procesamiento (control en automóvil, teléfonos móviles, PDA, etc.). En este caso
puede utilizarse un microcontrolador o microprocesador, además de periféricos y
memoria externa.
El siguiente criterio bajo consideración es el costo, este aspecto es esencial una vez que
se ha comprobado que el dispositivo cumple con las prestaciones requeridas, es decir,
después de un análisis del rendimiento del hardware y software, considerando el uso
medio o el peor de los casos. El costo de un microcontrolador o microprocesador puede
variar de 2 a 1000 dólares.
Una vez que se domina un microcontrolador no es complejo manejar uno diferente, por
lo que este hecho puede deberse a la carencia de dispositivos o herramientas, o bien a
31
la ausencia de soporte técnico. Si no se tienen problemas de disponibilidad y soporte, la
emigración a dispositivos con un mayor número de recursos es lo más adecuado, dado
que con una sola compuerta externa que se ahorre en un sistema, puede representar
grandes beneficios económicos si se considera una producción masiva.
1.8 Ejercicios
32
8. Indique el objetivo de los registros de propósito específico comúnmente encontrados
en una CPU:
a. Program Counter (PC)
b. Instruction Register (IR)
c. Stack Pointer (SP)
9. Liste los grupos de instrucciones típicos que maneja una CPU.
10. En qué difiere una arquitectura Harvard de una arquitectura basada en el modelo de
Neumann.
11. Explique las diferencias entre una arquitectura RISC y una arquitectura CISC.
12. Indique los tipos de memoria utilizados por los microcontroladores para el
almacenamiento de instrucciones y para el almacenamiento de datos.
13. Explique la función de los siguientes recursos en un microcontrolador:
a. Oscilador Interno
b. Temporizador (timer)
c. Perro guardián (watchdog timer)
d. Puerto Serie
e. Entradas y salidas digitales
f. Entradas y salidas analógicas
14. Muestre cómo se realizaría la suma: A = B + C + D, en una arquitectura:
a. Tipo Pila
b. Tipo Acumulador
c. Tipo Memoria-Registro
d. Tipo Registro-Registro (Carga-Almacenamiento)
Suponiendo que A, B, C y D son variables ubicadas en memoria de datos.
15. En orden de consideración, explique tres criterios que tomaría en cuenta al
seleccionar un microcontrolador para una aplicación.
33
34
2. Organización de los Microntroladores AVR de ATMEL
35
En concreto, este libro se enfoca a los dispositivos ATMega8 y ATMega16, para
ambos, sus principales características técnicas son:
• Memoria de código: 8 Kbyte (ATMega8) o 16 Kbyte (ATMega16) de memoria flash.
• Memoria de datos: 1 Kbyte de SRAM y 512 bytes de EEPROM.
• Terminales para entrada/salida: 23 (ATMega8) o 32 (ATMega16).
• Frecuencia máxima de trabajo: 16 MHz.
• Voltaje de alimentación: de 2.7 a 5.5 Volts.
• Temporizadores: 2 de 8 bits y 1 de 16 bits.
• Canales PWM: 3 (ATMega8) o 4 (ATMega16).
• Fuentes de interrupción: 19 (ATMega8) o 21 (ATMega16).
• Interrupciones externas: 2 (ATMega8) o 3 (ATMega16).
• Canales de conversión Analógico/Digital: 8 de 10 bits.
• Reloj de tiempo real.
• Interfaz SPI Maestro/Esclavo.
• Transmisor/Receptor Universal Síncrono/Asíncrono (USART).
• Interfaz serial de dos hilos.
• Programación “In System”.
• Oscilador interno configurable.
• Watchdog timer.
36
El ATMega8 incluye 3 puertos, 2 de 8 bits y 1 de 7 bits; mientras que el ATMega16
contiene 4 puertos, todos de 8 bits. También se observa que todas las terminales incluyen
una doble o triple función, esto significa que además de utilizarse como entrada o salida
de propósito general, las terminales pueden emplearse con un propósito específico,
relacionado con alguno de los recursos del microcontrolador.
37
Para maximizar el rendimiento y paralelismo, el AVR usa una arquitectura Harvard
con memorias y buses separados para el programa y los datos. Esto se observa en la
figura 2.3, el programa se ubica en la memoria flash y los datos están en 3 espacios
diferentes: En el archivo de registros (32 registros de 8 bits), en la SRAM y en la
EEPROM.
El flujo del programa por naturaleza es secuencial, con incrementos automáticos del PC.
Este flujo secuencial puede ser modificado con instrucciones de saltos condicionales o
incondicionales y llamadas a rutinas, éstas son instrucciones que modifican directamente
al PC, permitiendo abarcar completamente el espacio de direcciones.
3 MIPS, métrica para medir el rendimiento de procesadores, significa Millones de Instrucciones por
Segundo.
38
Figura 2.4 Segmentación a dos etapas realizado por el núcleo AVR
Para las instrucciones aritméticas y lógicas es suficiente con un ciclo de reloj para su
ejecución (posterior a la captura), al comienzo del ciclo se capturan los operandos de
los registros de propósito general, la ALU trabaja sincronizada con el flanco de bajada
y prepara el resultado para que sea escrito en el siguiente flanco de subida, esto se
muestra en la figura 2.5.
39
7 0 Dirección
R0 0x00
R1 0x01
R2 0x02
...
R14 0x0E
R15 0x0F
R16 0x10
R17 0x11
...
R26 (XL) 0x1A
X {
R27 (XH) 0x1B
R28 (YL) 0x1C
Y {
R29 (YH) 0x1D
R30 (ZL) 0x1E
Z {
R31 (ZH) 0x1F
40
Figura 2.7 Memoria de Programa en (a) un ATMega8 y (b) un ATMega16
41
Vector Dirección Fuente Definición de la Interrupción
15 0x00E ADC Conversión completa en el ADC
16 0x00F EE_RDY Concluye una escritura en la EEPROM
17 0x010 ANA_COMP Comparador analógico
18 0x011 TWI Interfaz serial de dos hilos
19 0x012 SPM_RDY Almacenamiento en memoria de programa listo
42
Figura 2.8 Memoria de Datos (a) SRAM y (b) EEPROM
El núcleo AVR está optimizado para trabajar con los registros de propósito general
(sección 2.2.2), las instrucciones los refieren como R0 a R31, o bien como apuntadores
(X, Y o Z). No obstante, estos registros también pueden ser referidos como cualquier
localidad de SRAM de propósito general, utilizando instrucciones de carga (LD) o
almacenamiento (ST). Esto se muestra en la figura 2.9, en donde se observa que los
registros tienen una dirección en el espacio de los datos.
Los Registros I/O son necesarios para el manejo de los recursos internos de un
microcontrolador, se tiene un espacio de direcciones para ubicar hasta 64 registros, las
direcciones están en el rango de 0x00 a 0x3F. Aunque el número de registros realmente
implementados puede variar entre dispositivos, dependiendo de los recursos internos
incluidos.
43
Figura 2.9 Memoria SRAM de Datos
La arquitectura de los AVR incluye a las instrucciones IN y OUT con las que se tiene un
acceso rápido a los Registros I/O, con IN se transfiere la información de un Registro I/O
a un Registro de Propósito General y con OUT se realiza la operación complementaria,
en ambos casos la ejecución se realiza en 1 ciclo de reloj.
De acuerdo con la figura 2.9, los Registros I/O también pueden ser referidos como
cualquier localidad de SRAM de propósito general, utilizando instrucciones de carga
(LD) o almacenamiento (ST), con direcciones en el rango de 0x20 a 0x5F. Tratar a los
Registros de Propósito General o a los Registros I/O como SRAM de propósito general
no es conveniente, porque las instrucciones de acceso a memoria se ejecutan en 2 ciclos
de reloj.
44
En la tabla 2.3 se muestra una parte de los Registros I/O, el mapa completo se encuentra
en el apéndice A. El objetivo de cada registro se describe conforme se van revisando
los recursos a los que pertenece, los recursos internos son descritos en los capítulos 4,
5, 6 y 7.
Tabla 2.3 Parte del mapa de Registros I/O
Dirección Dirección
Nombre Función
(Espacio I/O) (SRAM)
0x3F 0x5F SREG Registro de Estado y Control
0x3E 0x5E SPH Apuntador de Pila (byte alto)
0x3D 0x5D SPL Apuntador de Pila (byte bajo)
Registro para comparación del Temporizador /
0x3C 0x5C OCR0
Contador 0 (no disponible en ATMega8)
0x3B 0x5B GICR Registro General para el Control de la Interrupciones
0x3A 0x5A GIFR Registro General de banderas de Interrupciones
Registro para enmascarar las interrupciones por los
0x39 0x59 TIMSK
Temporizadores/Contadores
Registro de bandera de interrupciones por los
0x38 0x58 TIFR
Temporizadores/Contadores
... ... ... ...
Los Registros I/O que están en el rango de 0x00 a 0x1F pueden ser manipulados por
sus bits individuales. Con las instrucciones SBI (Set Bit in I/O Register, ajusta un bit
en un Registro I/O) y CBI (Clear Bit in I/O Register, limpia un bit en un Registro I/O)
es posible cambiar el estado de un bit individual sin modificar al resto, y a través de las
instrucciones SBIS (Skip if Bit in I/O Register is Set, brinca si el bit del Registro I/O
está en alto) y SBIC (Skip if Bit in I/O Register Cleared, brinca si el bit del Registro
I/O está en bajo) es posible evaluar el estado de un bit para determinar la realización
de un brinco.
Registro de Estado
El Registro de Estado (SREG, State Register) es parte de los Registros I/O, por lo
que su acceso puede hacerse con instrucciones IN y OUT. Este registro es importante
debido a que refleja el estado de la CPU y no de algún recurso específico, por eso
existen instrucciones especiales para modificar o evaluar a cada uno de sus bits
individualmente. Se ubica en la dirección 0x3F (o 0x5F de SRAM), después de un
reinicio, todos sus bits tienen el valor de 0. Los bits del Registro de Estado son:
7 6 5 4 3 2 1 0
0x3F I T H S V N Z C SREG
Con un 1 lógico las interrupciones son habilitadas, sin embargo, cada interrupción
también tiene su habilitador individual. Debe habilitarse por software. Cuando
ocurre una interrupción, este bit es limpiado por hardware, para evitar que durante
su atención ocurran otras interrupciones.
45
• Bit 6 – T: Bit de Almacenamiento para copias
Se pone en alto si después de una operación aritmética, existe un bit de acarreo del
nibble bajo al nibble alto.
Resultado
Operación Operando A Operando B
(Indicación de sobreflujo)
A+B ≥0 ≥0 <0
A+B <0 <0 ≥0
A–B ≥0 <0 <0
A–B <0 ≥0 ≥0
46
Ocasionalmente los bits de acarreo y sobreflujo suelen confundirse, aunque señalizan
dos situaciones diferentes. En una operación aritmética, si los operandos son de 8
bits se espera que el resultado ocupe sólo 8 bits, si el resultado no alcanza en 8
bits se genera un bit de acarreo. El sobreflujo tiene que ver con representaciones en
complemento a 2 y un sobreflujo no implica que el resultado tenga que requerir de
un 9º bit.
7 6 5 4 3 2 1 0
0x3E SP15 SP14 SP13 SP12 SP11 SP10 SP9 SP8 SPH
0x3D SP7 SP6 SP5 SP4 SP3 SP2 SP1 SP0 SPL
La Pila tiene un crecimiento de las direcciones altas de SRAM hacia las direcciones
bajas. Su acceso puede realizarse en forma explícita, mediante las instrucciones PUSH
y POP. Con PUSH se inserta un dato y se disminuye al SP, y con POP se incrementa
al SP y luego se extrae un dato. O bien de manera implícita, durante las llamadas y
retornos de rutinas. En la llamada a una rutina, en la Pila se almacena la dirección de
la instrucción que sigue a la llamada y con un retorno, el tope de la pila remplaza al
PC, para continuar con el flujo anterior a la llamada.
47
Figura 2.10 Accesos a la memoria SRAM de propósito general
48
Una memoria de cualquier tipo requiere de 3 buses para su manejo: un bus de datos, un
bus de direcciones y un bus de control. En el caso de la EEPROM, puesto que es interna
al microcontrolador, los buses son manejados por medio de 3 Registros I/O. Para el
manejo de las direcciones se tiene al registro EEAR (EEPROM Address Register),
EEAR ocupa dos espacios en los Registros I/O para direccionar 512 bytes (9 bits de
dirección), estos registros son:
7 6 5 4 3 2 1 0
0x1F - - - - - - - EEAR8 EEARH
0x1E EEAR7 EEAR6 EEAR5 EEAR4 EEAR3 EEAR2 EEAR1 EEAR0 EEARL
Para el manejo de los datos se dispone del registro EEDR (EEPROM Data Register),
el cual se ubica en la dirección 0x1D, dentro del mapa de Registros I/O. Si un dato va
a ser escrito en la EEPROM, debe ser colocado en EEDR, antes de iniciar con un ciclo
de escritura. Para lecturas de la EEPROM, después de un ciclo de lectura, el dato queda
disponible en EEDR.
Las señales de control son manejadas con el registro EECR (EEPROM Control
Register), en este registro se hacen las habilitaciones requeridas para iniciar los
ciclos de lectura o escritura, únicamente los 4 bits menos significativos están
implementados, éstos son:
7 6 5 4 3 2 1 0
0x1C - - - - EERIE EEMWE EEWE EERE EECR
49
• Bit 1 – EEWE: Habilitador de Escritura en la EEPROM
Al poner en alto a este bit se inicia con un ciclo de escritura, siempre que el bit
EEMWE haya sido puesto en alto en los 4 ciclos de reloj anteriores. No es posible
iniciar con un ciclo de escritura si hay una escritura en proceso. Cuando concluye
la escritura, el bit EEWE es automáticamente puesto en bajo, este evento puede
ser detectado por sondeo o bien, si el bit EERIE está en alto, se genera una
interrupción.
Al poner en alto a este bit se inicia con un ciclo de lectura, para lo cual sólo se
requiere que no haya una escritura en proceso. La lectura es inmediata, el dato
leído puede manipularse con la siguiente instrucción.
Ejemplo 2.1: Muestre cómo se codificaría una rutina en lenguaje ensamblador para
realizar una escritura en EEPROM.
Para esta rutina se asume que el dato a escribir está en R16 y que la dirección a utilizar
se describe en R18:R17, el código es:
EEPROM_write:
SBIC EECR, EEWE ; Asegura que no hay escritura en proceso
RJMP EEPROM_write
RET
__________
Con la instrucción SBIC EECR, EEWE (brinca si el bit EEWE del registro EECR
está en bajo) se está sondeando al bit EEWE. El brinco no se realiza si hay una escritura
en proceso y se continúa con la siguiente instrucción, la cual reinicia la rutina, el ciclo
se va a mantener mientras no concluya la escritura previa.
Ejemplo 2.2: Realice una rutina en lenguaje ensamblador para hacer una lectura en
EEPROM.
La rutina lee de la dirección formada por R18:R17 y el dato leído es colocado en R16.
EEPROM_read:
SBIC EECR, EEWE; Asegura que no hay escritura en proceso RJMP
EEPROM_read
50
OUT EEARH, R18 ; Establece la dirección
OUT EEARL, R17
SBI EECR, EERE ; Inicia la lectura
Ejemplo 2.3: Desarrolle 2 funciones en Lenguaje C, una para realizar una escritura
en EEPROM y la otra para hacer una lectura.
En lenguaje C, las instrucciones deben realizar las mismas operaciones sobre los
registros. La función para la escritura recibe como parámetros el dato a escribir y la
dirección en donde va a ser escrito:
void EEPROM_write (unsigned char dato, unsigned int direccion)
{
while ( EECR & 1 << EEWE ) // Asegura que no hay escritura en proceso
;
EEAR = direccion; // Establece la dirección
EEDR = dato; // Coloca el dato a escribir
51
Los puertos son de propósito general, es decir, el usuario puede utilizarlos para
monitorear entradas o generar salidas como mejor le convenga, no obstante, todas
las terminales tienen una función alterna, esto es necesario porque muchos de los
recursos internos van a requerir información del exterior. Por ejemplo, el puerto serie
necesita una terminal externa para recepción y otra para transmisión, ésta es la función
alterna para PD0 y PD1, respectivamente. La función alterna de las terminales se
revisa conforme se van describiendo los recursos internos del microcontrolador, los
recursos internos se describen en los capítulos 4, 5, 6 y 7.
Para el manejo de cada puerto se requiere de 3 registros del espacio de Registros I/O,
éstos son:
• PINx: Registro sólo de lectura, para hacer lecturas directas en las terminales de los
puertos.
La x hace referencia a cada uno de los puertos, puede ser A, B, C o D. Para el ATMega8,
como tiene 3 puertos requiere de 9 Registros I/O, éstos son:
7 6 5 4 3 2 1 0
0x18 PORTB7 PORTB6 PORTB5 PORTB4 PORTB3 PORTB2 PORTB1 PORTB0 PORTB
0x17 DDRB7 DDRB6 DDRB5 DDRB4 DDRB3 DDRB2 DDRB1 DDRB0 DDRB
0x16 PINB7 PINB6 PINB5 PINB4 PINB3 PINB2 PINB1 PINB0 PINB
0x15 - PORTC6 PORTC5 PORTC4 PORTC3 PORTC2 PORTC1 PORTC0 PORTC
0x14 - DDRC6 DDRC5 DDRC4 DDRC3 DDRC2 DDRC1 DDRC0 DDRC
0x13 - PINC6 PINC5 PINC4 PINC3 PINC2 PINC1 PINC0 PINC
0x12 PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0 PORTD
0x11 DDRD7 DDRD6 DDRD5 DDRD4 DDRD3 DDRD2 DDRD1 DDRD0 DDRD
0x10 PIND7 PIND6 PIND5 PIND4 PIND3 PIND2 PIND1 PIND0 PIND
52
El ATMega16 también tiene al puerto A, el cual requiere de los siguientes 3 registros:
7 6 5 4 3 2 1 0
0x1B PORTA7 PORTA6 PORTA5 PORTA4 PORTA3 PORTA2 PORTA1 PORTA0 PORTA
0x1A DDRA7 DDRA6 DDRA5 DDRA4 DDRA3 DDRA2 DDRA1 DDRA0 DDRA
0x19 PINA7 PINA6 PINA5 PINA4 PINA3 PINA2 PINA1 PINA0 PINA
53
En la figura 2.12 se observa que para cada terminal se tienen 3 rutas:
• Una ruta de salida que es manejada por el flip-flop tipo D denominado PORTxn,
el cual puede ser leído o escrito. Este flip-flop se conecta a la terminal de salida por
medio de un buffer de 3 estados. Una lectura en PORTxn no devuelve el valor de
la terminal, sino lo último que fue escrito en el flip-flop.
• Una ruta de entrada que es manejada por el flip-flop tipo D denominado PINxn, en
el cual continuamente se va a escribir el contenido de la terminal del puerto. Este
flip-flop va precedido por otro similar, ambos manejados por la señal del reloj de
entrada y salida. Esta conexión en cascada garantiza una señal estable al realizar
las lecturas del puerto, con el inconveniente de que un cambio en la terminal se
ve reflejado hasta el ciclo de reloj siguiente. También se observa un circuito para
desconectar al puerto ante algún modo de reposo (SLEEP) del microcontrolador,
así como un buffer con histéresis, para eliminar ruido. Si la terminal fue configurada
como salida (buffer de 3 estados habilitado), con una lectura en PINxn se obtiene
el dato escrito en PORTxn.
• Una ruta para el buffer de tres estados que es manejada por el flip-flop tipo D
denominado DDRxn, el cual puede ser leído o escrito. Este flip-flop se conecta con
el buffer de tres estados para determinar si el puerto va a estar configurado como
entrada (se escribe un 0 lógico para desactivar al buffer) o como salida (se escribe
un 1 lógico para activar al buffer).
También se observa una resistencia de fijación hacia un nivel alto de voltaje (pull-up),
su habilitación depende de valor del flip-flop PORTxn, del flip-flop DDRxn y del bit
PUD (PUD: Pull-Up Disable). El bit PUD se encuentra en el Registro I/O denominado
SFIOR (SFIOR: Special Function I/O Register, Registro I/O de función especial). Con
estos 3 bits se generan las combinaciones que se resumen en la tabla 2.5.
Tabla 2.5 Estado del Puerto ante las diferentes combinaciones entre DDRxn, PORTxn y PUD
PUD
DDRxn PORTxn E/S Pull-Up Comentario
(en SFIOR)
0 0 X Entrada No Entrada sin resistor de Pull-Up
0 1 0 Entrada Si Entrada con resistor de Pull-Up
0 1 1 Entrada No Entrada sin resistor de Pull-Up
1 0 X Salida No Salida en bajo
1 1 X Salida No Salida en alto
54
La versión en lenguaje ensamblador:
LDI R16, 0B00001111 ; Configuración de entradas y salidas
OUT DDRB, R16
Ejemplo 2.5: Muestre la secuencia de código que configure al puerto A como entrada
y al puerto B como salida, para luego transferir la información del puerto A al puerto B.
Cabe aclarar que después de un reinicio los registros de los puertos tienen el valor de
0x00, por lo que por omisión, un puerto es configurado como entrada.
55
El núcleo AVR cuenta con la unidad de interrupciones, un módulo que va a determinar
si se tienen las condiciones para que ocurra una interrupción. Son tres las condiciones
necesarias para que un recurso produzca una interrupción: El habilitador global de
interrupciones (bit I de SREG) debe estar activado, el habilitador individual de la
interrupción del recurso también debe estar activado y en el recurso debe ocurrir el evento
esperado.
La ISR debe colocarse en una dirección preestablecida por Hardware, la cual corresponde
con un vector de interrupciones.
Un aspecto importante es que los eventos pueden ocurrir en cualquier momento, es decir,
en forma asíncrona. Esto hace la diferencia entre una rutina normal y una ISR, dado
que en el primer caso se puede calcular con certeza cuándo se va a realizar una llamada,
podría decirse que el flujo de un programa sin interrupciones es conocido con antelación.
Por el contrario, en un programa con interrupciones el flujo puede cambiar en cualquier
momento, es como si el programa trabajara en dos niveles, el nivel del programa base y el
nivel de atención a las interrupciones, por lo tanto, como parte de las ISRs debe incluirse
el código necesario para proteger a las variables o registros cuyo contenido sea vital, al
nivel del programa base. En la figura 2.13 se ilustra la idea.
Figura 2.13 Representación de la ejecución de (a) un programa sin interrupciones y (b) un programa con interrupciones
56
En los microcontroladores AVR se tienen diferentes fuentes de Interrupción:
• Siete interrupciones por los temporizadores (ocho en el ATMega16), pueden ser por
comparación, captura o desbordamiento.
• Tres debidas el puerto serie (USART): por transmisión, por recepción y por buffer
vacío.
57
Ejemplo 2.6: Muestre como se organizaría un programa en lenguaje ensamblador
para utilizar interrupciones en un ATMega8.
.ORG 0x000
RJMP Principal ; Se evita el vector de interrupciones
.ORG 0x001
RJMP Externa_0 ; Bifurca a su ISR externa 0
.ORG 0x002
RJMP Externa_1 ; Bifurca a su ISR externa 1
.ORG 0x013
Principal: ; Aquí se debe ubicar el código principal
. . . ; Debe activar las interrupciones
. . .
; Posterior al código principal, deben situarse las ISRs
58
En lenguaje C todas las funciones de atención a interrupciones se llaman ISR, difieren
en que reciben argumentos diferentes, el argumento corresponde con una etiqueta
proporcionada por el fabricante, seguida de la palabra vect. Las etiquetas se encuentran
en la columna titulada como fuente en las tablas 2.1 y 2.2.
59
Cuando ocurre una interrupción, el microcontrolador automáticamente realiza lo
siguiente:
• El PC toma el valor del tope de la pila, para que la ejecución continúe en el programa
principal.
• Reset Externo: El MCU es inicializado cuando un nivel bajo está presente en la terminal
RESET por un tiempo mayor a 1.5 uS, que es la longitud mínima requerida (tRST).
4 JTAG es un acrónimo para Joint Test Action Group y es el nombre común de la norma IEEE 1149.1,
originalmente para la evaluación de circuitos impresos. Actualmente JTAG hace referencia a una interfaz
serial utilizada para la prueba de circuitos integrados y como medio para depurar sistemas empotrados.
60
• Reset por Watchdog: El MCU es inicializado cuando se ha habilitado al Watchdog
Timer y éste se ha desbordado.
• Reset por JTAG: El MCU es inicializado tan pronto como exista un 1 lógico en el
Registro de Reset del Sistema JTAG.
Referente a la figura 2.14, los bits BODEN, BODLEVEL, CKSEL y SUT son fusibles
que forman parte de los Bits de Configuración y Seguridad, su valor se define en el
momento en que se programa al dispositivo y no pueden ser modificados en tiempo de
ejecución.
61
Puesto que hay diferentes causas de reinicio, los AVR incluyen al Registro de Estado
y Control del MCU (MCUCSR, MCU Control and Status Register) en el cual queda
indicada la causa de reset por medio de una bandera. Los bits del registro MCUCSR
son:
7 6 5 4 3 2 1 0
0x34 JTD ISC2 - JTRF WDRF BORF EXTRF PORF MCUCSR
62
El Reset Interno es generado mientras transcurre el tiempo de establecimiento (tOUT),
cuya duración depende de la frecuencia de trabajo y del valor de los fusibles CKSEL
y SUT. Los MCUs ATMega8 y ATMega16 son comercializados con un tiempo de
establecimiento ajustado a 65 mS.
En la figura 2.16 se muestra la generación del Reset Interno como una respuesta a la
terminal RESET, en la cual debe conectarse un botón a tierra para su activación. En (a)
el RESET externo está activo al alimentar al dispositivo, por lo que la señal de Reset
Interno inicia en alto, el tiempo de establecimiento inicia desde el momento en que la
terminal RESET alcanza el umbral de encendido (VRST, valor máximo de 0.9 V) y al
finalizar el tiempo de establecimiento la señal de Reset Interno se va a un nivel bajo. En
la figura 2.16 (b) se muestra como en cualquier momento puede activarse la terminal
externa de RESET, generando nuevamente la señal de Reset Interno.
Figura 2.16 Reset externo (a) en el encendido y (b) en cualquier otro instante
63
Cuando el Watchdog Timer se desborda, genera un pulso en alto por un ciclo de reloj
que es suficiente para provocar una inicialización del MCU, esto se muestra en la figura
2.18, donde sólo se incluyen las señales involucradas. El tiempo de establecimiento
inicia inmediatamente después del desbordamiento.
La selección de la fuente de reloj se realiza por medio de los fusibles CKSEL que
son parte de los Bits de Configuración y Seguridad, otros fusibles involucrados son
CKOPT y SUT. El fusible CKOPT proporciona más alternativas al utilizar un cristal
o resonador externo o habilita la conexión de capacitores internos si se selecciona un
reloj externo o un cristal de baja frecuencia; mientras que con los fusibles SUT es
posible modificar el tiempo de establecimiento después de un reinicio.
64
En la tabla 2.6 se indica cuál es la fuente de reloj en función del valor de los fusibles
CKSEL, en algunos casos se tiene más de una combinación, porque se tienen diferentes
alternativas.
Tabla 2.6 Selección de Reloj a partir de los fusibles CKSEL
• clkADC: Reloj dedicado al ADC, el ADC trabaja a una frecuencia menor que
la CPU con el objetivo de reducir el ruido generado por interferencia digital
y mejorar las conversiones.
• clkASY: Es una señal de reloj asíncrona, con respecto al resto del sistema,
es empleada para sincronizar al temporizador 2, el módulo que genera esta
señal está optimizado para ser manejado con un cristal externo de 32.768
KHz. Frecuencia que permite al temporizador funcionar como un contador
de tiempo real, aun cuando el dispositivo está en reposo.
65
En los siguientes apartados se describen las fuentes de reloj y cómo seleccionarlas.
La figura 2.20 muestra como se debe hacer la conexión del cristal o resonador cerámico
junto con sus capacitores.
Con esta opción de reloj, se tienen los tiempos de establecimiento después de algún
modo de bajo consumo y los retardos después de un reinicio, mostrados en la tabla 2.8,
en donde ck significa: ciclos de reloj.
Con esta opción para el reloj, el hardware está acondicionado para ser manejado con un
cristal de 32.768 KHz, esta frecuencia proporciona la base para un contador de tiempo
real. Todo el sistema trabajaría a esta frecuencia, por lo que sólo es conveniente si la
aplicación requiere ejecutar instrucciones en periodos que son fracciones de segundos.
66
Tabla 2.8 Tiempos de establecimiento y retardos al emplear un resonador cerámico o cristal externo
Con esta opción para el reloj, los tiempos de establecimiento después de algún modo
de bajo consumo y los retardos después de un reinicio son mostrados en la tabla 2.9.
Tabla 2.9 Tiempos de establecimiento y retardos con un cristal de baja frecuencia externo
Esta es una alternativa de bajo costo si se requiere de una frecuencia diferente a las
que maneja el oscilador interno y si esta frecuencia no es un factor determinante en
el funcionamiento de un sistema, dado que el valor de R y C puede variar por sus
tolerancias intrínsecas y en función de la temperatura. El circuito RC se conecta como
se muestra en la figura 2.21, la frecuencia se determina como f = 1/(3RC) y el valor de
C debe ser por lo menos de 22 pF.
67
Con este tipo de oscilador, se tienen 4 combinaciones de CKSEL, debe seleccionarse la
que mejor se adapte a la frecuencia de trabajo. En la tabla 2.10 se muestra el rango de
frecuencias para cada una de las combinaciones.
Tabla 2.10 Opciones para el empleo de un oscilador RC externo
Para esta fuente de reloj, los tiempos de establecimiento después de algún modo de bajo
consumo y los retardos después de un reinicio se muestran en la tabla 2.11.
Tabla 2.11 Tiempos de establecimiento y retardos con un oscilador RC externo
Con esta fuente de reloj, después de algún modo de bajo consumo se tiene un tiempo
de establecimiento de 6 ciclos de reloj y después de un reinicio se tienen los retardos
mostrados en la tabla 2.13.
Los dispositivos se comercializan con CKSEL = “0001” y SUT = “10”, por lo que
inicialmente trabajan a una frecuencia de 1 MHz y con un retardo de 65 mS.
68
Tabla 2.13 Retardos con un oscilador RC calibrado interno y con un reloj externo
7 6 5 4 3 2 1 0
0x31 CAL7 CAL6 CAL5 CAL4 CAL3 CAL2 CAL1 CAL0 OSCCAL
69
Figura 2.22 Reloj Externo
70
Tabla 2.14 Dominios de reloj activos en los diferentes modos de reposo y eventos que lo “despiertan”
EEPROM, Memoria de
INT0, INT1, INT2
Temporizador 2
programa lista
Reloj Principal
Modo de Bajo Consumo de
Otros I/O
clkFLASH
Energía
clkADC
clkCPU
clkASY
ADC
Modo ocioso (idle) clkIO
X X X X X X X X X X X
Reducción de ruido en el ADC X X X X X X X X X
Baja potencia X X
Ahorro de potencia X X X X X
Modo de espera (standby) X X X
Modo de espera extendido X X X X X X
• Modo ocioso: En este modo todos los recursos del MCU trabajan, pero la CPU
no ejecuta instrucciones porque no tienen señal de reloj. El suministro del reloj
principal y del oscilador del temporizador están activos. El hecho de mantener
los recursos activos hace que, prácticamente cualquier evento de los diferentes
recursos provoque una salida del modo de reposo.
• Modo de baja potencia: En este modo no hay reloj en los módulos de recursos
y tampoco están activas las fuentes de oscilación, por lo tanto, es el modo con
el menor consumo de energía. El MCU puede ser reactivado por eventos en la
interfaz de dos hilos o por las interrupciones externas. Una posible aplicación para
este modo es un control remoto, porque casi siempre está inactivo, sólo cuando
se presiona una tecla del control remoto el MCU se despierta, emite el código
seleccionado y regresa al modo de reposo.
• Modo de ahorro de potencia: En este modo sólo se tiene al reloj asíncrono, con
su correspondiente oscilador. Por lo que prácticamente sólo se mantiene activo el
temporizador 2, sincronizado con una fuente de reloj externa. Esto hace al modo
ideal para aplicaciones que involucren un reloj de tiempo real. La salida del modo
es posible con eventos en la interfaz de dos hilos, interrupciones externas o del
temporizador 2.
71
• Modo de espera: Este modo es muy similar al modo de baja potencia, la única
diferencia es que en este modo se mantiene el suministro del reloj principal. Con
ello, el dispositivo despierta en 6 ciclos de reloj.
Para seleccionar uno de los modos debe configurarse al registro de Control del MCU
(MCUCR, MCU Control Register), los bits de este registro son:
7 6 5 4 3 2 1 0
0x35 SE SM2 SM1 SM0 ISC11 ISC10 ISC01 ISC00 MCUCR
Este bit se pone en alto después de ingresar a cualquiera de los modos de reposo,
lo cual se consigue con la ejecución de la instrucción SLEEP, pero antes, debe
seleccionarse el modo de reposo deseado.
Los modos de espera sólo pueden ser empleados con resonadores cerámicos
o cristales externos. La combinación “111” de la tabla 2.15 está sin uso en un
ATMega8, porque no cuenta con el modo de espera extendido. En un ATMega16,
la posición de los bits SE y SM2 está intercambiada, SM2 es el bit 7 y SE está en
la posición 6.
72
2.10 Ejercicios
ATMega8 ATMega16
Cantidad de Memoria de Código:
Cantidad de RAM (de propósito general):
Cantidad de EEPROM:
Registros de Propósito General:
Registros I/O:
2. Explique las ventajas de que el núcleo, en los AVR, trabaje en una segmentación de
2 etapas.
3. ¿Por qué se dice que los AVR están optimizados para trabajar con código C compilado?
5. Explique para qué se emplean los Registros I/O en los microcontroladores AVR.
6. Indique qué Registros I/O se emplean para el acceso a la EEPROM y el objetivo de
cada uno de ellos.
7. Muestre la organización de una terminal en un puerto y explique la funcionalidad
de cada uno de los registros que se requieren para su manejo.
8. Defina qué es una interrupción y explique por qué es conveniente el uso de
interrupciones.
9. Los microcontroladores AVR pueden ser operados por una gama muy amplia de
osciladores ¿Por qué es conveniente incorporar esta flexibilidad y no únicamente
manejarlos con un solo tipo de oscilador?
10. Describa tres fuentes de inicialización (o reset).
11. Explique el objetivo de los modos de bajo consumo de energía e indique cómo
ingresar y salir de cualquiera de estos modos de operación.
73
74
3. Programación de los Microcontroladores
Este grupo incluye instrucciones para las operaciones básicas de suma y resta, con
diferentes variantes, las cuales se muestran en la tabla 3.1.
Tabla 3.1 Instrucciones para las operaciones básicas de suma y resta
Instrucción Descripción Operación Banderas
ADD Rd, Rs Suma sin acarreo Rd = Rd + Rs Z,C,N,V,H,S
ADC Rd, Rs Suma con acarreo Rd = Rd + Rs + C Z,C,N,V,H,S
ADIW Rd, k Suma constante a palabra [Rd + 1:Rd] = [Rd + 1:Rd] + k Z,C,N,V,S
SUB Rd, Rs Resta sin acarreo Rd = Rd - Rs Z,C,N,V,H,S
SUBI Rd, k Resta constante Rd = Rd – k Z,C,N,V,H,S
SBC Rd, Rs Resta con acarreo Rd = Rd – Rs – C Z,C,N,V,H,S
SBCI Rd, k Resta constante con acarreo Rd = Rd – k – C Z,C,N,V,H,S
SBIW Rd, k Resta constante a palabra [Rd + 1:Rd] = [Rd + 1:Rd] - k Z,C,N,V,S
Todas las instrucciones de suma y resta modifican las banderas de cero (Z), acarreo
(C), negado(N), sobreflujo (V) y signo (S). Exceptuando a las instrucciones que operan
75
sobre palabras, el resto también modifica la bandera de acarreo del nibble menos
significativo (H). Las instrucciones que operan sobre datos de 8 bits se ejecutan en 1
ciclo de reloj, las otras en 2 ciclos de reloj.
Las sumas y restas de 8 bits son entre registros, con o sin acarreo. No hay una suma
de 8 bits con una constante, pero si se requiere, puede hacerse una resta con el negado
de la constante que se desea sumar, si hay una resta con una constante de 8 bits, por
ejemplo, para sumar 10 a R17 puede emplearse la instrucción SUBI R17, -10. Por
el formato de las instrucciones, el cual se revisa en la siguiente sección, con los modos
de direccionamiento, las instrucciones que involucran constantes sólo son aplicables a
los registros R16 a R31.
Para la suma y resta de 16 bits, el segundo operando es una constante entre 0 y 63.
La palabra de 16 bits se forma por 2 registros consecutivos entre R24 y R31, en la
instrucción puede especificarse al registro menos significativo del par (ADIW R26,
k), a ambos registros (ADIW R27:R26, k) o si es aplicable, el nombre de un registro
de 16 bits (ADIW X, k).
El grupo también cuenta con instrucciones aritméticas más complejas, como
multiplicaciones entre enteros y fracciones, éstas se listan en la tabla 3.2, todas se
ejecutan en 2 ciclos de reloj.
Tabla 3.2 Instrucciones para las operaciones de multiplicación
Puesto que los operandos son de 8 bits, el resultado a lo más es de 16 bits. Todas las
instrucciones dejan el resultado en R1 y R0 (en R1 la parte alta). Para las instrucciones
con enteros, los operandos pueden ser interpretados como números sin signo o con
signo. En la tabla 3.3 se muestran ejemplos que ilustran la diferencia entre instrucciones.
Tabla 3.3 Ejemplos de multiplicaciones con enteros
Valores en Decimal
R16 R17 Instrucción R1:R0
R16 R17 R1:R0
0000 0010 1111 1111 MUL R16, R17 0000 0001 1111 1110 2 255 510
0000 0010 1111 1111 MULS R16, R17 1111 1111 1111 1110 2 -1 -2
0000 0010 1111 1111 MULSU R16, R17 0000 0001 1111 1110 2 255 510
1111 1111 1111 1111 1111 1110 0000 0001 255 255 65,
MUL R16, R17
025
1111 1111 1111 1111 MULS R16, R17 0000 0000 0000 0001 -1 -1 1
1111 1111 1111 1111 MULSU R16, R17 1111 1111 0000 0001 -1 255 -255
76
En la tabla 3.3 se observa como las instrucciones interpretan a los operandos de
diferentes maneras. El resultado debe ser interpretado de acuerdo con el tipo de
instrucción. Para la instrucción MULSU el primer operando corresponde con un número
con signo, el segundo como un número sin signo y para que el resultado sea correcto,
debe interpretarse como un número con signo.
Por lo tanto, el número 1110 00002 también puede corresponder con - 0.25, dependiendo
de la instrucción que se utilice.
En la tabla 3.4 se tienen algunos ejemplos del uso de las instrucciones de multiplicación
fraccional, considerando números sin signo y con signo, con sus interpretaciones en
decimal.
Tabla 3.4 Ejemplos de multiplicaciones con fracciones en punto fijo
Valores en Decimal
R16 R17 Instrucción R1:R0
R16 R17 R1:R0
0100 0000 1100 0000 FMUL R16, R17 0110 0000 0000 0000 0.5 1.5 0.75
0100 0000 1100 0000 FMULS R16, R17 1110 0000 0000 0000 0.5 -0.5 -0.25
0100 0000 1100 0000 FMULSU R16, R17 0110 0000 0000 0000 0.5 1.5 0.75
1100 0000 1100 0000 FMUL R16, R17 0010 0000 0000 00001 1.5 1.5 2.251
1100 0000 1100 0000 FMULS R16, R17 0010 0000 0000 0000 -0.5 -0.5 0.25
1100 0000 1100 0000 FMULSU R16, R17 1010 0000 0000 0000 -0.5 1.5 -0.75
En este grupo también se cuenta con las instrucciones lógicas binarias que se muestran
en la tabla 3.5 (requieren 2 operandos). Estas instrucciones se aplican bit a bit, se
ejecutan en 1 solo ciclo de reloj y modifican a las banderas Z, N, V y S.
77
La EOR (OR exclusiva) sólo puede aplicarse entre registros, las operaciones AND y OR
además pueden aplicarse entre un registro con una constante.
Las operaciones lógicas por lo general se utilizan para enmascarar la información, una
máscara consiste en modificar algunos bits de un byte, poniéndolos en alto o en bajo, sin
modificar al resto. Las máscaras usualmente se realizan con operaciones AND y OR, pero
por su extenso uso, el grupo incluye dos instrucciones dedicadas, las cuales se muestran
en la tabla 3.6, en donde una constante especifica los bits a modificar en un registro. Estas
instrucciones se ejecutan en 1 ciclo de reloj y modifican a las banderas Z, C, N, V y S;
aunque por su enfoque, el valor de las banderas generalmente es ignorado.
Tabla 3.6 Instrucciones para enmascarar información
CBR Rd, k Pone en bajo los bits indicados en la constante Rd = Rd AND (0xFF – k)
78
3.1.2 Instrucciones para el Control de Flujo
79
La instrucción RETI es el retorno de una ISR (en la sección 2.6 se describió el
funcionamiento de las interrupciones), por lo tanto, con esta instrucción también se
pone en alto al bit I del registro de estado (SREG), para habilitar nuevamente al sistema
de interrupciones.
Las instrucciones de la tabla 3.10 realizan la comparación con base en una resta, pero sin
almacenar el resultado. Todas se ejecutan en 1 ciclo de reloj. En los programas es frecuente
encontrar una instrucción de comparación seguida de un salto condicional (tabla 3.11).
Tabla 3.11 Instrucciones de brincos condicionales
80
Los brincos condicionales pueden tardar 1 ó 2 ciclos de reloj en su ejecución, 1 ciclo
si el brinco no se realizó, porque la siguiente instrucción ya está en la etapa de captura
y 2 ciclos cuando el brinco se realiza, porque se debe anular a la instrucción que está
en la etapa de captura y continuar con la siguiente después del brinco. Estos brincos
son relativos al PC, es decir, la constante de la instrucción que se suma al PC + 1
puede ser positiva o negativa, para bifurcar hacia adelante o atrás de la instrucción
del brinco.
En la tabla 3.11 hay 20 instrucciones y todas evalúan los bits del registro de Estado
(SREG), sin embargo, sólo en las 2 primeras se especifica el número del bit a
evaluar (bit s, entre 0 y 7), ya que en las siguientes 18 el número del bit queda
implícito en la instrucción, podría decirse que son versiones particularizadas de
las primeras 2 instrucciones. El nombre y descripción de cada instrucción está
relacionado con la aplicación que se le puede dar a cada bandera, por eso se tienen
2 versiones para la bandera de acarreo. Estas 18 instrucciones se ordenaron de
acuerdo con la disposición de los bits en el registro Estado (del bit más significativo
al menos significativo).
Las últimas 2 instrucciones son frecuentemente utilizadas para monitorear los puertos
o para evaluar el estado de otros recursos, dado que todos los recursos son manejados
a través de los Registros I/O (sección 2.4.1.1).
81
3.1.3 Instrucciones de Transferencia de Datos
Las transferencias de datos no modifican las banderas del registro Estado. Para
transferencias entre registros sólo se tienen las 2 instrucciones mostradas en la tabla
3.13, una para mover un byte y la otra para mover una palabra de 16 bits. En las
transferencias de palabras, para cada operando, se debe especificar un registro con
número par, haciendo referencia a éste, como byte menos significativo, y al siguiente.
Ambas instrucciones se ejecutan en 1 ciclo de reloj.
Tabla 3.13 Transferencias entre registros
Para transferencias entre la memoria de datos y los registros se tiene una gama amplia
de instrucciones, a la transferencia de memoria a registro se le conoce como una carga
y a la transferencia de registro a memoria se le conoce como un almacenamiento.
82
En la figura 2.10 se ilustraron estas transferencias. En la tabla 3.15 se muestran
las instrucciones para cargas y almacenamientos, en ambos casos se tiene sólo 1
instrucción que utiliza direccionamiento directo, es decir, en la instrucción se
especifica la dirección de la localidad a la que se tiene acceso, y 11 instrucciones con
direccionamiento indirecto, empleando a uno de los registros de 16 bits (X, Y o Z)
como apuntador, en la instrucción se especifica al apuntador.
83
En el grupo hay otras dos instrucciones que también hacen transferencias entre registros
y SRAM, éstas no se incluyeron en la tabla 3.15 porque están enfocadas a trabajar en
el espacio destinado para la Pila, para insertar o extraer un dato en el tope de la pila,
el cual está referido por el registro SP, que es el apuntador de pila. En la tabla 3.16 se
muestran las instrucciones de acceso a la Pila, las cuales también se ejecutan en 2 ciclos
de reloj.
Los almacenamientos son poco usados en aplicaciones ordinarias, porque significa cambiar
datos que en principio fueron considerados constantes, como los parámetros de un sistema
de control, el contenido de un mensaje para un LCD, etc. Sólo se tiene 1 instrucción para
almacenar datos en la memoria de código (SPM), no obstante, debe considerarse que
una memoria Flash se modifica por páginas y cuenta con mecanismos de seguridad para
proteger su contenido. El uso de la instrucción SPM se describe en la sección 7.2.3.
Por último, para las transferencias entre Registros I/O y registros de propósito general se
tienen las instrucciones mostradas en la tabla 3.18, en donde la variable P hace referencia a
cualquiera de los 64 Registros I/O, sin importar a qué recurso pertenecen. Estas instrucciones
se ejecutan en 1 ciclo de reloj y no modifican las banderas del registro de Estado.
Tabla 3.18 Transferencias entre Registros I/O y registros de propósito general
84
3.1.4 Instrucciones para el Manejo de Bits
Figura 3.2 (a) Desplazamiento lógico a la izquierda, (b) a la derecha, (c) desplazamiento aritmético a la derecha, (d)
rotación a la izquierda y (e) rotación a la derecha
Otra instrucción que es parte de este grupo es para intercambiar el nibble alto con el
nibble bajo en un registro, ésta se muestra en la tabla 3.20. Se ejecuta en 1 ciclo de reloj
y no modifica banderas.
85
Tabla 3.20 Instrucción para el intercambio de nibbles
El grupo incluye 2 instrucciones para transferencias de bits, una para cargar (load) del
bit T a un bit de un registro de propósito general y otra para almacenar (store) un bit
de un registro de propósito general en el bit T. El bit T está en el registro SREG y es
empleado para respaldar el valor de un bit de un registro de propósito general. Estas
instrucciones se muestran en la tabla 3.22, se ejecutan en 1 ciclo de reloj y es evidente
que la instrucción de almacenamiento modifica al bit T.
Tabla 3.22 Instrucciones para transferencias de bits
Tabla 3.23 Instrucciones para manipular los bits del registro Estado
86
Instrucción Descripción Operación
Este grupo está integrado por 3 instrucciones para el ATMega8 y 4 para el ATMega16,
son instrucciones que, por sus características, no pueden integrarse en los otros grupos.
Estas instrucciones no modifican algún operando, su objetivo es auxiliar para la
adecuada ejecución de un programa.
Instrucción Descripción
87
3.2 Modos de Direccionamiento
6. Inmediato
7. Direccionamientos en bifurcaciones
En la instrucción se especifica el registro o registros que funcionan como operandos, ya que puede
ser sólo uno o dos registros, este modo se ilustra en la figura 3.3, en donde se observa que se dispone
de 5 bits para definir cada registro, por ello, bajo este modo de direccionamiento se puede utilizar a
cualquiera de los 32 registros. Ejemplos de instrucciones que emplean sólo un registro son:
COM R1
INC R2
SER R3
Ejemplos de instrucciones en donde se emplean dos registros son:
ADD R0, R1
SUB R2, R3
AND R4, R5
MOV R6, R7
88
Figura 3.3 Direccionamiento directo empleando (a) un registro y (b) dos registros
Con este modo de direccionamiento se tiene acceso a los Registros I/O, que son la base
para el manejo de los recursos en un MCU. En la figura 3.4 se ilustra el modo, se tienen
5 bits para el registro de propósito general (R), por lo que se puede utilizar cualquiera de
ellos, y 6 bits para especificar al Registro I/O (P), también puede referirse a cualquiera
de los 64 Registros I/O. Ejemplos de instrucciones con este modo de direccionamiento
son:
OUT PORTB, R13
IN R15, PINA
89
3.2.3 Direccionamiento Directo a Memoria de Datos
STS 0x0100, R5
LDS R16, 0x0110
90
Existen dos variantes de este modo de direccionamiento en donde además se modifica
al apuntador. La primera variante es con un post-incremento, donde primero obtiene
el dato de memoria y después se incrementa al apuntador, y la segunda con un pre-
decremento, en donde primero se disminuye al apuntador y luego se realiza el acceso
a memoria. Esto también es aplicable a los 3 registros, X, Y o Z, estas ideas se
muestran en la figura 3.7 y 3.8, respectivamente. Ejemplos de instrucciones con post-
incrementos y pre-decrementos son:
91
Otra opción es el direccionamiento indirecto con desplazamiento, en este modo se tiene
acceso a una dirección formada por la suma entre el apuntador y una constante, pero sin
modificar al apuntador. Para la constante se dispone de 6 bits, por lo que debe estar en
el rango de 0 a 63. Sólo es posible con los apuntadores Y o Z, esta idea se muestra en
la figura 3.9. Ejemplos de instrucciones que usan este modo de direccionamiento son:
LDD R5, Y+0x020
STD Z+0x10, R11
92
También existe una carga indirecta de memoria de código con post-incremento del
apuntador Z, su comportamiento sería similar al mostrado en la figura 3.7.
En la figura 3.11 se muestra cómo se organizan las instrucciones que utilizan este
modo de direccionamiento. Se observa que al quedar disponibles únicamente 4 bits
para definir el número de registro, sólo se puede referenciar a 16 de ellos, es por eso
que las instrucciones con constantes sólo pueden incluir registros en el rango de R16
a R31.
93
3.2.7.1 Bifurcaciones con Direccionamiento Relativo
Las bifurcaciones con direccionamiento relativo incluyen una constante que se suma al
PC, esta constante puede ser positiva o negativa, para bifurcar hacia adelante o atrás,
con respecto a la ubicación de la instrucción de la bifurcación, en realidad son relativas
a PC + 1, dado que el incremento del PC es automático. En la figura 3.12 se ilustra el
funcionamiento de las bifurcaciones relativas.
94
Figura 3.13 Bifurcaciones con direccionamiento indirecto
95
En la sección 3.1 se mostraron las instrucciones que puede ejecutar un MCU AVR
y en la sección 3.2, con los modos de direccionamiento, se revisaron los diferentes
formatos de las instrucciones. En esta sección, para contar con los elementos suficientes
para programar en Ensamblador, se revisan algunas de las directivas incluidas en el
ensamblador desarrollado por Atmel (AVRASM) y distribuido con la herramienta
AVR Studio53. No se revisan todas las directivas, sólo aquellas que son usadas con
mayor frecuencia, mostrando ejemplos de su uso con los microcontroladores bajo
estudio. Las directivas generalmente se preceden con un punto.
Esta directiva se utiliza para leer el código fuente de otro archivo, se coloca al inicio
de un programa y es común utilizarla para incluir todas las definiciones relacionadas
con un dispositivo particular. Por ejemplo, si se utiliza un ATMega8 se debe agregar:
.include <m8def.inc> ; Incluye definiciones de un ATMega8
Al emplear un ATMega16 debe agregarse:
.include <m16def.inc> ; Incluye definiciones de un ATMega16
5 AVR Studio es una suite para el desarrollo de aplicaciones con los microcontroladores AVR, proporciona
las facilidades para la simulación y ensamblado de programas, es de distribución libre y puede descargarse
del sitio de ATMEL (http://www.atmel.com).
96
• DSEG: Marca el inicio de un segmento para los datos, con ello, en un programa
se pueden reservar localidades de SRAM para un propósito especial. De manera
similar, puede haber múltiples segmentos de datos.
3.3.3 Directiva DB y DW
97
eelist1: .DB 1,2,3,4
eelist2: .DW 0,0xffff,10
La etiqueta con la definición puede utilizarse como referencia (dirección) para tener
acceso a las constantes en un programa. Si es una lista, con la etiqueta se tiene acceso
al inicio de la lista.
El ensamblador hace referencia a los Registros I/O por su dirección y a sus bits por su
posición, sin embargo, con la directiva INCLUDE se incluye una biblioteca con las
definiciones de un dispositivo, por lo que al escribir un programa es posible utilizar
sus nombres. Estas bibliotecas hacen un uso extensivo de la directiva EQU, asociando
etiquetas a las direcciones.
Por ejemplo:
.DSEG
.ORG 0x120
var1: .Byte 1 ; Variable ubicada en la dirección 0x120 del
;segmento de datos
.CSEG
.ORG 0x000 ;Código ubicado en la dirección 0x00
RJMP inicio
.ORG 0x010
inicio: ; Código ubicado en la dirección 0x10
MOV R1, R2
. . . .
98
Se emplea principalmente para organizar a las instrucciones de un programa cuando
se manejan interrupciones, porque hace posible la ubicación del código, de acuerdo
con los vectores de interrupciones, como se mostró en la sección 2.6.
Se utilizan para separar constantes de 16 bits, con High se hace referencia a la parte
alta y con Low a la parte baja. Por ejemplo, para cargar la constante 578 en los registros
R27 y R26:
LDI R27, HIGH(578)
LDI R26, LOW(578)
Se comentó al inicio que las directivas se preceden con un punto, esto no ocurre
en High y Low, pero son consideradas como directivas porque no generan código
máquina.
Reserva uno o más bytes en SRAM o EEPROM para el manejo de variables, la cantidad
de bytes debe especificarse. Este espacio no es inicializado, sólo queda reservado para
que posteriormente sea referido con una etiqueta, por ejemplo:
.DSEG
.CSEG
99
3.4 Programación en Lenguaje C
Uno de estos compiladores es el avr-gcc, incluido en una suite conocida como WinAVR64,
la cual es parte del proyecto GNU. Después de instalar a la suite, el compilador es
llamado automáticamente desde el entorno del AVR Studio cada vez que se requiere,
su uso queda transparente al programador. Además del compilador, la suite incluye un
conjunto de bibliotecas con funciones enfocadas a los recursos de los AVR.
El compilador está orientado al estándar ANSI C, se pueden emplear a todos los elementos
del lenguaje, como tipos de datos y estructuras de control de flujo. En esta sección se
revisan algunas características del lenguaje, principalmente las consideraciones para
trabajar con los microcontroladores AVR.
Pueden usarse los tipos básicos con sus diferentes modificadores, en la tabla 3.25 se
muestran los diferentes tipos de datos, con la cantidad de bits que requieren y el rango
de combinaciones que cubren.
100
Tipo Tamaño (bits) Rango
int 16 -32, 768 a 32, 767
short int 16 -32, 768 a 32, 767
unsigned int 16 0 a 65, 535
signed int 16 -32, 768 a 32, 767
long int 32 -2, 147, 483, 648 a 2, 147, 483, 647
unsigned long int 32 0 a 4, 294, 967, 295
signed long int 32 -2, 147, 483, 648 a 2, 147, 483, 647
float 32 +/- 1.175 x 10-38 a +/- 3.402 x 10+38
double 32 +/- 1.175 x 10-38 a +/- 3.402 x 10+38
En la tabla 3.25 se muestran diferentes tipos de datos con el mismo comportamiento, por
ejemplo float y double prácticamente hacen referencia al mismo tipo de datos, la inclusión de
ambos debe ser para mantener compatibilidad con el estándar ANSI C. Las variables de los
tipos char, unsigned char o signed char pueden asignarse directamente con los Registros I/O.
Al trabajar con un microcontrolador, debe considerarse el limitado espacio de memoria
para no agotarlo con un mal manejo de los tipos de datos, por ejemplo, si en un ciclo
repetitivo se realizan pocas iteraciones, es mejor usar un dato del tipo unsigned char
en lugar de un int. Ya que no sólo es un byte extra, sino que con un int se ejecutan
operaciones de 16 bits, requieriendo más instrucciones de bajo nivel.
En el entorno de desarrollo WinAVR se encuentran una serie de definiciones de tipos
de datos que surgen a partir de los estándares mostrados en la tabla 3.25, ejemplos de
estas definiciones de tipos son:
typedef signed char int8_t
typedef unsigned char uint8_t
typedef signed int int16_t
typedef unsigned int uint16_t
typedef signed long int int32_t
typedef unsigned long int uint32_t
Al programar se pueden utilizar los tipos de datos del ANSI C o las definiciones del
WinAVR, esto no afecta el comportamiento de un programa. En el código desarrollado
en este documento se utiliza al estándar y, sólo si es necesario, se emplea algún
modificador propio del entorno de desarrollo.
Aunque el compilador acepta todos los operadores del ANSI C (aritméticos, relacionales,
de incremento y decremento), únicamente se describen los operadores lógicos y para el
manejo de bits, porque son muy utilizados al trabajar con microcontroladores.
101
En la tabla 3.26 se muestran los operadores lógicos, sus operandos son expresiones
lógicas (proporcionan falso o verdadero) y se emplean para crear expresiones
lógicas de mayor complejidad, cualquier valor diferente de 0 es interpretado como
verdadero.
Tabla 3.26 Operadores lógicos
Operador Símbolo
AND &&
OR ||
En la tabla 3.27 se muestran los operadores para el manejo de bits, éstos trabajan sobre datos
de los tipos char, int o long (no trabajan sobre punto flotante) y afectan el resultado al nivel
de bits. Son muy utilizados para enmascarar información, es decir, modificar únicamente
algunos bits de un dato sin alterar a los demás, o bien para evaluar el estado de un bit.
Tabla 3.27 Operadores para el manejo de bits
Operador Símbolo
Complemento a 1 ~
Desplazamiento a la izquierda <<
Desplazamiento a la derecha >>
AND &
OR |
OR exclusivo ^
102
char cadena[] = “hola mundo”;
char *pcad;
pcad = cadena;
Las constantes son datos que no cambian durante la ejecución normal de un programa,
los datos de este tipo pueden ser almacenados en la memoria FLASH. Al manejar las
constantes en FLASH se liberan espacios significativos de SRAM, esto es fundamental
para aplicaciones que incluyan cadenas de texto o tablas de búsqueda.
Para que el compilador dirija las constantes hacia la FLASH, éstas deben identificarse
con la palabra reservada const e incluir al atributo PROGMEM, definido en la biblioteca
pgm space.h que es parte del WinAVR. Ejemplos de declaraciones de constantes
en FLASH son:
const char cadena[] PROGMEM = “Cadena con un mensaje constante”;
const unsigned char tabla[] PROGMEM = { 0x24, 0x36, 0x48, 0x5A, 0x6C };
Las funciones reciben como argumento la dirección del dato en FLASH, un ejemplo
para la lectura del dato i de la tabla de constantes es:
x = pgm_read_byte(&tabla[i]);
En el ejemplo 3.2, descrito en la sección 3.5, se presenta una aplicación que hace uso
de constantes en memoria FLASH.
103
3.4.3.3 Datos en EEPROM
Otra consideración debe tenerse para aquellas variables en las que se requiera conservar
su contenido, aun en ausencia de energía, estas variables no pueden manejarse en
SRAM porque es memoria volátil, deben almacenarse en la EEPROM.
Para ubicar una variable en la EEPROM, debe estar precedida con el atributo EEMEM,
el cual está definido en la biblioteca eeprom.h, que también es parte del entorno de
WinAVR. Este atributo hace que las declaraciones siguientes sean direccionadas a la
EEPROM, éstas deben ser globales y realizarse antes de la declaración de constantes
para la FLASH o variables para la SRAM. En el siguiente ejemplo se declaran
variables para la EEPROM:
El acceso a los datos en la EEPROM se realiza por medio de los registros EEAR,
EEDR y EECR, para ello pueden emplearse las funciones mostradas en la sección
2.4.2, o bien, desarrollar otras funciones en donde se involucre a la interrupción por
fin de escritura en EEPROM. En la biblioteca eeprom.h se cuenta con diversas
funciones para el acceso a la EEPROM, 2 de éstas son:
También se incluyen funciones para datos de 16 y 32 bits, así como para el manejo de
bloques de memoria.
104
3.5 Programas de Ejemplo
105
Fig. 3.16 Comportamiento deseado en el problema del parpadeo de un LED
Para el programa en Ensamblador, se debe realizar una rutina para los retrasos con
base en ciclos repetitivos, para ello, se asume un oscilador interno de 1 MHz, que
corresponde con la configuración inicial de un ATMega8.
.include <m8def.inc> ; Biblioteca con definiciones
106
Espera_500mS:
LDI R18, 2
et3: LDI R17, 250
et2: LDI R16, 250
et1: NOP ; Itera 250 veces, emplea 4 uS por iteración
DEC R16 ; 250 x 4 uS = 1000 uS = 1 mS
BRNE et1 ; La instrucción evalúa la bandera de cero
; brinca si no hay bandera de cero
DEC R17
BRNE et2 ; 1 mS x 250 = 250 mS
DEC R18
BRNE et3 ; 250 mS x 2 = 500 mS
RET
}
}
__________
107
Se observa que sin importar el lenguaje de programación, se debe conseguir el
comportamiento mostrado en la figura 3.16. En lenguaje C, la inicialización del
apuntador de pila no se realiza en el código fuente, estas instrucciones las agrega el
compilador en el momento en que genera el código de bajo nivel.
En otras palabras, en este ejemplo se ilustra el manejo de una búsqueda, en una tabla
de constantes.
Ejemplo 3.2 Desarrolle un programa que lea los 4 bits menos significativos del Puerto D
[PD3:PD0] y genere su código en 7 segmentos en el Puerto B. En la figura 3.17 se muestra
el hardware requerido con el valor de las salidas para cada una de las entradas, la solución
debe comportarse como el diagrama de flujo mostrado en la figura 3.18
Núm. g f e d c b a HEX
0 0 1 1 1 1 1 1 0x3F
1 0 0 0 0 1 1 0 0x06
2 1 0 1 1 0 1 1 0x5B
3 1 0 0 1 1 1 1 0x4F
4 1 1 0 0 1 1 0 0x66
5 1 1 0 1 1 0 1 0x6D
6 1 1 1 1 1 0 1 0x7D
7 0 0 0 0 1 1 1 0x07
8 1 1 1 1 1 1 1 0x7F
9 1 1 0 0 1 1 1 0x67
A 1 1 1 0 1 1 1 0x77
B 1 1 1 1 1 0 0 0x7C
C 0 1 1 1 0 0 1 0x39
D 1 0 1 1 1 1 0 0x5E
E 1 1 1 1 0 0 1 0x79
F 1 1 1 0 0 0 1 0x71
108
Figura 3.18 Comportamiento esperado en el decodificador de binario a 7 Segmentos
int main() {
109
En lenguaje ensamblador también se debe observar una tabla de constantes en memoria
de código y un registro funcionando como apuntador, para hacer las lecturas empleando
direccionamiento indirecto. El código es el siguiente:
.include <m8def.inc>
En este ejemplo también se mostró que existe una relación directa entre hardware y
software, en aplicaciones con MCUs normalmente ocurre que es posible un ahorro
de hardware si se escriben más líneas de código. O en caso contrario, si la memoria
de código se ha agotado, algunas tareas de software podrían realizarse con hardware
externo.
Respecto al ejemplo, al utilizar la AND para conservar sólo la parte baja del puerto
D, hace innecesario tener que aterrizar vía hardware a la parte alta del mismo puerto,
estas terminales pueden permanecer abiertas sin alterar el funcionamiento del sistema.
También, los resistores de Pull-Up ya se encuentran dentro del AVR, sólo fue necesaria
su habilitación para evitar el uso de resistores externos.
110
3.5.3 Diseño de una ALU de 4 Bits
Ejemplo 3.3 Construya una ALU de 4 bits utilizando un ATMega8, en donde los
operandos se lean del puerto B (nibble bajo para el operando A y nibble alto
para el operando B), el resultado se genere en el puerto D y con los 3 bits menos
s ignificativos del puerto C se defina la operación. En la figura 3.19 se
muestran las entradas, salidas y las operaciones.
PortC[2:0] Operación
000 R=A+B
001 R=A-B
010 R=A*B
011 R = A AND B
100 R = A OR B
101 a 111 R=0
111
El programa en lenguaje C es:
#include <avr/io.h>
int main() {
unsigned char A, B, R, Op; // Variables locales
while(1) {
switch( Op ) {
case 0: R = A + B; // Suma
break;
case 1: R = A - B; // Resta
break;
case 2: R = A * B; // Producto
break;
case 3: R = A & B; // AND lógica
break;
case 4: R = A | B; // OR lógica
break;
default: R = 0;
}
No se considera la posibilidad de acarreos porque los datos son de 4 bits, para las 3
operaciones aritméticas el resultado alcanza perfectamente en 8 bits.
En una estructura switch-case se debe consumir el mismo tiempo para bifurcar a
cada uno de los casos, ésta es la principal diferencia con un conjunto de estructuras
if-else anidadas. Este comportamiento también debe observarse en ensamblador, para
ello se utiliza una tabla de saltos, empleando bifurcaciones indirectas. El código en
ensamblador correspondiente es:
.include <m8def.inc>
112
LDI R16, 0xFF ; Resistores de Pull-Up
OUT PORTB, R16
OUT PORTC, R16
OUT DDRD, R16 ; Puerto D como salida
valido:
LDI R30, LOW(tabla); Z apunta al inicio de la tabla de saltos
LDI R31, HIGH(tabla)
ADD R30, R22 ; Suma el caso detectado
BRNE no_carry
INC R31 ; Se considera el acarreo
no_carry:
IJMP ;
tabla:
RJMP case_0 ; Tabla de saltos
RJMP case_1
RJMP case_2
RJMP case_3
RJMP case_4
RJMP default
case_0: ; Suma, el resultado queda en R23
MOV R23, R20 ; para todos los casos
ADD R23, R21
RJMP salir
case_1:
MOV R23, R20 ; Resta
SUB R23, R21
RJMP salir
case_2:
MUL R21, R20 ; Producto
MOV R23, R0 ; ubica el resultado
RJMP salir
case_3:
MOV R23, R20 ; AND lógica
113
AND R23, R21
RJMP salir
case_4:
MOV R23, R20 ; OR lógica
OR R23, R21
RJMP salir
default:
CLR R23 ; Operación no válida
salir: ; fin del switch-case
OUT PORTD, R23 ; Genera la salida
RJMP loop;
__________
114
El lenguaje ensamblador sería necesario en las siguientes situaciones:
3. La aplicación requiere una manipulación extensiva de bits, por ejemplo, para re-
ducir el espacio utilizado para almacenar un conjunto de datos, en lenguaje ensam-
blador directamente puede hacerse un empaquetamiento de datos para comprimir
la información.
• Restricciones: Este argumento puede omitirse, se utiliza para indicar los registros
que se están incluyendo en el código sin haber sido especificados como operandos
de entrada o salida.
115
La instrucción ejecutada en el primer ejemplo únicamente sirve para perder 1 ciclo de
reloj. Por lo que no afecta a los recursos del microcontrolador.
3.7 Ejercicios
Ante cambios en las entradas ¿Cuál es el tiempo de respuesta si el MCU está ope-
rando a 1 MHz?
116
3. Realice un contador de segundos con salida en un display de 7 segmentos co-
nectado en el puerto B de un AVR. Inicialmente muestre al 0, un segundo después,
incremente para mostrar al 1 y así sucesivamente (0, 1, 2, etc.). Al llegar a la F,
inicie nuevamente con el 0.
Figura 3.22 (a) Conexión de un botón y (b) espera a que el botón sea presionado
117
Tiempo
Rojo1 Amarillo1 Verde1 Rojo2 Amarillo2 Verde2
(Seg)
1 0 0 0 0 1 15
1 0 0 0 0 parpadeo 5
1 0 0 0 1 0 5
0 0 1 1 0 0 15
0 0 parpadeo 1 0 0 5
0 1 0 1 0 0 5
Tabla 3.28 Secuencia para los semáforos
118