PDA

View Full Version : Serin2,Serout2,Wait problem



Tobias
- 17th December 2011, 04:11
I have six boards, each with either a 18F2620 or 4431 chip talking back and forth through a wireless TX. Here is an example of code


serout2 WtX,84, ["P",1,OutgoingPop1.lowbyte,OutgoingPop1.Highbyte,Outg oingPop2.lowbyte,OutgoingPop2.Highbyte,_
OutgoingPop3.lowbyte,OutgoingPop3.Highbyte,Outgoin gPop4.lowbyte,OutgoingPop4.Highbyte,OF1,OF2,Of3,OF 4 ]

and then the receiving side.

' debugin [wait ("P"),UnitID2,TotalRate1.lowbyte,TotalRate1.Highbyte,T otalRate2.lowbyte,TotalRate2.Highbyte,_
' TotalRate3.lowbyte,TotalRate3.Highbyte,TotalRate4. lowbyte,TotalRate4.Highbyte,OFI1,OFI2,OFI3,OFI4]


The problem is, even for when I have just two boards talking back and forth is that both boards get into a scenario of both listening and not talking, opposite my marriage. Both are WAITing.

What is the trick to get around this? I was thinking of maybe sending another bit that when received would let the receiver know its ok to send. That seemed maybe feasible when there are only two boards talking back and forth but would get pretty complicated when six are talking. When I say six are talking, there is a main board and five others. The main board just listens to one board and talks back and forth to the other four boards.

Tobias
- 17th December 2011, 05:09
One thing I need to mention the WAIT character I am sending is different between the one board that is just sending and the other boards sending and receiving besides the main board listening to all. I think I need to change the WAIT character to the same for all then add another byte that is the board ID and do a loop that either exits when the ID is met or a counter meets the max. I will try that tonite with many Miller Lites.

mackrackit
- 17th December 2011, 08:19
Add a time-out to the wait.

Tobias
- 17th December 2011, 18:14
I thought TIMEOUT would only work when the incoming line wasn't active at all. If there is data on the input pin even if its wrong Timeout won't happen if I read the info correctly.

mackrackit
- 17th December 2011, 19:18
Here is something from Bruce that will time-out and active serial port. Works very well for radios.


'************************************************* ***************
'* Name : DEC.BAS *
'* Author : B. Reynolds *
'* Notice : Copyright (c) 2009 Reynolds Electronics *
'* : All Rights Reserved *
'* Date : 11/15/2009 *
'* Version : 1.0 (Momentary decoder version) *
'* Notes : 4-BIT DECODER IC FOR RF REMOTE CONTROL *
'* : USING THE PIC12F635 *
'************************************************* ***************
@ DEVICE PIC12F635,MCLR_OFF,INTRC_OSC_NOCLKOUT,WDT_OFF,BOD_ OFF
@ DEVICE PWRT_ON,FCMEN_OFF,IESO_OFF,WUREN_OFF,PROTECT_OFF

DEFINE OSC 4
DEFINE NO_CLRWDT 1 ' Watchdog timer is disabled, so we don't need to reset it
DEFINE INTHAND RESET_VT ' Interrrupt on Timer1 overflow to reset outputs in 65.5mS
' if no serial data received in this time period
SYMBOL MODE = GPIO.3 ' baud select. 1=4800, 0=2400
SYMBOL D_IN = GPIO.5 ' Encoder data input pin
SYMBOL TMR1IF = PIR1.0 ' Timer1 overflow interrupt flag (reset in int handler)
SYMBOL TMR1IE = PIE1.0 ' Timer1 interrupt enable bit

'Variables for saving state in interrupt handler
wsave VAR BYTE $70 system ' Saves W
ssave VAR BYTE bank0 system ' Saves STATUS
psave VAR BYTE bank0 system ' Saves PCLATH
fsave VAR BYTE bank0 system ' Saves FSR

