Developing in C for the ATmega328P: Functions - Serial input/output

4 minute read

Where I describe the functions for serial input/out - puts(), getchar() and printf().


The serial input/output capabilities of C are vastly superior to those in the Arduino framework. In order to communicate via the USB serial cable, you must run a serial monitor program such as the Arduino Serial Monitor, CoolTerm, or moserial. See this page for more details.

Currently available are:

  • getchar(): reads the next character from the standard input stream and returns it as type int
  • putchar(char): writes a character to the standard output stream
  • puts(string): print a null-terminated string to the standard output stream, ending with a newline character
  • printf(format, variable list): writes to the standard output stream, the list of variables using the formatting string specified. There is considerable detail as to how to use printf below.

How to Use Serial Input/Output

The concept of serial input/output (I/O) is to provide the capability to communicate to (input) the Uno and have the Uno communicate back (output) to the PC. For our purposes, the standard input and output stream will be the USB communications between the Uno and our computer.

To setup the Uno properly for serial communications, the following elements have to part of your program (see highlighted lines below):

#include <stdio.h>
#include "uart.h"

int main() {
// initialize code goes here 

printing code goes here...

The highlighted lines won’t print anything, however, what they will do is setup the Uno to be able to print. Following these three lines, you may use any one of the functions described in the Introduction to communicate with the Uno.


// Serial I/O test
// Requires serial monitor set to 9600, 8, 1, None with no line ending
// Use Arduino Serial Monitor, CoolTerm, or your favorite serial monitor
#include <stdio.h>
#include "uart.h"

int main(void) {    
    int input;

    puts("Serial I/O Test: Enter a character");
    while(1) {
        input = getchar();
        printf(" You entered the character %c, ", input);
        printf("%i in ASCII decimal, %x in ASCII hex\n", input, input);        
    return 0;
Line(s) Description
4-5, 8 Lines required to setup serial I/O between Uno and PC
11 will output a string of text followed by a newline
13 will get one char at a time from the serial connection
14 will output one char
15 prints the char as a character format
16 prints the char as a decimal integer format and hexadecimal integer format

Sample Output

Serial I/O Test: Enter a character
a You entered the character a, 97 in ASCII decimal, 61 in ASCII hex
b You entered the character b, 98 in ASCII decimal, 62 in ASCII hex
1 You entered the character 1, 49 in ASCII decimal, 31 in ASCII hex

printf(format, variable list)

Some of the details regarding format:

  • diouxX The int (or appropriate variant) argument is converted to signed decimal (d and i), unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation. The letters “abcdef” are used for x conversions; the letters “ABCDEF” are used for X conversions. The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer digits, it is padded on the left with zeros.
  • p The void * argument is taken as an unsigned integer, and converted similarly as a %#x command would do.
  • c The int argument is converted to an “unsigned char”, and the resulting character is written.
  • s The “char *” argument is expected to be a pointer to an array of character type (pointer to a string). Characters from the array are written up to (but not including) a terminating NUL character; if a precision is specified, no more than the number specified are written. If a precision is given, no null character need be present; if the precision is not specified, or is greater than the size of the array, the array must contain a terminating NUL character.
  • eE The double argument is rounded and converted in the format “[-]d.ddde┬▒dd” where there is one digit before the decimal-point character and the number of digits after it is equal to the precision; if the precision is missing, it is taken as 6; if the precision is zero, no decimal-point character appears. An E conversion uses the letter ‘E’ (rather than ’e’) to introduce the exponent. The exponent always contains two digits; if the value is zero, the exponent is 00.
  • fF The double argument is rounded and converted to decimal notation in the format “[-]ddd.ddd”, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears. If a decimal point appears, at least one digit appears before it.

For all of the details as to format, avr-libc manual: vprintf, printf uses vprintf to print.

Comments powered by Talkyard.