![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
spcshen
Joined: 06 Jul 2007 Posts: 4
|
RS232 Receiving problem with PIC 16F877A |
Posted: Fri Jul 06, 2007 3:52 pm |
|
|
Hello
I am trying to use PIC16F877A to receive data from a radio transceiver. My ultimate goal is to have the transceiver receive some charactors, and store in a string in the PIC for later use. So I am using the RS232 related functions to do it. My first test is to just receive 1 charactor, but I always end up receiving null.
here's my code
Code: |
#include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //Crystal oscillator
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES WRT_50% //Lower half of Program Memory is Write Protected
#use delay(clock=20000000, HS)
#use rs232(baud=9600, parity=N, xmit=PIN_A0, rcv=PIN_C7, timeout=500, bits=8, stop=1, errors)
#use fast_io(b) //set port b manually
void main()
{
char value;
set_tris_b(0x03); //set pin B0 and B1 as input pins
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B5);
output_low(PIN_B6);
output_low(PIN_B7);
while(true)
{
if(kbhit())
{
value=getc();
output_high(PIN_B3) //turn on an LED
putc(value);
delay_ms(100);
output_low(PIN_B3) //turn off the LED
}
}
}
|
First, I know my baud rate is correct. Since C7 is the USART receiving pin of the PIC, I specified it to be rcv in the #use rs232().
My transceiver will hold high to pin C7 when there's no data (at 2.8V, theoretically, it should be 3.3v). Say when a charactor is received through radio, the transciver will start sending this charactor right away. For example, the charactor 'a' is received, pin c7 first goes low for 1 pulse, the high for 1 pulse, low for 4 pulses, high for 2 pulses, low for 1 pulse, and return to holding high ( each pulse is 104us since baud rate is 9600). ASCII for 'a' is 110 0001 in binary, and there is a start bit at logic low, and an end bit at logic low, so I know the transceiver is doing correctly. (I am reading all these using an oscilloscope)
I used getc() to catch this charactor and save in a char, value. When I do putc(value), I read it, it's always null, 000000000 on the xmit pin, A0.
My understanding is that since pin c7 is a hardware USART pin, so when the transciver sends the pulse to pin c7, the charactor is saved in a buffer in the PIC, and when kbhit() returns true, that means I have received something and is ready to be read. I do get my LED turned on everytime i send something through radio, which means it's ready to read. Then why is the PIC not getting the charactor 'a'?
So, what maybe the problem? Am I missing something important(like I need to configure something?) ? Is the 2.8V a problem?
Any help and suggestion is greatly appreciated. THX! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 06, 2007 4:17 pm |
|
|
Quote: | My understanding is that since pin c7 is a hardware USART pin, so when
the transceiver sends the pulse to pin c7, the character is saved in a
buffer in the PIC. |
You must specify both hardware pins (C6 for xmit, C7 for recv) in the
#use rs232() statement, to make the compiler generate code for the
hardware UART. Your current statement (with A0 and C7) will generate
code for a software UART on both pins.
You didn't say what your PIC Vdd voltage is. If it's 5 volts, then 2.8v
is not high enough when driving pin C7. The PIC data sheet says that
pin C7 is a "schmitt trigger" input pin, and requires 0.8 x Vdd as the
minimum Vih level. If the PIC is running at 5v, then Vih is 4v for pin C7. |
|
![](templates/subSilver/images/spacer.gif) |
spcshen
Joined: 06 Jul 2007 Posts: 4
|
|
Posted: Fri Jul 06, 2007 6:27 pm |
|
|
thx for the hints. But since I don't have any component at hand to switch the voltage to high enough, can I use some kind of software UART code and different port or pins to accomplish this? You say that I must specify xmit to C6 since it's the hardware UART transmit pin, but I can successfully send data to my transceiver using pin A0. So what you mean is that both transmit and receive pins needs to to be specified as the hardware UART pins in order for the compiler to generate code for hardware UART? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 06, 2007 7:16 pm |
|
|
I would advise you to make test programs and look at the .LST file to
see what the compiler is doing.
See this thread. It tells how to check if the compiler is generating code
for a hardware UART:
http://www.ccsinfo.com/forum/viewtopic.php?t=22149 |
|
![](templates/subSilver/images/spacer.gif) |
Guest
|
|
Posted: Fri Jul 06, 2007 8:05 pm |
|
|
thx again for that reference. Now if I do want to use soft UART to do this job, it should be possible as well, isn't it? Most digital I/O pins that's not meant for hardware UART should be able to do it if the software UART is set up correctly, am I right? And how do you generate .LST file? I have never done it before...thx |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 06, 2007 8:35 pm |
|
|
Look in your project directory. A .LST file is generated after every
successful compilation.
If you can use the hardware UART, do so. It's far better than a software
UART. |
|
![](templates/subSilver/images/spacer.gif) |
spcshen
Joined: 06 Jul 2007 Posts: 4
|
|
Posted: Fri Jul 06, 2007 9:05 pm |
|
|
I also know that if I could get the hardware UART to work, it's a better choice. However, as you know, the transceiver outputs at 3.3V(2.8V in reality) rather than 5V, which is common in newer electronics, and the hardware UART pins for the PIC uses schmitt triggers, which requires more than 4V to function correctly. I have no ways to get around that currently, and making my system work has the highest priority. So if I could make software UART work, then I would settle with that for now untill I find some way to convert voltage. But in general, would you tell me how the software UART work? Since data comes in asynchronously, how is data stored before getc() or gets() can be called, and how many bytes can be stored? Thank you very much! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 06, 2007 11:52 pm |
|
|
The CCS software UART library code works by polling the specified Rx pin
to detect a start bit. Then it does software delay loops so it can test for
the remaining bits at specific intervals. The PIC cannot be interrupted
during while the software UART is receiving a byte, or the byte will be lost. |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Sat Jul 07, 2007 6:30 am |
|
|
I would only use the software UART as a last resort. There is no buffering of data, all data is sent and received while the processor is running a tight loop. Interrupts will be disabled during these loops to prevent corrupted data transmissions. Just think about a 9600 baud signal to stall your program 1ms for every byte you transmit or receive.
The main problem in the software UART is the reception of data. Because there are no interrupt signals to tell you data is comming in you will have to call kbhit() at least ten times the incomming bitrate to ensure no data is lost.
It is possible to get a pseudo interrupt mechanism for data reception by also connecting the incomming signal line to the external interrupt input pin. This works most of the time except when other interrupt routines are already active and generate an unwanted delay.
Have you considered using the LF version of the 877A? Than your processor can run at the same low voltage as the I/O device. Drawback is the maximum clock frequency of 8.8MHz at 2.8V. |
|
![](templates/subSilver/images/spacer.gif) |
spcshen
Joined: 06 Jul 2007 Posts: 4
|
|
Posted: Mon Jul 09, 2007 5:02 pm |
|
|
Since I can't get the transceiver to output above 4V, so I tested something else. I make a regular I/O pin to imitate the waveform that would have been from the transceiver, only it's at 5V to ensure that it would be read correctly. I used pin_b7 to do the output and tied b7 to c7 and have the following code to test receiving 1 single charactor 'a'.
Code: |
char value;
output_high(PIN_B7);
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
output_low(PIN_B7);
delay_us(104);
output_high(PIN_B7);
delay_us(104);
output_low(PIN_B7);
delay_us(416);
output_high(PIN_B7);
delay_us(208);
output_low(PIN_B7);
delay_us(104);
output_high(PIN_B7); //these lines are imitating 'a'
delay_ms(1);
if(kbhit())
{
value=getc();
printf(value); //I receive 'a' from here
}
|
using this piece of code, I would successfully receive an 'a' everytime on C7.
Then I tried to read 2 charactors at once using the following code, but received some weird values
Code: |
char value[10];
output_high(PIN_B7);
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
output_low(PIN_B7);
delay_us(104);
output_high(PIN_B7);
delay_us(104);
output_low(PIN_B7);
delay_us(416);
output_high(PIN_B7);
delay_us(208);
output_low(PIN_B7);
delay_us(104);
output_high(PIN_B7); //these lines are imitating 'a'
delay_us(104);
output_low(PIN_B7);
delay_us(208);
output_high(PIN_B7);
delay_us(104);
output_low(PIN_B7);
delay_us(312);
output_high(PIN_B7);
delay_us(208);
output_low(PIN_B7);
delay_us(104);
output_high(PIN_B7); //these lines are imitating 'b'
delay_ms(1);
if(kbhit())
{
gets(value);
printf(value); //I receive weird things from here
}
|
My guess is that even hardware UART could only hold 1 char at once, so when I read 2 chars together, something went wrong because I didn't use gets() or getc() early enough. If I started kbhit() and getc() or gets() before the end of the first char is send, I would receive correctly?
Could someone confirm my guess? Any suggestion is helpful and appreciated..Thanks!! |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 09, 2007 7:12 pm |
|
|
Read the CCS manual on Gets(). Here's the description:
Quote: | GETS()
Reads characters (using GETC()) into the string until a RETURN
(value 13) is encountered. The string is terminated with a 0. |
Also add the ERRORS parameter to your #use rs232() statement.
If you get an overrun error, it will then be cleared automatically. |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|