;-----------------------------------------------------------------------; ; MORSENBR.ASM Send numbers 0-9 in morse code to speaker and LEDs ; ;-----------------------------------------------------------------------; LIST P=16F84 ; tells which processor is used INCLUDE "p16f84.inc" ; defines various registers etc. Look it over. ERRORLEVEL -224 ; supress annoying message because of tris __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; configuration switches CBLOCK H'C' temp ; a temporary variable bitcount ; counter for bits nbr ; holds current number to send ENDC ORG 0 ; start at location 0 goto main ; jump over to main routine ;-----------------------------------------------------------------------; ; Use W to convert number in W to pattern needed to send # ; ;-----------------------------------------------------------------------; pattern: addwf PCL, f ; PCL points to the first entry in the table dt H'1F',H'0F',H'07',H'03',H'01',H'00',H'10',H'18',H'1C',H'1E' ; 0 1 2 3 4 5 6 7 8 9 ;-----------------------------------------------------------------------; ; Delay routine ; ;-----------------------------------------------------------------------; nmsec: ; delay for # msec in W on entry nop ; each nop is 0.122 milliseconds nop nop ; each total loop is 8 X 0.122 = 0.976 msec nop addlw H'FF' ; same as subtracting 1 from W btfss STATUS, Z ; skip if result is zero goto nmsec ; this is 2 X 0.122 msec return ; back to calling point ;-----------------------------------------------------------------------; ; Sound routine lasting about 100 milliseconds ; ;-----------------------------------------------------------------------; snd1: movlw D'153' ; 103 additional would mean roll-over sndloop: bsf PORTA,3 ; RA3 high nop nop bcf PORTA,3 ; RA3 low addlw 1 ; bump W and check for roll-over to 0 btfss STATUS, Z ; 8 instructions in loop goto sndloop ; 0.122 msec/instruction return ; 103 loops ;-----------------------------------------------------------------------; ; Output number in W to LEDs on Port B and to spkr on RA3 ; ;-----------------------------------------------------------------------; sendnbr: movwf PORTB ; display number on LEDs call pattern ; get pattern of dits and dahs movwf temp ; save it movlw 5 ; total of 5 dits or dahs ... movwf bitcount ; into a counter bitloop: btfss temp, 4 ; check 5th bit, if it is 1, send dah call dit ; else it is 0, send dit btfsc temp, 4 ; and skip next instruction call dah ; get here only if bit 5 is 1 rlf temp, f ; rotate left once giving new bit 5 decfsz bitcount, f ; are we finished? goto bitloop ; no, send new bit 5 clrf PORTB ; yes, turn display off return ;-----------------------------------------------------------------------; ; Dit routine ; ;-----------------------------------------------------------------------; dit call snd1 ; 100 msec of tone movlw D'100' ; followed by 100 msec of silence call nmsec return ;-----------------------------------------------------------------------; ; Dah routine ; ;-----------------------------------------------------------------------; dah: call snd1 ; 100 msec of tone call snd1 ; stretch it to 300 msec call snd1 movlw D'100' ; and 100 msec of silence call nmsec return ;-----------------------------------------------------------------------; ; Wait until button on RB4 is released ; ;-----------------------------------------------------------------------; waitup: btfss PORTB, 4 ; test RB4 goto $ -1 ; ck again if pressed movlw D'10' call nmsec ; wait 10 msec for debounce btfss PORTB, 4 ; check again, still up? goto waitup ; no start over return ; yes, finished ;-----------------------------------------------------------------------; ; Initialization Subroutine ; ;-----------------------------------------------------------------------; init: movlw 0 ; RA0 - RA4 outputs tris PORTA movlw H'10' ; all outputs except RB4 tris PORTB ; on port B movlw H'0' ; all outputs low (off) movwf PORTB movwf PORTA movlw 0 ; pull-ups enabled option return ;-----------------------------------------------------------------------; ; Main routine, sends a new number each time button pressed ; ;-----------------------------------------------------------------------; main: call init ; set up ports etc start: clrf nbr ; start with nbr = 0 mainloop: call waitup btfsc PORTB, 4 ; wait on button press goto $ -1 movf nbr, W ; get number into W call sendnbr ; and output it incf nbr, f ; set up for next number movlw H'0A' ; reached 10? subwf nbr, W btfss STATUS, Z ; yes start again at 0 goto mainloop ; no, wait for next button press goto start end
A major addition in this program is using a table to get patterns describing the dits and dahs to be sent. It appears right at the first of the assembly listing. The register PCL represents the low 8 bits of the program counter, ( tells where the next instruction comes from ). When a call to pattern is made the instruction 'addwf PCL, f' is executed. Just before the instruction is executed, PCL points at the instruction. After the instruction is executed PCL would normally point to the next memory location, but the instruction itself modifies PCL. If W = 0, then indeed no modification is made and the first entry in the data table, (dt), is taken as the next instruction. If W = 1, it is the 2nd entry in the table and so on.
The data table assembles as a bunch of 'retlw' instructions which in words says: ' return from the subroutine but first put this literal, (number), in W'. That is, in this case; retlw H'1F', retlw H'0F', retlw H'07' etc. So you see that the result of calling 'pattern' is to place a number in W given by the table value specified by W on entry. You of course have to stay within the table. If W is too large on entry you will overun the table.
The routine 'snd1' is like a delay routine with toggling of pin RA3 built in. The loops are 1 msec long and flipping is about half way through, meaning a almost square wave of frequency 1 kHz. The speaker is a piezoelectric speaker which is looks like a capacitor as a load. The 100 ohm resistor prevents a large inrush current. If you have a voice coil speaker you might also try it with a 100 resistor. Unless it is fairly high impedance, you may not get a very loud sound. Piezo speakers with a paper cone attached seem to give louder sound. I have what I think is a Radio Shack 40-1383 which works well.
This instructions rotates the bits of register f left through carry. Each bit 0 - 6 moves one bit position higher and the carry bit of STATUS moves into bit 0. Bit 7 is pushed into the carry bit of STATUS. There is also and instruction 'rrf', ( roll right through carry ), which moves the bits the other way. If you are concerned about the bits coming in from carry you should set, ( bsf STATUS, C), or clear, ( bcf STATUS, C ), carry before you do the shift. In this program we are only interested in getting the original bits 4-0 into the bit 4 position in order.
The program is supposed to be used to learn morse code numbers but it's too easy if you know what the next number is to be. How about changing it so you get a random number between 0 and 9. Where can we get a random number? How about TMR0? It is continually running and the press of the button should be fairly random. Can you write the code? Hint: how about adding a random number 0-2 to a random number 0-8 and not allowing 10?
How about sending the value of an external BCD switch out the speaker whenever a button is pressed? The switch could be hooked to RB4-RB7, with the pushbutton moved to RA0. Remember that Port A has no internal pull-up resistors, you will need to supply and external one.
The output from the Counter in program #2 could also be output to the speaker with the routines contained here. What happens when you get to double digits though, (10-15)? One way to handle this is to have a units and a tens register as in program #3. What if another button press comes in while the current number is being output on the speaker? Perhaps the counting can be done using an interrupt routine.
The code for this program was simplified considerably because it sends only numbers. Morse digits are all 5 dot-dash combinations long. Not so with other Morse characters. Can you think of a scheme to handle various length combinations?
One way to do this is to make all higher order bits not used zeros and then use a one to signify that all lower bits make up the valid pattern. Could you write the code to decode such a pattern?
Interested:
Comments:
See: