PDA

View Full Version : USART problems



egberttheone
- 13th January 2005, 19:06
I'm experiencing problems with a project the goal is to receive a time information string from 1
processor to the other.

setup:

16F628:

using the onboard crystal (4mhz)

DCF time decoder; code used for sending the data string to the other processor:



DEFINE HSER_TXSTA 20h
' Set baud rate
DEFINE HSER_BAUD 19200

HSerout ["A", STR TimeDate\6]


18F452:

10MHZ crystal; osc settings PLL X 4 runs on 40mhz

Code used to receive:



DEFINE OSC 40

intcon = %11000000 ' enable global and Peripheral interrupt
pie1.5 = 1 ' enable interrupt on usart receive
pir1.5 = 0 ' clearing interrupt flags
adcon1 = %00001110 ' setting all pin's to digital i/o pins

DEFINE HSER_RCSTA 90h
DEFINE HSER_BAUD 19200
DEFINE HSER_CLROERR 1 ' automatically clear error's on overflow

ON INTERRUPT GoTo handle

Disable ' interrupt handler
Handle:

HSerin 500,TimeOut,[WAIT("A"),STR TimeDate\6]
DCFSignal = 1
TimeDate(5) = TimeDate(5) + 1
GoTo Perfect

TimeOut:
GoSub SecondLineLCD
LCDOut "DCF Error"
DCFSignal = 0

Perfect:
pir1.5 = 0 ' clearing interrupt flags
pir1.3 = 0 ' clearing interrupt flags
Resume
Enable



I think the receiving issue is a sync problem because if I run the processor @ 20mhz and set the
define osc to 20 then it works fine. what am I doing wrong?

I'm also experiencing problems with the read and write commands for the onboard eeprom it give's
compiler error's; it doesn't give errors when I compile a program for a 16f877 using the old
compiler; the new compiler does give error's I'm using the MPASM V03.70.

mister_e
- 13th January 2005, 20:32
19200 baud @4MHZ... by the datasheet table 12-5 it's suppose to work. But i'll prefer to set USART in a different way.

What about if you remove the

DEFINE HSER_TXSTA 20h
' Set baud rate
DEFINE HSER_BAUD 19200


and you replace it by

DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 24h 'enable TXEN and BRGH=1
DEFINE HSER_SPBRG 12

these will give you 19231 baud +/-0.16% (depending the oscillator precision too)

On the other side¸
@40MHZ

remove :

DEFINE HSER_BAUD 19200

change it to:
DEFINE HSER_TXSTA 24h 'enable TXEN and BRGH=1
DEFINE HSER_RCSTA 90h
DEFINE HSER_SPBRG 129

this will also give you 1923x baud +/-0.16%

Always remind SPBRG change with the clock speed. Have to check in the datasheet.

For this speed of serial comm, i'll prefer use else than the internal oscillator. I'm a bit surprise that it can work @19200 baud with a simple 4MHZ crystal.

mister_e
- 13th January 2005, 20:42
I'm also experiencing problems with the read and write commands for the onboard eeprom it give's
compiler error's; it doesn't give errors when I compile a program for a 16f877 using the old
compiler; the new compiler does give error's I'm using the MPASM V03.70.

New MPLAB version 3.90 can maybe solve the problem. Wich version of PBP are you using?

I do a lot of 18F452 project as now and no problems with the WRITE/READ statement. Are you using some OPTION_REG statement with 18Fxxx ? in case... this is your problem. Some register of the 18Fxxx are different than the F877.

