AVR Programming in C
AVR Programming in C
AVR Programming in C
Systems
Engr. Rashid Farid Chishti
chishti@iiu.edu.pk
int main ()
{
unsigned int I, Sum = 0;
for (int I = 1 ; I <= 15 ; I+=2)
sum += I;
while (1);
return 0;
}
4
Data Types in Arduino
Data Type Size Range
bool 1 byte true(1) or false(0)
byte 1 byte 0 ~ 28-1 = 0 to 255
unsigned char (8 bits)
char 1 byte (-27) ~ (+27-1) = -128 ~ +127
signed char (8 bits) Used for storing Characters
short 2 bytes (-215) ~ (+215-1) =
signed short (16 bits) -32,768 ~ +32,767
int 2 bytes (-215) ~ (+215-1) =
signed int (16 bits) -32,768 ~ +32,767
word 2 bytes 0 ~ 216-1 = 0 to 65,535
unsigned short
unsigned int
long 4 bytes (-231) ~ (+231-1) =
signed long (32 bits) -2,14,74,83,648 ~ +2,14,74,83,647
Data Types in Arduino
Data Type Size Range
unsigned long 4 bytes 0 ~ (232 - 1) =
(32 bits) 0 ~ 4,29,49,67,295
float 4 bytes -3.4028 × 1038 ~ 3.4028 × 1038
double (32 bits)
+5V
I/O pins
PORTB, PORTC, and PORTD
Internal ADC pins
AREF, AVCC, ADCn
7
ATmega328 Simplest Connection
Vcc
ATmega328
7
VCC
Vcc 20
AVCC
22pF
10K
10
XTAL1
1 16MHz
RESET
XTAL2 9
Reset 22pF
Button
8
GND
22
GND
8
I/O Ports in AVR
ATmega328 is 28-pin chip
A total of 23 pins are
set aside for the 3 ports
PORTB, PORTC, PORTD.
Each port has 3 I/O reg-
isters associated with it
They are designated as
DDRx (Data Direction Reg-
ister), PORTx(Data Reg-
ister), and PINx(Port INput pins).
For example, for Port B we have PORTB, DDRB,
PINB registers.
each of the I/O registers is 8 bits wide, and
each port has a maximum of 8 pins.
The structure of IO pins
I/O Ports in AVR
Port Mem. Usage Port Mem. Usage
Address Address
PINB 0x23 Input PIND 0x29 Input
DDRB 0x24 Direction DDRD 0x2A Direction
PORTB 0x25 Output PORTD 0x2B Output
PINC 0x26 Input
DDRC 0x27 Direction
PORTC 0x28 Output
Data Direction Register
( DDRx
)
DDRx register is used for the purpose of
making a given port an input or output
port.
Setting (writing a one) to a bit in the
DDRx configures the pin as an Output.
Clearing (writing a zero) to a bit in the
DDRx configures the pin as an Input. e.g.
Imagine a person who has 0 dollars, he can
only get money, not give it. Similarly
when DDR contains 0’s the port gets data.
DDRC = 0xFF;
// Configure PRTC as output
DDRB = 0x00;
// Configure PRTB for input
Port Input Pin Register ( PINx )
To read the data present at the pins, we
should read the PINx register.
To send data out to pins we use the PORTx
register .
There is a pull-up resistor for each of
the AVR pins.
DDB = 0x00;
//configure PORTB for input
PORTB = 0xFF;
//turn-on the pull-up resistors
Example
15
Example 1
// Write a program that sends values 0 to 9 on Port B continuously.
16
Example 2
// Write a program that sends values 00-FF to Port D continuously.
17
Example 3
// Write a program to toggle Port D 200 times only.
18
Time Delay in Arduino
You can use predefined functions of Arduino to make
time delays
Syntax delay(ms)
Parameters ms: the number of milliseconds to
pause (unsigned long)
Returns Nothing
19
Example 4
// Write a program to toggle all bits of PORTD 50,000 times only.
void setup(){
DDRD = 0xFF; // PORTD is output
for(unsigned int i=0; i<50000 ; i++){
PORTD = ~PORTD;
delay(10); // put 10 ms sec delay
}
}
void loop(){
}
// Run the above program on your simulator to see how Port D toggles
// Notice that the maximum value for unsigned int is 65,535.
20
Example 5
// Write a program to toggle all bits of PORTD 100,000 times only.
void setup(){
DDRD = 0xFF; // PORTD is output
for(long i=0; i<100000 ; i++){
PORTD = ~PORTD;
delay(10); // put 10 ms sec delay
}
}
void loop(){
}
// Run the above program on your simulator to see how Port D toggles
// Notice that the maximum value for long is 2,14,74,83,647.
21
Example 6
// Write a program to send string a “hello world” to Port D
// only once.
void setup(){
DDRD = 0xFF; // PORTD is output
for(int i=0; msg[i]; i++){ // loop breaks at NULL
PORTD = msg[i] ; // send the character to PORTB
delay(1000); // put 1 sec delay
}
}
void loop(){
}
22
Example 7
// Write a program to send following bytes to Port D
// {0x01, 0x02,0x04,0x08,0x10,0x20,0x40,0x80} continuously.
void setup(){
DDRD = 0xFF; // PORTD is output
}
void loop(){
for( i=0; i<8; i++){ // loop breaks at i=8
PORTD = num[i] ; // send Byte to PORTB
delay(PAUSE);
}
for( i=7; i>=0; i--){ // loop breaks at i=-1
PORTD = num[i] ; // send Byte to PORTB
delay(PAUSE);
}
} 23
Bit-wise logical operators
~ 1110 1011
-----------
0001 0100
= 0x14
void setup(){
DDRD = 0xFF; // PORTD is output
}
void loop(){
PORTD = 0xEB & 0xCE ; delay(PAUSE);
PORTD = 0xEB | 0xCE ; delay(PAUSE);
PORTD = 0b11101011 ^ 0xCE ; delay(PAUSE);
}
25
Example 9
// Write a Program to toggle only lower 4 bits of PORTD with 1 sec
// delay without disturbing the higher 4 bits of PORTD.
// Initial Value of PORTD is 0xFF.
void setup(){
DDRD = 0xFF; // PORTD is output
PORTD = 0xAA; // Initialize PORTD with 0xFF
}
void loop(){
PORTD = PORTD ^ 0x0F ; delay(PAUSE);
}
26
Simple Shift Operations in AVR
data >> number of bits to be shifted right
data << number of bits to be shifted left
void setup(){
DDRD = 0xFF; // PORTD is output
}
void loop(){
PORTD = 0b11100000 >> 3; delay(PAUSE);
PORTD = 0b00000001 << 2; delay(PAUSE);
}
28
Example 11
// 8 LEDs are connected to each pin of Port D. Write a program to
// turn on each LED on PORTD from pin PD0 to PD7 with some delay.
void setup(){
DDRD = 0xFF; // PORTD is output
}
void loop(){
for(int i =0; i<8; i++){ // loop breaks at i=8
PORTD = 1<<i ; // Turn On One LED at a time
delay(PAUSE);
}
}
29
Setting a bit in a Byte to 1
We can use | operator to set a bit of a byte to 1
void setup(){
DDRB = DDRB & 0b11101111 ; // PB4 as input
PORTB = PORTB | 0b00010000 ; // Enable Pull-up at PB4
DDRD = 0xFF ; // PORTD as output
}
void loop(){
if( PINB & 0b00010000) // if we get logic 1 at PB4
PORTD = 0xF0 ; //
else
PORTD = 0x0F ; //
} 33
Example 13
// 1 LED is connected to PORTB.5(PB5). A Push Button is connected
// to PB4 with other end connected to ground. Write a program to
// turn ON LED when the input on
// PB5 is logic 0 and turn OFF LED
// otherwise.
void setup(){
DDRB = DDRB | 0b00100000 ; // PB5 as output
DDRB = DDRB & 0b11101111 ; // PB4 as input
PORTB = PORTB | 0b00010000 ; // Enable Pull-up at PB4
}
void loop(){
if( PINB & 0b00010000) // if we get logic 1 at PB4
PORTB = PORTB & 0b11011111 ; // Turn OFF LED
else
PORTB = PORTB | 0b00100000 ; // Turn ON LED
} 34
Example 14
// 1 LED is connected to PORTB.5(PB5). A Push Button is connected
// to PB4 with other end connected to ground. Write a program to
// turn ON LED when the input on
// PB5 is logic 0 and turn OFF LED
// otherwise.
// Use Shift Operators for
// masking
#define LED_PIN 5
void setup(){
DDRB = DDRB | (1<<LED_PIN) ; // PB5(LED) as output
DDRB = DDRB & ~(1<<4) ; // PB4 as input
PORTB = PORTB | (1<<4) ; // Enable Pull-up at PB4
}
void loop(){
if( PINB & (1<<4)) // if we get logic 1 at PB4
PORTB = PORTB & ~(1<<LED_PIN) ; // Turn OFF LED
else
PORTB = PORTB | (1<<LED_PIN) ; // Turn ON LED
} 35
36
37
38
pinMode() function in Arduino
pinMode() Configures the specified pin to behave either
as an input or an output.
39
digitalWrite() function in Arduino
digitalWrite() Writes a HIGH or a LOW value to a digital
pin.
Returns Nothing
40
digitalReD() function in Arduino
digitalRead() Reads the value from a specified digital pin,
either HIGH or LOW.
41
Example 15
// Write a program to blink on board LED with some delay in Adriano
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(PAUSE);
digitalWrite(LED_PIN, LOW);
delay(PAUSE);
}
42
Example 16
// Write a program to Read input from pin 7 and send it to pin 13
void setup() {
pinMode(ledPin, OUTPUT); // sets the digital pin 13 as output
pinMode(inPin, INPUT); // sets the digital pin 7 as input
}
void loop() {
val = digitalRead(inPin); // read the input pin
digitalWrite(ledPin, val); // sets the LED to the button's value
}
43
Example 17
// Write a program to read PB3 and PB4 of PORTB and issue an ASCII
// character to Port D
void setup(){
DDRB = DDRB & 0b11100111 ; // Set PB3 and PB4 as input
PORTB = PORTB | 0b00011000; // Enable Pull-up at PB3 and PB4
DDRD = 0xFF; // Set PORTD as output port
}
void loop(){
switch( PINB & 0b0001 1000){ // make decision
case(0b00000000): PORTD = '0'; break; // issue ASCII 0
case(0b00001000): PORTD = '1'; break; // issue ASCII 1
case(0b00010000): PORTD = '2'; break; // issue ASCII 2
case(0b00011000): PORTD = '3'; break; // issue ASCII 3
}
}
44
Example 17 Simulation in Proteus
45
Example 18
// Write a program to monitor bit 3 of Port B. If it is 1 make bit 4
// of Port B input; otherwise, change pin 4 of Port B to output.
void setup(){
DDRB = DDRB & ~(1<<3) ; // Set PB3 as input
PORTB = PORTB | (1<<3) ; // Enable Pull-up at PB3
}
void loop(){
if( PINB & (1<<3)) // if input pin is logic 1
DDRB = DDRB & ~(1<<4) ; // Set PB4 as input pin
else
DDRB = DDRB | (1<<4) ; // Set PB4 as output pin
}
46
BCD, Packed BCD and ASCII
conversion.
BCD Codes
Packed BCD
BCD1 BCD0
Example 19
// Write a program to convert packed BCD 0x29 to ASCII and display
// the bytes on PORTC with 2 sec delay.
void setup(){
DDRD = 0xFF ; // Set Port D as output port
R = P_BCD & 0x0F; // Clear upper 4 bits
R = R | 0x30; // Make it ASCII
L = P_BCD & 0xF0; // Clear lower 4 bits
L = L >> 4; // Shift it to lower 4 bits
L = L | 0x30; // Make it ASCII
} 0x29 0x29
0xF0 & 0x0F &
void loop(){ ---- ----
PORTD = L; delay(2000); 0x20 >> 4 0x09
PORTD = H; delay(2000); = 0x02 0x30 |
} ---- ----
0x22 0x39
L = '2' R ='9' 48
Example 20
// Write a program to convert to convert ASCII digits of ‘2’ and ‘9’
// to packed BCD and display Packet BCD number on PORTD.
void setup(){
DDRD = 0xFF ; // Set Port D as output port
R = P_BCD & 0x0F; // R = 0x04
R = R << 4; // R = 0x40
L = P_BCD & 0xF0; // L = 0x70
L = L >> 4; // L = 0x07
PORTD = L|R; // PORTD = 0x47 0x74 0x74
} 0xF0 & 0x0F &
---- ----
void loop(){ 0x70 >> 4 0x04 << 4
L = 0x07 R = 0x40
}
PORD = L | R
= 0x07 | 0x40
= 0x47 50
Example 22
// Write a program to convert 0b11111101 (= 0xFD = 253) to decimal
// and display each digit after two sec delay on PORTD.
void setup(){
DDRD = 0xFF ; // Set Port D as output port
D0 = N % 10; N /= 10; // D0 = 3, N = 25
D1 = N % 10; N /= 10; // D1 = 5, N = 2
D2 = N; // D2 = 2
}
void loop(){
PORTD = D2; delay(2000); // Show 2
PORTD = D1; delay(2000); // Show 5
PORTD = D0; delay(2000); // Show 3
}
51
Check Sum
To detect data corruption
Calculating checksum byte:
Add the bytes together and drop the carries
Take the 2’s complement of the total sum
Testing checksum
Add the bytes together and drop the carries
Add the checksum byte to the sum
If the result is not zero, data is corrupted
52
Check Sum Byte in ROM
Add the bytes together and drop the carries.
Take the 2's complement of the total sum.
This is the checksum byte, which becomes the last byte of the
series.
E.g. For 25H, 62H, 3FH, and 52H
sum = 25H, 62H, 3FH, and 52H = 118H
discard caries, sum = 18H
checksum = ~sum + 1
= ~(18H) + 1
= E7 + 1 = E8
Error = 25H + 62H + 3FH + 52H + E8 = 200
After discarding carries if remaining 8-bit answer is zero that
means no error.
Example 23
// Write program to program to calculate the checksum byte for
// {0x25, 0x62, 0x3F, 0x52} and show it on PORTD
void setup(){
DDRD = 0xFF ; // Set Port D as output port
for(int i=0; i<4; i++) // loop for i= 0 to 3
sum += data[i] ; // add them together sum = 0x18
check_sum = ~sum + 1; // check_sum = ~ 0x18 + 1 = 0xE8
PORTD = check_sum; // PORTD = 0xE8
}
void loop(){
}
54
Example 24
// Write a program to add the checksum byte 0xE8 with data
// {0x25, 0x62, 0x3F, 0x52}. If the data is good, send ASCII
// character 'G'(0x47) to PORTD. Otherwise, send 'B'(0x42) to PORTD.
void setup(){
DDRD = 0xFF ; // Set Port D as output port
for(int i=0; i<4; i++) // loop for i= 0 to 3
sum += data[i] ; // add them together sum = 0x18
sum += check_sum; // check_sum = 0x18 + 0xE8 = 0x00
PORTD = sum ? 'B':'G'; // PORTD = ‘G’ if sum == 0x00
}
void loop(){
}
55
Memory Types In AVR
Flash Memory
Not deleted when power is off
Big in size
Suitable for codes, tables and fixed data
EEPROM
Not deleted when power is off
Not very big in size
Suitable for small data that may be modified but should not
be lost when power is off
RAM
deleted when power is off
Suitable for storing the data we want to manipulate
because we have fast access to read or modify them.
Accessing Flash Memory
You can Store data in flash (program) memory instead of
SRAM using the keyword PROGMEM.
the keyword PROGMEM tells the compiler "put this
information into flash memory", instead of into SRAM.
#include <avr/pgmspace.h>
Syntax: const dataType variableName[] PROGMEM =
{data0, data1, data3…};
PROGMEM can also be used on a single variable.
Using PROGMEM is also a two-step procedure. After
getting the data into Flash memory, it requires special
methods (functions), also defined in the pgmspace.h
library, to read the data from program memory back into
SRAM, so we can do something useful with it. 57
Accessing Flash
These are
pgm_read_byte(address_short)
pgm_read_byte_near(address_short)
pgm_read_byte_far(address_long)
pgm_read_word(address_short)
pgm_read_word_near(address_short)
pgm_read_word_far(address_long)
pgm_read_dword(address_short)
pgm_read_dword_near(address_short)
pgm_read_dword_far(address_long)
pgm_read_float(address_short)
pgm_read_float_near(address_short)
pgm_read_float_far(address_long)
pgm_read_ptr(address_short)
pgm_read_ptr_near(address_short)
pgm_read_ptr_far(address_long)
58
Example 25
// Write a program to store {5,6,7,4} in Flash and then read and
// show each byte on PORTD with 1 sec delay.
#include <avr/pgmspace.h>
const byte PROGMEM lookup[] ={5,6,7,4};
void setup(){
DDRD = 0xFF ; // Set Port D as output port
}
void loop(){
for(int i=0; i<4; i++){ // loop from i= 0 to 3
PORTD = pgm_read_byte(&lookup[i]);
delay(1000);
}
}
59
Example 26
// Write a program to store “ABC” in Flash and then read and
// show each byte on PORTD with 1 sec delay.
#include <avr/pgmspace.h>
const char PROGMEM msg[] ="ABC";
void setup(){
DDRD = 0xFF ; // Set Port D as output port
}
void loop(){
for(int i=0; i<3 ; i++){ // loop for i= 0 to 3
PORTD = pgm_read_byte_near(msg + i);
delay(1000);
}
}
60
EEPROM
EEPROM isEEPROM
a place to Register
Address store (EEAR)
data. It is not
EEPROM Data Register (EEDR)
deleted when power is off
EEPROM Control Register (EECR)
ATmega328 has 1024 bytes of EEPROM
In AVR 3 registers are dedicated to EEPROM
EEARH:EEARL
EEDR
EECR
61
Accessing EEPROM in AVR
Every member of the AVR microcontrollers has some amount
of on-chip EEPROM.
The data in SRAM will be lost if the power is disconnected.
EEPROM memory can save stored data even when the power
is cut off.
The Size of EEPROM in different AVR Micro-controllers is given
below
Bit 15 14 13 12 11 10 9 8
EEARH - - - - - - EEAR9 EEAR8
Bit 7 6 5 4 3 2 1 0
Figure 6-15: EEPROM Address Register
Bit 7 6 5 4 3 2 1 0
Figure 6-16: EEPROM Control Register
EEPROM Registers
The When you set EEMPE to one, the hardware clears the bit
to zero after four clock cycles. This prevents unwanted write
operations on EEPROM contents.
Notice that you cannot start read or write operations before
the last write(program) operation is finished. You can check
for this by polling the EEPE bit. If EEPE is zero it means that
EEPROM is ready to start a new read or write(program)
operation.
EEPROM Ready Interrupt Enable (EERIE): This will be
explained later on. In Figure 6-16, bit number 6 and 7 of EECR
are unused at the present time and are reserved.
EEPROM Registers
EEPROM Programming Mode Bits (EEPM1:EEPM0): These
bits define which programming action that will be triggered
when writing EEPE.
While EEPE is set, any write to EEPMn will be ignored.
During reset, the EEPMn bits will be reset to 0b00 unless the
EEPROM is busy programming.
Programming the AVR to Write on EEPROM
To write on EEPROM the following steps should be followed.
1. Wait until EEPE becomes zero.
while(EECR & (1<<EEPE));
2. Write new EEPROM address to EEAR (optional).
EEAR = Address;
3. Write new EEPROM data to EEDR (optional).
EEDR = Data;
4. Set EEMPE bit to one.
EECR |= (1<<EEMPE);
5. Within four clock cycles after setting EEMPE, set EEPE to
one.
EECR |= (1<<EEPE);
68
Programming the AVR to Write on EEPROM
void EEPROM_Write(unsigned int Address, byte Data)
{
// Wait for completion of previous write
while(EECR & (1<<EEPE));
// Set up address and Data Registers
EEAR = Address; EEDR = Data;
// Write logical one to EEMPE
EECR |= (1<<EEMPE);
// Start EEPROM write by setting EEPE
EECR |= (1<<EEPE);
}
69
Programming the AVR to Read from EEPROM
To read from EEPROM the following steps should be followed.
1. Wait until EEWE becomes zero.
while(EECR & (1<<EEPE));
71
Example 27
// Write a program to store ‘a' into location Ox005F of EEPROM.
void setup(){
EEPROM_Write(0x5F, 'a');
}
void loop(){
72
Example 28
// Write a program to read the content of location 0x005F of EEPROM
// into PORTD.
void setup(){
DDRR = 0xFF; // Set PORTD as Output Port
PORTD = EEPROM_Read(0x5F);
}
void loop(){
73
Example 29 (1/2)
// Write a program to write two bytes at address 0x10 and 0x12 of
// EEPROM and then read the data from these two addresses and then
// show this data on PORTD with one sec delay.
74
Example 29 (2/2)
void setup(){
DDRD = 0xFF; // Set PORTD as Output Port
EEPROM_Write(0x10, 'a');
EEPROM_Write(0x12, 'b');
}
void loop(){
PORTD = EEPROM_Read(0x10);
delay(1000);
PORTD = EEPROM_Read(0x12);
delay(1000);
}
75
Example 30
// Write a program to write a string “www.iiu.edu.pk” to EEPROM
// starting from address 0x100 .
void EEPROM_Write(unsigned int Address, byte Data){
while(EECR & (1<<EEPE)); // Wait for completion of previous write
EEAR = Address; EEDR = Data; // Set up address and Data Registers
EECR |= (1<<EEMPE); // Write logical one to EEMPE
EECR |= (1<<EEPE); // Start EEPROM write by setting EEPE
}
void EEPROM_Write_Str(unsigned int Address, byte Data[]){
while(Data[Address]) // loop until we find NULL in the string
EEPROM_write(Address++, Data[i]); // Write then increment address
EEPROM_write(Address, 0); // Write NULL also
}
void setup(){
EEPROM_Write(0x100, "www.iiu.edu.pk");
}
void loop(){
}
76
Using EEPROM Library in Arduino
You can Store data in EEPROM memory instead of SRAM
using the keyword EEMEM.
the keyword EEMEM tells the compiler "put this
information into EEPROM", instead of into SRAM.
#include <avr/eeprom.h>
Syntax: dataType variableName[] EEMEM =
{data0, data1, data3…};
EEMEM can also be used on a single variable.
Using EEMEM is also a two-step procedure. After getting
the data into EEPROM, it requires special methods
(functions), also defined in the eeprom.h library, to read
the data from EEPROM back into SRAM, or to write data
to EEPROM. 77
Using EEPROM Library in Arduino
These are
uint8_t eeprom_read_byte (const uint8_t *__p)
uint16_t eeprom_read_word (const uint16_t *__p)
uint32_t eeprom_read_dword (const uint32_t *__p)
float eeprom_read_float (const float *__p)
void eeprom_read_block (void *__dst, const void *__src, size_t __n)
void eeprom_write_byte (uint8_t *__p, uint8_t __value)
void eeprom_write_word (uint16_t *__p, uint16_t __value)
void eeprom_write_dword (uint32_t *__p, uint32_t __value)
void eeprom_write_float (float *__p, float __value)
void eeprom_write_block (const void *__src, void *__dst, size_t __n)
void eeprom_update_byte (uint8_t *__p, uint8_t __value)
void eeprom_update_word (uint16_t *__p, uint16_t __value)
void eeprom_update_dword (uint32_t *__p, uint32_t __value)
void eeprom_update_float (float *__p, float __value)
void eeprom_update_block (const void *__src, void *__dst, size_t __n)
78
Example 31
// Write a program to write a byte to EEPROM then read it and show it
// on PORTD.
#include <avr/eeprom.h>
void setup(){
DDRD = 0xFF;
eeprom_write_byte(&myByte,'G'); // Write to EEPROM
PORTD = eeprom_read_byte(&myByte); // Read from EEPROM
}
void loop(){
}
79