CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

RS232 can't receive Character occasionaly?

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
stefsun



Joined: 23 May 2007
Posts: 22

View user's profile Send private message

RS232 can't receive Character occasionaly?
PostPosted: Thu May 24, 2007 12:07 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Thu May 24, 2007 2:26 am     Reply with quote

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







PostPosted: Thu May 24, 2007 5:15 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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