egberttheone
- 20th January 2005, 18:42
now it seems to work, is there any log file or something where MPASMWIN will place the error's because it says the code contains error's but not what the problem is, it very annoying since my code is miles long :(

thx for your help already! (the serial systeem still doesn't work it now seems to have problems with the interrupt)


EDIT:

I now use microcode studio, I first used codedesigner it did not send me the error message's now I have the error message's but don't know how to fix this problem it all appeared after a format c: so I think some thing is installed wrong can't figure out what. this are the message's it produce:

18F452.inc 20 : Symbol not previously defined (_CONFIG1)
18F452.inc 21 : Argument out of range (not a valid config address)
18F452.inc 22 : Symbol not previously defined (_CONFIG2)
18F452.inc 23 : Argument out of range (not a valid config address)
18F452.inc 24 : Symbol not previously defined (_CONFIG3)
18F452.inc 25 : Argument out of range (not a valid config address)
18F452.inc 26 : Symbol not previously defined (_CONFIG4)
18F452.inc 27 : Argument out of range (not a valid config address)

and so on...

egberttheone
- 24th January 2005, 21:31
Kick. not anyone known about the compile errors ? :( i found this but no reply : http://list.picbasic.com/forum/messages/4011/4278.html?1028408396

mister_e
- 25th January 2005, 01:04
Looks like your .inc file is corrupted or the MPASM .inc files directory and PBP directory are not include in your path.

i attach my MPASM .inc file. let me know

mister_e
- 25th January 2005, 01:06
and this one goes to your PBP directory

egberttheone
- 25th January 2005, 16:47
YOUR AWSOME! the .inc file from the PBP was corrupted, many thanks!

mister_e
- 25th January 2005, 23:56
Great to know everything is working now ;)

egberttheone
- 26th January 2005, 18:51
Originally posted by mister_e
Great to know everything is working now ;)

well the compiler does; my interrupt doesn't work and i can't find out why.




DEFINE OSC 40
DEFINE HSER_TXSTA 24h 'enable TXEN and BRGH=1
DEFINE HSER_RCSTA 90h
DEFINE HSER_SPBRG 129

intcon = %11000000 ' enable global and Peripheral interrupt
pie1.5 = 1 ' enable interrupt on usart receive
pir1.5 = 0 ' clearing interrupt flags
adcon1 = %00001110 ' setting all pin's to digitall i/o pins

teller var byte

on interrupt GoTo handle

main:

lcdout dec(teller)

goto main



Disable ' interrupt handler
Handle:

Teller = Teller + 1

pir1.5 = 0 ' clearing interrupt flags
Resume
Enable



I made my code as easy as possible to debug, if I send a serial signal to it it doesn't jump to the interrupt handler and ingreas teller by 1

mister_e
- 26th January 2005, 22:15
quick idea here before i give it a look to datasheet. What about if you change you mainloop like this



main:

If teller then
LCDOUT $FE,1,"i had interruption"
teller=0
endif

goto main

egberttheone
- 26th January 2005, 22:18
hmmm i don't think its gone help because it doesn't increas @ all and if you say "if teller then" that means that teller has to be 1 to trigger. correct me if i'm wrong. else ill try it tomorro

mister_e
- 26th January 2005, 22:29
My assumption is LCDOUT is too long to execute... only assumption. BTW i'll try it in a few. I'll check everything with the datasheet.

Bruce
- 27th January 2005, 03:17
You need to read RCREG to clear RCIF. I don't think you can clear it with pir1.5 = 0. If you don't clear RCIF you'll jump right back into the int handler each time you re-enable interrupts exiting your int handler.

Try something like this. Just change the LCD defines to match your LCD setup.

DEFINE OSC 40 ' _HSPLL_OSC_1H & _HS_OSC_1H

' // Setup for dev board LCD pinout
DEFINE LCD_DREG PORTB ' LCD I/O port
DEFINE LCD_DBIT 4 ' 4-bit data from RB4 to RB7
DEFINE LCD_RSREG PORTB ' Register select port
DEFINE LCD_RSBIT 2 ' Register select pin
DEFINE LCD_EREG PORTB ' Enable port
DEFINE LCD_EBIT 3 ' Enable pin
DEFINE LCD_BITS 4 ' 4-bit data bus
DEFINE LCD_LINES 2 ' 2-line LCD
DEFINE LCD_COMANDUS 2000 ' LCD command delay
DEFINE LCD_DATAUS 50 ' LCD data delay

' // Set USART parameters
DEFINE HSER_TXSTA 24h ' Enable TXEN and BRGH=1
DEFINE HSER_RCSTA 90h ' SPEN & CREN = 1
DEFINE HSER_SPBRG 129 ' SPBRG val for 19,200bps @40MHz

' // Set USART interrupts, A/D, reg defs, etc,,
SYMBOL RCIF = PIR1.5 ' Received character int flag
INTCON = %11000000 ' enable global and Peripheral interrupt
PIE1.5 = 1 ' USART receive interrupt enabled
ADCON1 = %00000111 ' Turn off A/D all digital

X VAR BYTE
Teller var byte

pause 1000 ' LCD power-up / init time
lcdout $FE,1 ' Clear screen / home cursor

on interrupt GoTo handle ' Point to int handler

Main:
lcdout $FE,1,dec teller ' Print to LCD clearing previous char
for X = 0 TO 50 ' Loop for 1 second
pause 20
next X
goto Main

Disable ' Interrupt handler
Handle:
while RCIF ' While RCIF is set, keep reading characters
Teller = RCREG ' Reading character into Teller clears RCIF
wend
Resume
Enable

END

You may need to edit your default PBP 18F452.INC header file to make sure you're turning on HSPLL for 40MHz with a 10MHz crystal.

Commented out this line.
;__CONFIG _CONFIG1H, _OSCS_OFF_1H & _XT_OSC_1H
Add this below it, and save the file.
__CONFIG _CONFIG1H, _HSPLL_OSC_1H & _HS_OSC_1H

egberttheone
- 27th January 2005, 16:59
Hello again! I tested the idea's but it doesn't work.... and it did work on a pic 16C877 the thing with the pir register(not this project).... is it possible if the bitrate does not match that it will not trigger the interrupt? because I use a pic16f628 @ this high speed and it runs on its internal osc. speed 4mhz. since time is not really a problem is it advisable to lower the speed? and what settings is preferable for an error free transfer? THX for your support already.

EDIT: I'm sure the pic gets a signal but I don't know if it is correct.

mister_e
- 27th January 2005, 17:34
what about if you send your data on LCD without any interrupt. Do you get the great data? Case not, your baudrate setting is no correct or your internal crystal don't provide a really accurate frequency for your baudrate.

egberttheone
- 27th January 2005, 17:46
Main:
lcdout $FE,1,Dec(Teller) ' Print to LCD clearing previous char
for temp = 0 TO 50 ' Loop for 1 second
pause 20
next temp
Teller= Teller + 1
HSerin [WAIT("A"),STR TimeDate\6]
goto Main


I tested it with this piece of code and it doesn't work(it stays zero) so I think it is a sync problem I'm going try to lower the baud rate.. what settings are preferable?

mister_e
- 27th January 2005, 18:28
Let's do it safe let's choose 2400 Bauds

DEFINE HSER_TXSTA 24h
DEFINE HSER_RCSTA 90h
DEFINE HSER_SPBRG 103

and then if it's working :

@ 9600 bauds

DEFINE HSER_TXSTA 24h
DEFINE HSER_RCSTA 90h
DEFINE HSER_SPBRG 25

@ 19200 bauds(not sure with internal osc)

DEFINE HSER_TXSTA 24h
DEFINE HSER_RCSTA 90h
DEFINE HSER_SPBRG 12

egberttheone
- 27th January 2005, 19:03
ok, that are the settings for the 16f628 but what do i need to set for a pic18f452 running @ 40mhz? the data sheet says N/A

Bruce
- 27th January 2005, 19:42
Well I just learned a few things about PBP USART defines.

1. If you use PBP USART defines like DEFINE HSER_TXSTA 24h, but do "not" use HSEROUT or HSERIN somewhere in the program, these defines don't configure the USART like one might assume.

In this case you need to write directly to USART registers to setup everything.

TXSTA = $24 ' Enable TXEN and BRGH=1
RCSTA = $90 ' SPEN & CREN = 1
SPBRG = 129 ' SPBRG val for 19,200bps

2. This also goes for DEFINE HSER_CLOERR 1. If you don't also use HSERIN or HSEROUT, then OERR never gets "automatically" cleared on over-run, and of course, it goes like splat when you shoot more than 2 characters at the USART before emptying RCREG.

This program below has been tested, and it definitely does generate a USART interrupt even with a baud rate missmatch.

Notes:
If you send 1 character, it displays that character.
If you send 2 characters, it displays the 2nd received.
If you send 3 or > characters, it still dispays only the 2nd character received because anything over 2 bytes shot at the USART before RCREG is cleared isn't transferred into RCREG from RSR.

This was tested with a PC sending serial data, but it should work the same with anything sending asynchronous serial data.


DEFINE OSC 40 ' _HSPLL_OSC_1H & _HS_OSC_1H

' // Setup for dev board LCD pinout
DEFINE LCD_DREG PORTB ' LCD I/O port
DEFINE LCD_DBIT 4 ' 4-bit data from RB4 to RB7
DEFINE LCD_RSREG PORTB ' Register select port
DEFINE LCD_RSBIT 2 ' Register select pin
DEFINE LCD_EREG PORTB ' Enable port
DEFINE LCD_EBIT 3 ' Enable pin
DEFINE LCD_BITS 4 ' 4-bit data bus
DEFINE LCD_LINES 2 ' 2-line LCD
DEFINE LCD_COMANDUS 2000 ' LCD command delay
DEFINE LCD_DATAUS 50 ' LCD data delay

' // Set USART parameters
TXSTA = $24 ' Enable TXEN and BRGH=1
RCSTA = $90 ' SPEN & CREN = 1
SPBRG = 129 ' SPBRG val for 19,200bps @40MHz

' // Set USART bit aliases
SYMBOL RCIF = PIR1.5 ' Received character int flag
SYMBOL OERR = RCSTA.1 ' Over-run error bit
SYMBOL CREN = RCSTA.4 ' Continuous receive enable/disable bit

' // Setup A/D, variables, etc,,
ADCON1 = %00000111 ' A/D off, all digital
X VAR BYTE ' Loop var
Teller VAR BYTE ' Holds char for display
Teller = "0" ' Start with ASCII 0

' // LCD init time / clear, home cursor
PAUSE 1000 ' LCD power-up / init time
lcdout $FE,1 ' Clear LCD

' // Setup interrupts
INTCON = %11000000 ' Enable global / peripheral interrupt
PIE1.5 = 1 ' USART receive interrupt enabled

on interrupt GoTo handle ' Point to int handler

Main:
lcdout $FE,1,Teller ' Clear LCD / diaplay last char
FOR X = 1 TO 50 ' Loop for 1 second in 20mS
PAUSE 20 ' intervals
NEXT X
goto Main

Disable ' Disable interrupts while in interrupt handler
Handle:
IF OERR THEN ' Clear over-runs if OERR set
CREN = 0 ' Disable USART receive
CREN = 1 ' Re-enable USART receive
ENDIF
Teller = RCREG ' Read RCREG buffer twice to
Teller = RCREG ' clear RCIF interrupt flag bit
Resume
Enable

end

mister_e
- 27th January 2005, 20:18
Originally posted by Bruce
Well I just learned a few things about PBP USART defines.

1. If you use PBP USART defines like DEFINE HSER_TXSTA 24h, but do "not" use HSEROUT or HSERIN somewhere in the program, these defines don't configure the USART like one might assume.

In this case you need to write directly to USART registers to setup everything.

TXSTA = $24 ' Enable TXEN and BRGH=1
RCSTA = $90 ' SPEN & CREN = 1
SPBRG = 129 ' SPBRG val for 19,200bps

That's interesting ! Thanks Bruce!

egberttheone

ok, that are the settings for the 16f628 but what do i need to set for a pic18f452 running @ 40mhz? the data sheet says N/A

In fact it make sense that a PIC who run @40MHZ provide slow serial com. The slowest you can do @40MHZ is 9600 Bauds

Everything is in the datasheet! @40 MHZ for 9600 bauds SPBRG=64 TXSTA=20h, RCSTA=90h

egberttheone
- 27th January 2005, 20:37
YES the interrupt does accure now! but i get a compiler error when i add "HSerin 500,TimeOut,[WAIT("A"),STR TimeDate\6]" into the routine "Handle"; the error is also resolved by setting the osc speed to 20 :( any idea ?


"pbppic18.lib 7153: argument out of range. least significant bits used"

if i just ignor the error and programm the device then it does jump to the interrupt but it does not receive any thing it jumps to timeout routine.

EDIT:


Originally posted by mister_e
That's interesting ! Thanks Bruce!

egberttheone

In fact it make sense that a PIC who run @40MHZ provide slow serial com. The slowest you can do @40MHZ is 9600 Bauds

Everything is in the datasheet! @40 MHZ for 9600 bauds SPBRG=64 TXSTA=20h, RCSTA=90h

yeah i found out 9600 was the minimum @40mhz

Bruce
- 27th January 2005, 21:42
If you use HSERIN & HSEROUT, then use the PBP USART defines.

Otherwise, when you compile, the PBP USART library routines attempt to set USART registers & baud rate automatically based on the defined OSC value.

If the defined OSC speed doesn't jive with 2400 baud (which is the PBP default data rate if you do not use the USART defines), then it returns the error "Argument out of range".

That's why when you change DEFINE OSC 40 to DEFINE OSC 20 it works. 40MHz didn't work out during PBP's attempt to compute reg values for 2400 bps by default.

Look in your PBPPIC18.LIB file just under ;* Default hardware serial port values.

You'll see the logical progression taken through the library as it tries to setup default USART parameters.

ifndef HSER_BITS
HSER_BITS = 8 ; Default to 8 bits
endif

If NOT defined HSER_BITS, then by default let's use 8-bit.

ifndef HSER_RCSTA ; Receive register data
if (HSER_BITS != 9)
HSER_RCSTA EQU 90h ; Receiver enabled
else
HSER_RCSTA EQU 0d0h ; Receiver enabled for 9 bits
endif

If NOT defined HSER_RCSTA and if HSER_BITS is NOT = 9, then set HSER_RCSTA to 90h. Or else set it to 0d0h for 9-bit.

Follow this down to where OSC, HSER_TXSTA, and HSER_BAUD are used to "automatically" compute the value for HSER_SPBRG and you'll see why the argument out of range error pops up. The numbers don't work out for 2400bps at 40MHz.

In short;

If you're not using HSERIN or HSEROUT, and just want to do everything manually by reading RCREG, handling over-runs, clearing RCIF, etc, then setup the USART registers manually as mentioned previously.

If you "are" using HSERIN & HSEROUT anywhere in your program, then you need to use the PBP USART defines - or select an oscillator speed that works with the default 2400bps.

egberttheone
- 27th January 2005, 22:13
ahhh thats why it did not work because the word hserout/hserin was not used ! i changed it back to the normal define's and putted the word hserin and it still goes to the interrupt! but it still goes to time out well ill(we) figure it out next week first some time for my girl friend ;) thank you very much for your help already your very clear in explaining!

egberttheone
- 31st January 2005, 20:50
Hi all! evry thing is running smoothly now thanks all! here are some pic's pic1 (http://picserver.org/view_image.php/IM070A6880R0) pic2 (http://picserver.org/view_image.php/T26I9D4SFK7D)

Demon
- 25th February 2005, 23:45
Bruce?

==================================================
In short;

If you're not using HSERIN or HSEROUT, and just want to do everything manually by reading RCREG, handling over-runs, clearing RCIF, etc, then setup the USART registers manually as mentioned previously.

If you "are" using HSERIN & HSEROUT anywhere in your program, then you need to use the PBP USART defines - or select an oscillator speed that works with the default 2400bps.
==================================================

I'm trying to receive a file to a PIC from a PC. I am able to manually send data via the serial window in Studio Plus to 2 consecutive HSERINs in the program, but I'd like it to be automatic. I'd like the 1st HSERIN to read the 1st variable, and then the 2nd HSERIN to read the balance of the record. As it stands I have to click SEND twice.

Do I have to do everything manually as you describe in option 1, or is there a method using HSERINs? Basically I'd like to set this up so it can read the entire file without manual intervention.

Specs: PIC 16F877, 20MHz crystal, COM1, MAX232CPE inverter, 19200 Baud, Windows Home XP, Studio Plus 2.1.0.8, PIC BASIC Pro 2.45a, caucasian, 6', married, 3 daughters, overweight, lazy and slowly going insane.

Thanks!

Robert
:)

mister_e
- 26th February 2005, 00:03
Robert,

in this case use of two Hserin can work. You'll need 1 extra i/o to confirm to pc to send next character.

By example, if you plan to download an EEPROM dump from your PC to your PIC and then dump it to an external eeprom, you need some time to get character, place in var, send to external eeprom, wait the appropriate delay time required by your EEPROM, and wait for the next character.

Easier with SERIN2 that handle everything for you and provide this extra 'flow control' pin.

Demon
- 26th February 2005, 03:07
Thanks Steve.

Ok, so I've converted my code over to SERIN2 and SEROUT2. One problem, don't know where to connect the 'flow' pin on the RS232 connector. I've chosen to try the resistor/inverted technique.

The manual doesn't mention that pin, so I'm doing searches now on where to connect it.

Robert
:)

