[Arduino][Register manipulation] How to make your own Serial.print() with registers?

(Using VSCode with PlatformIO IDE and Arduino UNO Rev3, witch have a ATmega328P microprocessor)

Hi, I started learning about embedded systems’ firmware developmenent using register manipulation. My first goal is to make a “Hello World” program:

Serial.begin(9600);
Serial.print("Hello world");

But directly setting register values to reproduce the same result as the code above.

Following the USART section of ATmega328P, I develop:

#include <Arduino.h>

// USART initialization parameters
#define FOSC 8000000 // Clock speed

unsigned int UBRRnAsynchronousNormalMode(int desiredBaud){
  return (FOSC/(16*desiredBaud))-1;
}

void serialBegin(unsigned int UBRRn){
  // Setting baud rate
  UBRR0H = (unsigned char) (UBRRn>>8);
  UBRR0L = (unsigned char) UBRRn;

  // Defining frame format
  UCSR0C = (1<<USBS0) | (3<<UCSZ00);

  // Enabling transmiter
  UCSR0B = (1<<TXEN0) | (1<<RXEN0);
}

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

void setup() {
  serialBegin(UBRRnAsynchronousNormalMode(9600));
  serialPrint('1');
}

The Serial Monitor says “Terminal on COM5 | 9600 8-N-1”, but my print results in:

OsSyF

Sounds like a common baud rate disparity problem, but as I understand, I set my rate to 9600 (same as indicated by the Serial Monitor). Have I made an error in the code, or missed some step to reproduce a Serial.print()?

Doesn’t the Uno Rev3 run at 16MHz? You could have just used the existing F_CPU macro here instead of defining your own one. It would even generalize better.

schematics.