' Working variables
MATCH VAR BYTE bank0 system ' Match variable
DAT_IN1 VAR BYTE ' 1st Data byte
DAT_IN2 VAR BYTE ' 2nd Data byte for verify
CHK_SUM VAR BYTE ' Holds checksum received
CheckSum VAR BYTE ' Checksum of data bytes received
LOOPS VAR BYTE ' Loop var
BAUD VAR WORD ' Holds baud rate

' Constants
Synch CON "~" ' 01111110 synch byte
N2400 CON 16780 ' 2400 bps inverted
N4800 CON 16572 ' 4800 bps inverted

' hardware init
GPIO = 0 ' Clear outputs on power-up
TRISIO = 101000 ' GPIO.5=data input, GPIO.3=baud select input
WPUDA = 0 ' Disable weak pull-ups
IOC = 0 ' Interrupt on change disabled
VRCON = 0 ' Comparator Vref disabled
CMCON0 = 7 ' Disable comparators
OSCCON = 100000 ' Internal 4MHz select
OPTION_REG = 128 ' Pull-ups off

' Setup Timer1 for resets after ~65.5mS
T1CON = 000000 ' Internal clock, 1:1 prescale, Timer1 off for now
TMR1L = 0
TMR1H = 0 ' Timer1 low & high bytes cleared
TMR1IF = 0 ' Clear Timer1 overflow flag before enabling interrupt
TMR1IE = 1 ' Enable Timer1 overflow interrupt
INTCON = 000000 ' Global & peripheral ints enabled
MATCH = 0 ' Clear match count
GOTO MAIN ' Jump over int handler

ASM
RESET_VT
movwf wsave ; Save W
swapf STATUS, W ; Swap STATUS to W (swap avoids changing STATUS)
clrf STATUS ; Clear STATUS
movwf ssave ; Save swapped STATUS
movf PCLATH, W ; Move PCLATH to W
movwf psave ; Save PCLATH
movf FSR, W ; Move FSR to W
movwf fsave ; Save FSR

; Do interrupt stuff here
bcf T1CON,TMR1ON ; Stop Timer1
clrf TMR1L ; Clear low byte
clrf TMR1H ; Clear high byte
bcf PIR1,TMR1IF ; Clear Timer1 interrupt flag bit
clrf GPIO ; Clear outputs on button release (or timeout)
clrf MATCH ; Clear match variable

; Restore FSR, PCLATH, STATUS and W registers
movf fsave, W ; retrieve FSR value
movwf FSR ; Restore it to FSR
movf psave, W ; Retrieve PCLATH value
movwf PCLATH ; Restore it to PCLATH
swapf ssave, W ; Get swapped STATUS value (swap to avoid changing STATUS)
movwf STATUS ; Restore it to STATUS
swapf wsave, F ; Swap the stored W value
swapf wsave, W ; Restore it to W (swap to avoid changing STATUS)
bsf T1CON,TMR1ON ; Re-enable Timer1 before exiting interrupt handler
retfie ; Return from the interrupt
ENDASM

MAIN:
' Set data rate
IF MODE = 1 THEN
BAUD = N4800
ELSE
BAUD = N2400
ENDIF

' Fire up Timer1 before entry to serial input routine
T1CON.0 = 1

' at 4MHz Timer1 overflows in 65536 * 1uS (~65.5mS) if no Synch byte
' and serial data arrive on time. SERIN2 timeout & label options
' are useless with a noisy RF receiver output - as noise continually
' resets the timeout period causing it to hang forever.

' Wait for Synch byte, then get new inbound data & checksum
SERIN2 D_IN,BAUD,[WAIT(Synch),DAT_IN1,DAT_IN2,CHK_SUM]

T1CON.0 = 0 ' Stop Timer1 once we've received data
TMR1L = 0 ' Clear low byte
TMR1H = 0 ' Clear high byte

' / **** Begin data validation **** /

' Calculate checksum
CheckSum = DAT_IN1 + DAT_IN2

' Test new checksum against one received in CHK_SUM
IF CheckSum != CHK_SUM THEN MAIN ' Failed checksum, return

' Test data bytes for match
IF DAT_IN1 != DAT_IN2 THEN MAIN ' Failed data comparison, return

