Here's the first part, transmitting manchester-encoded data over a single wire. It's based on our earlier SouceBoost code which we've already proven to work.
This code has been set up to run on a 16F882 (it was just one of the PIC microcontrollers we had lying around) and the only unusal thing of note is that we're using the internal oscillator at 8Mhz, not the default 4Mhz (see the OSCCON command at the start of the code). Other than that, this code should be useable by pretty much any of the 16F range of PICs (you may need to change a few pin assignments
Define CONFIG = 0x20c4
Define CONFIG2 = 0x3eff
Define CLOCK_FREQUENCY = 8
OSCCON = OSCCON Or 01110000b
AllDigital
declarations:
Dim buttondown As Bit
Symbol button = PORTB.0
Symbol led_red = PORTC.4
Symbol led_green = PORTC.2
Symbol led_blue = PORTC.3
Symbol data_pin = PORTC.5
ConfigPin PORTC = Output
ConfigPin button = Input
Dim testcount As Byte
Dim heartbeat As Bit
Dim databuffer(6) As Byte
Dim byteindex As Byte
Dim bytetosend As Byte
Dim bitssent As Byte
Dim bitflag As Bit
Dim sendnextbyte As Bit
Dim sending As Bit
Dim pinstate As Bit
Dim i As Byte
Dim k As Byte
init:
PORTC = 0
OPTION_REG.7 = 0 'enable pull ups on portb (RBPU)
Gosub setuptimer1
High led_blue
WaitMs 255
WaitMs 255
Low led_blue
loop:
Gosub getinput
If buttondown = 1 Then
databuffer(2) = 0x26
databuffer(3) = 0x11
databuffer(4) = 0x75
Gosub senddata
Endif
Goto loop
End
getinput:
buttondown = 0
If button = 0 Then
'debounce the button input
WaitMs 10
If button = 0 Then
While button = 0
'do nothing
Wend
buttondown = 1
Endif
Endif
Return
ledsoff:
Low led_red
Low led_green
Low led_blue
Return
flashled:
Gosub ledsoff
WaitMs 50
High led_red
WaitMs 200
Gosub ledsoff
WaitMs 50
High led_green
WaitMs 200
Gosub ledsoff
WaitMs 50
High led_blue
WaitMs 200
Gosub ledsoff
Return
setuptimer1:
'T1CON = 0x30
T1CON = 00001000b 'set bit zero to start the timer
INTCON.GIE = 1
INTCON.PEIE = 1
PIE1.TMR1IE = 1
PIR1.TMR1IF = 0
Return
preloadtimer1:
'at 8mhz, fosc/4=2Mhz (2,000,000)
'our radio modules are rated up to 4khz
'so let's use about half that, just to be safe
'so 2m/2k = 1,000
'we want our counter to go up to 1,000 then
'send another pulse
'65535-2000 = 63535 (0xF82F)
'65535-1000 = 64535 (0xFC17)
TMR1H = 0xfc
TMR1L = 0x17
Return
starttimer1:
'in case the timer is already running, stop it
T1CON.TMR1ON = 0
'reset the timer1 interrupt flag
PIR1.TMR1IF = 0
'preload with the correct value
Gosub preloadtimer1
'start the timer
T1CON.TMR1ON = 1
Return
stoptimer1:
'stop timer1
T1CON.TMR1ON = 0
'reset the timer1 interrupt flag
PIR1.TMR1IF = 0
Return
senddata:
sending = 1
testcount = 0
High led_blue
databuffer(0) = 10101010b
databuffer(1) = 10101011b
'databuffer 2,3,4 should already be populated
'so create a checksum for the three values
databuffer(5) = 0
databuffer(5) = databuffer(5) Xor databuffer(2)
databuffer(5) = databuffer(5) Xor databuffer(3)
databuffer(5) = databuffer(5) Xor databuffer(4)
'send the data: the interrupts will take care of
'moving this (blocking) function along
Low data_pin
byteindex = 0
bytetosend = databuffer(0)
bitssent = 0
bitflag = 0
sendnextbyte = 0
Gosub starttimer1
'this is a blocking Function
While sending = 1
'do nothing
Wend
Low led_blue
Return
sendbit:
'this is where we wiggle the pin
If bitflag = 0 Then
'this is the first half of sending:
'work out which way the Bit should be sent
'(start low For Bit value 1, start high For bit value zero)
k = bytetosend And 10000000b
If k = 0 Then pinstate = 0 Else pinstate = 1
'set the pin according to the bitState value
If pinstate = 0 Then Low data_pin Else High data_pin
'change the bit-flag so we will invert the output on the
'next timer1 interrupt
bitflag = 1
Else
'it doesn't matter which way the data pin is, just toggle it
pinstate = Not pinstate
If pinstate = 0 Then Low data_pin Else High data_pin
'keep track of the total number of bits sent
bitssent = bitssent + 1
If bitssent >= 8 Then
sendnextbyte = 1
Else
'move the value in the byte to send buffer
'(shift right)
bytetosend = ShiftLeft(bytetosend, 1)
sendnextbyte = 0
Endif
'change the bit-flag for the next timer1 interrupt
bitflag = 0
Endif
If sendnextbyte = 1 Then
byteindex = byteindex + 1
If byteindex >= 6 Then
'we've sent our six bytes from buffer(0-5)
'so chill out and have a brew now
Gosub endtransmission
Else
'prepare the next byte for transmission
bytetosend = databuffer(byteindex)
bitssent = 0
bitflag = 0
Endif
sendnextbyte = 0
Endif
Return
endtransmission:
'first things first, kill the timer
Gosub stoptimer1
'now wait a timer-width before pulling the line low
WaitMs 2
Low data_pin
'kill the sending flag
sending = 0
Return
On Interrupt
Save System
If PIR1.TMR1IF = 1 Then
'clear the interrupt flag for timer1
PIR1.TMR1IF = 0
Gosub preloadtimer1
Gosub sendbit
Endif
Resume
By running the clock at 8Mhz instead of 4Mhz, we've got about 1,000 clock instructions between Timer1 intervals. But even at the default 4Mhz, there would be 500 instructions between Timer1 intervals, which should be plenty to do the processing required between "ticks".
As before, we ran the single wire into pin4 of our PicKit2 programmer and ran the built-in Logic Analyser tool. This time, we wrote our data values in hex, so that they are easier to read back at the other end.
Amazingly, it worked first time!
Let's hope that converting the receiver code from SourceBoost C to Oshonsoft BASIC goes as smoothly!
No comments:
Post a Comment