Ch07 AVR Programming in C
Ch07 AVR Programming in C
ATmega328P
Vcc
ATmega328
7
VCC
Vcc 20
AVCC
10K
1
RESET
22pF
10
XTAL2
Reset
Button 16MHz
8
GND XTAL1 9
22
GND
22pF
I/O Ports in AVR
ATmega328 is 28-pin chip 777
666
A total of 23 pins are set aside for the 3 ports XTAL1
XTAL2
555 PB5 (SCK)
444 PB4 (MISO)
RESET 333 PB3 (MOSI/OC2A)
PORTB, PORTC, PORTD. VCC 222 PB2 (SS/OC1B)
GND 111 PB1 (OC1A)
PORTB
DDRx (Data Direction Register) (ADC0) PC0 000 777 PD7 (AIN1)
PD6 (AIN0)
(ADC1) PC1 111 666
(ADC2) PC2 222 555 PD5 (T1)
PORTx (Data Register) (ADC3) PC3 333 444 PD4 (T0/XCK)
(ADC4/SDA) PC4 444 333 PD3 (INT1)
PINx: 7 6 5 4 3 2 1 0
XTAL2 444 PB4 (MISO)
Px7 Px6 Px5 Px4 Px3 Px2 Px1 Px0
RESET 333 PB3 (MOSI/OC2A)
VCC 222 PB2 (SS/OC1B)
GND 111 PB1 (OC1A)
AVCC 000 PB0 (ICP1/CLK0)
PINB
AREF DDRB
PORTB
PORTC PORTD
DDRC DDRD
PINC PIND
(ADC0) PC0 PD7 (AIN1)
DDRx
000 777
0 1 (ADC1) PC1 111 666 PD6 (AIN0)
PORTx PD5 (T1)
(ADC2) PC2 222 555
444 PD4 (T0/XCK)
0 high impedance Out 0 (ADC3) PC3 3 3 3DDRx.n
333 PD3 (INT1)
(ADC4/SDA) PC4 444 PORTx.n
PORTB
Clearing (writing a zero) to a bit in the DDRx con PORTC
DDRC
PORTD
DDRD
get money, not give it. Similarly when DDR con- (ADC4/SDA) PC4 444 333 PD3 (INT1)
(ADC5/SCL) PC5 555 222 PD2 (INT0)
666 111 PD1 (TXD)
tains 0’s the port gets data. 777 000 PD0 (RXD)
PORTB
PORTC PORTD
DDRC DDRD
PINC PIND
(ADC0) PC0 PD7 (AIN1)
000 777
(ADC1) PC1 666 PD6 (AIN0)
111
(ADC2) PC2 222 555 PD5 (T1)
(ADC3) PC3 333 444 PD4 (T0/XCK)
(ADC4/SDA) PC4 444 333 PD3 (INT1)
555 222 PD2 (INT0)
Different States of a Pin in the AVR Microcontroller
(ADC5/SCL) PC5
666 111 PD1 (TXD)
777 000 PD0 (RXD)
DDRx
PORTx
0 1
0 Input & high impedance Out 0
1 Input & Pull-up Out 1
Data Register ( PORTx )
The PORTx register controls if the pull-up is activated or not
Writing a 1 to the PORTx register will activate the internal pull-up resistor
Writing a 0 to the PORTx register will deactivate or turn off the internal pull-up
resistor
vcc
DDB = 0x00; // configure PORTB for input 1 = Close
PORTB = 0xFF; // turn-on the pull-up resistors PORTx.n 0 = Open
AVR AVR
VCC VCC
14
Example 3
// Write a program to toggle Port D 200 times only.
1010 1010 =
0xAA
/*** SOLUTION ***/ Bitwise NOT
-----------
// the setup function runs once when you press 0101 0101 =
// reset or power the board 0x55
void setup(){
DDRD = 0xFF;
PORTD = 0xAA;
for (int i = 0; i < 200; i++) {
PORTD = ~PORTD;
delay(1000); // 1 sec delay
}
}
}
15
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
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.
17
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.
18
Example 6
// Write a program to send string a
// “hello world” to Port D only once.
void setup(){
DDRD = 0xFF; // PORTD is output port
// loop breaks at NULL
for(int i=0; msg[i]; i++) {
// send the character to PORTB
PORTD = msg[i] ;
delay(1000);// put 1 sec delay
}
}
void setup(){
DDRD = 0xFF; // PORTD is output
}
void loop(){
PORTD = 0xEB & 0xCE ; delay(PAUSE);
PORTD = 0xEB | 0xCE ; delay(PAUSE);
PORTD = 0b11101011 ^ 0xCE ; delay(PAUSE);
}
22
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 loop(){
PORTD = PORTD ^ 0x0F ; delay(PAUSE);
}
-------------- --------------
0001 1100 0000 0100
= 0x1C = 0x04
Example 10
// Write a Program to Show the Result of
// (a) 1110 0000 >> 3 on PORTD
// (a) 0000 0001 << 2 on PORTD
// with 3 sec delay after each output
25
0x01 = 0000 0001
Example 11 1<<0
1<<1
=
=
0000
0000
0001
0010
=
=
0x01
0x02
1<<2
// 8 LEDs are connected to each pin of Port D. Write a program = 0000 0100 = 0x04
1<<3
// to turn on each LED on PORTD from pin PD0 to PD7 with some = 0000 1000 = 0x08
// delay. 1<<4 = 0001 0000 = 0x10 =
16
/*** SOLUTION ***/ 1<<5 = 0010 0000 = 0x20 =
const int PAUSE = 500; 32
1<<6 = 0100 0000 = 0x40 =
void setup(){ 64
DDRD = 0xFF; // PORTD is output 1<<7 = 1000 0000 = 0x80 =
} 128
void loop(){
for(int i =0; i<8; i++)
{
// loop breaks at i=8
// Turn On One LED at a time
PORTD = 1<<i ;
delay(PAUSE);
}
}
26
Setting a bit in a Byte to 1
We can use | (Bitwise OR) operator to set a bit of a byte to 1
void setup(){
// PC4 as input
DDRC = DDRC & 0b11101111 ;
// Enable Pull-up at PC4
PORTC = PORTC | 0b00010000 ;
DDRD = 0xFF ; // PORTD as output
}
void loop(){
// if we get logic 1 at PC4
if( PINC & 0b00010000)
PORTD = 0xF0 ; //
else
PORTD = 0x0F ; //
30
}
Example 13
// 1 LED is connected to PB5. A Push Button is connected to PC4 with other end
connected to
// ground. Write a program to turn ON LED when the Push Button is pressed and turn
OFF LED
// otherwise.
/*** SOLUTION ***/
void setup(){
// PB5 as output
DDRB = DDRB | 0b00100000 ;
// PC4 as input
DDRC = DDRC & 0b11101111 ;
// Enable Pull-up at PC4
PORTC = PORTC | 0b00010000 ;
}
void loop(){
if( PINC & 0b00010000) // if Button is released
PORTB = PORTB & 0b11011111 ; // Turn OFF LED
else
PORTB = PORTB | 0b00100000 ; // Turn ON LED
31
Example 14
// 1 LED is connected to PB5. A Push Button is connected to PC4 with other end
connected to
// ground. Write a program to turn ON LED when the Push Button is pressed and turn
OFF LED
// otherwise. Use Shift Operators for masking
void loop(){
if( PINC & (1<<4)) // if we get logic 1 at PC4
PORTB = PORTB & ~(1<<LED_PIN) ; // Turn OFF LED
else
PORTB = PORTB | (1<<LED_PIN) ; // Turn ON LED
32
}
ATmega328 and Arduino UNO Pinout Diagram
Arduino MEGA 2560 Pinout Diagram
Arduino MEGA 2560 Pinout Diagram
pinMode() function in Arduino
pinMode() Configures the specified pin to behave either as an input or an
output.
Parameters
pin: the number of the pin whose mode you wish to set
mode : INPUT, OUTPUT, or INPUT_PULLUP.
Returns Nothing
digitalWrite() function in Arduino
digitalWrite() Writes a HIGH or a LOW value to a digital pin.
Parameters
pin: the pin number on Arduino.
value : HIGH or LOW.
Returns Nothing
digitalRead() function in Arduino
digitalRead() Reads the value from a specified digital pin, either HIGH or
LOW.
Parameters
pin: the pin number on Arduino.
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(PAUSE);
digitalWrite(LED_PIN, LOW);
delay(PAUSE);
}
39
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_PULLUP); // 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
}
40
Example 17
// Write a program to read PB3 and PB4 of PORTB and issue an ASCII character to Port
D
void setup(){
// Set PB3 and PB4 as input
DDRB = DDRB & 0b11100111 ;
// Enable Pull-up at PB3 and PB4
PORTB = PORTB | 0b00011000;
DDRD = 0xFF;// PORTD is output
}
void loop(){
switch( PINB & 0b00011000) { // 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
}
41
}
Example 18
// Write a program to monitor PB3. If it is 1 make bit 4 of Port B input; otherwise,
change
// bit 4 of Port B to output.
void setup(){
// Set PB3 as input
DDRB = DDRB & ~(1<<3) ;
// Enable Pull-up at PB3
PORTB = PORTB | (1<<3) ;
}
void loop(){
if( PINB & (1<<3))// if input pin is logic 1
// Set PB4 as input pin
DDRB = DDRB & ~(1<<4) ;
else
// Set PB4 as output pin
DDRB = DDRB | (1<<4) ;
42
}
BCD, Packed BCD and ASCII conversion.
BCD1 BCD0
Packed BCD
Example 19
// Write a program to convert packed BCD 0x29 to
// ASCII and display the bytes on PORTD with 2 sec
// delay.
void setup(){
DDRD = 0xFF ; // Set Port D as output port
R = P_BCD << 4; // R = 0x40
L = P_BCD >> 4; // L = 0x07
PORTD = L|R; // PORTD = 0x47
}
void loop(){
0x74 >> 0x74 <<
} 4 4
L = 0x07 R = 0x40
PORD = L | R
= 0x07 | 0x40
= 0x47 46
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(500); // Show 2
PORTD = D1; delay(500); // Show 5
PORTD = D0; delay(1000); // Show 3
}
47
Check Sum Byte in ROM
To detect data corruption E.g. For 0x25, 0x62, 0x3F, and 0x52
Calculating checksum byte: sum = 0x25+0x62+0x3F+0x52
Add the bytes together and = 0x118
drop the carries sum = 0x18 discard caries
Take the 2’s complement of the
void setup() {
DDRD = 0xFF ; // Set Port D as output port
void loop() {
}
49
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
void loop(){
}
50
Memory Types In AVR
Flash Memory RAM
Not deleted when power is off deleted when power is off
Big in size
Suitable for storing the data we
Suitable for codes, tables and
want to manipulate because we
fixed data have fast access to read or
modify them.
EEPROM
Not deleted when power is off
Not very big in size
Suitable for small data that may
pgm_read_word(address_short) pgm_read_ptr(address_short)
pgm_read_word_near(address_short) pgm_read_ptr_near(address_short)
pgm_read_word_far(address_long) pgm_read_ptr_far(address_long)
pgm_read_dword(address_short)
pgm_read_dword_near(address_short)
pgm_read_dword_far(address_long)
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 as output port
}
void loop(){
// loop from i= 0 to 3
for(int i=0; i<4 ; i++) {
PORTD = pgm_read_byte(&lookup[i]);
delay(500);
}
}
54
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 ;// Port D as output port
}
void loop(){
// loop for i= 0 to 3
for(int i=0; i<3 ; i++) {
PORTD = pgm_read_byte_near(msg + i);
delay(500);
}
}
55
EEPROM
EEPROM is a EEPROM Address Register (EEAR)
place to store EEPROM Data Register (EEDR)
Bit
data. It is not
15 14 13 12 11 10 9 8
EEPROM Control Register (EECR)
EEARH - - - - - - EEAR9 EEAR8
7
EEAR6 EEAR5
6 5
EEAR4
4
EEAR3 EEAR2
3 2
EEAR1
1
EEAR0
0
power is off
ATmega328 has
1024 bytes of
EEPROM EECR
dedicated to EEPROM
EEDR
EEARH:EEARL
EEDR
EECR 1023
EEPROM
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
Chip Bytes Chip Bytes Chip Bytes
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 Control Register (EECR)
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 Control Register (EECR)
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);
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));
void setup(){
EEPROM_Write(0x5F, 'a');
}
void loop(){
}
67
Example 28
// Write a program to read the content of location 0x005F of EEPROM into PORTD.
void setup(){
DDRD = 0xFF; // Set PORTD as Output Port
PORTD = EEPROM_Read(0x5F);
}
void loop(){
}
68
Example 29
/* Write a program to write two bytes byte EEPROM_Read(unsigned int Address){
at address 0x10 and 0x12 of EEPROM and // Wait for completion of previous write
then read the data from these two while(EECR & (1<<EEPE));
addresses and then show this data on EEAR = Address; // Set up address
PORTD with one sec delay. */ register
// Start EEPROM read by writing EERE
/*** SOLUTION ***/ EECR |= (1<<EERE);
return EEDR; // Return data from Data
void EEPROM_Write(unsigned int Register
Address, }
byte Data) void setup(){
{ DDRD = 0xFF; // Set PORTD as Output Port
// Wait for completion of previous EEPROM_Write(0x10, 'a');
write EEPROM_Write(0x12, 'b');
while(EECR & (1<<EEPE)); }
// Set up address and Data Registers
EEAR = Address; EEDR = Data; void loop(){
// Write logical one to EEMPE PORTD = EEPROM_Read(0x10);
EECR |= (1<<EEMPE); delay(1000);
// Start EEPROM write by setting EEPE PORTD = EEPROM_Read(0x12);
Page Page
69
EECR |= (1<<EEPE); delay(1000);
Example 29
70
Example 30
/* Write a program to write a string byte EEPROM_Read(unsigned int Address){
"9876543210 Aa" to EEPROM starting // Wait for completion of previous write
from address 0x100. */ while(EECR & (1<<EEPE));
// Set up address register
/*** SOLUTION ***/ EEAR = Address;
// Start EEPROM read by writing EERE
void EEPROM_Write(unsigned int EECR |= (1<<EERE);
Address, return EEDR; // Return data from Data
byte Register
Data) }
{ void EEPROM_Write_Str (unsigned int Address,
// Wait for completion of previous byte Data[])
write {
while(EECR & (1<<EEPE)); int i = 0;
// Set up address and Data Registers // loop until we find NULL in the string
while(Data[i])
EEAR = Address; EEDR = Data; // Write first then increment
// Write logical one to EEMPE // both address and index number of array
EECR |= (1<<EEMPE); EEPROM_Write(Address++, Data[i++]);
// Start EEPROM write by setting // Write NULL also
EEPROM_Write(Address, 0);
EEPE }
Page Page
71
EECR |= (1<<EEPE);
Example 30
void setup() void loop()
{ {
// Set Port D as output port byte aByte;
DDRD = 0xFF; for( unsigned int adr =0x100 ; ; adr++)
// Write a string in EEPROM {
// starting from address 0x100 // Read One Byte from EEPROM
EEPROM_Write_Str(0x100,"9876543210 aByte = EEPROM_Read(adr);
Aa");
} // if it is NULL then break the loop
if(aByte == 0)
break;
else
// else show it on PORTD
PORTD = aByte;
// delay of 1 second
delay(1000);
}
}
Page Page
72
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.
List of Functions in EEPROM Library
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)
Example 31
// Write a program to write a byte to EEPROM then read it and show it on PORTD.
#include <avr/eeprom.h>
// Reserve a location in EEPROM
byte EEMEM myByte;
void setup() {
DDRD = 0xFF; // Set Port D as output port
// Write to EEPROM
eeprom_write_byte(&myByte,'G');
void loop() {
}
75
Assignment # 1
1. Write a program to find number of 1s in a byte.
2. Write a program to find the average of the following numbers.
byte No[] = {'8','9','4','7','6','2','5'}; Notice that they are ASCII and must be
converted to BCD (or binary) before the average is calculated.
3. Write a program to calculate y where y = x2 + 2x + 1. x is between 0 and 9 and
the look-up table for x2 is located in Flash Memory. Take the values of x from
PORTB and Show the answer in binary at PORTD.
4. Write a program to read 8-bit number (234) from PORTD, Separate each digit,
convert digits to ASCII, store them in character array in the form of string
"234" and Finally store this string in EEPROM starting from address 0x100.
5. Write a program to read a string "234" from EEPROM starting from address
0x100, convert the string back to 8-bit number and show this number on
PORTD.