\begin{verbatim} ;Morse1.asm ;Dhananjay V. Gadre ;4th June, 1999 ;last revision 6th June 1999 ;Synopsis: ;--------- ;A simple Morse keyer with speed adjust. ;Input= 3 switches. ;The switches are: Mode, playdot/decrement and playdash/increment ;switches. playdot and playdash switches at the input ;serve as dot and dash paddles. Pressing the playdot switch ;generates a tone for a dot duration, while pressing the playdash ;switch generates a tone for a dash duration. ;If the playdot/playdash switches are held pressed, then ;the dot/dash generation is repeated with a gap of dot duration. ;If the Mode switch is pressed, and the decrement(playdot) switch ;is pressed, it reduces the speed while pressing the increment ;switch(playdash) while keeping the Mode switch pressed increases ;the speed (i.e. reduces the dot/dash time duration) ;When the Mode switch is pressed, Mode LED is lit ON ;The default dot duration is that for 12 words per minute .include "1200def.inc" ;Crystal freq is 4.000 MHz .equ T1 = -70 ; reload value for Tone 1 .equ TONE_ON=255 .equ TONE_OFF=0 .equ LOW=20 ;limits for the count that determine the speed .equ HIGH=240 .equ PLAYDOT=0 ;key codes for various activities .equ PLAYDASH=1 .equ INCSPEED=2 .equ DECSPEED=3 .def save_status = r0 ;used to store the SREG during an ISR .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 .cseg .org 0 rjmp RESET ;Reset Handle rjmp RESET ;for IRQ0 rjmp Timer0_int ;Timer0 Interrupt Subroutine rjmp RESET ;for Ananlog Comparator ; Initialization Section RESET: 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, 0 ;configure PORT D for all inputs out DDRD, sundry ldi sundry, 255 ;put on the pull ups on PORTD so ;that the switches can be read out PORTD, sundry ldi sundry, 255 out DDRB, sundry ;configure PORTB as output ldi sundry, $ff ;everything on PORTB is off out PORTB, sundry ldi count, 100 ;default duration is for 5WPM ldi count_low, 99 ldi temp_count, 0 ;current duration is 0 sei ldi stat_flag, TONE_ON ldi temp_count, 0 ;This is the main part of the program ;The program just loops to get a key stroke and ;to act accordingly. It allows 4 actions: play a dot, play a ;dash, increment speed or decrement speed loop_here: rcall get_keycode cpi key_val, PLAYDOT breq play_dot cpi key_val, PLAYDASH breq play_dash cpi key_val, INCSPEED breq inc_speed cpi key_val, DECSPEED breq dec_speed rjmp loop_here ;This segment just plays the tone for a dot duration ;followed by no tone for another dot duration play_dot: ldi temp_count, 0 ldi stat_flag, TONE_ON more_dot: cpi stat_flag, TONE_ON breq more_dot ldi temp_count, 0 dot_d1: cp temp_count, count brne dot_d1 rjmp loop_here ;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: 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 ldi temp_count, 0 dot_d2: cp temp_count, count brne dot_d2 rjmp loop_here ;This increases the dot/dash duration ;thus reducing the speed dec_speed: cpi count, HIGH ;compare if upper limit is reached breq nomore ;then dont increase anymore ldi temp, 10 ;else increase count by 10 add count, temp add count_low, temp nomore: rjmp loop_here ;This decreases the dot/dash duration thus ;increasing the speed. inc_speed: cpi count, LOW ;check is lower limit is reached breq noless ;dont reduce any more subi count, 10 'else reduce count by 10 subi count_low, 10 noless: rjmp loop_here ;This routine returns a key code depending upon the ;combination of keys that are pressed ;key/s pressed key code ;------------- -------- ;PD0 PLAYDOT ;PD1 PLAYDASH ;PD0 and PD2 DECSPEED ;PD1 and PD2 INCSPEED get_keycode: sbis PIND, 2 ;if PD2 is pressed then light up cbi PORTB, 0 ;LED on PB0 sbic PIND, 2 ;else put it off sbi PORTB, 0 ;LED is active LOW sbis PIND, 0 ;if PD0 is pressed rjmp some_key sbis PIND, 1 ;or PD1 is pressed rjmp some_key ;then act on it rjmp get_keycode ;else just loop around some_key: in key_val, PIND ori key_val, 0b11111000 mov temp, key_val cpi temp, 0b11111110 ;if PD0 is pressed brne not1 ;set key code to PLAYDOT and return ldi key_val, PLAYDOT ret not1: cpi temp, 0b11111101 ;if PD1 is pressed brne not2 ;then PLAYDASH ldi key_val, PLAYDASH ret not2: cpi temp, 0b11111010 ;if PD0 and PD2 then DECSPEED brne not3 ldi key_val, DECSPEED ;also wait for the PD0 key to rjmp got_it ;be released and debounced not3: cpi temp, 0b11111001 ;if PD1 and PD2 then INCSPEED brne get_keycode ldi key_val, INCSPEED got_it: in temp, PIND ;wait for PD1 or PD0 to be ori temp, 0b11111100 ;released cpi temp, 255 brne got_it ldi high_del, 20 ;then debounce it with a small load_low: ;delay ldi temp, 100 decit: dec temp brne decit dec high_del brne load_low ret ;now return ;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, $7f 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, $80 ;PB7 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 \end{verbatim}