PDA

View Full Version : crucial error in a 90% working hardware uart



mimmmis
- 23rd September 2008, 00:55
Hi guys. Thanks to all that bother reading my question.
After huge amount of work i wrote the following program (4MHz pic16f876a).Although i can see MessageA and MessageB (when portb.7 is 5volts), and
HSerout [DEC B0,",",DEC B1,",",DEC B2,13,10] the problem is always tha the latter seems to stop the microcontroller. Although i can see HSerout [DEC B0,",",DEC B1,",",DEC B2,13,10] for a couple of times about in the 4th giving of data i take no response from microcontroller.With a reset everything is fine until another 3-4 giving of data.Has anything to do with overrun buffers? but i have included DEFINE HSER_CLOERR 1 ' automatic clear overrun error . Thanks anyway.....



INCLUDE "MODEDEFS.BAS"
DEFINE OSC 4

B0 VAR WORD
B1 VAR WORD
B2 VAR WORD
B3 VAR WORD
B4 VAR WORD

TRISC = %10000000 ' PORTC.7 is the RX input
' PORTC.6 is the TX output
' Serial communication definition
' ===============================
' Using internal USART and MAX232 to interface to PC
'
DEFINE HSER_RCSTA 90h ' enable serial port,
' enable continuous receive

DEFINE HSER_TXSTA 24h ' enable transmit,
' BRGH=1

DEFINE HSER_BAUD 9600
DEFINE HSER_CLOERR 1 ' automatic clear overrun error


RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)

Pause 10 ' safe start-up delay
B0=0 '(duty cycle pwm)

HSerout ["Hi"]
main:

IF PORTB.7=1 Then
GoSub MessageA
EndIF

HSerout ["MessageB",13,10]
HPwm 1,B0,1000
High PORTB.5
Pause 1000
Low PORTB.5
Pause 1000
IF (RCIF) AND (PORTB.7=0) Then ' incomming data?
HSerin [WAIT ("d"),DEC B0,DEC B1,DEC B2]
HSerout [DEC B0,",",DEC B1,",",DEC B2,13,10] ' send it
EndIF
GoTo main

GoTo main
MessageA:
HSerout ["MessageA",13,10]
HSerout ["MessageA",13,10]
HSerout ["MessageA",13,10]
Pause 1000
HPwm 1,127,1000
GoTo main
End

Charles Linquis
- 23rd September 2008, 01:51
It looks like your send routine takes up so much time that it doesn't get back to HSERIN before the receive buffer overflows. Your CLOERR define clears the overflow error, but that also dumps the buffer. As a result, you are losing characters.

It looks like you need an interrupt-driven receive routine.

Are the characters coming in continuously, or in bursts?

mimmmis
- 23rd September 2008, 11:13
thanx for replying! my characters come continuously.actually one thinks it works excellent but after a while it does nothing! i am desperate.have you any idea how to look to inerrupts uart?

Charles Linquis
- 23rd September 2008, 13:42
If the data really comes in continuosly, at full speed with no breaks, then you are in real trouble, since eventually you will overflow any size buffer you put in your PIC (which is limited by RAM size).

Is there some way you could send at a baud rate higher (like 2X) than you are receiving? They you would have a chance.

It would help a bit if you would run a faster oscillator as well (20MHz). And *WHY* are you not using an 18F series part?

Jerson
- 23rd September 2008, 14:18
Charles is right. You are not looking at the serial port while your code is sending MessageA thrice and then pausing for 1000 ms. During that time, whatever comes in is bound to overflow the receive register. Cloerr will mitigate the problem to an extent, but imagine, you just received your "d" and are waiting for the decimal values for B0, B1 or B2. During that time if the input packet has already finished, you're in trouble. That's because the DEC modifier parses numbers only. If it doesn't find a number, either your number read is wrong or it will end up waiting indefinitely on the "d".

Ideal solution, put in an interrupt routine to capture the incoming serial characters. Catch them to a circular buffer and read that buffer often. How to do it? This is how I would do it....



' These variables are used to save the machine state on interrupt
wsave var byte $20 SYSTEM ' location for W if in bank0
wsave1 var byte $A0 SYSTEM ' location for W if in bank1
wsave2 var byte $120 SYSTEM ' location for W if in bank2
wsave3 var byte $1A0 SYSTEM ' location for W if in bank3
ssave var byte BANK0 SYSTEM ' location for STATUS register
psave var byte BANK0 SYSTEM ' location for PCLATH register
fsave var byte BANK0 SYSTEM ' location for FSR register
intR0 var byte BANK0 SYSTEM ' interrupt temporary variables
intR1 var byte BANK0 SYSTEM

' Receive buffer
RxBuf var byte[16] ' buffer holding received chars
WrPtr var byte ' write index
RdPtr var byte ' write index

' define the interrupt handler
define INTHAND _IntHandler

goto OverInterrupt
IntHandler:
'************************************************* ******************************
' Interrupts can be from a number of sources. See INTCON p25
' We use the following
' RBIF - interrupt on RB change
' T0IF - Timer0 overflow interrupt
IntHandler:
asm ; identify the interrupt source
movf FSR,w
movwf fsave ; save the fsr

btfss PIE1,RCIE ; if enabled and
goto EndInt
btfss PIR1, RCIF ; receive interrupt?
goto EndInt
RxISR
movlw 6
andwf RCSTA,w ;FERR(4) + OERR(2)
btfss STATUS,Z ;not set
bcf RCSTA,CREN ;clear errors
bsf RCSTA,CREN ;by putting CREN=0,1
;
movf _WrPtr, W
addlw low (_RxBuf)
movwf FSR
movf RCREG,w
movwf INDF ;RxBuf[WrPtr]=RCREG
;
incf _WrPtr
movlw 0fh
andwf _WrPtr
EndInt
movf fsave,w ;restore the FSR
movwf FSR
movf psave,w ;restore PCH
movwf PCLATH
swapf ssave, W ;restore STATUS
movwf STATUS
swapf wsave, F
swapf wsave, W ;restore W
retfie
ENDASM


' initialize the serial buffer
Ser_Init:
RCSTA=$90 ' Enable serial port & continuous receive
TXSTA=$20 ' Enable transmit, BRGH = 0
SPBRG=25 ' 2400 Baud @ 4MHz, 0.0%
RdPtr=0
WrPtr=0
return

' read a serial character
Ser_Getc:
while RdPtr=WrPtr:wend
gr[0]=RxBuf[RdPtr]
RdPtr=RdPtr+1
RdPtr=RdPtr & $0f
return

' read the value of a hex digit to gr[0]
Ser_GetHex:
gosub Ser_Getc
if gr[0]>"9"then gr[0]=gr[0]-7
gr[0]=gr[0]-"0"
return

' read the value of 2 hex digits to gr[0]
Ser_GetHex2:
gosub Ser_GetHex
gr[1]=gr[0]<<4
gosub Ser_GetHex
gr[0]=gr[1]+gr[0]
return

ProcessRX:
while RdPtr <> WrPtr
gosub Ser_GetC
if gr[0]="d" then ProcRX10 ' Proceed only after we get the "d"
wend
return
ProcRX10:
' process the data here


This is just a framework and is incomplete. Use it at your own risk.

Jerson