; Battmon v1.0a 18/9/2004 ; ; ; Atmel ATtiny15L ;pin 1 RESET ;pin 2 ADC3 analouge input ((Vbatt-0.6)/3) ;pin 3 PB3 Roger Beep enable/disable (freq_up ;pin 4 GND ;pin 5 PB0/MOSI Push To Talk output and CAL input (pull high on powerup for CAL) ;pin 6 OC1A/PB1/MISO Transmit Audio output (10KHz cal) ;pin 7 PB2/SCK Receiver Squelch input (freq_down) ;pin 8 VCC ; .include "tn15def.inc" ;Register aliasing .def LOW_BATT=r0 ; ADC value for low battery .def A=r16 ;working register E .def D=r17 ;working register F .cseg .org 0 ;interrupt table rjmp RESET rjmp INT ; External Interrupt (INT0) Handler rjmp PCI ; Pin Change Interrupt handler reti reti reti reti reti reti .db "Ross Whenmouth 18/9/2004" RESET: ldi A, 0b10000000 ; disable analouge comparator to save power out ACSR, A ldi A, 0 ; load OSCCAL value from eeprom and write to OSCCAL register out EEAR, A ; set address sbi EECR, 0 ; strobe EERE in A, EEDR ; read the byte out OSCCAL, A ; write to OSCCAL io register ldi A, 1 ; load ADC value from eeprom and write to LOW_BATT register out EEAR, A ; set address sbi EECR, 0 ; strobe EERE in LOW_BATT, EEDR ; read the byte into LOW_BATT register in A, PINB sbrc A, 0 ; if PTT is pulled high goto calibration routine rjmp CAL ldi A, 0b00000100 ; set PORTB outputs to zero, turn on pullup on PB2 out PORTB, A ldi A, 0b00000011 out DDRB, A ; set PB0, PB1 as outputs ldi A, 0b00100011 ; set vref=vcc, input=ADC3/pin2, left-adjusted result (8 bit) out ADMUX, A MAINLOOP: ldi A, 0b00110000 ; enable sleep, set sleep mode = powerdown, INT0 on low level out MCUCR, A ; sleep until the the radio receiver pulls PB2 to ground (squelch opened) cli ; global interrupt disable ldi A, 0b01000000 out GIMSK, A ; enable INT0 ldi A, 0b01000000 out GIFR, A ; clear INT0 flag sei ; global interrupt enable sleep sbic PINB, PB2 ; if (PB2 != 0) then the cpu was woken by noise or another pin rjmp MAINLOOP ; go back to sleep! sbi PORTB, PB0 ; turn on PTT ; go back to sleep until the squelch closes and stays closed for 100ms ; PB2 will go high when the squelch closes (pinchange interrupt) WAIT_QSO: cli ; global interrupt disable ldi A, 0b00100000 out GIMSK, A ; enable PCI ldi A, 0b00100000 out GIFR, A ; clear PCI flag sei ; global interrupt enable sleep rcall DELAY sbis PINB, PB2 ; if PB2 != 1 then the cpu was woken by noise or another pin rjmp WAIT_QSO ; go back to sleep sbi PORTB, 3 ; turn on PB3 pullup ; sqelch has closed, compare battery voltage to LOW_BATT cli ; global interrupt disable ldi A, 0b10001101 ; enable the ADC and ADC interrupt, CK/32 clock (50KHz) out ADCSR, A ldi A, 0b00101000 ; change sleep mode to ADC Noise Reduction mode out MCUCR, A sei ; global interrupt enable sleep ; do ADC conversion in A, ADCH ; put current battery voltage into A cbi ADCSR, 7 ; disable ADC ADEN cbi ADCSR, 3 ; disable ADC ADIE cp A, LOW_BATT brlo ALARM ; if battery voltage is lower than V_BATT, sound alarm sbic PINB, PB3 ; if PB3 pulled low make `Roger beep' tone rjmp END ; inject roger beep tone into TX audio ldi A, 0 out TCNT1, A ; clear timer1 counter register ldi A, 133 out OCR1A, A ; set tone frequency to 750Hz ldi A, 0b10011000 ; set clear on compare match, toggle OC1A on compare match, and ck/8 out TCCR1, A ; start the timer rcall DELAY ; wait approx 200ms before terminating tone rcall DELAY ldi A, 0 out TCCR1, A ; disable timer (stop the tone) cbi PORTB, PB1 ; ensure PB1 is turned off rjmp END ALARM: ; inject alarm tones into TX audio ldi A, 0 out TCNT1, A ; clear timer1 counter register ldi A, 100 out OCR1A, A ; set tone frequency to 1000Hz ldi A, 0b10011000 ; set clear on compare match, toggle OC1A on compare match, and ck/8 out TCCR1, A ; start the timer rcall DELAY ; approx 200ms till next tone rcall DELAY ldi A, 133 out OCR1A, A ; set tone frequency to 750Hz ldi A, 0 out TCNT1, A ; clear timer1 counter register rcall DELAY ; approx 200ms till next tone rcall DELAY ldi A, 100 out OCR1A, A ; set tone frequency to 1000Hz rcall DELAY ; approx 200ms till next tone rcall DELAY ldi A, 133 out OCR1A, A ; set tone frequency to 750Hz ldi A, 0 out TCNT1, A ; clear timer1 counter register rcall DELAY ; approx 200ms till next tone rcall DELAY ldi A, 0 out TCCR1, A ; disable timer (stop the tone) cbi PORTB, PB1 ; ensure PB1 is turned off END: cbi PORTB, PB0 ; turn off PTT cbi PORTB, PB3 ; turn off PB3 pullup rjmp MAINLOOP PCI: ldi A, 0 out GIMSK, A ; disable PCI reti INT: ldi A, 0 out GIMSK, A ; disable INT0 reti DELAY: ldi D, 100 ;set timer0 counter to 99 (count from 99 to 255) out TCNT0, D in D, TIFR ;clear timer0 overflow flag sbr D, 0b00000010 out TIFR, D ldi D, 0b00000101 ;set timer0 clock to ck/1024 (starts timer) out TCCR0, D DELAY_LOOP: ;loop until timer0 overflows (approx 100ms with CK=1.6MHz) in D, TIFR sbrs D, 1 ;if timer0 has overflowed then break out of loop rjmp DELAY_LOOP in D, TIFR ;clear timer0 overflow flag sbr D, 0b00000010 out TIFR, D ldi D, 0 out TCCR0, D ;stop timer0 clock ret CAL: ldi A, 0b00001100 ; set PORTB outputs to zero, turn on pullup on PB2 & PB3 out PORTB, A ldi A, 0b00000010 out DDRB, A ; set PB1 as output ldi A, 0 out TCNT1, A ; clear timer/counter ldi A, 7 out OCR1A, A ; set PWM duty cycle (7+1) / (15+1) = 1:1 ldi A, 15 out OCR1B, A ; set PWM cycle length CK / (15+1) = 100KHz ldi A, 0b01100101 out TCCR1, A ; set timer1 to PWM mode & start clocking @ CK (output on OC1A) CAL_OSC_LOOP: sbic PINB, PB3 ; if freq_up on then increment OSCCAL rjmp CAL_OSC_DEC in A, OSCCAL ; read OSCCAL inc A ; increment it out OSCCAL, A ; write back to OSCCAL rcall DELAY rcall DELAY ; wait approx 200msec CAL_OSC_DEC: sbic PINB, PB2 ; if freq_down on then decrement OSCCAL rjmp CAL_OSC_NULL in A, OSCCAL ; read OSCCAL dec A ; decrement it out OSCCAL, A ; write back to OSCCAL rcall DELAY rcall DELAY ; wait approx 200msec CAL_OSC_NULL: sbic PINB, PB0 ; break from loop if calibrate jumper is removed rjmp CAL_OSC_LOOP cli ; disable all interrupts CAL_OSC_not_rdy: sbic EECR,1 ; wait until eeprom ready rjmp CAL_OSC_not_rdy ldi A, 0 ; set the adress to write to out EEAR, A in A, OSCCAL ; read OSCCAL byte into A register out EEDR, A ; put the OSCCAL byte to write into the EEDR sbi EECR, 2 ; set MASTER write enable sbi EECR, 1 ; set write enable (strobe) ldi A, 0 out TCCR1, A ; turn off timer1 to indicate completion of calibration sei ; re-enable interrupts ldi A, 0b00100011 ; set vref=vcc, input=ADC3/pin2, left-adjusted result (8 bit) out ADMUX, A ldi A, 0b10001101 ; enable the ADC and ADC interrupt, CK/32 clock (50KHz) out ADCSR, A ldi A, 0b00101000 ; enable ADC noise reduction sleep mode out MCUCR, A rcall DELAY ; give the ADC a chance to stabilise rcall DELAY rcall DELAY sleep ; sleep and do ADC conversion in LOW_BATT, ADCH ; read low battery voltage from ADC cli ; disable all interrupts CAL_BATT_not_rdy: sbic EECR,1 ; wait until eeprom ready rjmp CAL_BATT_not_rdy ldi A, 1 ; set the adress to write to out EEAR, A out EEDR, LOW_BATT ; put the ADC battery voltage byte to write into the EEDR sbi EECR, 2 ; set MASTER write enable sbi EECR, 1 ; set write enable (strobe) sei ; re-enable interrupts ldi A, 0b00000001 ; set PB0 as output out DDRB, A CAL_DONE: ; flash PB0 at 2.5Hz to indicate end of calibration rcall DELAY rcall DELAY sbis PORTB, PB0 rjmp CAL_FLASH cbi PORTB, PB0 rjmp CAL_DONE CAL_FLASH: sbi PORTB, PB0 rjmp CAL_DONE