3 Send ‘Hello World’
This use case demonstrates how to send a string to the PC and visualize it in the terminal. The USART will be configured for Asynchronous mode, and only the TX pin will be used.
The USART1 instance default pins, PC0 (TX) and PC1 (RX), are connected directly to the debugger interface. They can be used to send data bytes to a host PC by using the Virtual COM Port (CDC) interface of the Embedded Debugger (EDBG), bypassing the need for an additional UART to USB converter.
This use case follows the steps:
- Set the baud rate
- Enable the Transmitter (TX)
- Configure the pins
How to Configure the Baud Rate
The baud rate shows how many bits are sent per second. The higher the baud rate, the faster the communication. Common baud rates are 1200, 2400, 4800, 9600, 19200, 38400, 57600 and 115200, with 9600 being the most commonly used one.
On the megaAVR 0-series, the maximum baud rate is limited to 1/8 * (maximum USART clock) in Asynchronous mode and 1/2 * (maximum USART clock) in Synchronous mode. To set the baud rate, write to the USARTn.BAUD register:
USART1.BAUD = (uint16_t)USART1_BAUD_RATE(9600);
Notice the use of the USART1_BAUD_RATE
macro to compute the register’s
value from the baud value. This macro must be defined based on the formula in the image
below. This formula depends on the USART configurations, so it might not be the same in
other modes.
S is the number of samples per bit. In Asynchronous operating mode, it is 16 (NORMAL mode) or 8 (CLK2X mode). For Synchronous operating mode, S equals 2.
This is how the USART1_BAUD_RATE
macro is defined. It uses
F_CPU
because the USART clock matches the CPU clock.
#define F_CPU 3333333 #define USART1_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)
How to Enable the Transmitter and Send Data
Depending on the application needs, the user may choose to enable only the receiver or the USART module transmitter. Since in this use case only the microcontroller sends messages, only the transmitter needs to be enabled.
USART1.CTRLB |= USART_TXEN_bm;
Before sending data, the user needs to check if the previous transmission is completed by checking the USARTn.STATUS register. The following code example waits until the transmit DATA register is empty and then writes a character to the USARTn.TXDATA register:
void USART1_sendChar(char c)
{
while (!(USART1.STATUS & USART_DREIF_bm))
{
;
}
USART1.TXDATAL = c;
}
The Send register is nine bits long. Therefore, it was split into two parts: The lower part that holds the first eight bits, called TXDATAL, and the higher part that holds the remaining one bit, called TXDATAH. TXDATAH is used only when the USART is configured to use nine data bits. When used, this ninth bit must be written before writing to USARTn.TXDATAL, except if CHSIZE in USARTn.CTRLC is set to ‘9-bit - Low byte first’, where USARTn.TXDATAL should be written first.
How to Configure Pins
The TX pin must be configured as an output. By default, each peripheral has some associated pin positions. The pins are described in the Multiplexed Signals section in the device-specific data sheet. Each USART has two sets of pin positions. The default and alternate pin positions for USART1 are shown below.
Pin name(1,2) | USARTn |
---|---|
PC0 | 1,TxD |
PC1 | 1,RxD |
PC2 | 1,XCK |
PC3 | 1,XDIR |
VDD | |
GND | |
PC4 | 1,TxD(3) |
PC5 | 1,RxD(3) |
PC6 | 1,XCK(3) |
PC7 | 1,XDIR(3) |
- Pin names are of type Pxn, with x being the PORT instance (A,B,C, ...) and n the pin number. Notation for signals is PORTx_PINn. All pins can be used as event input.
- All pins can be used for external interrupt, where pins Px2 and Px6 of each port have full asynchronous detection.
- Alternate pin positions. For selecting the alternate positions, refer to the PORTMUX documentation.
For this use case, the default USART1 pin position is used; this is PC0 to PC1. The following code sets the TX pin direction to output.
PORTC.DIR |= PIN0_bm;
To use the alternate pin positions, write to the PORTMUX.USARTROUTEA register.
PORTMUX.USARTROUTEA |= PORTMUX_USART10_bm;
Demo Code
This code example is used to continuously send the 'Hello World!' string through USART. A
string is sent character by character. The ‘USART1_sendString
’ function
calls the ‘USART1_sendChar
’ function for each character in the ‘Hello
Word!’ string. Before sending each character, the ‘USART1_sendChar
’
function waits for the previous character transmission to be completed. This is done by
polling the Data Register Empty Interrupt Flag, DREIF, from the STATUS register until it
is set.
#define F_CPU 3333333 #define USART1_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5) #include <avr/io.h> #include <util/delay.h> #include <string.h> void USART1_init(void); void USART1_sendChar(char c); void USART1_sendString(char *str); void USART1_init(void) { PORTC.DIR &= ~PIN1_bm; PORTC.DIR |= PIN0_bm; USART1.BAUD = (uint16_t)USART1_BAUD_RATE(9600); USART1.CTRLB |= USART_TXEN_bm; } void USART1_sendChar(char c) { while (!(USART1.STATUS & USART_DREIF_bm)) { ; } USART1.TXDATAL = c; } void USART1_sendString(char *str) { for(size_t i = 0; i < strlen(str); i++) { USART1_sendChar(str[i]); } } int main(void) { USART1_init(); while (1) { USART1_sendString("Hello World!\r\n"); _delay_ms(500); } }
<avr/delay.h>
header.An MPLAB® Code Configurator (MCC) generated code example for AVR128DA48 with the same functionality as the one described in this section can be found here: