Arduino to AVR-C Reference Guide
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
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 modeTCCRiB |= (1<<WGMi2);
//Set Target Timer CountOCRiA = Target Timer Count;
//Enable Timer InterruptsTIMSKi |= (1<<OCIEiA);
//Enable Global Interruptssei();//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
Target Frequency = Frequency of PWM; Target Timer Count = What timer counter will “hit” after Target Period has been reached.