Bruce
- 26th February 2005, 03:58
What's the purpose of two HSERIN's?

Demon
- 26th February 2005, 04:03
I have a variable length file. The first SERIN2 processes a RECORDTYPE, the second processes VARIABLEDATA.

That way I can have record A: 33 characters, and record B: 24 characters. My file consists of 6 different record layouts at the moment, and I'd like to process all the records in one batch. I'd like to avoid having to use 6 different PICs to load them onto EEPROM.

I can't find any reference to where the flow pin is connected on the DB-9 connector. I checked here:

http://www.klm-tech.com/technicothica/ttlrs232.html#pinouts

And my best guess would be pin 8, but it's not working, neither is 7. Actually, I tried all the empty pins without success. Maybe I need a resistor like on the RX and TX pins?

Robert
:)

Demon
- 26th February 2005, 04:55
I found this Assembler program that uses CTS and RTS:

http://www.ecomorder.com/techref/microchip/16F/628/uartinttst-rh.htm

I kinda follow the code, sorta. At least I understand his note about how RTS and CTS have to be opposite since MAX232 will invert their value; so you set 0 to get 1 and vice versa.

I figure the same routine could be written in BASIC Pro, I'm just not sure on some of the variables and sizes (like for the input/output buffers, stuff like that).

So now I gotta tear at my MAX232 circuit, I had only used one line, leaving the other unused. I put it on a small board for the sake of convenience when moving it about my projects. Well, having no working room on it isn't proving convenient any more.

