compudanzas/src/tomatimer.gmo

348 lines
6.5 KiB
Plaintext
Raw Permalink Normal View History

2021-12-17 19:26:33 +00:00
# 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)
```