You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
6.5 KiB
347 lines
6.5 KiB
# tomatimer |
|
|
|
a small pomodoro timer on an attiny85, programmed with {avr-asm}. |
|
|
|
part of the {s-camino} practice. |
|
|
|
=> ./img/foto_tomatimer.png photo of the tomatimer: a small circuit with two leds, a buzzer, the attiny85, all of them over a plastic card. |
|
|
|
# about |
|
|
|
tomatimer works as a 25 and 5 minutes timer, cycling between them. |
|
|
|
a couple of LEDs indicate via blinking which one of the two timers is active at a given moment. |
|
|
|
at the end of each timer, a buzzer plays an alarm during some seconds. |
|
|
|
all the durations can be reconfigured via the source code if needed. |
|
|
|
# connections |
|
|
|
```diagrama de pines |
|
┌──────┐ |
|
│1 8│ VCC |
|
│2 7│ PB2: LED state 1 |
|
│3 6│ PB1: LED state 0 |
|
GND │4 5│ PB0: Buzzer |
|
└──────┘ |
|
``` |
|
|
|
LEDs are connected such that an output of "high" will turn them on. |
|
|
|
# source code |
|
|
|
with billingual comments |
|
|
|
``` |
|
; tomatimer.S |
|
#include <avr/io.h> |
|
|
|
; TIMER1 tiene su reloj a clk/512 (~1953 Hz) |
|
; contando 244 pulsos se va a 8Hz (frame freq) |
|
; i.e. 8 frames son 1 segundo |
|
; r16 y r17 se usan como registros auxiliares |
|
|
|
; duraciones en minutos de los timers |
|
#define DUR_TIMER0 25 |
|
#define DUR_TIMER1 5 |
|
; duraciones en segundos de la alarma |
|
#define DUR_ALARMA0 3 |
|
#define DUR_ALARMA1 5 |
|
|
|
; más chico es más agudo |
|
#define WAVE_PERIOD0 3 |
|
#define WAVE_PERIOD1 6 |
|
|
|
; teórico: 244 |
|
#define TIMER1_PERIOD 240 |
|
|
|
#define rFrames r20 |
|
#define rSegundos r21 |
|
#define rMinutos r22 |
|
#define rFlags r23 |
|
|
|
#define fAlarmOn 0 |
|
#define fAlarmLevel 1 |
|
#define fCualTimer 2 |
|
|
|
#define pinAlarm PB0 |
|
#define pinState0 PB1 |
|
#define pinState1 PB2 |
|
|
|
; para hacer fast modulo 8 |
|
#define MASK_FRAMES 0x07 |
|
|
|
; *********************** |
|
; vectores de interrupts: |
|
; *********************** |
|
; Reset |
|
.org 0x0000 |
|
rjmp main |
|
|
|
; dirección 0x0003 * 2 |
|
.org 0x0006 |
|
rjmp timer1compareA_isr |
|
|
|
; dirección 0x0009 * 2 |
|
.org 0x0012 |
|
rjmp timer1compareB_isr |
|
|
|
; *********************** |
|
; Main |
|
; *********************** |
|
.org 0x001E |
|
main: |
|
;---------------------------------- |
|
; configuración general |
|
;---------------------------------- |
|
|
|
; habilita interrupciones |
|
sei |
|
|
|
; pin PB0 como pin de salida |
|
ldi r16, (1<<DDB2) | (1<<DDB1) | (1<<DDB0) ; pins de salida |
|
sts DDRB, r16 |
|
|
|
;---------------------------------- |
|
; configuración TIMER0 para buzzer |
|
;--------------------------------- |
|
; CS0: 0b011, clock select clk/64 |
|
; WGM0: 0b010, Clear timer on compare match (CTC mode) |
|
; COM0A: 0b01, toggle OCOA on compare match (0b00 para apagar) |
|
ldi r16, (0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00) |
|
sts TCCR0B, r16 |
|
ldi r16, (0<<COM0A1) | (1<<COM0A0) | (1<<WGM01) | (0<<WGM00) |
|
sts TCCR0A, r16 |
|
|
|
; el TOP es el valor en OCR0A |
|
; más pequeño es más agudo |
|
ldi r16, WAVE_PERIOD0 |
|
sts OCR0A, r16 |
|
|
|
;---------------------------------- |
|
; configuración TIMER1 para frames |
|
;---------------------------------- |
|
; CS1 en 0b1010 es CK/512 |
|
ldi r16, (1<<CTC1) | (1<<CS13) | (0<<CS12) | (1<<CS11) | (0<<CS10) |
|
sts TCCR1, r16 |
|
|
|
; establece el valor A al que cuenta el timer1 para interrupt |
|
ldi r16, TIMER1_PERIOD |
|
sts OCR1A, r16 |
|
|
|
; establece el valor C al que cuenta el timer1 para resetear |
|
sts OCR1C, r16 |
|
|
|
; establece el valor B para mitad de periodo |
|
lsr r16 ; divide entre 2 |
|
sts OCR1B, r16 |
|
|
|
; set timer output compare A interrupt enable 1 |
|
; y timer output compare B interrupt enable |
|
ldi r16, (1<<OCIE1A) | (1<<OCIE1B) |
|
sts TIMSK, r16 |
|
|
|
;enciende alarma |
|
ldi rFlags, (1<<fAlarmOn) |
|
|
|
; time count |
|
ldi rFrames, 0 ; frames |
|
ldi rSegundos, 0 ; seconds |
|
ldi rMinutos, 0 ; minutes |
|
|
|
; enciede state 0 |
|
ldi r16, (1<<pinState0) |
|
sts PORTB, r16 |
|
|
|
loop: |
|
sleep |
|
rjmp loop |
|
|
|
; ----------------------- |
|
; interrupts |
|
|
|
; main time counting |
|
timer1compareA_isr: |
|
; apaga alarm level |
|
clt |
|
bld rFlags, fAlarmLevel |
|
|
|
; apaga pwm output |
|
lds r16, TCCR0A |
|
andi r16, ~(1<<COM0A0) |
|
sts TCCR0A, r16 |
|
|
|
; incrementa frames |
|
inc rFrames |
|
andi rFrames, MASK_FRAMES |
|
breq incrementsec ; salta si rFrames%8 == 0 |
|
reti |
|
|
|
incrementsec: |
|
inc rSegundos ; cuenta segundos |
|
|
|
lds r16, PORTB |
|
; en qué timer estamos? |
|
bst rFlags, fCualTimer |
|
brts checksegundos1 ; salta si es el 1 |
|
|
|
checksegundos0: |
|
bst rSegundos, 0 |
|
brts ledstate0off |
|
|
|
ledstate0on: |
|
ori r16, (1<<pinState0) |
|
rjmp comparesegundos0 |
|
|
|
ledstate0off: |
|
andi r16, ~(1<<pinState0) |
|
|
|
comparesegundos0: |
|
sts PORTB, r16 |
|
cpi rSegundos, DUR_ALARMA0 ; time == DUR_ALARMA0? |
|
brne updateminutes |
|
rjmp turnalarmoff |
|
|
|
checksegundos1: |
|
bst rSegundos,0 |
|
brts ledstate1off |
|
|
|
ledstate1on: |
|
ori r16, (1<<pinState1) |
|
rjmp comparesegundos1 |
|
|
|
ledstate1off: |
|
andi r16, ~(1<<pinState1) |
|
|
|
comparesegundos1: |
|
sts PORTB, r16 |
|
cpi rSegundos, DUR_ALARMA1 ; time == DUR_ALARMA0? |
|
brne updateminutes |
|
|
|
turnalarmoff: ; si es la duración correspondiente, apaga alarma |
|
clt |
|
bld rFlags, fAlarmOn |
|
|
|
updateminutes: |
|
cpi rSegundos,60 ; segundos == 60? |
|
breq minute |
|
reti |
|
|
|
minute: |
|
ldi rSegundos, 0 ; reset seconds |
|
inc rMinutos ; increment minutes |
|
|
|
bst rFlags, fCualTimer |
|
brts checkminutes1 |
|
|
|
checkminutes0: |
|
cpi rMinutos, DUR_TIMER0 |
|
breq firealarm |
|
reti |
|
|
|
checkminutes1: |
|
cpi rMinutos, DUR_TIMER1 |
|
breq firealarm |
|
reti |
|
|
|
firealarm: |
|
ldi rMinutos, 0 ; reset minutes |
|
; inicia alarma |
|
set |
|
bld rFlags, fAlarmOn |
|
; invierte timer |
|
bst rFlags, fCualTimer |
|
brts settimer0 ; salta si el timer es 1 |
|
|
|
settimer1: |
|
set |
|
bld rFlags,fCualTimer |
|
|
|
; cambia tono de alarma |
|
ldi r16, WAVE_PERIOD1 |
|
sts OCR0A, r16 |
|
|
|
; apaga otro led |
|
lds r16, PORTB |
|
andi r16, ~(1<<pinState0) |
|
sts PORTB, r16 |
|
reti |
|
settimer0: |
|
clt |
|
bld rFlags,fCualTimer |
|
|
|
; cambia tono de alarma |
|
ldi r16, WAVE_PERIOD0 |
|
sts OCR0A, r16 |
|
|
|
; apaga otro led |
|
lds r16, PORTB |
|
andi r16, ~(1<<pinState1) |
|
sts PORTB, r16 |
|
reti |
|
|
|
|
|
; enciende pin de alarma |
|
timer1compareB_isr: |
|
bst rFlags, fAlarmOn ; bit store |
|
|
|
; branch if T bit is set |
|
brts turnonalarmlevel |
|
reti |
|
|
|
turnonalarmlevel: |
|
; set alarmlevel on |
|
set |
|
bld rFlags, fAlarmLevel |
|
|
|
; enciende pwm output |
|
lds r16, TCCR0A |
|
ori r16, (1<<COM0A0) |
|
sts TCCR0A, r16 |
|
reti |
|
``` |
|
|
|
# makefile |
|
|
|
to assemble: |
|
|
|
``` |
|
make hex |
|
``` |
|
|
|
to flash: |
|
|
|
``` |
|
make flash |
|
``` |
|
|
|
## makefile |
|
|
|
``` |
|
# Makefile |
|
# nombre del programa sin .S : |
|
PROG = tomatimer |
|
# config hardware |
|
BOARD = attiny85 |
|
PROGRAMMER = usbasp |
|
|
|
# ensambla programa .S a .hex |
|
hex: |
|
avr-gcc -Os -DF_CPU=8000000 -mmcu=$(BOARD) -c $(PROG).S |
|
avr-ld -o $(PROG).elf $(PROG).o |
|
avr-objcopy $(PROG).elf -O ihex $(PROG).hex |
|
rm $(PROG).o $(PROG).elf |
|
|
|
# flashea |
|
flash: |
|
avrdude -c $(PROGRAMMER) -p $(BOARD) -U flash:w:$(PROG).hex:i |
|
|
|
# lee la memoria flash a read.hex |
|
read: |
|
avrdude -c $(PROGRAMMER) -p $(BOARD) -U flash:r:read.hex:i |
|
|
|
# prueba conexión con programador y micro |
|
test: |
|
avrdude -c $(PROGRAMMER) -p $(BOARD) |
|
```
|
|
|