Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Primer Ejemplo en Assembler PDF
Primer Ejemplo en Assembler PDF
1 = Prende Dispositivo
0 = Apaga
Debemos seleccionar:
¿Y ahora?
Bueno lo primero que hay que hacer indefectiblemente es estudiar la arquitectura del dispositivo,
a diferencia de la programación clásica en PCs (comúnmente arquitectura i386 o AMD64 FIJA) en
la programación de uC lo que cambia es justamente la arquitectura en función del dispositivo
elegido, y el desarrollo del software tiene que “machear” perfectamente con ella.
Datasheet
¡A desarrollar!
¿Que es lo primero que tenemos que incluir? (no vale mirar abajo)
Si, el archivo que hace la redefinición de nombre de los registros, podríamos programar esto
sbi 0x25, 2
Que funcionaria bien, pero claramente es mejor escribir la sentencia de la siguiente manera
sbi PORTB,2 // set bit 2 in register 0x25 (que para el ATmega328 es el puerto B )
Esto permita que el código sea mucho más portable que el primer ejemplo. Por lo tanto
incluyamos el archivo de definiciones.
.include <m328def.inc>
loop_for_ever:
rjmp loop_for_ever
Una vez que agregamos esto vamos a ensamblar el código todo ok?
En este punto tenemos un programa que se puede bajar al micro (aunque como se ve no hace
nada) si vamos a “Project Patht”/lape se puede ver los archivos generados. Abrir el .hex con el
block de notas…
Continuemos ahora asignando algunos nombres a registros, que utilizaremos como variables, pero
tiene que quedar bien en claro que no son variables sino registros de hardware, o sea que no
están en memoria RAM.
.org 0x0000
rjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp PC_INT0 ; PCINT0 Handler
rjmp PC_INT1 ; PCINT1 Handler
rjmp PC_INT2 ; PCINT2 Handler
rjmp WDT ; Watchdog Timer Handler
rjmp TIM2_COMPA ; Timer2 Compare A Handler
rjmp TIM2_COMPB ; Timer2 Compare B Handler
rjmp TIM2_OVF ; Timer2 Overflow Handler
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA ; Timer1 Compare A Handler
rjmp TIM1_COMPB ; Timer1 Compare B Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_COMPA ; Timer0 Compare A Handler
rjmp TIM0_COMPB ; Timer0 Compare B Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART, RX Complete Handler
rjmp USART_UDRE ; USART, UDR Empty Handler
rjmp USART_TXC ; USART, TX Complete Handler
rjmp ADC_RDY ; ADC Conversion Complete Handler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWI ; 2-wire Serial Interface Handler
rjmp SPM_RDY ; Store Program Memory Ready Handler
EXT_INT0:
EXT_INT1:
PC_INT0:
PC_INT1:
PC_INT2:
WDT:
TIM2_COMPA:
TIM2_COMPB:
TIM2_OVF:
TIM1_CAPT:
TIM1_COMPA:
TIM1_COMPB:
TIM1_OVF:
TIM0_COMPA:
TIM0_COMPB:
TIM0_OVF:
SPI_STC:
USART_RXC:
USART_UDRE:
USART_TXC:
ADC_RDY:
EE_RDY:
ANA_COMP:
TWI:
SPM_RDY:
reti
loop_for_ever:
rjmp loop_for_ever
¿Que falta?
RESET:
ldi r16, high(RAMEND); Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16, low(RAMEND)
out SPL,r16
sei ; Enable interrupts
En este punto se setea donde comienza la pila de programa (STACK), y se habilitan las
interrupciones.
Hasta el momento tenemos lo que llamaríamos un template de programa, ahora hay que escribir
la lógica. Comenzaremos escribiendo las rutinas de retardo, como no estamos utilizando
interrupciones ni timers la única forma de crear un retardo es a través de espera ocupada (Busy
Wait) del CPU. Para esto hay que saber principalmente 2 cosas
1) Frecuencia de CPU
2) Tiempo que tardan en ejecutarse cada instrucción del set.
La frecuencia la escogemos nosotros, por ejemplo 4MHz, y para los tiempos de instrucción
podemos ir al datasheet ( Instruction Set Summary) y ver cuanto tarda cada instrucción
involucrada en la rutina. Un ejemplo a continuación.
Comenzaremos realizando un retardo de 5 ms
;--------------------------------------------------------------
;Rutinas de Retardo de 5ms
;--------------------------------------------------------------
; hacer un llamado tarda 5 ciclos
delay5ms:
ldi Temp1, 66 ;para 8mhz ; 1 ciclo
LOOP0:
ldi temp2, 200 ; 1 ciclo
LOOP1:
dec temp2 ; 1 ciclo
brne LOOP1 ; 1 si es falso 2 si es verdadero
dec Temp1 ; 1
brne LOOP0 ; 2
ret
;--------------------------------------------------------------
Llamada 5 * 1
Ldi 1 1 * 1
LDI 2 1 * 66
dec 1 1 * 200
brne 1 2 * 200
dec 2 1 * 66
brne 2 2 * 66
ret 4 * 1
De la misma manera procedemos para hacer un retardo de 0,5 seg utilizando la rutina anterior
;--------------------------------------------------------------
;Rutinas de Retardo de 500ms
;--------------------------------------------------------------
delay500ms:
ldi temp3,100 ;para 8mhz
LOOP500ms:
call delay5ms
dec temp3
brne LOOP500ms
ret
;--------------------------------------------------------------
También podían utilizar la aplicación AVRdelayloop.exe que les hace estos cálculos
automáticamente ;) .
Ahora hay que inicializar el puerto escogido como salida. y por último PRENDER y APAGAR el LED
RESET:
ldi Temp1, low(RAMEND)
out SPL, Temp1
ldi Temp1, high(RAMEND)
out SPH, Temp1
ldi temp1,0xFF
out DDRB,temp1
sei
;********************************************
; Bucle Principal
;********************************************
final:
call delay500ms
sbi PORTB,0
call delay500ms
cbi PORTB,0
rjmp final
Como último paso hay que debuggear, así que podemos hacerlo apretando con F11 nos
movemos por el código. si queremos algo más pro Proteus!!!