|
|
View previous topic :: View next topic |
Author |
Message |
MrColin
Joined: 05 Sep 2014 Posts: 13
|
#use rs232 and its effect on parity |
Posted: Fri Dec 12, 2014 10:20 am |
|
|
Compiler: v4.121
PIC: 16F1960
Hi. My code is doing something a little unexpected and I'm hoping you can clear up why.
My device has to be able to support RS232 with and without parity. At the start of my software I have:
Code: | #use rs232(baud=57600, UART1, PARITY=N, BITS=8, ERRORS, STOP=1, DISABLE_INTS, stream=UART_NO_PARITY)
#use rs232(baud=57600, UART1, PARITY=O, BITS=8, ERRORS, STOP=1, DISABLE_INTS, LONG_DATA, stream=UART_PARITY) |
And when the device needs to reconfigure itself I update my serial settings:
Code: |
if (serial_setup.parity){
setup_uart(57600, UART_PARITY);
}
else{
setup_uart(57600, UART_NO_PARITY);
}
|
Then, when reading data on an ISR I use:
Code: |
if(serial_setup.parity){
long_c = fgetc(UART_PARITY);
c = (uint8_t)(long_c&0x00FF);
p_bit = ((long_c&0x0100) == 0x0100);
else{
c = fgetc(UART_NO_PARITY);
}
|
The problem I am seeing though is that when I'm reading back data which has no parity, and the device is reading using the UART_NO_PARITY stream, it is reading the data incorrectly unless I have parity enabled on the device it is talking to. It does not use the NO_PARITY stream.
However, when writing everything works as expected.
If I flip the order of my '#use rs232' directives (ie. declare NO_PARITY last) then my reading operations work as expected, but my write operations are broken.
Here is my write operation:
Code: |
if(serial_setup.parity){
long_c = parity_bit(c, serial_setup.parity);
long_c <<= 8;
long_c |= c;
fputc(long_c, UART_PARITY);
}
else{
fputc(c, UART_NO_PARITY);
}
|
Am I missing something critical here? Thanks for your time. |
|
|
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Fri Dec 12, 2014 10:45 am |
|
|
Since both #use statements refer to UART1, only the last one will actually be used. You won't end up with two different streams pointing to the same UART.
What you're trying to do may be possible by manually changing some register values - I've never tried this so I don't know if you can change them "on the fly". _________________ Jürgen
www.jgscraft.com |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 12, 2014 11:23 am |
|
|
Quote: | Compiler: v4.121
PIC: 16F1960 |
I don't know what PIC you have, since that one doesn't exist.
I compiled the following test program with vs. 5.032 and vs. 4.121.
I then compared the two .LST files with ExamDiff (vs. 1.9).
http://www.prestosoft.com/edp_examdiff.asp
Code: |
#include <16F886.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=57600, UART1, PARITY=N, BITS=8, ERRORS, STOP=1, DISABLE_INTS, stream=UART_NO_PARITY)
#use rs232(baud=57600, UART1, PARITY=O, BITS=8, ERRORS, STOP=1, DISABLE_INTS, LONG_DATA, stream=UART_PARITY)
//======================
void main()
{
int16 long_c;
int8 c;
setup_uart(57600, UART_PARITY);
long_c = fgetc(UART_PARITY);
fputc(long_c, UART_PARITY);
setup_uart(57600, UART_NO_PARITY);
c = fgetc(UART_NO_PARITY);
fputc(c, UART_NO_PARITY);
while(TRUE);
}
|
Here is the .LST file for the two setup lines for vs. 4.121:
Code: | .................... setup_uart(57600, UART_PARITY);
008E: BSF STATUS.RP0
008F: BSF BAUDCTL.BRG16
0090: MOVLW 10
0091: BCF STATUS.RP1
0092: MOVWF SPBRG
0093: MOVLW 00
0094: MOVWF SPBRGH
0095: MOVLW E6
0096: MOVWF TXSTA
....................
.................... setup_uart(57600, UART_NO_PARITY);
00A2: BSF STATUS.RP0
00A3: BSF STATUS.RP1
00A4: BSF BAUDCTL.BRG16
00A5: MOVLW 10
00A6: BCF STATUS.RP1
00A7: MOVWF SPBRG
00A8: MOVLW 00
00A9: MOVWF SPBRGH
00AA: MOVLW A6
00AB: MOVWF TXSTA
|
Here is the .LST file for vs. 5.032. Notice that it configures the RCSTA
register for parity/no parity, but your version does not:
Code: | .................... setup_uart(57600, UART_PARITY);
008F: BSF STATUS.RP0
0090: BSF BAUDCTL.BRG16
0091: MOVLW 10
0092: BCF STATUS.RP1
0093: MOVWF SPBRG
0094: MOVLW 00
0095: MOVWF SPBRGH
0096: MOVLW E6
0097: MOVWF TXSTA
0098: MOVLW D0 <== *** vs. 5.032 puts 0xD0 in RCSTA
0099: BCF STATUS.RP0
009A: MOVWF RCSTA
....................
.................... setup_uart(57600, UART_NO_PARITY);
00A5: BSF STATUS.RP0
00A6: BSF STATUS.RP1
00A7: BSF BAUDCTL.BRG16
00A8: MOVLW 10
00A9: BCF STATUS.RP1
00AA: MOVWF SPBRG
00AB: MOVLW 00
00AC: MOVWF SPBRGH
00AD: MOVLW A6
00AE: MOVWF TXSTA
00AF: MOVLW 90 <== *** vs. 5.032 puts 0x90 in RCSTA
00B0: BCF STATUS.RP0
00B1: MOVWF RCSTA |
You could fix this manually with a #byte statement to define RCSTA
and then write to it directly in your program. Example:
Code: |
#byte RCSTA = getenv("SFR:RCSTA")
.
.
.
if (serial_setup.parity){
setup_uart(57600, UART_PARITY);
RCSTA = 0xd0; // Fix for vs. 4.121
}
else{
setup_uart(57600, UART_NO_PARITY);
RCSTA = 0x90; // Fix for vs. 4.121
} |
Quote: | If I flip the order of my '#use rs232' directives |
That's because the last #use rs232() statement is the one used by
the compiler to configure the UART setup code at the start of main().
If you flip the statements, you change the initial setup code.
This setup code can be seen in the .LST file.
In your case, the parity stream is the last one, so RCSTA is setup for
parity. Your problem then occurs because of a bug in setup_uart() in
vs. 4.121, where it fails to setup RCSTA. So RCSTA stays setup for
parity, when you wanted it to change it to no parity. |
|
|
MrColin
Joined: 05 Sep 2014 Posts: 13
|
|
Posted: Mon Dec 15, 2014 4:34 am |
|
|
Wow. Thanks for that incredibly full answer. Setting that bit-flag worked straight away! Parity is now restored.
Also, it was the PIC16F690. Dyslexic fingers said it was a 960.
Thanks again! |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Mon Dec 15, 2014 5:22 am |
|
|
Hmm, you're probably aware of all this stuff, but just in case, and for others reading the thread who may not be so sure, its probably worth talking a bit about parity and data bits in async comms.
I'm not sure about parity on CCS C comms, but generally the parity bit is separate from the data bits. So 8N1 is eight data bits, no parity and one stop bit, so, including the start bit, that's ten in all. 8O1 would be one start, eight data bits, one parity bit and one stop bit, so eleven bits in all.
ASCII is, or was for much of its life, a seven bit code, often with even parity, one or two stop bits, i.e. 7E1 or 7E2. Two stop bits was often only needed on mechanical terminals, such as the classic ASR33. VDUs generally were often fast enough to be able to cope with just one stop bit. Parity was often ignored, and so over time people tended to use what would be the parity bit for data giving eight bits of useful data, but without parity, i.e. the familiar 8N1. The equivalent of 8N1 with odd parity is 7O1, not 8O1, which gives a longer, and incompatible frame. Of course, if the parity is to be generated by software rather than hardware, then seven bits plus parity and one stop bit can be transmitted with hardware set to 8N1.
I'm not sure what the CCS code/Microchip hardware does - I've not had to write code to transmit and receive async comms with parity for a decade or more - I do everything 8N1. I do use Modbus, but I use the CCS drivers for that, and it deals with the issue by having a fixed 8 (RTU) or 7 (ASCII) data field and one stop bit if there's parity e.g. 8E1, and two if there's not, e.g. 8N2. But for a given mode, ASCII or RTU, the data frames are always the same length regardless of whether parity is used or not. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|