At least it's a start as to how to use USART with RTS and CTS. I can't find any references for the 'flow pin' used in SERIN2 so my options are getting slimmer.

Robert
:(

Bruce
- 26th February 2005, 04:58
With hardware handshaking, the PC transmits data when CTS is asserted, but you'll also need to setup your PC & terminal software to use hardware handshaking.

Bruce
- 26th February 2005, 05:09
How about something like this?


' ** // PIC16F877, 20MHz crystal, MCS+ loader
' ** // Interrupt driven serial receive

' ** // Buffers up to 80 characters using the hardware
' ** // USART. Buffering ends when the EOM "~" character
' ** // is received.

' ** // Includes auto over-run reset + RCIF bit polling
' ** // for new serial characters

define LOADER_USED 1
define OSC 20
define HSER_BAUD 19200 ' Set data rate
DEFINE HSER_CLROERR 1 ' Automatically clear over-run errors
DEFINE HSER_RCSTA 90h ' Enable USART receive
DEFINE HSER_TXSTA 24h ' TXSTA=%00100100. TX enable, BRGH=1 for high-speed
' TXSTA=%00100000. TX enable, BRGH=0 for low-speed

GP VAR BYTE ' GP variable
BytesIn var byte[80] ' Up to 80 bytes
ByteCnt var byte ' Indicates number of bytes in buffer
X VAR BYTE ' GP var
EOM CON "~" ' "End Of Message" marker
OERR VAR RCSTA.1 ' Alias USART over-run bit
CREN VAR RCSTA.4 ' Alias USART continuous receive enable bit
RCIF VAR PIR1.5 ' Alias USART received character interrupr flag bit

' ** // Zero vars & A/D off
ByteCnt = 0 ' Zero counter
ADCON1 = 7 ' A/D off, all digital

' ** // Setup serial interrupts
INTCON = %11000000 ' Enable interrupts
PIE1.5 = 1 ' Enable interrupt on USART

On Interrupt Goto Main
GOTO Doodle

Disable
Main:
WHILE RCIF ' If RCIF=1 there's a new character in RCREG
BytesIn[ByteCnt]=RCREG ' Yes. Then store it in array
If BytesIn[ByteCnt]=EOM then OutMsg ' Display on receipt of terminating char
ByteCnt=ByteCnt+1 ' Increment array index pointer
WEND ' Exit only when RCREG is clear
RESUME ' Return to normal operation prior to interrupt
ENABLE

OutMsg: ' Note: Interrupts are still disabled here
HSEROUT [13,10,dec ByteCnt," Bytes Rcvd",13,10]
HSEROUT [str BytesIn\ByteCnt,13,10]
FOR GP=0 to ByteCnt ' Clear array bytes 0 to ByteCnt
BytesIn[GP]=0 '
NEXT '
ByteCnt=0 ' Reset index pointer back to first element
WHILE RCIF ' Trash any left over characters in RCREG buffer
GP=RCREG ' after EOM has been received
WEND
GOTO Main ' RCIF is clear, so return

Doodle: ' Waste time here waiting for serial interrupt
HIGH PORTB.0
FOR X = 0 TO 250
PAUSEUS 20 ' Do not use long pauses. It slows down interrupt
NEXT X ' processing, and requires a slower data rate to work
LOW PORTB.0 ' with on interrupt
FOR X = 0 TO 250
PAUSEUS 20
NEXT X
GOTO Doodle

end
If you have a terminator on the end of your data packets, this makes the whole process pretty simple.

If you just need to PIC to tell the PC to stop sending data, connect the PIC flow control pin to the PC CTS pin.

Demon
- 27th February 2005, 02:53
That's perfect Bruce! Thanks!

I read a tutorial on controlling the DB9 pins directly, modem style, and I was going nowhere fast. Your technique is much better, I had read about it earlier but I didn't know how to tie it all together. And best of all, it uses USART instead of SERIN2.

Yup, I had an asterisk as end of record marker, but I like tilde even better. There's no chance at all that it will appear in the text so it makes a better choice.

I don't really care about telling the PC to stop sending, but I'll keep your solution in mind. My main goal was just to download a file onto EEPROM, once complete, I didn't really care about cleaning up. This will be used for one-shots, once the data is on the EEPROM, I don't alter the data.

Welp, I'm off to try this. If I got it right; MAIN is the USART I/O routine, DOODLE is waiting for input and OUTMSG is an end of record summary.

Robert
:)

