how to write/read from USART Rx/Tx

Thread Starter

tuanvoi

Joined Oct 31, 2008
56
Hi all,
I've read the data sheet for my PIC18F4550. It explains me everything (i.e. how turn on USART, how to set mode "synchronous, a synchronous"...). However, one part that I think is not clearly explained is how to read/write the Tx/Rx pins. Could you please help me with this write/read from the pins Rx/Tx (I prefer MPLAB C compiler)? For example, If I want to write '1' to the Tx, how do I use the method? Or how do I read from pin Rx?
Thank you!
Tom
 
Last edited:

kbupnorth

Joined Sep 8, 2008
4
Somebody correct me if I'm wrong, but if I understand what your asking is you want to read/write to the pin as if it is a input/output pin. When the PIC is configured for USART, signals on the TX or RX pins are buffered into the TXREG or RXREG and read/write as a byte.
 

thatoneguy

Joined Feb 19, 2009
6,359
Here is a test snippet to test USART Comms on a 16F877A


Rich (BB code):
 
 3: #include[SIZE=+1]<pic[SIZE=+1].[/SIZE]h[SIZE=+1]>[/SIZE]              //include MCU head file
 4:  __CONFIG[SIZE=+1]([/SIZE]0x1832[SIZE=+1])[/SIZE][SIZE=+1];[/SIZE]        
 5: //THE configure of MCU,watchdog OFF,electrify delay OPEN,power down check OFF,
 6: //LOW power programme OFF,encrypt,4M crystal HS surge.
 7: 
 8: //---------------------------------------------
 9: //main program
10: void main[SIZE=+1]([/SIZE][SIZE=+1])[/SIZE]
11:  [SIZE=+1]{[/SIZE]
12:   TRISC[SIZE=+1]=[/SIZE]0XFF[SIZE=+1];[/SIZE]                 // set C PORT all OUTPUT 
13:   SPBRG[SIZE=+1]=[/SIZE]0XC[SIZE=+1];[/SIZE]                  //set baud rate 19200BPS 
14:   TXSTA[SIZE=+1]=[/SIZE]0X24[SIZE=+1];[/SIZE]                 //enable USART,set band rate is high
15:   RCSTA[SIZE=+1]=[/SIZE]0X90[SIZE=+1];[/SIZE]                 //enable USART continue receive
16:   RCIE[SIZE=+1]=[/SIZE]0X1[SIZE=+1];[/SIZE]                   //enable receive interrupt
17:   GIE[SIZE=+1]=[/SIZE]0X1[SIZE=+1];[/SIZE]                    // enable general interrupt 
18:   PEIE[SIZE=+1]=[/SIZE]0X1[SIZE=+1];[/SIZE]                   //enable outside interrupt
19:   while[SIZE=+1]([/SIZE]1[SIZE=+1])[/SIZE]                    // wait for interrupt
20:    [SIZE=+1]{[/SIZE][SIZE=+1];[/SIZE][SIZE=+1]}[/SIZE]
21:   [SIZE=+1]}[/SIZE]
22: 
23: //--------------------------------------------
24: //interrupt function
25: void interrupt usart[SIZE=+1]([/SIZE]void[SIZE=+1])[/SIZE]
26:   [SIZE=+1]{[/SIZE]
27:    if[SIZE=+1]([/SIZE]RCIE[SIZE=+1][SIZE=+1]&[/SIZE][SIZE=+1]&[/SIZE][/SIZE]RCIF[SIZE=+1])[/SIZE]            //judge if COMM receive interrupt
28:      [SIZE=+1]{[/SIZE]
29:       TXREG[SIZE=+1]=[/SIZE]RCREG[SIZE=+1];[/SIZE]           //send back  the receive data 
30:      [SIZE=+1]}[/SIZE]
31:    [SIZE=+1]}[/SIZE]
[/SIZE]

 

Thread Starter

tuanvoi

