Another Baudrate Issue, when switching from 9600baud to 300baud

baudrate

I am communicating with an 8051 MCU via a CPU. When I i/p a character on the Keyboard, I expect the MCU to transmit a character string back to the CPU, which I can view from the terminal window., one for 9600 Baud, 8N1 and the other for 300 baud,7E1. At initialization, I am communicating at 9600. At a the input of another command character, I intend to switch the baud rate to 300 baud. And this works, as it MCU send a confirmation string to the 300baud terminal. But after the switching it appears that the MCU does not receive any longer, as though the Serial ISR no longer functions. I used a serial port monitor to see what happens, and I discovered that I am actually sending after the switching, but the MCU does not recognize it, appearing to be in a while(1) loop. Find below the C code:

Main:

main()    
{    
    SET=1;    
    IE=0x90;    //Enabling serial interrupt.    
    initUART_baud(SET);     //9600 Baud.    
    while(1)    
    {    
        if(debug  && !ch_baud)    
        {
            debug=0; 
            UART_SND(intro);
        } else if(debug1 && !ch_baud) {
            debug1=0;
            UART_SND(intro1);
        } else if(ch_baud) {
            initUART_baud(SET=~SET);    //change baud rate.    
            ch_baud=0;    
            UART_SND(NEWbaud);    
        } else 
            continue;    
    }    
}

void initUART_baud(unsigned char change)    
{ //initializing UART to initial 300baud.

    SCON = 0x50;            //UART in MODE 1, RECIEVED enabled.    
    TMOD = 0x20;            //auto-reload mode and Timer 1 selected    
    if(!change)//if Zero    
    {
        TH1=TL1=0xA0;
        ST_7E1=0;
    }   //300 BAUD    
    else    
    {
        TH1=TL1=-3;
        ST_7E1=1;
    }   //9600 BAUD    
    TR1 = 1;                //ACTIVATE TIMER T1    
}    

void UART_SND(unsigned char *SND_BUFF)    
{//SENDING STRING

    unsigned char value;        
    while(*SND_BUFF)    
    {   
        if(!ST_7E1)    
            value = Parity_7E1(*SND_BUFF);  //CHANGE DATA FORMAT (7E1)    
        else    
            value=*SND_BUFF;    
        SBUF=value;    
        while(!TI);    
        TI=0;    
        SND_BUFF++;    
    }    
    SBUF = 0x0D;    //'CF'    
    while(!TI);                                
    TI=0;    
}       


void serial_Optical_isr(void) interrupt 4      
{ 
    RI = 0;    
    IR_BUFF = SBUF;     //putting the value in UART into temporary buffer    
    switch (IRvalue)    
    {    
        case START:                      
            if(IR_BUFF==0x54)   // If "T" is send    
            {//HHU sending Request    
                IRvalue=DIS;    
            }    
            break;    

        case DIS:    
            if(IR_BUFF==0x44)   //D    
            {
                debug=1;
                IRvalue=START;
            }
            else if (IR_BUFF==0x42)    //B    
            {
                debug1=1;
                IRvalue=START;
            }
            else if (IR_BUFF==0x43)    //C    
            {
                ch_baud=1;
                IRvalue=START;
            }    
            else 
                IRvalue=START;   
            break;   
    }
}

This code ought to transmit the character in buffer "intro", when TD is pressed, and the character in buffer "intro1", when TB is pressed. And when TC is pressed, the baud rate changes and transmit character in buffer "NEWbaud" to the 300baud terminal. And the TD & TC send intro and intro1 string respectively when pressed at the same 300 baud.

I will appriciate any form of assistanc. If there is a bug in the code, do point my attention to it. Thanks a buncH!

Best Answer

If I remember correctly, the 8051 will ignore any character which is received with an invalid stop bit (detected framing error). If characters are being sent back-to-back, it's possible for an arbitrary number of characters to have framing errors unless the data stream contains a FF, FE, FC, F8, F0, E0, C0, 80, or 00 (the nine characters which, if written in binary, do not contain the bit sequence "01"). Those nine characters may be received incorrectly, but the characters following them will be received correctly).

Addendum

A standard UART will drive its transmit line high when idle, until data is supposed to be sent. It will then drive the line low for precisely one bit time (called the "start bit"), then send (typically) eight bits of data, LSB first, for precisely one bit time each, and drive the line high for a minimum of one bit time (called the "stop bit") before sending the next byte (which will result in precisely one bit time low, then the data bits, etc.)

When a UART's receiver is idle, it will wait for a high-low transition. When one is seen, it will check the data line half a bit time later to ensure the line is still low; if not, it will go back to idle state. If the data line was still low at that point, it will then sample the data line nine more times, at one-bit-time intervals. The first eight of these will be latched as the eight data bits. The ninth sample (which should occur during the transmitted stop bit) should be high. If it isn't, either there was noise on the line when the stop bit was being transmitted or (more likely) the receiver was triggered by a high-low transition other than the start bit; this condition is called a framing error.

The stop bit serves two purposes:

  1. It ensures that the next transmitted byte of data will begin with a high-low transmission;
  2. It provides an opportunity for the receiver to detect framing errors.
Note that depending upon the precise data being transmitted, it's possible that framing errors might not be detected, and that different UARTs will behave differently when they do occur. The 8051 reacts to framing errors by simply pretending that a mis-framed byte was not received at all, behavior which is really not terribly helpful. Some other UARTs will record, for each byte, whether it was received with correct or incorrect framing; others will set a flag when a framing error occurs, and the flag will remain set until the processor explicitly clears it, the idea being that when one is receiving a bunch of data, a framing error during a single byte will likely imply that much of the data is corrupt.

When framing errors occur, the receiver may not be able to function correctly until a pattern of data occurs on the line which will allow it to get back into sync. The best pattern for this purpose, which will work with essentially all receivers, is a data byte "FF". This byte will be sent with a single high-low transition (indeed, with only a single "low" bit--the start bit). If the receiver was out of sync when the byte is transmitted, its start bit may be mistakenly identified as a data bit from an earlier byte, but all of its data bits and the stop bit will be regarded as idle time between bytes. The next high-low transition on the line will be the start bit of the next character (as it should be).

PS--On many UART receive circuits, any of the byte values I listed will work to allow reception to get back in sync with transission. Some, however, will regard a "0" bit that's received where a stop bit should have been to be the start bit for the next byte. The value "FF" should work for any UART receive circuit, however.