Stupidlesser as each day goes on...

Demon
- 27th February 2005, 03:12
Bruce,

Can you PM or email me your last name please?

roberthedan AT hotmail DOT com

I'd like to give credit where credit is due in the comments.

And you've also made yourself a new customer at Rentron.

Robert
:)

Demon
- 27th February 2005, 19:28
On Interrupt Goto Main
GOTO Doodle

Disable
Main:
WHILE RCIF ' If RCIF=1 there's a new character in RCREG
BytesIn[ByteCnt]=RCREG ' Yes. Then store it in array
If BytesIn[ByteCnt]=EOM then OutMsg ' Display on receipt of terminating char
ByteCnt=ByteCnt+1 ' Increment array index pointer
WEND ' Exit only when RCREG is clear
RESUME ' Return to normal operation prior to interrupt
ENABLE

---------------------------------------------------

Isn't DISABLE an unexecutable statement? Shouldn't it be the 1st statement of Main?

Then at the bottom of OutMsg, we could GOTO the WHILE statement as it is doing now; label Main1 on Disable, and Main2 on While?

Or am I missing something?

Robert
:)

mister_e
- 27th February 2005, 19:51
Hi Robert,

NOP, see PBP manual. Interrupt handler must be write like this. I agree that it looks weird but compiler handle it for you.