MATCH = MATCH + 1 ' We have a match so increment match count
IF MATCH = 2 THEN DECODE ' Everything matched twice, we're good
GOTO Main ' Else do it all over

' Everything looking good - so place new data on outputs

DECODE:
' Place decoded values on port pins..
GPIO = (DAT_IN1 & 010111)
DAT_IN1 = !DAT_IN2 ' Destroy the match
MATCH = 0
GOTO MAIN

END
.
The forum is stripping off "%". But you should get the idea.

Charles Linquis
- 18th December 2011, 00:06
Tobias, is there some reason why you aren't using the HARDWARE serial port? Using interrupts on the receive side solves 90% of all problems.

Tobias
- 18th December 2011, 05:15
I have the wireless module connected to the hardware serial port pins but I have never used that before. Is there any good reading to learn how?

Charles Linquis
- 18th December 2011, 06:01
It is just as easy as using SERIN/SEROUT

I don't know what speed your chips are running - but.

Use MisterE's PIC Multi-Calc to help you set up the proper DEFINES

Then use something like the following:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



CR CON 13
LF CON 10

DataStatus = 0

INTCON.7 = 1
INTCON.6 = 1

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX1_INT, _GetChar, PBP, yes
endm
INT_CREATE
ENDASM

;----------------------------------------------------------------------------

goto OverISRs:

;------------------------------------------------------------------------------------

GetChar:
HSEROUT[CR,LF,"At least some data received"] ; THIS IS JUST FOR DEBUG!!! REMOVE IN ACTUAL PGM.

HSERIN 15,BadData,[wait ("P"),UnitID2,TotalRate1.lowbyte,TotalRate1.Highbyte,T otalRate2.lowbyte,TotalRate2.Highbyte,_
TotalRate3.lowbyte,TotalRate3.Highbyte,TotalRate4. lowbyte,TotalRate4.Highbyte,OFI1,OFI2,OFI3,OFI4]
DataStatus = 1
GOTO GoodData
BadData:
DataStatus.7 = 1
GoodData:

@ INT_ENABLE RX1_INT
@ INT_RETURN

;-------------------------------------------------
OverISRs:


