Title: AVR Programming
1AVR Programming
2ATmega328P
3I/O for our labs
- To get data into and out of our Arduino its a
little trickier than using printf and scanf as
you did in CS211 - Since the Arduino doesn't have an Operating
System we need to write and read data directly
to/from the I/O ports - Access to the ports is through the Special
Function Registers (SFRs) that are defined
symbolically in iom328p.h which is included in
your program by io.h
4io.h
include ltavr/iom165p.hgt elif defined
(__AVR_ATmega168__)? include
ltavr/iom168.hgt elif defined (__AVR_ATmega168P__)?
include ltavr/iom168p.hgt elif defined
(__AVR_ATmega169__)? include
ltavr/iom169.hgt elif defined (__AVR_ATmega169P__)?
include ltavr/iom169p.hgt elif defined
(__AVR_ATmega8HVA__)? include
ltavr/iom8hva.hgt elif defined (__AVR_ATmega16HVA__
) . . . include ltavr/iom3250.hgt elif defined
(__AVR_ATmega3250P__) include
ltavr/iom3250.hgt elif defined (__AVR_ATmega328P__)
defined (__AVR_ATmega328__) include
ltavr/iom328p.hgt elif defined (__AVR_ATmega329__)
include ltavr/iom329.hgt ?
5iom328p.h
/ avr/iom328p.h - definitions for ATmega328P.
/ / This file should only be included from
ltavr/io.hgt, never directly. / ifndef
_AVR_IO_H_ error "Include ltavr/io.hgt instead
of this file." endif ifndef _AVR_IOXXX_H_
define _AVR_IOXXX_H_ "iom328p.h" else error
"Attempt to include more than one ltavr/ioXXX.hgt
file." endif ifndef _AVR_IOM328P_H_ define
_AVR_IOM328P_H_ 1 / Registers and associated
bit numbers / define PINB _SFR_IO8(0x03) defin
e PINB0 0 define PINB1 1 define PINB2 2 define
PINB3 3 define PINB4 4 define PINB5 5 define
PINB6 6 define PINB7 7 define DDRB
_SFR_IO8(0x04) define DDB0 0 define DDB1
1 define DDB2 2 define DDB3 3 define DDB4 4
6sfr_defs.h
- included in every compile via io.h
- contains macro definitions for accessing Special
Function Registers as if they were just c
language variables - in iom328p.h the statement define
PINB _SFR_IO8(0x03) the symbol PINA is mapped
to the SFR at address 0x03 in SFR memory - _SFR_IO8( ) is a macro (look in sfr_defs.h )?
7Why this is done
- in your program you include io.h and io.h in
turn includes iom328p.h (because in your project
definition you picked the ATmega328p as the
processor)? - pass 1 of the compiler does all includes and
macro substitutions ( in our example with PINA
all occurrences of the symbol PINB in your
program will be replaced with a reference to SFR
0x03)? - This makes all SFR references look like
references to C variables
8Memories
9Getting Digital Data Into and Out Of
- Initialize the ports B or D
- set bits in the Data Direction Registers (DDRB
and DDRD) for input or output - 1 for output 0 for input?
- use PORTB or PORTD for output
- don't forget the current limiting, series
resistors - use PINB or PIND for input
- don't forget the pull-up resistors
10Blink.c
/------------------------------------------------
------------------------------/ / Name Blink.c
/ / Author Steflik
/
/ Description This is the MCU equivalent of
Hello World, instead of saying / / Hello
World it blinks an led at a one second rate
/ /-------------------------
--------------------------------------------------
---/ include ltavr/io.hgt //This
contains definitions for all the registers
locations and some //
other things, must always be included define
F_CPU 16000000UL //F_CPU tells the compiler that
our crystal is an 16Mhz one so it
// can generate an accurate delay,
must be declared above delay so
// delay knows what is the value of
F_CPU include ltutil/delay.hgt //Contains some
delay functions that will generate accurate
delays // of ms and
us int main(void) //In ANSI C, the
main function as always an int return and using
// void will give
you an warning DDRB (1ltltPB5)
//Define digital pin13/PORTB5 as an output so we
can blink our led while(1) //This
gives us an infinite loop, there should always be
an infinite loop // in your
code, because micro-controllers cant return from
main // to anywhere and
that will give you bad results and unpredicted
// behavior PORTB
(1ltltPB5) //Turn led on, this is the led
included in the arduino(digital pin 13)
_delay_ms(1000) //Wait 1 second PORTB
(1ltltPB5) //Turn led off _delay_ms(1000)
//Wait another second return 1
11daemons
- a daemon is a program that will sit in memory
forever and run until the system loses power - since most embedded system run forever (until
they lose power) our main() should be written as
a never ending loop. - processing to be done can be done either in the
body of the loop or asynchronously in response to
an external or internal event (interrupt)?
12Interrupts
- How Interrupts are handled
- Somewhere in your program you define an Interrupt
Servicing Subroutine (ISS), the compiler will put
the address of this routine into the proper
location in the interrupt vector (low memory)? - When the interrupt occurs the system state is
saved, a branch to the ISS is made via the
interrupt vector - The ISS executes and returns the state of the
system and you are right where you were before
the interrupt occurred
13ATmega328p Interrupt Vector
14What we want to do
- use 8 LEDs for output
- 8 switches for input
- 1 button to tell when it is OK to read the
switches - to do this we should us an interrupt
15The way it should work
/ Interrupt handler / // disable
interruptes // read the switches //
save the data at the next location in an array
// light the lights // enable
interrupts int main ()? // initialize
ports B D // initial Port E for interrupt
on PE2 // loop forever this is our daemon
16volatile keyword
- the keyword volatile should be used to define
any variable that may be modified inside of an
interrupt handler - volatile flags a variable to the optimizing
compiler to not optimize variables with the
volatile keyword
volatile char switches 0 volatile
uint8_t flags 0
17char uint8_t
- Remember the char data type can be used for ASCII
characters or a signed 8 bit integer - The AVR header files define another data type
that allows an unsigned 8 bit integer, this is
convenient for working with gpio ports as they
are not usually signed data.
18internal pullups for gpio inputs
- on many MCUs you must add an external pullup
resistor on gpio input lines - Atmel MCUs have built-in internal pullup
resistors - to use the internal pullups write a one to that
line after it has been defined as an input line
in the DDR
// define Port B as all outputs and Port D as all
inputs DDRB 0xFF DDRD 0x00 //turn on the
internal pullup resistors for Port D PORTD 0xFF
19Setting up an interrupt handler
- Signal or ISR
- the ISR macro has superceded the Signal macro and
is the preferred way of setting up an interrupt
handler
ISR( name of the int from processor .h file)?
........ ISR(SIG_PIN_CHANGE1)? ....
20Pin Change Interrupts
- Input lines on Ports B, C and D can be set up to
generate a pin change interrupt - Each port has an associated mask register
- to enable an interrupt put a 1 into the correct
position in the appropriate mask register - Port B PCMSK2
- Port C PCMSK1
- Port D PCMSK0
21PCINT Mapping
PORT D PCINT7 7 SIG_PIN_CHANGE0 P
CINT6 6 PCINT5 5 PCINT4 4 PCINT3 3 PCINT2 2 PCINT
1 1 PCINT0 0 PORT B PCINT23 7
SIG_PIN_CHANGE1 PCINT22 6 PCINT21 5 PCINT20 4
PCINT19 3 PCINT18 2 PCINT17 1 PCINT16 0
22Example
//set bit 2 of Port B to cause an
interrupt PCMSK1 0x04 // set bit 2 of
Port B to cause interrupt EIMSK 0xC0
// Ext Int Mask Reg EIFR 0xC0 //
Ext Int Flag Reg DDRB 0xFB // make
bit 2 an input line PORTB 0x04 //
turn on pullup ISR(SIG_PIN_CHANGE1)?
cli( ) // disable interrupts . .
. sei( ) // enable interrupts