En esta sección se muestran unos ejemplos sencillos de programación en ensamblador de AVRs de la casa ATMEL. El código utilizado es para el ATMEL AVR Assembler Assembler y si se desea utilizar estos mismos ejemplos para el AVR IAR Assembler Assembler debemos realizar algunas modificaciones en el código. Estos cambios se comentan en el amblador par par a AV Rs. Rs. Solo deberíamos cambiar algunas directivas que apartado En samblador tienen distinto formato ya que las instrucciones son las mismas para ambos programas. Estos ejemplos son muy útiles para la gente que está empezando a programar en ensamblador con los microcontroladores AVR. Podrá encontrar ejemplos de utilización del Watchdog, Wat chdog, de SRAM, EEPROM, Comparador Analógico, UART y del convertidor A/D. Las notas que acompañan a los programas le permitirán seguir de una manera sencilla paso a paso lo que se está realizando en cada momento.
ESTABLECIMIENTO ESTABLECIMIE NTO Y CONTROL DEL WATCHDOG DESCRIPCIÓN Esta aplicación muestra como establecer y controlar el timer Watchdog para los dispositivosAT90S1300,AT90S2312 y AT90S8414. Se supone una frecuencia de CPU de 10MHz.
.include "2312def.inc" "2312def.inc" rjmp RESET ;Salto relativo a la subrutina RESET ;* ;* "delay" ;* ;* Esta subrutina genera una demora basada en el parámetro de entrada "del". ;* La demora resultante viene dada por: ;* ;* delay = del * 0.1 ms (aproximadame (aproximadamente) nte) ;* ;* Número de words : 7 ;* Número de ciclos : 1026 * del + 4 ;* Registros bajos usados : 1(delcnt) ;* Registros altos usados : 1(del) ;* ;***** Variables de registro de la Subrutina .def del = r16 ;Tamaño del bloque que se va a copiar .def delcnt = r0 ;Contador de "loop" ;***** Código delay:
clr
delcnt
;Inicio contador "loop"
loop: dec delcnt nop brne loop dec del brne loop ret
;Decrementar delcnt ;No operar ;Desvío a loop si el flag Z de SREG es cero ;Decrementar del ;Desvío a loop si el flag Z de SREG es cero ;Retorno de subrutina
;* ;* Programa Principal ;* ;* Este programa empieza habilitando el watchdog con un periodo de timeout de 16 ;*ms. El programa entonces empieza un camino donde el watchdog se resetea en un ;*periodo aproximado de 10 ms. Cuando acaba este primer camino, el programa entra ;*en un segundo camino donde el watchdog se resetea cada 20 ms. Este camino nunca ;*funcionará porque el watchdog resetea la CPU 16 ms después de la última ;*instrucción wdr. ;* ;***** Variables de registro del Programa Principal .def temp = r16 ;Variable de almacenamiento temporal .def counter = r17 ;Contador de "loop" ;***** Código RESET: ldi temp,RAMTOP out SPL,temp ;Inicio del Stack Pointer ;* ;* Inicializar el timer Watchdog ;* ;* Este trozo de código habilita el timer watchdog e introduce un periodo de 16 ms de ;* timeout ;* ;* Número de words: 3 ;* Número de ciclos: 3 ;* Registros bajos usados: 1(temp) ;* Registros altos usados: Ninguno ;* wdr ;Reset del timer watchdog antes de habilitarlo para ;prevenir los reset no deseados antes del wdr siguiente ldi temp,(1<
rcall delay ;Generar un retardo de 10 ms dec counter brne mloop1 ;Volver a mloop1 si no acaba ldi counter,5 ;Iniciar el contador de loop ;***** Rutina que no llega nunca hasta el final porque el reset de watchdog se da ;***** después de 20 ms. mloop2: wdr ;Reset de watchdog ldi del,200 rcall delay ;Genera un retardo de 20 ms ;------------------ CÓDIGO NO EJECUTABLE! -----------------dec counter brne mloop2 ;Volver a mloop2 forever:
rjmp
forever LECTURA Y ESCRITURA EN EEPROM
DESCRIPCIÓN Esta aplicación muestra como leer y escribir datos en la EEPROM del AVR AT90S1200. Se listan las rutinas de acceso aleatorio y secuencial. Para el resto de dispositivos el bit de habilitación de escritura maestro EEMWE debe ponerse a set previamente a poner a set el bit EEWE.
.include "1200def.inc" rjmp RESET ;Salto relativo a la subrutina RESET ;* ;* EEWrite ;* Esta subrutina espera hasta que la EEPROM esté preparada para ser ;* programada, entonces programa la EEPROM con la variable de registro "EEdwr" ;* en la dirección "EEawr" ;* ;* ;* Número de words : 5 + return ;* Número de ciclos : 10 + return (si la EEPROM está disponible) ;* Registros bajos usados : Ninguno ;* Registros altos usados : 2 (EEdwr,EEawr) ;* ;***** Variables de registro de la Subrutina .def EEdwr =r16 ;Byte de dato a escribir en la EEPROM .def EEawr =r17 ;Dirección en la que escribir
;***** Código EEWrite: sbic EECR,EEWE rjmp out out sbi
EEWrite EEAR,EEawr EEDR,EEdwr EECR,EEWE
;Saltar la siguiente instrucción si EEWE está ;borrado ;Esperar más si EEWE no está borrado ;Escribir la dirección de salida en EEAR ;Escribir el dato de salida ;Poner a 1 el bit EEWE ( EEPROM Write strobe ) ;Este bit habilita la escritura en EEPROM ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock
ret ;* ;* EERead ;* ;* Esta subrutina espera hasta que la EEPROM está preparada para ser ;* programada, entonces lee la variable de registro "EEdrd" desde la dirección ;* "EEard" ;* ;* Número de words : 6 + return ;* Número de ciclos : 12 + return (Si la EEPROM está disponible) ;* Registros bajos usados : 1 (EEdrd) ;* Registros altos usados : 1 (EEard) ;* ;***** Variables de registro de la Subrutina .def EEdrd = r0 ;Byte de dato resultado .def EEard = ;Dirección de la que leer r16 ;***** Código EERead: sbic EECR,EEWE ;Saltar la siguiente instrucción si EEWE está ;borrado rjmp EERead ;Esperar más si EEWE no está borrado out EEDR,EEard ;Escribir la dirección de salida sbi EECR,EERE ;Poner a 1 el bit EEWE ( EEPROM Read strobe ) ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock sbi EECR,EERE ;Poner a 1 el bit EEWE ( EEPROM Read strobe ;2nd time ) ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock ;Al poner a set EERE se detiene la CPU durante 4 ;ciclos de clock in EEdrd,EEDR ;Obtener el dato
ret ;* ;* EEWrite_seq ;* ;* Esta subrutina incrementa por uno la dirección de EEPROM y espera hasta que la ;* EEPROM está preparada para ser programada. Entonces programa la EEPROM ;* con la variable de registro "EEdwr_s". ;* ;* Número de words : 7 + return ;* Número de ciclos : 10 + return (si la EEPROM está disponible) ;* Registros bajos usados : 1 (EEWtmp) ;* Registros altos usados : 1 (EEdwr_s) ;* ;***** Variables de registro de la Subrutina .def EEwtmp = r0 ;Almacenamiento temporal de la dirección .def EEdwr_s = r16 ;Dato que se va a escribir ;***** Código EEWrite_seq: sbic EECR,EEWE ;Saltar la siguiente instrucción si EEWE está ;borrado rjmp EEWrite_seq ;Esperar más si EEWE no está borrado in EEwtmp,EEAR ;Obtener la dirección inc EEwtmp ;Incrementar la dirección out EEAR,EEwtmp ;Escribir la dirección de salida out EEDR,EEdwr_s ;Escribir el dato de salida sbi EECR,EEWE ;Poner a 1 el bit EEWE ( EEPROM Write strobe ) ;Este bit es el de habilitación de escritura en ;EEPROM ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock ret ;* ;* EERead_seq ;* ;* Esta subrutina incrementa la dirección almacenada en EEAR y lee la EEPROM ;* en la variable de registro "EEdrd_s". ;* ;* Número de words : 6 + return ;* Número de ciclos : 12 + return (si la EEPROM está disponible) ;* Low Registers used : 2 (EErtmp,EEdrd_s) ;* High Registers used: : Ninguno ;* ;***** Variables de registro de la Subrutina .def EErtmp = r0 ;Almacenamiento temporal de la dirección .def EEdrd_s = r1 ;Byte de dato resultado
;***** Code EERead_seq: in EErtmp,EEAR inc EErtmp out EEAR,EErtmp sbi EECR,EERE sbi
in ret
;Obtener la dirección ;Incrementar la dirección ;Escribir la dirección de salida ;Poner a 1 el bit EEWE ( EEPROM Read strobe ) ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock EECR,EERE ;Poner a 1 el bit EEWE ( EEPROM Read strobe ;2nd time ) ;Esta instrucción necesita 4 ciclos de clock ya que ;detiene la CPU durante dos ciclos de clock ;Al poner a set EERE se detiene la CPU durante 4 ;ciclos de clock EEdrd_s,EEDR ;Obtener el dato
;* ;* Programa de Test/Ejemplo ;* ;***** Variables de registro del Programa Principal .def counter = r18 .def temp = r19 ;***** Código RESET: ;***** Programar una posición aleatoria ldi EEdwr,$aa ldi EEawr,$10 rcall EEWrite ;Almacena $aa en la posición $10 de EEPROM ;***** Leer desde unas posiciones aleatorias ldi EEard,$10 rcall EERead ;Leer la dirección $10 out PORTB,EEdrd ;Escribir el valor de salida en el Puerto B ;***** Rellenar la EEPROM con el patrón $55,$aa,$55,$aa,... ldi counter,64 ;Iniciar el contador de "loop" ser temp ;Pone TEMP a set ( $ff ) out EEAR,temp ;EEAR <- $ff (Dirección de comienzo - 1) loop1: ldi EEdwr_s,$55 rcall EEWrite_seq ;programar la EEPROM con $55 ldi EEdwr_s,$aa rcall EEWrite_seq ;Programar la EEPROM con $aa dec counter ;decrement counter brne loop1 ;saltar a loop1 si Z = 0, es decir Rd no igual que Rr ;***** Copiar los 10 primeros bytes de la EEPROM a los registros r2-r11 ldi temp,$ff out EEAR,temp ;EEAR <- $ff (Dirección de comienzo - 1)
ldi loop2: rcall st inc cpi brne forever: rjmp
ZL,2
;El puntero Z apunta al registro r2
EERead_seq Z,EEdrd_s ZL ZL,12 loop2
;Obtener el dato de la EEPROM ;Almacenar en la SRAM
forever
;Comprueba si ha llegado al final ;saltar a loop2 si Z = 0, es decir Rd no igual que Rr ;Mantenimiento en "forever"