Joined Oct 31, 2008
56
When the Rx receives an 8bit data which is saved in register 'RCREG'. How do I read(what method) so that I can convert it back to binary.
And also how do I write to Tx 'TXREG' register?
Please correct me if I'm wrong. If I want to write 00000001 to TXREG. I will write TXREG = 00000001?
And on the receiver side Rx, how to I read the '00000001'? Thank you.
 

thatoneguy

Joined Feb 19, 2009
6,359
You need to define a variable to get the contents of the RX Register.

In the example above, it simply retransmits anything received.

Look at the datasheet for the IC to determine the serial properties, speed, byte size, buffer size, start/stop bits, parity, etc.

When data is received, it will create an interrupt, as seen above, at which time you can copy the data to a variable, test it for a value, etc. To send data, you need to simply assign the data to TX Register (as RX is above, you could use a different variable as source). You need to be sure the size of data is correct, which is shown in data sheet, configuration options.
 

Thread Starter

tuanvoi

Joined Oct 31, 2008
56
The 'variable' you've mentioned above, is it in 'char' or it depends on what type of data you define for Tx/Rx? If the variable type is only in 'char', how could I convert it to 'int' ?
I've read my datasheet saying that I can only send 1 byte at a time. When a byte sent, the interupt will occur to indicate a byte received. My problem is how to assign '00000001' (is it just TXREG = 00000001, if I want to send 1 in decimal?) to the Tx register (TXREG) to send. On the receive side, how can I test if 1 in decimal has been sent? Could you please explain to me 'thatoneguy'?
 

thatoneguy

Joined Feb 19, 2009
6,359
The PIC won't transmit until the size of transmit buffer is full. It will then send a start bit, data, stop bit typically, depends on your configuration.

A 0b00000001 wouldn't appear in the receive buffer until a start bit, 7 '0' data, 1 '1' data, then stop bit. Those would have to be received in a complete frame at the baud rate selected.

If you are only going to be looking for a single bit change, hi/low, then either set up an interrupt on change, or poll that pin for change.

Use an unsigned char in C for the variable if you are using 8 bit bytes, otherwise unsigned int, and lower speeds so errors can be analyzed. A 20MHz clock has about 1% clock errors in at certain data rates, such as 19,200.
 
Last edited:

Thread Starter

tuanvoi

Joined Oct 31, 2008
56
Here is my code
Rich (BB code):
#include <p18f4550.h>
#include <usart.h>
#include <delays.h>
#pragma config WDT=OFF,LVP=OFF,FOSC=HSPLL_HS,PLLDIV=5,CPUDIV=OSC2_PLL3 //run with external oscillator

