;mtutor1.asm ;Radio Beacon Controller ;Dhananjay V. Gadre ;22 July, 1999 ;final 25th July ;Synopsis: ;--------- ;Radio Beacon Controller plays morse code stored ;in it's internal EEPROM memory over repeatedly. ;The time between repeating the message is programmable ;from 2 seconds to about 500 seconds (about 8 minutes) ;The speed at which the code is played is also programmable ;from 5 wpm to 30 wpm ;The message to be played is stored in the internal EEPROM ;as a sequence of numbers. Each number corresponds to a morse ;code as shown in the table below. 0 corresponds to A, 1 ;corresponds to B, 2 corresponds to C etc. ;The controller produces 2 outputs: a transmitter key output ;and a sidetone audio output. The sidetone audio output signal ;drives a miniature piezo speaker for audio monitoring. ;The morse code itself is composed of 1 word. ;The lower byte, lower nibble indicates how ;many character long is the code. THe higher byte has the morse ;symbols: 0 is a dot and 1 is a dash ;The processr is ATTiny22, but the nearest .def is used. .include "2323def.inc" ;Clock source is the internal RC oscillator at 1 MHz .equ T1 = -18 ; reload value for the audio tone .equ TONE_ON=255 .equ TONE_OFF=0 .equ LOW=20 ;limits for the count that determine the speed .equ HIGH=240 .equ rst_count_ptr=$70 ;SRAM mem location that holds a software ;counter to count the number of watchdog ;resets that have occured .equ SLEEPTIME=10 ;this corresponds to about 20 seconds of sleep .equ SPEED=70 .def save_status = r1 ;used to store the SREG during an ISR .def eep_offset =r2; used to dip into the morse message table .def sundry=r16 .def temp_count=r17 ;to keep track of time duration for which ;note is played .def count=r18 ;Time for which the tone is played on the ;output pin PORTB7 .def key_val=r19 ;key code. Keys are on PORTD0, 1 and 2 ;code is 0, 1 and 2 .def count_low=r20 ;one less than value in count register .def high_del=r21 ;another delay variable .def stat_flag=r22 ;status flag indicates whether to play the tone .def temp=r23 ;temperory variable .def temp1=r24 ;another temperory variable .def temp2=r25 ;yet another temporary variable .def play_t=r26 ;play note 0 .def random_num=r27 ;either a sequential or randum number .cseg .org 0 rjmp RESET ;Reset Handle .org 2 rjmp Timer0_int ;Timer0 Interrupt Subroutine RESET: ldi temp, low(RAMEND) ;init the stack pointer out SPL, temp ldi ZL, rst_count_ptr ;init the reset counter pointer ldi ZH, 0 in temp, MCUSR ;check source of reset andi temp, $03 breq its_wdr ;if it is 0, then it is watch dog reset ldi temp, 0 ;else it is external or power on reset out MCUSR, temp ;so reset the POR and EXTR flags ldi count, 0 ;reset the count st Z, count rjmp work_todo its_wdr: ;if this is watch dog reset ld count, Z ;then get the software count cpi count, SLEEPTIME ;compare with max_count breq ok_doit ;if they are equal, then do the Job inc count ;else increment the count st Z, count ;store it back in SRAM rjmp endtrans ok_doit: ;its time to do the job ldi count, 0 ;reset the count st Z, count work_todo: ldi stat_flag, TONE_OFF ;status flag to indicate ;whether to toggle output ;tone bit ldi sundry, 3 ;DIV64 selected for timer0 out TCCR0, sundry ;timer 0 counts up now ldi sundry, 2 ;Set the TOIE0 bit to enable out TIMSK, sundry ;the Timer0 Interrupt to occur ldi sundry, T1 ;Load note 1 count in Timer0 out TCNT0, sundry ; ldi sundry, 255 out DDRB, sundry ;configure PORTB as output ldi sundry, 0 ;everything on PORTB is off out PORTB, sundry ldi count, SPEED ;default duration is for 12WPM ldi count_low, SPEED-1 ldi temp, 0 mov eep_offset, temp ldi temp_count, 0 ;current duration is 0 sei ldi stat_flag, TONE_ON ldi temp_count, 0 ldi ZH, high(morse_table*2) ldi ZL, low(morse_table*2) ;init the Z-pointer ;This is the main part of the program loop_here: rcall get_number ;get a number as an offset into the andi random_num, $3f ;morse table rol random_num ;multiply it by 2 just_fine: ldi ZH, high(morse_table*2) ldi ZL, low(morse_table*2); init the Z-pointer add ZL, random_num ;add offset lpm ;get the count of characters mov sundry, r0 ;sundry has the count adiw ZL, 1 lpm ;get the symbols mov random_num, r0 ;random_num has the morse char andi sundry, 0b00001111 cpi sundry, 0b00001001 breq big_space ;if count = 9 then word space cpi sundry, 0b00001111 ;if count = 15 then end of transmission breq endtrans cpi sundry, 0 ;if count=0, means that is a problem breq loop_here rjmp gen_morse ;else generate morse big_space: rcall playspace ;after each morse character rjmp loop_here ;no sound for 3T (total) gen_morse: rol random_num brcc its_dot rcall play_dash rjmp skip_next its_dot: rcall play_dot skip_next: dec sundry cpi sundry, 0 breq play_end ;since the character is played ;wait for 2T time before next char rjmp gen_morse play_end: rcall playspace ;this routine just waits for 2T time ;and then returns rjmp loop_here endtrans: cli rcall enb_wdt ;enable the watch dog timer go_sleep: ;and sleep ldi temp, $30 ;in power down mode out MCUCR, temp sleep rjmp endtrans get_number: ldi ZL, low(morse_msg) add ZL, eep_offset inc eep_offset eep_notrdy: sbic EECR,1 ;skip if EEWE clear rjmp eep_notrdy ;Waits until EEPROM ready read: out EEAR, ZL ;output address low sbi EECR, 0 ;set EERE (Read-strobe) nop nop in random_num, EEDR ;inputs data ret ;This segment just plays the tone for a dot duration ;followed by no tone for another dot duration play_dot: sbi PORTB, 1 ldi temp_count, 0 ldi stat_flag, TONE_ON more_dot: cpi stat_flag, TONE_ON breq more_dot cbi PORTB, 1 ldi temp_count, 0 dot_d1: cp temp_count, count brne dot_d1 ret ;This segment plays tone for a dash duration (which is ;three times the dot duration) followed by no tone ;for a dot duration. play_dash: sbi PORTB, 1 ldi stat_flag, TONE_ON ldi temp_count, 0 dash1: cp temp_count, count_low brne dash1 ldi temp_count, 0 dash2: cp temp_count, count_low brne dash2 ldi temp_count, 0 dash3: cpi stat_flag, TONE_ON breq dash3 cbi PORTB, 1 ldi temp_count, 0 dot_d2: cp temp_count, count brne dot_d2 ret ;this produces silence for 2 time periods. Used at ;the end of a morse character. playspace: ldi temp_count, 0 pls1: cp temp_count, count brne pls1 ldi temp_count, 0 pls2: cp temp_count, count brne pls2 ret ;silence for 5T time. Used for inter word spacing playwspace: ldi temp_count, 0 plw1: cp temp_count, count brne plw1 ldi temp_count, 0 plw2: cp temp_count, count brne plw2 ldi temp_count, 0 plw3: cp temp_count, count brne plw3 ldi temp_count, 0 plw4: cp temp_count, count brne plw4 ldi temp_count, 0 plw5: cp temp_count, count brne plw5 ret ;Timer0 Interrupt Subroutine. Timer0_int: in save_status, SREG ;save machine state ldi play_t, T1 ;reload TCNT0 register out TCNT0, play_t ;so that Timer0 int can occur inc temp_count ;increment the count which keeps ;track of how many ISRs have occurred cpi stat_flag, TONE_OFF ;chk if tone is to be played brne carry_on ;else put PB7 to logic 0 in temp2, PORTB andi temp2, $fe out PORTB, temp2 rjmp no_tone carry_on: cp temp_count, count ;check if play brne play_it ;duration is over ldi stat_flag, TONE_OFF ;reset the flag then rjmp no_tone play_it: in stat_flag, PORTB ;esle prepare to toggle the ldi temp2, $1 ;PB0 bit which generates eor stat_flag, temp2 ;the tone out PORTB, stat_flag ldi stat_flag, TONE_ON no_tone: out SREG, save_status ;restore machine state and reti ;return enb_wdt: ;enable the watch dog timer wdr ldi temp, $0f out WDTCR, temp ret .org 0X200 morse_table: ;char offset .db 2, 0b01000000 ;A .- 0 .db 4, 0b10000000 ;B -... 1 .db 4, 0b10100000 ;C -.-. 2 .db 3, 0b10000000 ;D -.. 3 .db 1, 0b00000000 ;E . 4 .db 4, 0b00100000 ;F ..-. 5 .db 3, 0b11000000 ;G --. 6 .db 4, 0b00000000 ;H .... 7 .db 2, 0b00000000 ;I .. 8 .db 4, 0b01110000 ;J .--- 9 .db 3, 0b10100000 ;K -.- 10 .db 4, 0b01000000 ;L .-.. 11 .db 2, 0b11000000 ;M -- 12 .db 2, 0b10000000 ;N -. 13 .db 3, 0b11100000 ;O --- 14 .db 4, 0b01100000 ;P .--. 15 .db 4, 0b11010000 ;Q --.- 16 .db 3, 0b01000000 ;R .-. 17 .db 3, 0b00000000 ;S ... 18 .db 1, 0b10000000 ;T - 19 .db 3, 0b00100000 ;U ..- 20 .db 4, 0b00010000 ;V ...- 21 .db 3, 0b01100000 ;W .-- 22 .db 4, 0b10010000 ;X -..- 23 .db 4, 0b10110000 ;Y -.-- 24 .db 4, 0b11000000 ;Z --.. 25 .db 5, 0b01111000 ;1 .---- 26 .db 5, 0b00111000 ;2 ..--- 27 .db 5, 0b00011000 ;3 ...-- 28 .db 5, 0b00001000 ;4 ....- 29 .db 5, 0b00000000 ;5 ..... 30 .db 5, 0b10000000 ;6 -.... 31 .db 5, 0b11000000 ;7 --... 32 .db 5, 0b11100000 ;8 ---.. 33 .db 5, 0b11110000 ;9 ----. 34 .db 5, 0b11111000 ;0 ----- 35 .db 9, 0b00000000 ;SPACE 36 .db 15, 0b00000000 ;end 37 .eseg .org 0 ;Start of the message morse_msg: .db 2 ;C .db 16 ;Q .db 36 ;SPACE .db 2 ;C .db 16 ;Q .db 36 ;SPACE .db 2 ;C .db 16 ;Q .db 36 ;SPACE .db 3 ;D .db 4 ;E .db 36 ;SPACE .db 21 ;V .db 20 ;U .db 27 ;2 .db 13 ;N .db 14 ;O .db 23 ;X .db 37 ;END of sequence .db 37