;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