Problems in Serial Communication with Registers

Hello guys, I am currently working on a project which requires serial communication between an Arduino Nano (ATmega328P) and my computer. Due to data transmission speed issues, I thought of performing the communication through the registers of the microcontroller. So far, I developed the following code:

unsigned char rx;

unsigned char receive() {
  while (!(UCSR0A & (1 << RXC0))) {
    return UDR0;
  }
}

void transmit(unsigned char c) {
  while (!(UCSR0A & (1 << UDRE0))) {
    UDR0 = c;
  }
}

int main(void) {
  cli();
  //---------------------------------------------------------------------------------------------
  // Enable USART Receiver and Transmitter
  // Set 8-bit Character Size
  UCSR0B |= (1 << RXEN0) | (1 << TXEN0);
  UCSR0B &= ~(1 << UCSZ02);
  //---------------------------------------------------------------------------------------------
  // Set USART Asynchronous Mode
  // Set 8-bit Character Size
  UCSR0C &= ~(1 << UMSEL01) & ~(1 << UMSEL00);
  UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00);
  //---------------------------------------------------------------------------------------------
  // Set USART Baud Rate Register to 25 to set 38400 bps Baud Rate
  UBRR0 = 25;
  //---------------------------------------------------------------------------------------------
  sei();
  //---------------------------------------------------------------------------------------------
  while (1) {
    if (UCSR0A & (1 << RXC0)) {
      rx = receive();
    }
    transmit(rx);
  }
}

During the code developing, I looked at the microcontroller datasheet and found that above 9600 baud, the rate with the lowest error rate was 38400 baud, because the application where the communication will be set up, a 9600 baud rate is slow. However, I have no output on the serial monitor configured at 38400 baud when sending a character.

Why are we not using the existing hardware Serial capability.

you are making your life way more difficult than it probably needs to be... Just use the HardwareSerial class and be done with it

See Serial Input Basics to get some ideas on how to deal with an asynchronous stream

Your return statements are in the wrong place...

  while (1) {
    if (UCSR0A & (1 << RXC0)) {
      rx = receive();
    }
    transmit(rx);
  }

Also, you continue to transmit the last character even when no new character has been received.

Maybe to save a few bytes of memory, or for fun :sunglasses:

1 Like

There are no 'transmission speed issues' ... Most microcontrollers easily deal with serial ---> USB ---> PC at 115200 BAUD (or faster) assuming you are using a quality USB cable.

As a rule-of-thumb, Serial communications are normally error free if the BAUD clocks are +/- 2.5%

@gfma2301

1. It could be that OP is doing an exercise and now he may study/practice the following Register Level codes (along with non-working codes of post #1) to exchange data between Serial Monitor and UART port of the ATmega328P MCU of the UNO Board on polling strategy.

void setup()
{
  UCSR0A = 0x00;                           //reset; Bd factor is not doubled,
  UCSR0B |= (1 << RXEN0) | (1 << TXEN0);  //Serial transmitter/receiver are enabled
  UCSR0C |= bit(UCSZ01)|bit(UCSZ00);      //8-bit charcater size, 1-StopBit
  UBRR0 = 25; //Bd = 38400
}

void loop()
{
  while (bitRead(UCSR0A, RXC0) != HIGH)//check if RXC0flag HIGH indicating data ready
  {
    ; //wait until a chacter has arrived from Serial Monitor
  }
  char ch = UDR0;  //read the arrived data from Recievr, TXC0 flag is cleared
  while(bitRead(UCSR0A, UDRE0) != HIGH)//check if transmit buffer is empty
  {
    ;  //
  }
  UDR0 = ch;  //send the charcater back to OutputBox of Serial Monitor.
}

2. Interrupt Strategy
It is left as an exercise for OP.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.