void tryAgain_0(void)
{
   while(1)
   {
    if(!(BusyUSART()))
    {
     
     WriteUSART('1');//transmit char '1'
    }
    if (PIR1bits.RCIF == 1) // check if this bit is set meaning a byte received
     {
      char c = ReadUSART();//return a received byte in buffer, and put in parameter c
      if(c == '1')
       PORTAbits.RA0 = 1;
      else
       PORTAbits.RA0 = 0;
     }
   }
}
void tryAgain_1(void)
{
 while(1)
   {
    if(!(BusyUSART()))
    {
     
     WriteUSART('0');//transmit char '0'
    }
    if (PIR1bits.RCIF == 1) // check if this bit is set, meaning a byte received
     {
      char c = ReadUSART();//return a received byte in buffer, and put in parameter c
      if(c == '1')
       PORTAbits.RA0 = 1;
      else
       PORTAbits.RA0 = 0;
     }
   }
} 
void main(void)
{
//USART setup
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH & USART_ADDEN_OFF, 25);
/*
USART_TX_INT_OFF = 0b00000000  // Transmit interrupt off
USART_RX_INT_OFF = 0b00000000  // Receive interrupt off
USART_ASYNCH_MODE = 0b00000000  // Asynchronous mode
USART_EIGHT_BIT = 0b11111101  // 8-bit data
USART_CONT_RX = 0b00001000  // Continuous reception
USART_BRGH_HIGH = 0b11111111  // High baud rate
USART_ADDEN_OFF = 0b11011111
SPBRG = 25
*/
baudUSART(BAUD_IDLE_CLK_HIGH & BAUD_8_BIT_RATE & BAUD_WAKEUP_OFF & BAUD_AUTO_OFF & BAUD_IDLE_RX_PIN_STATE_HIGH & BAUD_IDLE_TX_PIN_STATE_HIGH);
/*
BAUD_IDLE_CLK_HIGH = 0b00010000  // idle state for clock is a high level
BAUD_8_BIT_RATE = 0b00000000  // 8-bit baud generation rate
BAUD_WAKEUP_OFF = 0b00000000  // RX pin not monitored
BAUD_IDLE_RX_PIN_STATE_HIGH = 0b11011111  // idle state for RX pin is high level
BAUD_IDLE_TX_PIN_STATE_HIGH = 0b11101111  // idle state for TX pin is high level
*/
ADCON0bits.ADON=0;
ADCON1 = 0x07;
//CMCON = 0x07;
TRISA = 0x00;
/* To set up USART */
RCSTAbits.SPEN = 1;
PORTCbits.RC7 = 1; //input coming from Rx pin
PORTCbits.RC0 = 0; //output meaning write to Tx pin
//TXSTA = 0b01101110; //configurations for transmit register
//RCSTA = 0b00110000; //configurations for receive register
TRISB = 0xFF;
 if(PORTBbits.RB0 == 1)
  {
    while(1)
   {
    if(!(BusyUSART()))
    {
     
     WriteUSART('1');//transmit char '1'
    }
    if (PIR1bits.RCIF == 1) // check if this bit is set meaning a byte received
     {
      char c = ReadUSART();//return a received byte in buffer, and put in parameter c
      if(c == '1')
       PORTAbits.RA0 = 1;
      else
       PORTAbits.RA0 = 0;
     }
       
    else if((BusyUSART()) && PIR1bits.RCIF !=0)
    {
     Delay10KTCYx(100);//delay approximately 1s    
     tryAgain_0();
    }
   }    
  }   
 
 else if (PORTBbits.RB0 == 0)
   while(1)
   {
    if(!(BusyUSART()))
    {
     
     WriteUSART('0');//transmit char '0'
    }
    if (PIR1bits.RCIF == 1) // check if this bit is set, meaning a byte received
     {
      char c = ReadUSART();//return a received byte in buffer, and put in parameter c
      if(c == '1')
       PORTAbits.RA0 = 1;
      else
       PORTAbits.RA0 = 0;
     }
       
    else if((BusyUSART()) && PIR1bits.RCIF !=0)
    {
     Delay10KTCYx(100);//delay approximately 1s    
     tryAgain_1();
    }
   }    
  
   
}
Could you please check if it is correct?
The purpose of this code is to turn on or off PORTAbits.RA0 depending on what is received on the Rx pin (if char '1' set PORTAbits.RA0 = 1, and if char '0' set PORTAbits.RA0 = 0). Thank you!
 

thatoneguy

Joined Feb 19, 2009
6,359
What is the PIC communicating with?

All serial settings need to match on both devices. When that is set up with the configuration flags you have in your program, and the wiring is correct, it works. If not, try running under ICD to see what is being received, or get data and write to an LCD, etc.
 

Thread Starter

tuanvoi

Joined Oct 31, 2008
56
What is the PIC communicating with?

All serial settings need to match on both devices. When that is set up with the configuration flags you have in your program, and the wiring is correct, it works. If not, try running under ICD to see what is being received, or get data and write to an LCD, etc.
Hi thatoneguy,
I'll use 2 bluetooth devices to connect to Rx/Tx respectively so that the 2 PIC18F4550 can communicate with each other.
I have a question please!
If I send char '1' which means '49' in HEX, do I have to convert '1' to HEX so that I can compare the HEX number? If yes, could you please give me the method of converting char to HEX? Thank you.
 
Top