;Dick Cappels' project pages sap@cappels.org - you shoudl be able to copy and paste this text into an assembler file.   ;©2002 Richard Cappels All Rights Reserved;Use of information presented on this page is for personal, nonprofit educational;and noncommercial use only. This material (including object files) is copyrighted;by Richard Cappels and may not be republished or used directly for commercial ;purposes without explicit permission For commercial license, click HERE.;;HOME;******************************************************;Send and receive FM data, pass through UART at 9600 baud;******************************************************   .include "2313def.inc" ; 	memory index	=r0	; used for fetching strings from memory.def	bitsout		= r02	; counter for bits sent (couple also use a delay counter).def	sendheader	= r03	;headerr to place on outgoing RF byte.def	receiveaddress	= r04	; Address mask for RF received data header    .def	temp 		= r16	; Scratch register..def	tcounter	= r17   ; 8 Bit loop timing counter..def	delaycounter	= r18	; Delay to increase time measureble with 8 bit tcounter.   .def	runincount	= r19	; Used to keep track of consecutive zeros detected in runin code..def	wirelessdat 	= r19	; data to be sent via wireless port			;REGISTER 19 USED TWICE ON PURPOSE   .def	inbyte		= r20	; Decoded data byte could be same register as runincoung   .def	header		= r21.def	outbyte		= r21	;Byte value to be sent (input to send routine)			;REGISTER 21 USED TWICE ON PURPOSE   .equ	minzeros	= 9	;Minimum number of consecutive zeros to qualify as run-in code   .equ	defaultsendheader = $10 ;Default value of RF sendingheaderr..equ	defaultreceiveaddress =$02 ;Default value for RF receiveing address in header      .equ	RFxmitdat	= 5	Port bit used to send transmit data to RF transmitter.equ	RFrcvdat	= 6	Port bit used to receive data from RF receiver   				;SETTING UP THE UART.equ	clock		= 4000000		;clock frequency.equ	baudrate	= 9600		;choose a baud rate.equ	baudkonstant 	= (clock/(16*baudrate))-1   ; Used for memory index	= ZL,ZH   ;PORT D;	bit 0	this pin used for UART RX pin;	bit 1	this pinused for UART TX pin;	bit 5	Send data to RF transmitter;	bit 6	receive data from RF receiver   ;EEPROM;0 not used;1 sendheader;2 receiveaddress      .cseg.ORG $0000		;START INITIALIZATION	ldi     temp,low(ramend)	out     spl,temp     	;Set the 8 bit stack pointer to the top of ram.		ldi	temp,baudkonstant;load baud rate into the UART 	out	ubrr,temp			cbi	PORTD,RFrcvdat	;no pullup on receiver input	cbi	DDRD,RFrcvdat	;make receier input pin an input	cbi	PORTD,RFxmitdat	 ;initial state of transmitter output is low	sbi	DDRD,RFxmitdat	;make transmitter output pin an output	;	ldi	temp,defaultsendheader	;Establish the default RF sendingheaderr;	mov	sendheader,temp				;88888TEMPRORAILLY COMMENTED OUT!!!!!!!!!!!!					;Fetch default transmit address from EEPROM	ldi	temp,$01	out	eear,temp		;Set up the read address	sbi	eecr,eere		;Trigger the read	in	temp,eedr		;Get the data into temp	mov	sendheader,temp 						;Fetch default receive address from EEPROM	ldi	temp,$02	out	eear,temp		;Set up the read address	sbi	eecr,eere		;Trigger the read	in	temp,eedr		;Get the data into temp	mov	receiveaddress,temp 	;	mov	receiveaddress,temp		;Put it into receiveaddress register.		sbi	ucr,rxen	;enable UART receive function				;FINISHED WITH THE INITIALIZATION		;SEND GREETING	rcall	greeting   	main:	;MAIN FOREGROUND LOOP FOR THIS MACHINE   rcall rsreceiveit	;Check for RS-232 data coming in and send via RF link if anything's readyrcall rssendit		;Check for incoming RF data. If coming in, decode and send to RS-232 device.   rjmp main         rsreceiveit:	;CHECK FOR DATA FROM TERMINAL. IF PRESENT, RESEND IT. Trap and intrepret Escape sequences.	sbis	usr,rxc			;wait for data	rjmp    norsdata	in	wirelessdat,udr		;read data	cpi	wirelessdat,$1B		;See if this is an escape character.	brne	NotEscapeCommand	;If it keep going as if nothing happened -skip to bottom	receivecommand:				;If that was an Escape, then wait for command.	sbis	usr,rxc			;wait for data	rjmp    receivecommand	in	wirelessdat,udr		;read command	andi	wirelessdat,$DF		;And with $DF to make ASCII upper-casce.	receiveparameter:			;Receive the parameter	sbis	usr,rxc			;wait for data	rjmp    receiveparameter	in	temp,udr		;Read parameter (interpreded as in the range of 0..7).	subi	temp,$30		;Then make into address to insert into the header.	andi	temp,$07	lsl	temp	lsl	temp	lsl	temp	mov	bitsout,temp		;Store results in bitsout for now.				;Now interpret the command   	cpi	wirelessdat,$54		;"T" set transmit address	brne	NotTransmit	mov	temp,bitsout	mov	sendheader,temp		;Store the address	wrat:	sbic	eecr,eewe		;Wait for EEPROM write to not be busy	rjmp	wrat	ldi	temp,$01	out	eear,temp		;Set up the write address	mov	temp,sendheader			out	eedr,temp		;Set up the  write data	sbi	eecr,eemwe	sbi	eecr,eewe		;Trigger the write			NotTransmit:   	cpi	wirelessdat,$52		;"R" set receive  address	brne	NotReceive	mov	receiveaddress,bitsout	;Put the number in the address receive registerwrar:	sbic	eecr,eewe		;Wait for EEPROM write to not be busy	rjmp	wrar	ldi	temp,$02	out	eear,temp		;Set up the write address	mov	temp,receiveaddress			out	eedr,temp		;Set up the  write data	sbi	eecr,eemwe	sbi	eecr,eewe		;Trigger the write		NotReceive:	   		ret				;End of processing escape.		NotEscapeCommand:;	com	wirelessdat		;///////////////////TEST ONLY INVERTED DATA if not commented out///////////	rcall 	sendabytenorsdata:	ret           rs_send:		;SEND CONTENTS OF TEMP VIA SERIAL PORT     sbi 	ucr,txen     ;set sender bit     sbis  	usr,udre     ;wait till register is cleared     rjmp 	rs_send          out	udr,temp     ;send the contents of temp.     cbi  	ucr,txen     ;clear sender bit     ret               ;go back      sendstring:          ;call with location of string in Z     lpm                    ; Load byte from program memory into r0     tst	r0               ; Check if we've reached the end of the message     breq 	finishsendstering     ; If so, return     mov 	temp,r0     rcall	rs_send     adiw 	ZL,1               ; Increment Z registers     rjmp 	sendstringfinishsendstering:     ret   greeting:     ldi 	ZH,high(2*gteetingmessage)     ; Load high part of byte address into ZH     ldi	ZL,low(2*gteetingmessage)     ; Load low part of byte address into ZL     rcall	sendstring          ; sent it.        mov	temp,sendheader		;display defualt transmit address     andi	temp,$78	;mask off all but the address     lsr	temp	;shift to right to make address into a binary number     lsr     	temp     lsr	temp     ori	temp,$30	;make into an ascii number     rcall	rs_send            ldi 	ZH,high(2*greetingsecondpart)     ; Load high part of byte address into ZH    ldi		ZL,low(2*greetingsecondpart)     ; Load low part of byte address into ZL    rcall	sendstring          ; sent it.          mov	temp,receiveaddress		;display defualt receive address     andi	temp,$78	;mask off all but the address     lsr	temp	;shift to right to make address into a binary number     lsr     	temp     lsr	temp     ori	temp,$30	;make into an ascii number     rcall	rs_send            			;print some blank lines     ldi 	ZH,high(2*crlfs)     ; Load high part of byte address into ZH     ldi	ZL,low(2*crlfs)     ; Load low part of byte address into ZL     rcall	sendstring                 ret            gteetingmessage:.db	$0A,$0D.db	"RF interface.              02JUN2002 Dick Cappels.".db	$0A,$0D.db	"To change receive address, type <ESC>, R, <Address> ".db	$0A,$0D.db	"To change transmit address, type <ESC>, T, <Address>".db	$0A,$0D.db	"Where the valid range of address is 0..7".db	$0A,$0D.db	"Default transmit address is set to  = $0".db	$00,00   greetingsecondpart:.db	$0A,$0D.db	"Default receive address is set to = $0".db	$00,00   crlfs:.db	$0A,$0D.db	$0A,$0D.db	$0A,$0D.db	$00,00   ;/////////////////////////////////////////////////////////////////////////////////////////////////////rssendit:	;CHECK FOR DATA FROM RADIO RECEIVER AND IF PRESENT, SEND TO TERMINAL		rcall	TryToGetbytemessage ; returns with header in header and data in inbyte 	andi	header,$78		;mask off all but the address part of the header	cp	header,receiveaddress		;check the header to see if header matches address	brne	notforme		;if not for address $01 then don't send it on.	mov	temp,inbyte		;if it is addressed tho this machine then send it on to terminal         waittosend:	sbi	ucr,txen	;set sender bit	sbis	usr,udre	;wait till register is cleared	rjmp	waittosend		out	udr,temp	;send the recived data	cbi	ucr,txen	;clear sender bit		notforme:ret      ;///////////////RADIO RECEIVE BYTE ROUTINES///////////////////   ;Try and decode a valid header and data byte. In the case or error, return with header = $00ErrorQuitReceiving:	ldi	header,$00	ret    TrytoGetbytemessage:	      	ldi	header,$00	ldi	temp,$00	mov	runincount,tempGetAnotherZero:			;Start of loop to gather minzeros zeros in runin code.	rcall	Getbit	brts	ErrorQuitReceiving	;It Getbit comes back with T set, its an error; start over.	brcs	ErrorQuitReceiving	;If Getbit comes back with carry set, its a one, not a zero -start over		inc	runincount	cpi	runincount,minzeros	brmi	GetAnotherZero  	   WaitForStartbit:		;Start of loop waiting for a one, which will be the start bit.	rcall	Getbit	brts	ErrorQuitReceiving	;It Getbit comes back with T set, its an error; start over.	brcc	WaitForStartbit	;If its a zero, keep looking			;OK, Now we have the start bit, so the next 8 bits will be the header. Shift them in.		ldi	temp,$08	mov	runincount,tempGetheader:	rcall 	Getbit	brts	ErrorQuitReceiving	;It Getbit comes back with T set, its an error; Stop receiveing.	rol	header		;Shift new bit into header byte	dec	runincount		brne	Getheader	;If all bits aren't in yet, go get another.   ;At this point, one could tell whether this data is addressed to this machine, but I am going to leave ;address qualification to another part of the code. If time were very precious, one could stop ;execution of this part of the receive routine right here. 		rcall	Getbit		;Throw this one away. Its the start bit for the next byte 				;It must be here so two bytes of zeros can't look like 				;the runing code.	brts	ErrorQuitReceiving	;It Getbit comes back with T set, its an error; start over.			;Now we have the runinbits, the start bit, and the header. Next is the data. Shift it in.				ldi	temp,$08	mov	runincount,tempGetInbyte:	rcall 	Getbit	brts	ErrorQuitReceiving	;It Getbit comes back with T set, its an error; Stop receiveing.	rol	inbyte		;Shift new bit into input data byte	dec	runincount		brne	GetInbyte	;If all bits aren't in yet, go get another		   	ret		;RETURN WITH header IN header AND DATA IN INBYTE   	Getbit:		;Subroutine to get a received bit. 		;It returns the value of the received bit in the carry bit		;If this routine does not receive a valid data bit IT WILL NOT RETURN.		;If it is necessary to recover from this situation, the watchdog timer can be used.		;It measures the time between rising edges on the input pin (B3 originally).		;Successfult bit decoding will return with T flag clear. T flag =1 means error.      		ldi	tcounter,$00		;Zero the counter.		;Count, waiting for pin to go low.		   WaitForLow:			ldi	delaycounter,$16 ;load with $16, 1 cycle takes 17.5 usdelayloop1:	dec	delaycounter	brne	delayloop1	inc 	tcounter	breq	nobit	sbic	PIND,RFrcvdat	rjmp	WaitForLow			;Continue to count, waiting for pin to go high.	WaitForHigh:	ldi	delaycounter,$16delayloop2:	dec	delaycounter	brne	delayloop2		inc 	tcounter	breq	nobit	sbis	PIND,RFrcvdat	rjmp	WaitForHigh			;Determine if we measured a "legal" bit and if so wheter it as a one of a zero.		;pcode:		;If tcount < $42 start over   		;If tcount <$6E its a one		;If tcount is < $84 start over		;If tcount is >$DC start over		;Else, its a zero			cpi	tcounter,$42	brmi	nobit	cpi	tcounter,$6E	brmi	ItsAOne	cpi	tcounter,$84	brmi	nobit	cpi	tcounter,$DC	brpl	nobit			;If it gets here, its a valid zero.;	clt		;Clear T flag (no error), set the carry bit to show that its a zero and return.			clc	ret      ItsAOne:clt		;Clear T flag (error) set carry flag (data is a one), and return.	sec			ret      nobit:			;Error receiving a bit, set T flag and leave	set	ret   ;/////////////////////////RADIO SEND BYTE ROUTINES/////////////////////////   Sendabyte:				;SEND RUNIN CODE (16 ZEROS)		ldi	outbyte,$00		;get ready to send 16 zeros	ldi	temp,$0F		;$0F databits plus a zero "start bit"	mov	bitsout,temp	clc				;no start bit	(it goes as another zero)	rcall	LateTransmitAByte	;jump into byte sending routine	   	;Send the header byte. The first and last bit in the headder is always a "1". Its the law.	mov	outbyte,sendheader	rcall	TransmitAByte			;(Ok, now the 16 bits of runin, the start bit, and the 8 bits of header have been sent.	;Time to send the data byte.   	mov	outbyte,wirelessdat	rcall	TransmitAByte			ldi	outbyte,$FF		;get ready to send 1 one, channel idle, to finish the last data bit.	ldi	temp,$02		;$01 databits plus a start bit	mov	bitsout,temp	sec				;no start bit		rcall	LateTransmitAByte	;jump into byte sending routine   	ret			;finished sending the one byte message         TransmitAByte:	;send a byte out the wireless port	ldi	temp,$09	mov	bitsout,temp	sec	;start bit is a "one"		LateTransmitAByte:SendACycle:	;a one or a zero, depending on the state of carry bit	sbi	PORTD,RFxmitdat	ldi	tcounter,$00	ldi	delaycounter,$04	brcs	notazero1	ldi	delaycounter,$08notazero1:   Delay:	dec	tcounter	brne	Delay	dec	delaycounter	brne	delay		cbi	PORTD,RFxmitdat   		ldi	tcounter,$00	ldi	delaycounter,$04	brcs	notazero2	ldi	delaycounter,$08notazero2:   Delay2:	dec	tcounter	brne	Delay2	dec	delaycounter	brne	delay2				rol	outbyte	;sent start bit and all 8 data bits yet?	dec	bitsout	brne	SendACycle	;if not send another bit		ret	      ;//////////END OF CODE FOR SEND ROUTINE///////////////;http://projects.cappels.org/      ;HOME
