Developing in C for the ATmega328: Using the Standard C Framework

7 minute read

Where I illustrate developing code for the ATmega328P using the new Standard C framework.



The Github repository referenced above is a new Standard C framework which mimics a subset of the Arduino framework. [Note: Standard C refers to using a standardized version of C, in this case, avr-gcc (ANSI C) as compared to Arduino C++, which is a combination of C, C++ and Arduino classes and templates. Many universities have an expectation of their students to understand C in the context of ANSI C.] The intent of the repository is to provide the capability for someone to use Standard C in programming an Arduino Uno (or similar type of microcontroller.)

The differences between using the Arduino Framework and this (AVR_C) framework are:

  1. The AVR_C framework is standard C compliant. It doesn’t use C++ or unique Arduino code, which means you are learning C and not a variant of C/C++.
  2. The code is much smaller which allows you to do more in the small memory configurations of the ATtiny microcontrollers.
  3. In some situations such as serial printing, AVR_C is far more simple. The AVR_C approach uses the Standard C functions of puts(), getchar() and printf() as compared to the laborious Serial.print() classes.

Install git

The best way to use this repository (or any Github repository) is to install git and add the repository by cloning. This allows you to update it easily when the repository is updated.

Linux (and Windows Subsystem for Linux)

For Linux systems, git is probably already installed. To test that:

git --version

If you don’t get a message showing git and its version, it isn’t installed. To install use:

sudo apt install git

Once installed, perform the git –version command in the command line.


For macOS systems, git probably won’t be installed. To test that:

git --version

If you don’t get a message showing git and its version, it isn’t installed. To install use: (*Note: If you don’t have homebrew already installed, see this )

brew install git

Once installed, perform the git –version command in the command line.


Windows doesn’t have a standardized Unix/Linux environment, unless you’ve installed WSL. In this case, we’ll install Git for Windows. Click on Download and save the file to your Downloads directory. Install Git for Windows by double-clicking on the downloaded file. It will ask a series of questions and for now go with the defaults.

Once installed, go to the Windows search bar and enter git , which will start git in the command line. Enter:

git --version

to confirm git was installed.

Use git

# go to folder where you want your github repositories to be, i.e; Documents/github.
# I'll start by making a repository folder
mkdir github
cd github
# go to the repository site as in
# click on the green Code button and copy either the HTTPS link or SSH link
git clone
cd AVR_C

The alternative is to download the ZIP file and extract it to where you want to use it. This will require you to periodically replace it with a new version.

Once you have the folder local to your computer. I recommend you read the README file to get an overview of the repository.

Testing Code

Once you are in the repository, you will want to begin testing your setup. In this case, it is ensuring tool chain, serial connection and your board all work together to enable C code creation.

Tool Chain

Note: My assumption on this page, is that you have already completed Setup for your respective platform. And by completed, you have been successful using your favorite code editor, make and an Arduino/compatible board. You are able to make changes to the led program and load it on the UNO. If you haven’t done this, please go the Setup page and complete the steps for your platform, otherwise, the rest of this page will be impossible.

Repository Configuration

The repository has two main folders, Library and examples. Each folder in examples is a simple example as to how to use an aspect of the Library. In each one of these examples there are two files, a c file, main.c and a make file, Makefile.

The first step is to ensure the Makefile is setup properly for your serial connection and your board.

Serial connection

The easiest method to determine your serial connection to your board is to use the Arduino IDE (yes, this is ironic). In the IDE, use Tools -> Port -> (list of ports) to identify the port connected to your board. Typically, the Arduino will call out the name of the board next to the port name.

Ultimately, you will want to have the system specific name of the serial port. For Linux/macOS, it will be similar to /dev/ttyACM0 or /dev/cu.usbmodem4301, respectively. For Windows, it will be something like COM3. Once you have identified the serial port, make the change on the 5th line of the Makefile:

5 SERIAL = /dev/cu.usbmodem3101

Board Changes

If your board is an Arduino UNO or one that is quite similar, then you don’t need to make any adjustments to line 10 “MCU = atmega328p”. If you have a different processor, for example if you are using an ATtiny84 board, use “attiny84”, for the MCU parameter.

First Test

Let’s try delayTest as the first test. It is the Arduino “blink” example, however it uses the C Library code, instead of the Arduino framework. It will help ensure the Library is being used for your code.

To run the code:

# switch to the example folder
cd delayTest
# compile code and upload to 
make flash
# the above command will compile, link and load the Uno
# just as the Upload command would do in the Arduino IDE

If there are errors in compiling the code, you will need to confirm a change in the Makefile. We are adding the Library to the compilation, so we need to confirm the location of the Library to the Makefile.

# Make sure line 18 is uncommented
18 LIBDIR = ../../Library
# and line 65 has -I$(LIBDIR) at the end

Serial Test

The avr-gcc tool chain brings a much better serial communications capability to the Library. Once the uart code has been added to support the ATmega328P processor, you are able to use the standard C input/output commands such as getchar(), puts() and printf().

To begin testing the serial port, open the examples/serialio folder. Run make flash as you normally do. To see the output and provide input to the program you will need a serial monitor. Consider using the following based on your platform: (You can also use the Arduino Serial Monitor on all three platforms.)

A couple of notes on serial I/O using Standard C. The current simple approach for serial I/O uses polling, where the input/output routines wait for a char to be received/sent, respectively. This makes the I/O very slow (9600 baud), is blocking (no I/O, nothing happens) and requires some upfront initialization. This is fine for now, as we’re more interested in developing Standard C programs then production code.

For the last point regarding I/O (initialization), this does mean one needs to do the following: (Use the serialio example for guidance.)

At the top of the file, add
#include <stdio.h>
#include "uart.h"

# Inside of main(), add prior to your I/O 
    init_serial(); // this is a macro, so no () are required

Note: As noted in the README file in the repository, I have found a serial application, which seem to have an issue with this serial I/O approach. On Linux, using minicom, the serialio program wouldn’t respond with input. I tested the serialio using the Arduino serial monitor and it worked well. I haven’t seen the issue on any other combinations.

Make Commands

The Makefile in each folder has a variety of options which can be quite useful. Here are a few of them:

# Same as Verify in Arduino IDE, simply compiles the main.c program
# Same as Upload in Arduino IDE, compiles, links and uploads the code to the UNO
make flash
# Create a an assembly listing of the code complete with C source code
make disassembly
# Show the size of the code created in great detail
make size
# Remove all files except source files (main.c and Makefile)
make all_clean
# Remove all the current object files in the Library 
make LIB_clean

Comments powered by Talkyard.