Arduino to AVR-C Reference Guide

Jordan Réjaud
4 min readMay 3, 2016

--

Note: This reference guide is intended for those who are very familiar with programming using the Arduino framework and want an in-depth reference reference when programming an ATMega328p directly in C using AVR-C.

If the above paragraph makes no sense to you, then the following is going to make even less sense. But that’s alright, it’s intended to be a somewhat esoteric guide.

The ATMega328p is the microcontroller “brains” inside of the Arduino Uno. Anyone who has spend any significant time working with Arduino boards will quickly realize the limitations of the Arduino framework. A more powerful (and complex) alternative is to use AVR-C instead.

The purpose of this Reference Guide is to help “translate” Arduino functions, like digitalWrite(), to their AVR-C equivalents.

1. Port Manipulation

Arduino Equivalent: pinMode()

Atmel Datasheet: Section 14.4

Source: http://www.chicoree.fr/w/Arduino_sur_ATmega328P

Syntax

//Set Pin for output
DDRx |= (1<<PDn);
//Set Pin for input
DDRx &= ~(1<<PDn);
//Set internal pull-up resistor (after setting pin for input)
PORTx |= (1<<PDn);

Registers

DDRx: Port x Data Direction RegisterPDn: AVR-C Library "shortcut" for pin number nx = PORT; A, B, C, or Dn = Pin number; 0, 1, 2, 3, ect.

Explanation

Set pin value to 1 for output; 0 for input

2. Digital Input

Arduino Equivalent: digitalWrite()

Atmel Datasheet: Section 14.4

Syntax

//Set Pin High
PORTx |= (1<<PDn);
//Set Pin Low
PORTx &= ~(1<<PDn);

Registers

PORTx: Port x Data RegisterPDn: AVR-C Library “shortcut” for pin number nx = PORT; A, B, C, or Dn = Pin number; 0, 1, 2, 3, ect.

Explanation

Set pin to 1 for HIGH (5V on ATmega328p); 0 for LOW (0V on ATmega328p)

3. Digital Input

Arduino Equivalent: digitalRead()

Atmel Datasheet: Section 14.4

Syntax

if (PINx & (1<<PDn));

Registers

PINx: Port x Input Pins AddressPDn: AVR-C Library “shortcut” for pin number nx = PORT; A, B, C, or Dn = Pin number; 0, 1, 2, 3, ect.

Explanation

Don’t forget to turn on pull-up resistors if you need them!Will return 0 is pin is LOW; will return NOT 0 is pin is HIGH

4. Analog Input

Arduino Equivalent: analogRead()

Atmel Datasheet: Sections 24 and 14.4

Syntax (ADC initialize example)

//16Mhz / 128 = 125kHz ADC reference clock
ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));
//Voltage reference from AVcc (5V on ATMega328p)
ADMUX |= (1<<REFS0);
//Turn on ADC
ADCSRA |= (1<<ADEN);
//Do a preliminary conversion
ADCSRA |= (1<<ADSC);

Syntax (ADC read example)

//Clear previously read channel
ADMUX &= 0xF0;
//Define new ADC Channel to read (which analog pin: 0–5 on ATMega328p
ADMUX |= channel;
//New Conversion
ADCSRA |= (1<<ADSC);
//Do a preliminary conversion
ADCSRA |= (1<<ADSC);
//Wait until conversion is finished
while(ADCSRA & (1<<ADSC));
//Return ADC value
return ADCW;

Registers

ADCSRA and ADCSRB: ADC Control and Status Registers A and BADPS[2:0]: ADC Prescaler Select BitsADMUX: ADC Multiplexer Selection RegisterREFS[1:0]: Voltage Reference Selection BitsADEN: ADC EnableADSC: ADC Start ConversionADCW: “Shortcut” by AVR-C, holds ADV value

Explanation

Analog read from Pins!

It’s dangerous to go alone, read this tutorial.

5. Delays and Timers

Arduino Equivalent: delay()

Atmel Datasheet: Sections 15, 16, and 18

Syntax (Delay)

//Include delay .h
#include <util/delay.h>
//Delay for delay_timer ms
_delay_ms(delay_timer);

Syntax (Normal Mode)

//Set Prescaler (256 in this example)
TCCRiB |= (1<<CSi2);
if (TCNTi >= Target Timer Count)
{
//Write your code here :)
//Reset Timer TCNTi = 0;
//Disable Timer (Haven't tested this yet)
TCCRiB &= ~((1<<CSi0)|(1<<CSi1)|(1<<CSi2));
}

Syntax (CTC, Clear Timer on Counter Match)

//Set Prescaler (256 in this example)TCCRiB |= (1<<CSi2);
//Set timer to CTC mode
TCCRiB |= (1<<WGMi2);
//Set Target Timer Count
OCRiA = Target Timer Count;
//Enable Timer Interrupts
TIMSKi |= (1<<OCIEiA);
//Enable Global Interrupts
sei();//ISR Example//Define ISR Function
ISR(TIMERi_COMPA_vect)
{
//Write your code here :)}

Registers

TCCRiA: Timer/Counter Control Register ATCCRiB: Timer/Counter Control Register BTCNTi: Timer/Counter RegisterCSi[2:0]: Clock SelectWGMi[2:0]: Waveform Generation ModeOCRiA: Output Compare Register AOCRiB: Output Compare Register BTIMSKi: Timer/Counter Interrupt Mask RegisterOCIEiA: Timer/Counter0 Output Compare Match A Interrupt EnableOCIEiB: Timer/Counter0 Output Compare Match B Interrupt Enablei = Timer; 0, 1, 2 (on ATMega328p)

Explanation

Timer Frequency = System Clock Frequency / Prescaler

Target Timer Count = Timer Frequency / Target Frequency — 1 = Target Period / Timer Period — 1

System Clock Settings: Section 9; Arduino Uno clock frequency is 16mHz.

Prescaler Settings

Source: http://www.chicoree.fr/w/Arduino_sur_ATmega328P

Target Frequency = Frequency of PWM; Target Timer Count = What timer counter will “hit” after Target Period has been reached.

Waveform Settings

Source: Table 15–8 of ATMega328p datasheet

--

--