Demon
- 27th February 2005, 19:57
The compiler is wrong, and I am right...

Robert
:D

Demon
- 27th February 2005, 23:52
Bruce, your code works perfectly when I process a single record. But I'm trying to add a paragraph at the bottom to read multiple records and failing miserably. I'm sure I'm screwing up the INTERUPT controls. As it stands, RESUME returns into the Doodle paragraph and stays there until my hair falls out (which will be soon).

I tried to add ON INTERUPT immediately before the Doodle, followed by an INTCON=$80, but I must be messing something up doing that. I want the interupts to happen ONLY during the Doodle logic. I don't want it to fire up while I'm in the middle of extracting the bytes from BytesIn and writing them onto the EEPROM.

Also, when you 'Trash any left over characters in RCREG buffer, I will be losing characters from the next record. I have to save that in a temporary array and load it back at the start of BytesIn somehow.

Robert
:(

Demon
- 28th February 2005, 01:21
Ok,

I started again from your code, and modified one thing at a time. I've removed the comments to make it easier to read here (I figure you don't need your own comments). :)

1. I saved the data from the 1st record by copying it into BytesGP[ByteGPN]. I need that data so I can write it to the EEPROM.

2. I was able to get just Doodle under Interupt control.

3. I was able to save the data from RCREG. There was indeed the 1st character from the next record in there. The data is stored in BytesBK[ByteBKN].

