He estado tratando de hacer parpadear un LED con ensamblaje AVR. Estoy usando un chip ATMega168 y una cadena de herramientas avr-gcc. Aquí está mi código:
.include "m168.h"
.global main
main:
ldi r16, 0b00000001
out DDRB,r16 ; Set PB0 to output
out PORTB,r16 ; Set PB0 high
ldi r16, 0b00000101
out TCCR0B,r16 ; Set prescaler to 1024
loop:
in r17, TCNT0 ; If the counter is >= 128,
cpi r17, 128 ; branch to dim
brge dim ; otherwise continue to light
light:
sbi PORTB, 0
rjmp loop
dim:
cbi PORTB,0
rjmp loop
Calculo que mi LED debe estar encendido ~50% del tiempo (valores 0-127) y apagado el 50% del tiempo (valores 128-255). Pero no se enciende en absoluto (visiblemente).
Si ejecuto el programa en mi cabeza, es así.
loop
atraviesa sin bifurcarse haciadim
light
salta de nuevo aloop
Los pasos 3 y 4 ocurren en un ciclo para todos los valores de TCNT0 donde 0 <= TCNT0 <= 127, lo que significa que la luz está encendida todo este tiempo
dim
salta de nuevo aloop
Los pasos 5 y 5 ocurren en un ciclo para todos los valores de TCNT0 donde 128 <= TCNT0 <= 255, lo que significa que la luz está apagada todo este tiempo
Suponiendo que la velocidad de mi reloj es de 8 Mhz (no sé cómo encontrar esto en la hoja de datos), el temporizador se incrementa una vez cada 1024 ciclos de reloj o aproximadamente 4 ms (10248 (1/8 ^ 6)). Lo que significa que mi LED debe estar encendido durante 512 ms (128 * 4) y luego apagado durante 512 ms.
Claramente, estoy haciendo algo mal aquí o la lógica anterior no es sólida, pero no estoy seguro de dónde.
Editar:
Si configuro la comparación para comparar con 255, parpadea. ¡Esto me confunde aún más!
brge
es una comparación mayor o igual con signo. El literal 128 de 8 bits es -128 en complemento a dos, que es el valor más bajo posible, por lo que TCNT
siempre será mayor y el LED permanecerá apagado. Intente usar brsh
en su lugar si desea usar valores sin firmar.
Por cierto, el literal 255 es -1 en complemento de dos, por lo que su código funciona correctamente cuando lo usa en su lugar.