;
; morse.asm -- send morse code...
;
; also includes some local labels (for testing...)
;

;
; example source code for picasm by Timo Rossi
;

;
; define PIC device type
;
	device	pic16f84

;
; define config fuses
;
	config	CP=off,WDT=off,PWRT=off,OSC=hs

;
; include PIC register definitions, and some macros
;
	include "pic16f84.i"
	include "picmac.i"

;
; include file with morse code definition macros
;
	include "morse.i"

;
; bit definitions for port A
;
A_MOUT	equ	0	;morse code output (buzzer)
A_LED2	equ	1	;led (not really used in this program)


DOT_DELAY	equ	15
DASH_DELAY	equ	3*DOT_DELAY

;
; define some register file variables
;

	org	$0C

delay_cnt	ds	1	;200hz delay counter

d_cnt		ds	1	;internal delay counter

morsebyte	ds	1
bitcnt		ds	1

pa_xor_val	ds	1

temp_w		ds	1
temp_s		ds	1

;
; define a morse code message in data EEPROM
;
	org	0

	morsedata edata,"hello world "

	edata	0	;end marker
;
; code start
;
	org	0
	goto	reset_entry


	org	4
;
; interrupt entry point
;
; 4MHz crystal --> 1MHz instruction clock
; TMR0 free-running, prescaler divides by 4 -->
;
; timer interrupt occurs 976 times per second
;
	save_w_stat

	decf	d_cnt,F
	bnz	int_a

	movlw	5
	movwf	d_cnt

;
; delay_cnt is decremenmented every 6's interrupt
; --> 195 times per second (delay approx 5 ms)
;
	decf	delay_cnt,F

int_a
;
; sound is generated by toggling the buzzer output once per interrupt,
; so the fundamental frequency is 488 Hz.
;
	movf	pa_xor_val,W
	xorwf	PORTA,F

	bcf	INTCON,T0IF
	restore_w_stat
	retfie

reset_entry:
	movlw	0xff
	movwf	PORTA	;initialize port A so that LED and buzzer are off

	bsf	STATUS,RP0			;register page 1
	movlw	~((1<<A_MOUT)|(1<<A_LED2))	;LEDs as outputs,
	movwf	TRISA^80h			;other PORTA pins as inputs

; timer counts instruction cycles, assign prescaler to timer, divide by 4
; (and disable port B weak pull-ups)
	movlw	(1<<RBPU)|(1<<PS0)
	movwf	OPTION_REG^80h

	bcf	STATUS,RP0			;register page 0

	movlw	1
	movwf	d_cnt

	clrf	pa_xor_val

	movlw	(1<<T0IE)|(1<<GIE)	;enable timer interrupt
	movwf	INTCON

restart_string
	clrf	EEADR

loop
	bsf	STATUS,RP0	;reg. page 1
	bsf	EECON1^80h,ERD	;read EEPROM
	bcf	STATUS,RP0	;reg. page 0
	movf	EEDATA,W
	bz	restart_string

	call	send_morse_char
	incf	EEADR,F
	goto	loop

;
; send one morse code character
; character code (generated by the morsechar macro) in W
;
send_morse_char
	movwf	morsebyte
	comf	morsebyte,W
	bz	send_space

	movlw	7
	movwf	bitcnt

	local

skip_pad_loop
	brset	morsebyte,7,=skipped
	decf	bitcnt,F
; we don't care if carry is set or not, the bits shifed in
; by the following instruction are not used anyway
	rlf	morsebyte,F
	goto	skip_pad_loop

=skipped
	rlf	morsebyte,F

	endlocal

	local
=loop
	btfss	morsebyte,7
	call	dot
	btfsc	morsebyte,7
	call	dash
	rlf	morsebyte,F

	movlw	DOT_DELAY
	call	delay

	decfsz	bitcnt,F
	goto	=loop

	endlocal

	movlw	2*DOT_DELAY	;inter-character gap
	call	delay
	return

send_space
	movlw	2*DOT_DELAY
	call	delay
	movlw	3*DOT_DELAY
	call	delay
	return

dash	movlw	DASH_DELAY
	goto	dot_dash

dot	movlw	DOT_DELAY

dot_dash
	bsf	pa_xor_val,A_MOUT	;start sound
	call	delay
	bcf	pa_xor_val,A_MOUT	;end sound
	bsf	PORTA,A_MOUT		;make sure the buzzer is off
	return

	local
;
; delay approx. W*5ms
;
delay	movwf	delay_cnt
=loop
	bpos	delay_cnt,=loop
	return

	endlocal

	end