?. But I can't figure out what I'm doing wrong to get the rest of the 2nd record. I must be losing some kind of flag or something to tell USART not to hyperspace the rest of the 2nd record.

====================================
define LOADER_USED 1
ASM
LIST
INCLUDE 'M16F87X.INC' ; PM header
DEVICE PIC16F877, HS_OSC, WDT_OFF, PWRT_ON, BOD_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, PROTECT_OFF
XALL
NOLIST
ENDASM
define OSC 20
define HSER_BAUD 19200
DEFINE HSER_CLROERR 1
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 24h

GP VAR BYTE
BytesIn var byte[80]
ByteCnt var byte
BytesGP VAR BYTE[80]
ByteGPN VAR BYTE
BytesBK VAR BYTE[80]
ByteBKN VAR BYTE
X VAR BYTE
EOM CON "~"
OERR VAR RCSTA.1
CREN VAR RCSTA.4
RCIF VAR PIR1.5
ByteCnt = 0
ADCON1 = 7
INTCON = %11000000
PIE1.5 = 1
' -------------------------------------------------------------
GOTO Start
' -------------------------------------------------------------
Main:
WHILE RCIF
BytesIn[ByteCnt]=RCREG
If BytesIn[ByteCnt]=EOM then OutMsg
ByteCnt=ByteCnt+1
WEND
RESUME
' -------------------------------------------------------------
OutMsg:
HSEROUT [13,10,dec ByteCnt," Bytes Rcvd:",STR BytesIn\ByteCnt]
FOR GP=0 to ByteCnt
BytesGP[GP]=BytesIn[GP]
BytesIn[GP]=0
NEXT
ByteGPN=ByteCnt-1
ByteCnt=0
ByteBKN=0
WHILE RCIF
BytesBK[ByteBKN]=RCREG
ByteBKN=ByteBKN+1
WEND
GOTO Main
' -------------------------------------------------------------
On Interrupt Goto Main
Doodle:
FOR X = 0 TO 250 : PAUSEUS 20 : NEXT X
FOR X = 0 TO 250 : PAUSEUS 20 : NEXT X
RETURN
INTCON=$80
' -------------------------------------------------------------
Start:
ByteGPN=0
WHILE ByteGPN=0 : GOsub Doodle : Wend
'''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''
' BytesGP[ByteGPN] Data from BytesIn is saved here for EEPROM
'''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''
' Place contents trashed from RCREG back in beginning of BytesIn
ByteCnt=ByteBKN-1
For X=0 TO ByteCnt
BytesIn[X]=BytesBK[X]
NEXT X

HSEROUT [13,10,dec ByteCnt," Bytes Saved:",STR BytesIn\ByteCnt]
GOTO Start
' -------------------------------------------------------------
end

Demon
- 28th February 2005, 03:28
I went for a nap after my last post and not 2 minutes later, I remember this:

"If you just need to PIC to tell the PC to stop sending data, connect the PIC flow control pin to the PC CTS pin."

Robert
:)

Bruce
- 28th February 2005, 03:51
Why not do something useful with the data received instead of wasting time in the doodle routine or writing everything received into another array?

Once you receive the terminating character, write your data to EEPROM, then wait for the next packet.

Also, you don't need all this;

ASM
LIST
INCLUDE 'M16F87X.INC' ; PM header
DEVICE PIC16F877, HS_OSC, WDT_OFF, PWRT_ON, BOD_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, PROTECT_OFF
XALL
NOLIST
ENDASM

Just drop in your fuse definitions like below, and leave the rest to PBP. It does all this for you.

@ DEVICE PIC16F877, HS_OSC, WDT_OFF, PWRT_ON, BOD_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, PROTECT_OFF

This routine;

WHILE RCIF
BytesBK=RCREG
ByteBKN=ByteBKN+1
WEND

Just clears whatever characters may have arrived after the terminating character was received. You want to be sure RCREG is empty & RCIF is clear before your next data packet shows up.

At some point, you're going to need some kind of synchronization with your PC program sending your data. You can't just keep slamming data into the USART without doing something with it to clear the array, and you're going to need some time to write your data to EEPROM (without interrupts enabled).

You do not want interrupts enabled when writing data to the EEPROM, so you will definitely want to implement something to let the PC know you're busy.

Example scenario:

PIC requests data from PC.
PC sends packet with terminating character.
PIC receives & stashes data in array until terminating character is received.
PIC processes data.
PC waits for signal from PIC to send next packet.
PIC says OK, let's have it.
PC sends next data packet.

[b]Two way communications is the key.

Strip all the useless stuff out of my example. You don't need to send everything back to the PC terminal program or waste time in the doodle sub-routine. That was just an example showing how to receive streaming data, and key on the terminating character to find the end-of-packet.

The time you spend in re-writing everything into another array, pauses, etc,, could be used for processing your inbound data, and let you setup & wait for the next packet.

Note: Watch for stuff like this;