MAIN:
If DataStatus.0 then
HSEROUT [CR,LF,#UnitID2,#TotalRate1," .............................
endif
if DataStatus.7 then
HSEROUT [CR,LF,"Data Error!"]
DataStatus = 0
goto main



I haven't actually tested this but it should work.

Charles Linquis
- 18th December 2011, 13:23
I missed something in my earlier post - between OVERISRs and MAIN you need the line

@ INT_ENABLE RX1_INT


Also, you can use LEDs in place of the HSEROUTs to show you have reached that point in the code (as a debugging aid).

Tobias
- 19th December 2011, 04:25
Charles, thanks I will give that a go when I get back. I am on the road for the next four days.

One other thing I was thinking about today flying from CO to PA...First off here is what I am doing. I am controlling electric motors on a agriculture planter. Each row has an electric motor. For each four rows I have one control box. In the tractor I have a board and touchscreen. The tractor board can be called the master board. It sends the required motor speed to each board for each rows motor. The planter boards then take the speed, do the PID and then report back to the master the row speed.

The thing I was thinking about was right now I have the master sending out data to each board separately. I was wondering if it would be better if it sent out one data packet that had Control Box ID and the four speeds for every control box within one data stream. So for example I have a 16 row planter. There are four control boxes talking back and forth to the master/tractor board. The master sends out four different packets. Each with Control Box ID and the four row speeds. So all four boards are getting data, only one is doing something with it. The other three are waiting for their data. I am wondering if there would be any drawbacks to send out one packet that would be like this

Box1, Speed1, Speed2, Speed3, Speed4,Box2, Speed5, Speed6, Speed7, Speed8,Box3, Speed9, Speed10, Speed11, Speed12,
Box4, Speed13, Speed14, Speed15, Speed16,

Then the tractor only has to take time to send out one data pack and each control box gets speed data every time the tractor sends out data, no waiting for its own data.

Are there any drawbacks to sending longer data streams?

Charles Linquis
- 19th December 2011, 13:37
I think that the "large packet" idea has no drawbacks, and is easier to maintain and code. By the way, I grew up on a farm in southwest Iowa and got my EE degree at Iowa State.

Tobias
- 19th December 2011, 21:00
you will be able to appreciate this then, here is my site

www.grahamelectricplanter.com



I think that the "large packet" idea has no drawbacks, and is easier to maintain and code. By the way, I grew up on a farm in southwest Iowa and got my EE degree at Iowa State.

BrianT
- 19th December 2011, 21:33
I have 6 PICs chattering amongst themselves in a gas mixer. The comms is cable based, not wireless, but there are similarities. I found I had to send a number of preamble characters to get the receivers reliably synchronised. The number of preamble characters and the value of the character need to be chosen with some care in an attempt to get a 'balanced' signal on the line. Sending four $AA or $55 characters then "$" as a 'start of message' works a treat for me.

/code:
Snip from RxPacket:
GetSoM:
serin2 msg, 84, 250, rxpacketdone, [wait ("$")]

GetPktInfo:
for C_A = 0 to 1
serin2 msg, 84, [rxchar[C_A]]
chksum = chksum + rxchar[C_A]
next C_A
pkttype = rxchar[0] : msglen = rxchar[1]

GetPayLoad:
for C_A = 2 to (msglen + 1)
serin2 msg, 84, [rxchar[C_A]]
chksum = chksum + rxchar[C_A]
next C_A

GetEoMandChkSum:
for C_A = 2 to 3
serin2 msg, 84, [rxchar[msglen + C_A]]
next C_A

BadMsgCheck:
if rxchar[msglen + 2] <> "*" then getmessage 'should be EoM.
if rxchar[msglen + 3] <> chksum then getmessage 'try again

Snip from TxPacket:
'Send PreAmble
chksum = 0
for C_A = 1 to precnt
serout2 msg, 84,[preambl]
next C_A

'Send Start of Message
serout2 msg, 84,["$"]

'Send message and accumulate ChkSum
for C_A = 0 to (msglen + 1)
serout2 msg, 84, [txchar[C_A]]
chksum = chksum + txchar[C_A]
next C_A

'Send EoM and ChkSum
txchar[msglen+2] = "*" : txchar[msglen+3] = chksum
serout2 msg, 84, [txchar[msglen+2], txchar[msglen+3]]
pause 5 'time enough for recipient to let go of Ack line
if ack = 0 then sendmessage 'recipient is requesting a repeat

TxPacketDone:
'Message sent or timed out so release CommsBus
TRISB = %11111111

/endcode

HTH
BrianT

Tobias
- 11th March 2012, 21:10
Charles
I am playing around with HSERIN and not having much luck. I am pretty sure I have sorted out the problem and I am hosed for making HSERIN work on this board. WHen I use DEDBUGIN here is the setup info

DEFINE DEBUGIN_REG PORTC
DEFINE DEBUGIN_BIT 7
DEFINE DEBUGIN_MODE 1 ' 1 = inverted, 0 = true

If I am understanding the manual correctly, I can't configure HSERIN for inverted mode.

Here is the HSERIN code


define CODE_SIZE 48
define OSC 8
Include "modedefs.bas" ' Mode definitions for Serout

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts

RCSTA = $90 ' Enable serial port & continuous receive
TXSTA = $20 ' Enable transmit, BRGH = 0
SPBRG = 12 ' 9600 Baud @ 8MHz, 0.16%

DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 12 ' 9600 Baud @ 8MHz, 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

''''''''THIS IS WHAT I NORMAL USE TO CONFIGURE TX/RX for SERIAL
'DEFINE DEBUG_REG PORTC
'DEFINE DEBUG_BIT 5
'DEFINE DEBUG_BAUD 9600
'DEFINE DEBUG_MODE 1 ' 1 = inverted, 0 = true

'DEFINE DEBUGIN_REG PORTC
'DEFINE DEBUGIN_BIT 7
'DEFINE DEBUGIN_MODE 1 ' 1 = inverted, 0 = true

Switch4 var PortD.0
Switch3 var PortE.2
Switch2 var PortC.0
Switch1 var PortC.3
MotorSpeed var PortC.1
Population var PortC.2
Enable4 var PortD.1
Enable3 var PortD.2
Enable2 var PortD.3
Enable1 var PortD.4
Input1 var PortB.1
Input2 var PortB.4
Input3 var PortB.3
Input4 var PortD.7
LCD var PortD.5
WTX Var PortC.5
WRX var PortC.7
StandAlone var PortD.6

RPM var word
Duty1 Var Word
Duty2 Var Word
Duty3 Var Word
Duty4 Var Word
Duty1S data word 200 '20% Duty Cycle
Duty2S data word 400 '20% Duty Cycle
Duty3S data word 600 '20% Duty Cycle
Duty4S data word 800 '20% Duty Cycle
HighCycle var word
LowCycle var word
BCD1 var byte
BCD10 var byte
TotalRate var word
TotalRate1 var word
TotalRate2 var word
TotalRate3 var word
TotalRate4 var word
RPM1 var word
RPM2 var word
RPM3 vaR WORD
RPM4 VAR WORD
MotorCount var byte 'Tracks motorspeed input
HighTime1 var word
LowTime1 var word
HighTime2 var word
LowTime2 var word
HighTime3 var word
LowTime3 var word
HighTime4 var word
LowTime4 var word
TotalTime1 var word
TotalTime2 var word
TotalTime3 var word
TotalTime4 var word
Freq var word
UpperLimit VAR word
LowerLimit VAR word
ChannelCount var byte
TotalTime var word
MaxTotalTime var word
UnitID var byte
EPDID var byte
Rate1 var word
Rate2 var word
Rate3 var word
Rate4 var word
T1 var word 'Used to measure RPM
T2 var word 'Used to measure RPM
T3 var word 'Used to measure RPM
RSTATE1 var byte
RSTATE2 var byte
RSTATE3 var byte
RSTATE4 var byte
GoodBad var bit
Prefix con $FE
LcdCls CON $51
CursorPS con $45
Backlight con $53
Contrast con $52

INTCON.7 = 1
INTCON.6 = 1
INTCON2.7 = 1 'Pull Ups disabled
ADCON0 = 0 'A/D OFF
ANSEL0 = %00010000 'All analogue channels to digital except AN4
ANSEL1 = %00000000 'All analogue channels to digital
TRISA = %111111 'PortA to inputs
TRISB = %00100000 'PortB to outputs, except B5----------------------------------------------------04
TRISC = %10010110 'PortC, Switch3 and Switch4 outputs; Motorspeed and Population inputs
TRISD = %01000000 'PortD, Switch 1 output; Enable1-4
TRISE = %011
PWMCON0=%01111111 'All odd PWMs enabled, all independent
PTCON0 = %00001000 '2.0khz=00000100 2.9khz=00000000 '400hz/20Mhz=00001000
Freq= 249 '2.0kHz=249 2.9kHz=50000 '400hz/20mHz=50000
LowerLimit=100 '200 is 6%
UpperLimit=1000 '1000=100% (Max is 3332 3000 is 90% for 2.9khz)
PTPERL =Freq.LowByte '
PTPERH =Freq.HighByte
Symbol Capture = PIR2.0 ' CCP2 capture flag
Symbol Overflow = PIR1.0
Overflow = 0 '
PWMCON1 = 1 ' updates enabled, overrides sync w/timebase
PTCON1 = %11000000 ' PWM time base is ON, counts up 500hz
FLTCONFIG = %00000000 ' enable fault A, cycle-by-cycle mode
RCSTA.7=1 'SPEN serial port enable bit
INTCON = 0 ' Interrupts off
CCP2CON = %00000101 ' Capture mode, capture on rising edge
T2CON = %10000001 ' TMR1 prescale=1, clock=Fosc/4, TMR1=on
T1CON = %10010001 ' TMR1 prescale=1, clock=Fosc/4, TMR1=on

rpm=0
TotalTime1=0
MaxTotalTime=20000

pause 100
Serout2 LCD, 84, [Prefix,LcdCLS]
pause 10
SEROUT2 LCD,84, [Prefix,CursorPS,0, "EPD HSERINTEST"]
pause 2000
Serout2 LCD, 84, [Prefix,LcdCLS]

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_char, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
@ INT_ENABLE RX_INT ; enable external (INT) interrupts

goto OverISRs:

Get_char:
HSERIN 100, BadData, [wait ("I"),RPM.LowByte,rpm.highbyte,RSTATE1,RSTATE2,RSTATE3 ,RSTATE4]
GoodBad=1
goto GoodData

BadData:
goodBad=0

GoodData:
@ INT_RETURN

OverISRs:

RunAround:
gosub DisplayData
goto RunAround

DisplayData:
If GoodBad = 1 then
SEROUT2 LCD,84, [Prefix,CursorPS,0, "Good Data"]
else
SEROUT2 LCD,84, [Prefix,CursorPS,0, "Bad Data"]
endif
GoodBad = 0
return

MeasureRPM:
If MotorCount = 1 then
If Enable1 = 0 then
High Switch1
Low Switch2
Low Switch3
Low Switch4
gosub Get_RPM
hightime1=HighCycle
lowtime1=lowcycle
TotalTime1 = HighTime1+LowTime1
endif
endif

If MotorCount = 2 then
If Enable2 = 0 then
Low Switch1
High Switch2
Low Switch3
Low Switch4
gosub Get_RPM
hightime2=HighCycle
lowtime2=lowcycle
TotalTime2 = HighTime2+LowTime2
endif
EndIf

If MotorCount = 3 then
If Enable3 = 0 then
Low Switch1
Low Switch2
High Switch3
Low Switch4
gosub Get_RPM
hightime3=HighCycle
lowtime3=lowcycle
TotalTime3 = HighTime3+LowTime3
endif
Endif

If MotorCount = 4 then
If Enable4 = 0 then
Low Switch1
Low Switch2
Low Switch3
High Switch4
gosub Get_RPM
hightime4=HighCycle
lowtime4=lowcycle
TotalTime4 = HighTime4+LowTime4
endif
endif

If MotorCount = 4 or Motorcount >4 then
MotorCount = 1
else
MotorCount = MotorCount + 1
endif
return

NoRPM:
HighCycle = 0 ' High pulse width = T2 - T1
LowCycle = 0
overflow = 0
return

Get_RPM:
pauseus 300
Capture = 0
CCP2CON = %00000101

overflow = 0
WHILE Capture=0 and overflow=0
WEND
If OVerflow=1 then
goto NoRPM
endif

T1.HighByte = CCPR2H : T1.LowByte = CCPR2L
Capture = 0
CCP2CON.0 = 0

WHILE Capture=0 and overflow=0
Wend
If OVerflow=1 then
goto NoRPM
endif

T2.HighByte = CCPR2H : T2.LowByte = CCPR2L
Capture = 0
CCP2CON.0 = 1

WHILE Capture=0 and overflow=0
Wend
If OVerflow=1 then
goto NoRPM
endif

T3.HighByte = CCPR2H : T3.LowByte = CCPR2L

CCP2CON = 0
HighCycle = T2-T1
LowCycle = T3-T2
return

BCD:
BCD1=PORTA
BCD1=BCD1 & $0F
BCD1=BCD1^ $0F
Unitid=bcd1

' BCD1=PORTA
' BCD1=BCD1 & $F0
' BCD1=BCD1^ $F0
' BCD1 = BCD1 >>4
' Unitid=bcd1
return

ScaleRobotics
- 11th March 2012, 21:45
If you want to invert your hserial, you can do that with the PIC18 devices. Look in the datasheet at the baudcon register, and set RXDTP and TXCKP. This would let you do things like connect to a computer's serial port without using a max RS232 interface. A little more info here: http://www.picbasic.co.uk/forum/showthread.php?t=10361

Tobias
- 11th March 2012, 22:16
gracias!!!

Tobias
- 11th March 2012, 22:18
it seems that function isn't available for all 18F's including my 4431. Good info to know though.