|
|
View previous topic :: View next topic |
Author |
Message |
stefsun
Joined: 23 May 2007 Posts: 22
|
RS232 can't receive Character occasionaly? |
Posted: Thu May 24, 2007 12:07 am |
|
|
I use the pic16F877's RS232 Communication with PC,
After acquisiting the V of A0,when delay is long,PIC16F877 can't receive the single character,(for example the character Q,pic16F877 is still acqisiting)
printf( "delay_ms(300)\n" );
delay_ms(300);
when delay is 300ms,PIC can receive Q and stop acquisiting,
when delay is 3000ms(3s),PIC can't receive Q.
the code is
Code: |
///////////////////////////////////////////////////////////////////////////////
// MPLAB IDE V7.11 + CCS C3.18
// Use 16F877A ADC and Rs232 for MCD2-demo
//
///////////////////////////////////////////////////////////////////////////////
#include <16F877.h> // PIC16F877 header file
#pragma device ADC=10 // 10 bits ADC
#pragma use delay(clock=4000000) // for 4Mhz crystal
#pragma fuses XT, NOWDT, NOPROTECT, NOLVP // for debug mode
#pragma use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, stream=MYPC)
// rs232 setting
#define DO_NOTHING 0
#define DO_START_ADC 1
#define DO_END_ADC 2
/*===========================================================================*/
void main(void)
{
int16 int_volt;
int8 str_volt[21];
float flt_volt;
int8 do_what = DO_NOTHING;
int8 tmp;
SET_TRIS_A( 0x01 );
while(1){
// if rs232 get char
delay_ms(100);
if(0 != kbhit())
{
tmp = fgetc(MYPC);
switch(tmp)
{
case 'S':
case 's':
printf( "S:StartADC\n" );
do_what = DO_START_ADC;
// init pic16f877a adc
setup_adc_ports(RA0_ANALOG);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(0);
break;
case 'Q':
case 'q':
printf( "Q:EndADC\n" );
do_what = DO_END_ADC;
// adc off
setup_adc(ADC_OFF);
break;
default : // rs232 get other char
putc(tmp);
break;
}//end switch(tmp)
}//end if(kbhit())
switch(do_what)
{
case DO_START_ADC:
// start adc and send result to PC
int_volt = read_adc();
flt_volt = 5.0 * int_volt / 0x3ff;
sprintf(str_volt, "ADC_CH0:%1.3fV\n", flt_volt);
printf(str_volt);
printf( "delay_ms(30)\n" );
delay_ms(300);
break;
case DO_END_ADC:
// you want to do
break;
case DO_NOTHING:
// you want to do
break;
default:
break;
}//end switch(do_what)
}//end while(1)
}//end main() |
|
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Thu May 24, 2007 2:26 am |
|
|
RS232 is asynchronous. That means when you code is executing an incoming character can arrrive at anytime. Anytime often meanss right in the middle of any line of code. Code that takes the most time Ex delays is then the most vunerable. The only way to guarantee the char can be received is with the hardware UART and an interrupt service routine. Sure if the baud rate is low and you main code has no delays you can make it work providing your rs232 polling loop executes in the order of a bit time ( approx 1/10 th of the baud rate) or less. This issue has been asked and answered often on this board. Again rs232 is asynchronous the chars don't show up when you read them so your code must be there ( at kbhit() ) when they arrive. The reason that some chars are seen by your code is probably just luck that your code got to kbhit in time to see the start bit. |
|
|
Ttelmah Guest
|
|
Posted: Thu May 24, 2007 5:15 am |
|
|
With the hardware UART, there are two characters of input buffering, plus the input shiift regoster (giving just under 3 characters of total buffer). If more than this number of characters are received, without calling code to retrieve the characters from the hardware, the hardware raises the 'OERR' flag (overrun error), _and disables the UART_.
Now at 9600bps, a character can basically arrive every mSec. You don't say how the characters are being sent, but with the 3 second delay, whatever is sending the characters, is sending more characters than can be held in the hardware, so the UART gets disabled...
First, add the keyword 'ERRORS' to your #use RS232 line. This adds code to the handler, which will automatically reset this overrun error if it occurs. Data will still have been lost, but at least the system has the ability to recover.
Then 'rethink' how you work. Look at making the receive task interrupt driven, so that a larger buffer can be used. Then look at other ways of doing delays. Generally, long software 'delays' inside code, are relatively poor programming, on systems that want to perform tasks. Instead look at using one of the hardware timers, to generate a system 'tick' (this is how the PC works, with a 'tick' of 10mSec, or 18mSec, depending on the OS). Then when you want to delay for 3 seconds, simply 'count' ticks, while still looping, and checking for other data to arrive.
Best Wishes |
|
|
|
|
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
|