On Interrupt Goto Main
Doodle:
FOR X = 0 TO 250 : PAUSEUS 20 : NEXT X
FOR X = 0 TO 250 : PAUSEUS 20 : NEXT X
RETURN
INTCON=$80

Program flow will never reach INTCON=$80 because it RETURNs before landing on it.

Demon
- 6th March 2005, 02:55
Hi Bruce,

"If you just need to PIC to tell the PC to stop sending data, connect the PIC flow control pin to the PC CTS pin."

I tried that, didn't work.

"Once you receive the terminating character, write your data to EEPROM, then wait for the next packet."

I tried that too, writing to EEPROM takes too long. The balance of data goes to hyperspace.

"Just clears whatever characters may have arrived after the terminating character was received. You want to be sure RCREG is empty & RCIF is clear before your next data packet shows up."

I can't exactly do that. Those characters sitting in the 2nd byte of RCREG and in RSR are the start of the next record.

"You do not want interrupts enabled when writing data to the EEPROM, so you will definitely want to implement something to let the PC know you're busy."

Yup, I only have interupts enabled in a small loop where I'm waiting for input. Besides CTS, which I can't get to work, is there another means of telling the PC to stop sending? It looks to me like the PC only listens to CTS at the end of his packet, not in the middle.

"At some point, you're going to need some kind of synchronization with your PC program sending your data. You can't just keep slamming data into the USART without doing something with it to clear the array, and you're going to need some time to write your data to EEPROM (without interrupts enabled)."

Do you have any idea how to do that? I've been going through pages 101 and 102 of the PIC 16F877 - USART ASYNCHRONOUS RECEIVER, and tried a ton of combinations using the flags they mention. Nothing works as expected.

I can read my entire file without any problems, I just don't have time to process the records. I don't even have time to write to EEPROM without doing any record formatting whatsoever. I just set the location to 1 and write a record with zeroes.

I have to momentarily interrupt the transfer, but I can't figure out how. Mister E has been giving this a try on his end and as far as I know, he's still stumped.

Robert
:(

Demon
- 6th March 2005, 05:36
I think I figured it out.

I lowered the BAUD rate down until I got to 2400 and things seem ok at first glance. Since the PC didn't want to wait or wasn't receiving the CTS flag fast enough, I guessed that lowering the transfer speed would give it more time to react.

I have to go line by line to make sure no garbage crept through isolated areas, but the records line up and look good.

Robert
:)

mister_e
- 6th March 2005, 09:54
to use CTS, you must ensure your terminal software handle it. If you're using MicroCode studio... it does'nt. Only RealTerm, or others with proper FlowControl setting CTS/RTS or DSR/DTR will stop when you clear CTS... in the worst case... $#%#$!#%$##*#$* hyperterm can stop too... if you're able to make it work... $%$### hyperterm ...

BTW, at this poit, it looks like any of those terminal program i use, handle poor the flow control. I can stop, receive echo back a character of 4Mb files without any delay between receive, but if i place 5-10 or else uSec or mSec delay between each CTS i'm screw up. it's skip character, or i get garbage...

still looks like the program stop serial out in the middle of a character or else.

i figure i'll have to make my own software... again. we can't never trust somebody on this earth... still a pain to have a 100% workable program... Terminal 2.xyz is a big piece of &^&^%@@$%... sorry for the person who refer this program...

As Bruce said, 2 way comm is the way... i agree. Probably better than CTS/RTS bulls.h.i.t... wich is probably just good enough to start transfer and stop at the end... or

i'm missing something trivial on that.
my terminal program is not good enough.. but for sure better than Hyperterm

Demon
- 6th March 2005, 19:32
Yup,


I couldn't get RealTerm to work properly either, I get garbage chatacters echoed back, and nothing goes to the PIC. HypeTerminal (R intentionally left out) is worse, I don't get any feedback at all.

I've been using the serial window from Studio Plus and it looks like the best solution for me. I copy my datafile from NotePad, paste in the SEND window, CLICK, and away it goes. I lose out on some of the echo at the bottom of the file, but I don't really care. I also display on the LCD and the last records seem to be there.

So now I'm going to write a program to read back from EEPROM. It's a link list database, so I have to write the code to follow through all the pointers and display the data back on the PC; using HSEROUT should not be a problem at this point.

It's not a perfect solution, 2400 BAUD ain't something to brag about, but it seems to work. Since this download will not be used often, that suits me fine. As long as it works reliably, I'm happy.

Robert
:)

Bruce
- 6th March 2005, 21:12
Take a look at the source code for one of the free boot-loader programs out there. You'll see how the PIC firmware & PC loader software work together (with two-way communications) to transfer large files from PC to PIC.

mister_e
- 6th March 2005, 21:45
yup, that's for sure Bruce, this is why i plan to do my own terminal program for some 'specific' purpose.

Send a packet to PIC, PIC send 'ok' (or whatever else), once PC receive it, send next packet, and so on. That imply to build our own program instead of using CTS/RTS DTR/DSR with already made terminal program. AND we save i/o for handshaking.