Atmel AVR Microcontroller Primer: Programming and Interfacing
Atmel AVR Microcontroller Primer: Programming and Interfacing
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted
in any form or by any means---electronic, mechanical, photocopy, recording, or any other except for brief
quotations in printed reviews, without the prior permission of the publisher.
DOI: 10.2200/S00100ED1V01Y200712DCS015
A Publication in the Morgan & Claypool Publishers series
Lecture #15
Series Editor: Mitchell A. Thornton, Southern Methodist University
Series ISSN
Daniel J. Pack
United States Air Force Academy
ABSTRACT
This textbook provides practicing scientists and engineers a primer on the Atmel AVR microcon-
troller. Our approach is to provide the fundamental skills to quickly get up and operating with
this internationally popular microcontroller. The Atmel ATmega16 is used as a representative
sample of the AVR line. The knowledge you gain on the ATmega16 can be easily translated
to every other microcontroller in the AVR line. We cover the main subsystems aboard the
ATmega16, providing a short theory section followed by a description of the related
microcontroller subsystem with accompanying hardware and software to exercise the subsytem.
In all examples, we use the C programming language. We conclude with a detailed chapter
describing how to interface the
microcontroller to a wide variety of input and output
devices.
KEYWORDS
Atmel microcontroller, microcontroller, ATmega16, Atmel AVR, microcontroller interfacing
vi ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING AND INTERFACING 5
Preface
In 2006, Morgan & Claypool Publishers (M&C) released our textbook Microcontrollers
Fundamen- tals for Engineers and Scientists. The purpose of this textbook was to provide
practicing scientists and engineers a tutorial on the fundamental concepts and the use of
microcontrollers. The text- book presented the fundamental concepts common to all
microcontrollers. Our goals for writing this follow-on book are to present details on a specific
microcontroller family---the Atmel AVR Microcontroller.
Why Atmel? There are many excellent international companies that produce
microcontrollers. As Atmel states, ‘‘Atmel Corporation is an industry leader in the design
and manufacture of advanced semiconductors, with focus on microcontrollers, nonvolatile
memory, logic, radio frequency components and sensors.’’ Some of the highlights of the Atmel
AVR line include
Although all of these features are extremely important, we have chosen to focus on the
Atmel
AVR line of microcontrollers for this primer for a number of other related
reasons:
• The learning curve for Atmel microcontrollers is gentle. If this is your first exposure to
microcontrollers, you will quickly come up to speed on microcontroller programming
and interfacing. If you already know another line of processors, you can quickly apply
your knowledge to this powerful line of 8-bit processors.
• It is relatively inexpensive to get started with the Atmel AVR microcontroller line.
The microcontrollers themselves are inexpensive, and the compilers and programming
hardware and software are relatively inexpensive.
• The AVR line provides a full range of processing power, from small 8-pin processors to
complex 100-pin processors. The same compiler and programming hardware may be
used with a wide variety of microcontrollers.
• Many of the AVR microcontrollers are available in dual inline package, which makes
them readily useable on a printed circuit board prototype (e.g., senior design projects).
• Many of the microcontrollers in the AVR line are pin-for-pin compatible with one
another.
This allows you to easily move up and down the AVR line as your project becomes
better defined.
• Atmel has documentation available for every microcontroller at your fingertips. Simply
visit www.atmel.com. Furthermore, Atmel customer support is good and responsive.
• There is worldwide interest in the AVR microcontroller line. We would be remiss to not
mention AVR Freaks. This is a dedicated, international group of AVR experts who
share their expertise online with other high-power users and novices alike.
Contents
CH AP T E R 1
a)
Port x Data Register - PORTx
7 0
Port x Data Direction Register - DDRx
7 0
Port x Input Pins Address - PINx
7 0
b)
FIGURE 1.2: ATmega16 port configuration registers: (a) port-associated registers and (b) port pin
configuration.
• Data Direction Register (DDRx)---used to set a specific port pin to either output (1) or
input (0), and
• Input Pin Address (PINx)---used to read input data from the port.
Figure 1.2(b) describes the settings required to configure a specific port pin to either input
or output. If selected for input, the pin may be selected for either an input pin or to operate in the
high-impedance (Hi-Z) mode. In Hi-Z mode, the input appears as high impedance to a
particular pin. If selected for output, the pin may be further configured for either logic low or
logic high.
Port pins are usually configured at the beginning of a program for either input or output,
and their initial values are then set. Usually, all eight pins for a given port are configured
simultaneously. A code example is provided below to show how ports are configured. Note that
because we are using the C programming language with a compiler include file, the register
contents are simply referred to by name. Note that the data direction register (DDRx) is first
used to set the pins as either input or output, and then the data register (PORTx) is used to set
the initial value of the output port pins.
//***************************************************************
//initialize_ports: provides initial configuration for I/O ports
//***************************************************************
void initialize_ports(void)
{
DDRA=0xfc; //set PORTA[7:2] as output, PORTA[1:0]
//as input (1111_1100)
PORTA=0x03; //initialize PORTA[7:2] low, PORTA[1:0]
//current source
DDRB=0xa0; //PORTB[7:4] as output, set PORTB[3:0] as input
PORTB=0x00; //disable PORTB pull-up resistors
:
:
:
The ATmega16 is equipped with four PWM channels. The PWM channels coupled with
the flexibility of dividing the time base down to different PWM subsystem clock source
frequencies allows the user to generate a wide variety of PWM signals, from relatively high-
frequency, low-duty cycle signals to relatively low-frequency, high-duty cycle signals.
PWM signals are used in a wide variety of applications, including controlling the position
of a servo motor and controlling the speed of a DC motor. We discuss the operation,
programming, and application of the PWM system in Chapter 5 of the text.
1.4.4.1 Serial USART. The serial USART is used for full duplex (two-way) communication
between a receiver and transmitter. This is accomplished by equipping the ATmega16 with inde-
pendent hardware for the transmitter and receiver. The USART is typically used for
asynchronous communication. That is, there is not a common clock between the transmitter
and receiver to keep them synchronized with one another. To maintain synchronization
between the transmitter and receiver, framing start and stop bits are used at the beginning and
end of each data byte in a transmission sequence.
The ATmega16 USART is quite flexible. It has the capability to be set to a variety of data
transmission rates known as the baud (bits per second) rate. The USART may also be set for
data bit widths of 5 to 9 bits with one or two stop bits. Furthermore, the ATmega16 is equipped
with a hardware-generated parity bit (even or odd) and parity check hardware at the receiver. A
single parity bit allows for the detection of a single bit error within a byte of data. The
USART may also be configured to operate in a synchronous mode. We discuss the operation,
programming, and application of the USART in Chapter 2 of the text.
1.4.4.2 Serial Peripheral Interface. The ATmega16 SPI can also be used for two-way serial
communication between a transmitter and a receiver. In the SPI system, the transmitter and
receiver share a common clock source. This requires an additional clock line between the
transmitter and receiver but allows for higher data transmission rates as compared with the
USART.
The SPI may be viewed as a synchronous 16-bit shift register with an 8-bit half residing
in the transmitter and the other 8-bit half residing in the receiver. The transmitter is designated
the master because it provides the synchronizing clock source between the transmitter and the
receiver. The receiver is designated as the slave. We discuss the operation, programming, and
application of the SPI in Chapter 2 of the text.
1.4.4.3 Two-Wire Serial Interface. The TWI subsystem allows the system designer to network
a number of related devices (microcontrollers, transducers, displays, memory storage, etc.)
together into a system using a two-wire interconnecting scheme. The TWI allows a maximum
of 128 devices to be connected together. Each device has its own unique address and may both
transmit and receive over the two-wire bus at frequencies up to 400 kHz. This allows the
device to freely exchange information with other devices in the network within a small area.
1.5.1 Packaging
The ATmega16 comes in three different packaging styles: a 40-pin plastic dual in-line package
(DIP), a 44-lead thin quad flat pack package, and a 44-pad quad flat nonlead/microlead frame
package. The Pinout Diagram for the different packaging options are provided in Figure 1.3.
b)
FIGURE 1.3: Atmel AVR ATmega16 Pinout Diagram: (a) 40-pin plastic DIP and (b) thin quad flat
pack/microlead frame. Figure used with permission of Atmel.
microcontroller is placed in sleep mode using the SLEEP command and ‘‘wakened’’ from SLEEP
when an interrupt occurs. Additionally, power consumption can be further reduced by operating
the microcontroller at the lowest practical clock frequency for a given application.
PORTB
ch VDD = 5 VDC 74HC14 3-(AIN0) PB2 PA2 (ADC2)-38 R T
ha 4-(AIN1) PB3 PA3 (ADC3)-37 R
5-(SS) PB4 PA4 (ADC4)-36 47 G
O
rd 4.7K 6-(MOSI) PB5 PA5 (ADC5)-35
wa VDD 1M 7-(MISO) PB6 PA6 (ADC6)-34
R L
re. 1.0 uF 8-(SCK) PB7
sys reset 9-RESET PA7 (ADC7)-33 L
SW7 470K AREF-32 47 G
10-Vcc VDD E
0.1 uF AGND-31
11-GND AVCC-30
R
R
PORTD PORTC
12-XTAL2 PC7 (TOSC2)-29 P
13-XTAL1 PC6 (TOSC1)-28 47 G
14-(RXD) PD0 PC5-27
RI
R
15-(TXD) PD1 PC4-26 M
16-(INT0) PD2 PC3-25
47 G
E
17-(INT1) PD3 PC2-24
18-(OC1B) PD4 R:
PC1-23
19-(OC1A) PD5 PC0-22 P
20-(ICP) PD6 PD7 (OC2)-21 R
ZTT 10MHz R O
resonator
Vcc G
Vcc R
2N2222 A
3.0 K M
- M
+ IN
LM324 2N2907
G
3.0 K A
N
1515 ATMEL AVR MICROCONTROLLER PRIMER:
ATMELPROGRAMMING
AVR ARCHITECTURE
AND OVERVIEW
INTERFACING 1515
Aside from the input hardware on PORTB and the output display hardware on PORTA of
the controller, there are power (pins 10, 30, and 32) and ground (pins 11 and 31) connections. A
standard 5-VDC power supply may be used for the power connections. For portable
applications, a 9-VDC battery equipped with a 5-VDC regulator (LM340-05 or uA7805) may
be used as a power source. Pins 9 through 11 have a resistor (1 M), two capacitors (1.0 µF), and
a tact switch configured to provide a reset switch for the microcontroller. We use a ZTT 10-
MHz ceramic resonator as the time base for the Testbench. It is connected to pins 12 (XTAL2)
and 13 (XTAL1) of the ATmega16.
• Comments
• Include Files: We have included the ImageCraft ICC AVR include file for the
ATmega16 (iom16v.h). This file provides the software link between the names of the
ATmega16 hardware registers and the actual hardware locations. When a register is
used by name in the program, reference is made to the contents of that register.
• Function Prototypes
• Global Variables
• Main Program: We begin the main program by calling the function to initialize the ports
and then enter a continuous loop. Within the loop body, the ATmega16 monitors for a
status change on PORTB. When the user depresses one of the tact switches connected
to PORTB, a change of status is detected and the appropriate LED is illuminated on
PORTA.
• Function Definition
//*************************************************************
//file name: testbench.c
//function: provides test bench for ATMEL AVR ATmega16 controller
//target controller: ATMEL ATmega16
//
//ATMEL AVR ATmega16 Controller Pin Assignments
//Chip Port Function I/O Source/Dest Asserted Notes
//Pin 1 PB0 to active high RC debounced switch
//Pin 2 PB1 to active high RC debounced switch
//Pin 3 PB2 to active high RC debounced switch
//Pin 4 PB3 to active high RC debounced switch
//Pin 5 PB4 to active high RC debounced switch
//Pin 6 PB5 to active high RC debounced switch
//Pin 7 PB6 to active high RC debounced switch
//Pin 8 PB7 to active high RC debounced switch
//Pin 9 Reset
//Pin 10 VDD
//Pin 11 Gnd
//Pin 12 Resonator
//Pin 13 Resonator
//Pin 14 PD0 to tristate LED indicator
//Pin 15 PD1 to tristate LED indicator
//Pin 16 PD2 to tristate LED indicator
//Pin 17 PD3 to tristate LED indicator
//Pin 18 PD4 to tristate LED indicator
//Pin 19 PD5 to tristate LED indicator
//Pin 20 PD6 to tristate LED indicator
//Pin 21 PD7 to tristate LED indicator
//Pin 22 PC0
//Pin 23 PC1
//Pin 24 PC2
//Pin 25 PC3
//Pin 26 PC4
//Pin 27 PC5
//Pin 28 PC6
//Pin 29 PC7
//Pin 30 AVcc to VDD
//Pin 31 AGnd to Ground
//Pin 32 ARef to Vcc
//Pin 33 PA7
//Pin 34 PA6
//Pin 35 PA5
//Pin 36 PA4
//Pin 37 PA3
//Pin 38 PA2
//Pin 39 PA1
//Pin 40 PA0
//
//author: Steven Barrett and Daniel Pack
//created: July 12, 2007
//last revised: July 12, 2007
//***************************************************************
//include files**************************************************
#include<iom16v.h> //ImageCraft ICC AVR
//include file
//for ATmega16
//function prototypes********************************************
//main program***************************************************
//global variables
unsigned char old_PORTB =
unsigned char new_PORTB;
void main(void)
{
initialize_ports();
while(1){//main loop
new_PORTB = PINB;
//***************************************************************
//initialize_ports: provides initial configuration for I/O ports
//***************************************************************
void initialize_ports(void)
{
DDRA=0xff; //set PORTA[7:0] as output
PORTA=0x00; //initialize PORTA[7:0] low
as opposed to:
1.9 SUMMARY
In this chapter, we provided a brief overview of the ATmega16 microcontroller, a representative
sample of the AVR microcontrollers. Information presented in this chapter can be readily applied
to other microcontrollers in the AVR line. We then provided the Testbench hardware and
software that we use throughout the text to illustrate peripheral subsystem operation aboard the
ATmega16. In upcoming chapters, we provide additional details on selected ATmega16
subsystems.
2. Question: How does the ATmega16 interact with the external world?
3. Question: What are the different methods of applying a clock source to the ATmega16?
6. Question: With a specific port, can some port pins be declared as output pins while
others as input pins?
7. Question: Describe the serial communication features aboard the ATmega16. Provide a
CH AP T E R 2
2.2.6
Parity
To further enhance data integrity during transmission, parity techniques may be used. Parity is
an additional bit (or bits) that may be transmitted with the data byte. The ATmega16 uses a
single parity bit. With a single parity bit, a single-bit error may be detected. Parity may be even
or odd. In even parity, the parity bit is set to 1 or 0, such that the number of 1’s in the data byte
including the parity bit is even. In odd parity, the parity bit is set to 1 or 0, such that the
number of 1’s in the data byte including the parity bit is odd. At the receiver, the number of
bits within a data byte including the parity bit are counted to ensure that parity has not changed,
indicating an error, during transmission.
FIGURE 2.1: ASCII Code. The ASCII code is used to encode alphanumeric characters. The ‘‘0x’’
indicates hexadecimal notation in the C programming
language.
one another. To maintain synchronization between the transmitter and receiver, framing start and
stop bits are used at the beginning and end of each data byte in a transmission sequence. The
Atmel USART also has synchronous features. Space does not permit a discussion of these
USART enhancements.
The ATmega16 USART is quite flexible. It has the capability to be set to a variety of data
transmission or baud (bits per second) rates. The USART may also be set for data bit widths of 5
to 9 bits with one or two stop bits. Furthermore, the ATmega16 is equipped with a hardware-
generated parity bit (even or odd) and parity check hardware at the receiver. A single parity bit
allows for the detection of a single bit error within a byte of data. The USART may also be
configured to operate in a synchronous mode. We now discuss the operation, programming, and
application of the USART. Because of space limitations, we cover only the most basic capability
of this flexible and powerful serial communication system.
transmission hardware, the receiver hardware, and three control registers (UCSRA, UCSBR, and
UCSRC). We discuss each in turn.
2.3.1.1 USART Clock Generator. The USART Clock Generator provides the clock source
for the USART system and sets the baud rate for the USART. The baud rate is derived from
the
3030 ATMEL AVR MICROCONTROLLER PRIMER:
SERIAL
PROGRAMMING
COMMUNICATION
AND SUBSYSTEM
INTERFACING 3030
overall microcontroller clock source. The overall system clock is divided by the USART baud
rate registers UBRR[H:L] and several additional dividers to set the baud rate. For the
asynchronous normal mode (U2X bit = 0), the baud rate is determined using the following
expression:
where UBRR is the content of the UBRRH and UBRRL registers (0--4095). Solving for
UBRR
yields
2.3.1.2 USART Transmitter. The USART transmitter consists of a Transmit Shift Register.
The data to be transmitted are loaded into the Transmit Shift Register via the USART I/O Data
Register (UDR). The start and stop framing bits are automatically appended to the data within
the Transmit Shift Register. The parity is automatically calculated and appended to the Transmit
Shift Register. Data are then shifted out of the Transmit Shift Register via the TxD pin a single
bit at a time at the established baud rate. The USART transmitter is equipped with two status
flags: the USART Data Register Empty (UDRE) and the transmit complete (TXC) flags. The
UDRE flag sets when the transmit buffer is empty, indicating it is ready to receive new data. This
bit should be written to a zero when writing the USART Control and Status Register A
(UCSRA). The UDRE bit is cleared by writing to the UDR. The TXC flag bit is set to logic 1
when the entire frame in the Transmit Shift Register has been shifted out and there are no new
data currently present in the transmit buffer. The TXC bit may be reset by writing a logic 1 to it.
2.3.1.3 USART Receiver. The USART Receiver is virtually identical to the USART Transmitter
except for the direction of the data flow, which is reversed. Data are received a single bit at a
time via the RxD pin at the established baud rate. The USART receiver is equipped with the
receive complete (RXC) flag. The RXC flag is logic 1 when unread data exist in the receive
buffer.
2.3.1.4 USART Registers. In this section, we discuss the register settings for controlling the
USART system. We have already discussed the function of the UDR and the USART baud rate
registers (UBRRH and UBRRL). Note: The USART Control and Status Register C (UCSRC)
and the USART baud rate register high (UBRRH) are assigned to the same I/O location in the
memory map (Figure 2.3). The URSEL bit (bit 7 of both registers) determines which register
USART Control and Status Register A (UCSRA)
RXC T
7 0
USART Control and Status Register B (UCSRB)
RXCIE TX
7 0
USART Control and Status Register C (UCSRC)
URSEL=1 UM
7 0
USART Data Register - UDR
UDR(Read)
RXB7
UDR(Write)
TXB7
7 0
URSEL=0
UBRRL
UBRR7
7 0
is being accessed. The URSEL bit must be 1 when writing to the UCSRC register and 0 when
writing to the UBRRH register.
UCSRA. This contains the RXC, TXC, and the UDRE bits. The function of these bits has
already been discussed.
UCSRB. This contains the receiver and transmitter enable bits (RXEN and TXEN,
respectively). These bits are the ‘‘on/off’’ switch for the receiver and transmitter, respectively. The
UCSRB register also contains the UCSZ2 bit. The UCSZ2 bit in the UCSRB register and the
UCSZ[1:0] bits contained in the UCSRC register together set the data character size.
UCSRC. This allows the user to customize the data features to the application at hand. It
should be emphasized that both the transmitter and receiver be configured with the same data
features for proper data transmission. The UCSRC contains the following bits:
b) USART initialization
//*************************************************************
//USART_init: initializes the USART system
//*************************************************************
void USART_init(void)
{
UCSRA = 0x00; //control register initialization
UCSRB = 0x08; //enable transmitter
UCSRC = 0x86; //async, no parity, 1 stop bit,
//8 data bits
//Baud Rate initialization
UBRRH = 0x00;
UBRRL = 0x40;
}
//*************************************************************
//USART_transmit: transmits single byte of data
//*************************************************************
//*************************************************************
2.3.3.1 SPI Operation. The SPI may be viewed as a synchronous 16-bit shift register with an
8-bit half residing in the transmitter and the other 8-bit half residing in the receiver as shown in
Figure 2.5. The transmitter is designated the master because it provides the synchronizing
clock source between the transmitter and the receiver. The receiver is designated as the slave. A
slave is chosen for reception by taking its slave select (SS) line low. When the SS line is
taken low, the slave’s shifting capability is enabled. SPI transmission is initiated by loading a
data byte into the master configured SPI Data Register (SPDR). At that time, the SPI clock
generator provides clock pulses to the master and also to the slave via the SCK pin. A single bit
is shifted out of the master designated shift register on the Master Out Slave In (MOSI)
microcontroller pin on every
Master Device Slave Device
MISO MISO
(PB6) (PB6) SPI Data Register (SDR)
SPI Data Register (SDR) MSB LSB
MSB LSB
MOSI MOSI
(PB5) (PB5)
SCK SCK shift
system enable
SPI Clock Generator SPI SCK SCK
clock
(PB7) (PB7)
Status Register (SPSR) SPI
SCK pulse. The data are received at the MOSI pin of the slave designated device. At the same
time, a single bit is shifted out of the Master In Slave Out (MISO) pin of the slave device and
into the MISO pin of the master device. After eight master SCK clock pulses, a byte of data has
been exchanged between the master and slave designated SPI devices. Completion of data
transmission in the master and data reception in the slave is signaled by the SPI Interrupt Flag
(SPIF) in both devices. The SPIF flag is located in the SPI Status Register (SPSR) of each
device. At that time, another data byte may be transmitted.
2.3.3.2 Registers. The registers for the SPI system are provided in Figure 2.6. We will
discuss each one in turn.
SPI Control Register. The SPI Control Register (SPCR) contains the ‘‘on/off’’ switch for
the SPI system. It also provides the flexibility for the SPI to be connected to a wide variety of
devices with different data formats. It is important that both the SPI master and slave devices be
configured for compatible data formats for proper data transmission. The SPCR contains the
following bits:
• SPI Enable (SPE) is the ‘‘on/off’’ switch for the SPI system. A logic 1 turns the system on
and logic 0 turns it off.
SPI Control Register - SPCR
SPIE
7 0
SPI Status Register - SPSR
SPIF
7 0
SPI Data Register - SPDR
MSB
7 0
• Data Order (DORD) allows the direction of shift from master to slave to be controlled.
When the DORD bit is set to 1, the least significant bit (LSB) of the SPDR is
transmitted first. When the DORD bit is set to 0, the Most Significant Bit (MSB) of
the SPDR is transmitted first.
• The Master/Slave Select (MSTR) bit determines if the SPI system will serve as a master
(logic 1) or slave (logic 0).
• The Clock Polarity (CPOL) bit allows determines the idle condition of the SCK pin.
When CPOL is 1, SCK will idle logic high, whereas when CPOL is 0, SCK will idle
logic 0.
• The Clock Phase (CPHA) determines if the data bit will be sampled on the leading (0)
or trailing (1) edge of the SCK.
• The SPI SCK is derived from the microcontroller’s system clock source. The system clock
is divided down to form the SPI SCK. The SPI Clock Rate Select (SPR[1:0]) bits and
the Double SPI Speed (SPI2X) bit are used to set the division factor. The following
divisions may be selected using SPI2X, SPR1, and SPR0:
{ 000: SCK = system
clock/4
{ 001: SCK = system
clock/16
{ 010: SCK = system
clock/64
{ 011: SCK = system clock/1284
{ 100: SCK = system
clock/2
{ 101: SCK = system
clock/8
{ 110: SCK = system clock/32
{ 111: SCK = system clock/64
SPI Status Register. This contains the SPIF. The flag sets when eight data bits have been
transferred from the master to the slave. The SPIF bit is cleared by first reading the SPSR after
the SPIF flag has been set and then reading the SPDR. The SPSR also contains the SPI2X bit
used to set the SCK frequency.
SPI Data Register. As previously mentioned, writing a data byte to the SPDR initiates SPI
transmission.
2.3.3.3 Programming. To program the SPI system, the system must first be initialized with
the desired data format. Data transmission may then commence. Functions for initialization,
transmission, and reception are provided below. In this specific example, we divide the clock
oscillator frequency by 128 to set the SCK clock frequency.
//*************************************************************
//spi_init: initializes spi system
//*************************************************************
//*************************************************************
//spi_write: Used by SPI master to transmit a data byte
//*************************************************************
//*************************************************************
//spi_read: Used by SPI slave to receive data byte
//*************************************************************
return SPDR;
}
//*************************************************************
2.5 SUMMARY
In this chapter, we have discussed the differences between parallel and serial communications
and key serial communication-related terminology. We then, in turn, discussed the operation of
USART, SPI, and TWI serial communication systems. We also provided basic code examples to
communicate with the USART and SPI systems.
2. Question: Summarize the differences among the USART, SPI, and TWI methods of serial
communication.
3. Question: Draw a block diagram of the USART system, label all key registers, and all keys
USART flags.
4. Question: Draw a block diagram of the SPI system, label all key registers, and all keys
USART flags.
5. Question: If an ATmega16 microcontroller is operating at 12 MHz, what is the
maximum transmission rate for the USART and the SPI?
6. Question: What is the ASCII encoded value for ‘‘Claypool’’?
7. Question: Draw the schematic of a system consisting of two ATmega16 that will
exchange data via the SPI system. The system should include RS-232 level shifting.
8. Question: Write the code to implement the system described in the question above.
• • • •
4141 ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING AND 41
INTERFACING
CH AP T E R 3
Analog-to-Digital Conversion
intensity changes in the spatial axis. The same analysis can be performed as we move from the
top to the bottom of the image.
Analog signals are those whose physical variable values change continuously over their
independent variable. Most physical variables, your speech, movement of stars, and the music you
hear at a concert are analog signals, signals that we find all around us. Digital signals, on the
other hand, have their physical variables defined only for discrete instances over their
independent variables. Although it may look continuous to human eyes, the photo example shown
in Figure 3.2 is a discrete signal because pixels that make up a camera image cannot capture all
space within the camera frame. The image is only a finite composition of intensity values seen by
a discrete number of pixels.
Digital signals are important because all signals represented in digital systems,
computers, and microcontrollers are in digital forms. The important task is how to faithfully
represent analog
signals using digital signals. For example, human voices must be converted to corresponding
digital signals before they can be routed by digital switching circuits in telephone
communication systems. Similarly, voice commands to robots must be converted to a digital form
before robots can understand the command.
As shown in the examples above, we live in an analog world; that is, physical variables
are analog signals. It is precisely this reason why the ADC is so very important in any digital
systems that interact with an analog environment.
and Pack [2] listed in the References section. Sampling is important because when we want to
represent an analog signal in a digital system, such as a computer, we must use the appropriate
sampling rate to capture the analog signal for a faithful representation in digital systems.
Now that we understand the sampling process, let us move on to the second process of the
ADC, quantization. Each digital system has a number of bits, which it uses as the basic units to
represent data. A bit is the most basic unit where single binary information, 1 or 0, is
represented. A nibble is made up of 4 bits put together. A byte is 8 bits.
In the previous section, we tacitly avoided the discussion of the form of captured signal
samples. When a signal is sampled, digital systems need some means to represent the captured
samples. The quantization of a sampled signal is how the signal is represented as one of
quantization level. Suppose you have a single bit to represent an incoming signal. You only have
two different numbers, 0 and 1. You may say that you can distinguish only low from high.
Suppose you have
2 bits. You can represent four different levels, 00, 01, 10, and 11. What if you have 3 bits? You
now can represent eight different levels: 000, 001, 010, 011, 100, 101, 110, and 111. Think of it as
follows. When you had 2 bits, you were able to represent four different levels. If we add one
more bit, that bit can be 1 or 0, making the total possibilities 8. Similar discussion can lead us to
conclude that given n bits, we have 2n different numbers or levels one can represent.
Figure 3.4 shows how n bits are used to quantize a range of values. In many digital systems,
the incoming signals are voltage signals. The voltage signals are first obtained from physical
signals with the help of transducers, such as microphones, angle sensors, and infrared sensors.
The voltage signals are then conditioned to map their range with the input range of a digital
system, typically
0 to 5 V. In Figure 3.4, n bits allow you to divide the input signal range of a digital system
into
1
For the sake of our discussion, we ignore other overheads involved in processing a phone call such as
multiplexing, demultiplexing, and serial-to-parallel conversion.
5050 ATMEL AVR MICROCONTROLLER PRIMER:
ANALOG-TO-DIGITAL
PROGRAMMING ANDCONVERSION
INTERFACING 5050
to digital signals. Typically, you will find 8 to 12 bits used in commercial ADCs, translating the
8 12
dynamic range from 20 log 2 dB to 20 log 2 dB (Oppenheim and Schafer [3]).
B.
FIGURE 3.7: A block diagram of the signal conditioning for an ADC. The range of the sensor
voltage output is mapped to the ADC input voltage range. The scalar multiplier maps the
magnitudes of the two ranges, and the bias voltage is used to align two limits.
The variable V1 max represents the maximum output voltage from the input transducer. This
voltage occurs when the maximum physical variable (Xmax ) is presented to the input transducer.
This voltage must be scaled by the scalar multiplier (K ) and then have a DC offset bias voltage
(B) added to provide the voltage V2 max to the input of the ADC converter.
Similarly, The variable V1 min represents the minimum output voltage from the input
transducer. This voltage occurs when the minimum physical variable (Xmin ) is presented to the
input transducer. This voltage must be scaled by the scalar multiplier (K ) and then have a DC
offset bias voltage (B) added to produce voltage V2 min to the input of the ADC converter.
Usually, the values of V1 max and V1 min are provided with the documentation for the
transducer. Also, the values of V2 max and V2 min are known. They are the high and low reference
voltages for the ADC system (usually 5 and 0 VDC for a microcontroller). We thus have two
equations and two unknowns to solve for K and B. The circuits to scale by K and add the offset
B are usually implemented with operational amplifiers. We refer interested readers to Thomas
and Rosa [4] listed in the References section.
Once a physical signal has been converted to its corresponding electrical signal with the
help of an input transducer and the output of the transducer mapped correctly to the input of the
ADC, the ADC process can start. The first step of the ADC process is the sampling of the
analog signal. When selecting a converter, one must consider the type of physical signal that is
being converted to properly ensure the sampling rate. As discussed in the previous section, using
the proper sampling rate is the first step that determines whether an analog signal will be
represented correctly in digital
systems. What this means for the reader is to select an ADC that can handle a required
conversion rate. Because most microcontrollers now come with a built-in ADC, one must
study the user manual portion discussing the conversion rate and make sure that the required
sampling rate for the application falls under the advertised conversion rate. For example, if you
need to convert the signal representing a person’s blood pressure, the sampling rate with 100 Hz
(100 samples per second) will suffice. On the other hand, if you are dealing with human voice,
you need at least an 8-kHz sampling rate capacity (see Enderle et al. [5] for details).
Once the analog signal has been sampled, the quantization process takes place. For this
process, again one must decide how much quantization error can be allowed. At one extreme
where you are only concerned with finding out only two states, say on and off, quantization error
of 1 V is not important. We can operate safely with 2 bits with maximum quantization error of
1.25 V. On the other hand, if we can only operate with maximum quantization error of 0.01 V,
we need to choose a converter with, at minimum, 10 bits (about 5 mV). To determine the
number of bits and its corresponding maximum quantization error, we use the following
equation.
range
Resolution = b .
2
Thus, we can determine the number of bits that will meet the error requirement using the
equation above.
Once the quantization level has been determined, we can now encode it using the
available bits. As seen in the previous section, the process is a simple conversion of a
decimal number (quantization level) to a binary number. Note that the binary number should use
all available bits. For example, quantization level 4 using 8 bits is converted as 0000 0100, not
100.
In summary, the ADC process has three steps for completion: sampling, quantization, and
encoding. In the next section, we delve into four different technologies used to implement the
ADC process.
Example 3.1 A photodiode is a semiconductor device that provides an output current corre-
sponding to the light impinging on its active surface. The photodiode is used with a
transimpedance amplifier to convert the output current to an output voltage. A
photodiode/transimpedance ampli- fier provides an output voltage of 0 V for maximum rated
light intensity and −2.50 VDC of output voltage for the minimum rated light intensity.
Calculate the required values of K and B for this light transducer, so it may be interfaced to a
microcontroller’s ADC system.
0 V = (-2.50 V × K) + B
3.3.1 Successive
Approximation
The successive approximation technique uses a DAC, a controller, and a comparator to perform
the ADC process. Starting from the MSB down to the LSB, the controller turns on each bit at a
time and generates an analog signal, with the help of the DAC, to be compared with the
original input analog signal. Based on the result of the comparison, the controller changes or
leaves the current bit and turns on the next MSB. The process continues until decisions are
made for all available bits. One can consider the process similar to a game children play often.
One child thinks of a number in the range of 0 to 10 and asks another child to guess the number
within n turns. The first child will tell the second child whether a guessed number is higher or
lower than the answer at the end of each turn. The optimal strategy in such a situation is to
guess the middle number in the range, say 5. If the answer is higher than 5, the second guess
should be 8. If the answer is lower than 5, the second guess should be 3. The strategy is to narrow
down to the answer by partitioning the available range into two equal parts at every turn. The
successive approximation method works similarly in that the MSB is used to partition the
original input range of an ADC into halves, the
a)
b)
c)
d)
FIGURE 3.8: Four different technologies used to convert analog signals to digital signals: (a)
successive approximation converter, (b) integration-based converter, (c) counter-based converter, and
(d) parallel ADC.
second MSB divides the remaining half into two quarters of the input range, and so forth. Figure
3.8(a) shows the architecture of this type of converter. The advantage of this technique is that
the conversion time is uniform for any input, but the disadvantage of the technology is the use of
complex hardware for implementation.
3.3.2 Integration
The integration technique uses an integrator, a comparator, and a controller to convert analog
signals to digital signals. A sampled analog signal is integrated over a fixed period, say n clock
cycles of the digital system. Another fixed reference signal is integrated over time and
compared with the input analog signal integrated. Although the value of the reference signal
integrated is smaller than the input analog signal integrated, the reference signal is
continuously integrated, and the time for the integration is measured. When the two integrated
values equal, the measured time is converted to a digital encoded value. Figure 3.8(b) shows the
system components of the converter. One disadvantage of this technique is the varying time for
the conversion process. A small analog value will take less time to convert compared with a large
value.
• 10-bit resolution,
• ±2 LSB absolute accuracy,
• 13 ADC clock cycle conversion time,
• 8 multiplexed single-ended input channels,
• selectable right or left result justification, and
• 0 to Vcc ADC input voltage range.
Let us discuss each feature in turn. The first feature of discussion is ‘‘10-bit resolution.’’
Resolution is defined as:
b
resolution = (VRH − VRL )/2 .
VRH and VRL are the ADC high and low reference voltages, whereas b is the number of
bits available for conversion. For the ATmega16 with reference voltages of 5 VDC, 0 VDC,
and 10 bits available for conversion, resolution is 4.88 mV. Absolute accuracy specified as ±2
LSB is then
±9.76 mV at this resolution.
It requires 13 analog-to-digital clock cycles to perform an ADC conversion. The ADC
system may be run at a slower clock frequency than the main microcontroller clock source. The
main microcontroller clock is divided down using the ADC Prescaler Select (ADPS[2:0]) bits
in the ADC Control and Status Register A (ADCSRA).
The ADC is equipped with a single successive approximation converter. Only a single
ADC channel may be converted at a given time. The input of the ADC is equipped with an
eight-input analog multiplexer. The analog input for conversion is selected using the
MUX[4:0] bits in the ADC Multiplexer Selection Register (ADMUX).
The 10-bit result from the conversion process is placed in the ADC Data Registers,
ADCH and ADCL. These two registers provide 16 bits for the 10-bit result. The result may be
left justified by setting the ADLAR (ADC Left Adjust Result) bit of the ADMUX register.
Right justification is provided by clearing this bit.
The analog input voltage for conversion must be between 0 and Vcc V. If this is not the
case, external circuitry must be used to ensure the analog input voltage is within these prescribed
bounds as discussed earlier in the chapter.
3.4.2.1 ADC Multiplexer Selection Register. As previously discussed, the ADMUX register
contains the ADLAR bit to select left or right justification and the MUX[4:0] bits to determine
which analog input will be provided to the ADC for conversion. To select a specific input for
conversion is accomplished when a binary equivalent value is loaded into the MUX[4:0] bits.
For example, to convert channel ADC7, ‘‘00111’’ is loaded into the ADMUX register. This
may be accomplished using the following C instruction:
ADMUX = 0x07;
3.4.2.2 ADC Control and Status Register A. The ADCSRA register contains the ADC
Enable (ADEN) bit. This bit is the ‘‘on/off’’ switch for the ADC system. The ADC is turned on
by setting this bit to a logic 1. The ADC Start Conversion (ADSC) bit is also contained in the
ADCSRA register. Setting this bit to logic 1 initiates an ADC. The ADCSRA register also
contains the ADC Interrupt flag (ADIF) bit. This bit sets to logic 1 when the ADC is
complete. The ADIF bit is reset by writing a logic 1 to this bit.
The ADPS[2:0] bits are used to set the ADC clock frequency. The ADC clock is
derived from dividing down the main microcontroller clock. The ADPS[2:0] may be set to the
following values:
3.4.2.3 ADC Data Registers (ADCH and ADCL). As previously discussed, the ADC Data
Register contains the result of the ADC. The results may be left (ADLAR=1) or right
(ADLAR=0) justified.
//*************************************************************
//InitADC: initialize analog-to-digital converter
//*************************************************************
//*************************************************************
//ReadADC: read analog voltage from analog-to-digital converter -
//the desired channel for conversion is passed in as an unsigned
//character variable. The result is returned as a left justified,
//10 bit binary result. The ADC prescalar must be set to 8 to
//slow down the ADC clock at higher external clock frequencies
//(10 MHz) to obtain accurate results.
//*************************************************************
{
unsigned int binary_weighted_voltage, binary_weighted_voltage_low;
unsigned int binary_weighted_voltage_high; //weighted binary
//voltage
ADMUX = channel;
ADCSRA |= 0x43;
while (!(ADCSRA
ADCSRA |= 0x10;
binary_weighted_
//*************************************************************
3.4.4 Digital-to-Analog Conversion
Once a signal is acquired to a digital system with the help of the ADC process and has been
processed, frequently, the processed signal is converted back to another analog signal. A simple
example of such a conversion occurs in digital audio processing. Human voice is converted to a
digital signal, modified, processed, and converted back to an analog signal for people to hear.
The process to convert digital signals to analog signals is completed by a DAC. The most
commonly used technique to convert digital signals to analog signals is the summation method
shown in Figure 3.11.
With the summation method of DAC, a digital signal, represented by a set of 1’s and 0’s,
enters the DAC from the MSB to the LSB. For each bit, a comparator checks its logic state,
high or low, to produce a clean digital bit, represented by a voltage level. Typically, in a
microcontroller
FIGURE 3.11: A summation method to convert a digital signal into a quantized analog signal.
Comparators are used to clean up incoming signals, and the resulting values are multiplied by a
scalar multiplier, and the results are added to generate the output signal. For the final analog
signal, the quantized analog signal should be connected to a low pass filter followed by a transducer
interface circuit.
context, the voltage level is 5 or 0 V to represent logic 1 or logic 0, respectively. The voltage is
then multiplied by a scalar value based on its significant position of the digital signal as shown
in Figure 3.11. Once all bits for the signal have been processed, the resulting voltage levels are
summed to produce the final analog voltage value. Notice that the production of a desired analog
signal may involve further signal conditioning such as a low pass filter to ‘‘smooth’’ the quantized
analog signal and a transducer interface circuit to match the output of the DAC to the input of
an output transducer.
3.5 SUMMARY
In this chapter, we presented the differences between analog and digital signals and used this
knowledge to discuss three subprocessing steps involved in ADCs: sampling, quantization, and
encoding. We also presented the quantization errors and the data rate associated with the ADC
process. The dynamic range of an ADC, one of the measures to describe a conversion process,
was also presented. Two different categories exist to represent technologies used to convert
analog signals to their corresponding digital signals: direct approach and indirect approaches.
For the direct approach, we presented the successive approximation, counter-based, and parallel
conversion techniques. For the indirect approach, the integration-based conversion technique
was discussed. We then reviewed the operation, registers, and actions required to program the
ADC system aboard the ATmega16. We concluded the chapter with a brief presentation of
DACs.
degree symbol.] flexure and 40 kΩ of resistance for 90deg [TS: I can’t generate the
degree symbol.] of flexure. Design a circuit to convert the resistance change to a voltage
change (hint: consider a voltage divider). Then design a transducer interface circuit to
convert the output from the flex sensor circuit to voltages suitable for the ATmega16 ADC
system.
7. Question: If an analog signal is converted by an ADC to a binary representation and
then back to an analog voltage using a DAC, will the original analog input voltage be the
same as the resulting analog output voltage? Explain.
• • • •
6565 ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING AND 65
INTERFACING
CH AP T E R 4
Interrupt Subsystem
Decode
Execute
When an interrupt occurs, the microcontroller completes the current instruction, stores
the address of the next instruction on the stack, and starts executing instructions in the designated
ISR corresponding to the particular interrupt source. It also turns off the interrupt system to
prevent further interrupts while one is in progress. The execution of the ISR is performed by
loading the beginning address of the ISR specific for that interrupt into the program counter.
The ISR will then commence. Execution of the ISR continues until the return from interrupt
instruction (reti) is encountered. Program control then reverts back to the main program.
• Ensure the ISR for a specific interrupt is tied to the correct interrupt vector address,
which points to the starting address of the ISR.
6767 ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
INTERRUPT
AND SUBSYSTEM
INTERFACING 6767
FIGURE 4.2: Atmel AVR ATmega16 Interrupts [2]. Figure used with permission of Atmel.
• Ensure the interrupt system has been globally enabled. This is accomplished with the
assembly language instruction SEI.
• Ensure the specific interrupt subsystem has been locally enabled.
• Ensure the registers associated with the specific interrupt have been configured correctly.
In the next two examples that follow, we illustrate how to accomplish these steps. We use
the ImageCraft ICC AVR compiler, which contains excellent support for interrupts. Other
compilers have similar features.
4.4 APPLICATION
In this section, we provide two representative samples of writing interrupts for the ATmega16.
We provide both an externally generated interrupt event and also one generated from within the
microcontroller. The ImageCraft ICC AVR compiler uses the following syntax to link an ISR to
the correct interrupt vector address:
void timer_handler(void)
{
:
:
}
As you can see, the #pragma with the reserved word interrupt handler is used to
communicate to the compiler that the routine name that follows is an ISR. The number that
follows the ISR name corresponds to the interrupt vector number in Figure 4.2. The ISR is then
written like any other function. It is important that the ISR name used in the #pragma
instruction matches the name of the ISR in the function body. Because the compiler knows the
function is an ISR, it will automatically place the RETI instruction at the end of the ISR when
the corresponding assembly language is generated.
7 0
INT2
0: falling edge
1: rising edge
General Interrupt Control Register - GICR
INT1
7 0
0: interrupt disabled
1: interrupt enabled
//function prototypes
void int0_ISR(void);
void initialize_interrupt0(void);
//***************************************************************
:
initialize_interrupt0();
:
//***************************************************************
//function definitions
//***************************************************************
//initialize_interrupt0: initializes interrupt INT0.
//Note: stack is automatically initialized by the compiler
//***************************************************************
void int0_ISR(void)
{
4.4.2 Internal
Interrupt
In this example, we use Timer/Counter0 to provide prescribed delays within our program.
Recall that Timer/Counter0 is an 8-bit timer. It rolls over every time it receives 256 timer clock
‘‘ticks.’’ There is an interrupt associated with the Timer/Counter0 Overflow. If activated, the
interrupt will occur every time the contents of the Timer/Counter0 transitions from 255 back to
0 count. We can use this overflow interrupt as a method of keeping track of real clock time
(hours, minutes, and seconds) within a program. In this specific example, we use the overflow to
provide precision program delays.
In this example, the ATmega16 is being externally clocked by a 10-MHz ceramic resonator.
The resonator frequency is further divided by 256 using the CS[2:1:0] bits in the Timer/Counter
Control Register 0 (TCCR0). When CS[2:1:0] are set for [1:0:0], the incoming clock source is
divided by 256. This provides a clock tick to Timer/Counter0 every 25.6 µs. Therefore, the 8-bit
Timer/Counter0 will rollover every 256 clock ticks, or every 6.55 ms.
To create a precision delay, we write a function called delay. The function requires an
unsigned integer parameter value indicating how many 6.55-ms interrupts the function should
delay. The function stays within a while loop until the desired number of interrupts has occurred.
For example, to delay 1 s, the function would be called with the parameter value ‘‘153.’’ That is, it
requires 153 interrupts occurring at 6.55-ms intervals to generate a 1-s delay.
The code snapshots to configure the Time/Counter0 Overflow interrupt is provided
below along with the associated ISR and the delay function.
//function prototypes********************************************
//delay specified number
//6.55ms
void delay(unsigned int number_of_6_55ms_interrupts);
void init_timer0_ovf_interrupt(void); //initialize timer0
//overflow interrupt
//global variables***********************************************
unsigned int input_delay; //counts number of
//Timer/Counter0
//Overflow interrupts
//main program***************************************************
void main(void)
{
init_timer0_ovf_interrupt(); //initialize Timer/
//Counter0
//Overflow
//interrupt call once at
//beginning of program
:
:
delay(153); //1 second delay
//***************************************************************
//int_timer0_ovf_interrupt(): The Timer/Counter0 Overflow
//interrupt is being employed as a time base for a master
//timer for this project.
//The ceramic resonator operating at 10 MHz is divided by 256.
//The 8-bit Timer0 register (TCNT0) overflows every 256 counts or
//every 6.55 ms.
//***************************************************************
void init_timer0_ovf_interrupt(void)
{
TCCR0 = 0x04; //divide timer0 timebase by 256, overflow occurs
//every 6.55ms
TIMSK = 0x01; //enable timer0 overflow interrupt
asm("SEI"); //enable global interrupt
}
//***************************************************************
//***************************************************************
//timer0_interrupt_isr:
//Note: Timer overflow 0 is cleared by hardware when executing
// the corresponding interrupt handling vector.
//***************************************************************
void timer0_interrupt_isr(void)
{
input_delay++; //increment overflow
//counter
}
//***************************************************************
//delay(unsigned int num_of_6_55ms_interrupts): this generic delay
//function provides the specified delay as the number of 6.55 ms
//"clock ticks" from the Timer/Counter0 Overflow interrupt.
//Note: this function is only valid when using a 10 MHz crystal or
// ceramic resonator
//***************************************************************
} //interrupts
}
//***************************************************************
4.5 SUMMARY
In this chapter, we provided an introduction to the interrupt features available aboard the
ATmega16. We also discussed how to program an interrupt for proper operation and provided
two representative samples: an external and an internal interrupt.
5. Question: What steps are required by the system designer to properly configure an interrupt?
6. Question: How is the interrupt system turned ‘‘on’’ and ‘‘off ’’?
7. Question: A 10-MHz ceramic resonator is not available. Redo the example of the
CH AP T E R 5
Timing Subsystem
5.1 OVERVIEW
One of the most important reasons for using microcontrollers in embedded systems is the
capabilities of microcontrollers to perform time-related tasks. In a simple application, one can
program a microcontroller system to turn on or turn off an external device at a programmed time.
In a more involved application, we can use a microcontroller to generate complex digital
waveforms with varying pulse widths to control the speed of a DC motor [1]. In this chapter,
we review the capabilities of the Atmel ATmega16 [2] microcontroller to perform time-related
functions. We begin with a review of timing-related terminology. We then provide an overview
of the general operation of a timing system followed by the timing system features aboard the
ATmega16. Next, we present a detailed discussion of each of its timing channels, Timer 0, Timer
1, and Timer 2, and their different modes of operation.
7676 ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
TIMING
AND SUBSYSTEM
INTERFACING 7676
5.2 TIMING-RELATED TERMINOLOGY
5.2.1 Frequency
Consider signal x(t ) that repeats itself. We call this signal periodic with period T if it
To measure the frequency of a periodic signal, we count the number of times a particular event
repeats within a 1-s period. The unit of frequency is Hertz, or cycles per second. For example, a
sinusoidal signal with a 60-Hz frequency means that a full cycle of a sinusoid signal repeats itself
60 times each second, or every 16.67
ms.
5.2.2 Period
The flip side of a frequency is a period. If an event occurs with a rate of 1 Hz, the period of that
event is 1 s. To find a period, given a frequency, or vice versa, we simply need to remember their
inverse relationship f = T1 where f and T represent a frequency and the corresponding period,
respectively. Both periods and frequencies of signals are often used to specify timing constraints
of embedded systems [3,4]. For example, when your car is on a wintery road and slipping, the
engineers who designed your car configured the antislippage unit to react within some
millisecond period, say 20 ms. The constraint then forces the design team that monitors the
slippage to program their monitoring system to check a slippage at a rate of 50 Hz.
100 %
(a)
25 %
100 % (b)
FIGURE 5.1: Two signals with the same period but different duty cycles: (a) periodic signal with a
50% duty cycle and (b) periodic signal with a 25% duty
cycle.
timer-related units reference the contents of the free-running counter to perform I/O time-related
activities: measurement of periods, capture of timing events, and generation of time-related
signals.
For input time-related activities, all microcontrollers typically have timer hardware com-
ponents that detect signal logic changes on one or more input pins. Such components rely on a
free-running counter to capture external event times. We can use such ability to measure the
period of an incoming signal, the width of a pulse, and the time of a signal logic change.
For output timer functions, a microcontroller uses a comparator, a free-running counter,
logic switches, and special-purpose registers to generate time-related signals on one or more output
pins. A comparator checks the value of the free-running counter for a match with the contents
of another special-purpose register where a programmer stores a specified time in terms of the
free-running counter value. The checking process is executed at each clock cycle, and when a
match occurs, the corresponding hardware system induces a programmed logic change on a
programmed
Special Storage Comparator Free-Running
Register Counter
Programmed
Event
Timer Output - Toggle
Flag - Logic high
- Logic low
output port pin [5]. Using such capability, one can generate a simple logic change at a designated
time incident, a pulse with a desired time width, or a PWM signal to control servo or DC motors.
You can also use the timer input system to measure the pulse width of an aperiodic
signal. For example, suppose that the times for the rising edge and the falling edge of an
incoming signal are 1.5 and 1.6 s, respectively. We can use these values to easily compute the
pulse width of 0.1 s.
The second overall goal of the timer system is to generate signals to control external
devices. Again, an event simply means a change of logic states on an output pin of a
microcontroller at a specified time. Now consider Figure 5.2. Suppose an external device
connected to the microcontroller requires a pulse signal to turn itself on. Suppose the particular
pulse the external device needs is 2-ms wide. In such situations, we can use the free-running
counter value to synchronize the time of desired logic state changes. Naturally, extending the
same capability, we can also generate a periodic pulse with a fixed duty cycle or a varying duty
cycle.
From the examples we discussed above, you may have wondered how a microcontroller
can be used to compute absolute times from the relative free-running counter values, say 1.5 and
1.6 s. The simple answer is that we cannot do so directly. A programmer must use the relative
system clock values and derive the absolute time values. Suppose your microcontroller is
clocked by a 2-MHz signal, and the system clock uses a 16-bit free-running counter. For such
a system,
16
each clock period represents 0.5 µS, and it takes approximately 32.78 ms to count from 0 to 2
(65,536). The timer input system then uses the clock values to compute frequencies, periods, and
pulse widths. For example, suppose you want to measure a pulse width of an incoming
aperiodic signal. If the rising edge and the falling edge occurred at count values $0010 and
$0114, can you find the pulse width when the free-running counter is counting at 2 MHz? Recall
that the $ symbol represents that the following value is in a hexadecimal form. Let us first convert
the two values into their corresponding decimal values, 276 and 16. The pulse width of the
signal in the number of counter value is 260. Because we already know how long it takes for the
system to count 1, we can readily compute the pulse width as 260 × 0.5 µs = 130 µs.
Our calculations do not take into account time increments lasting longer than the rollover
time of the counter. When a counter rolls over from its maximum value back to 0, a flag is set
to notify the processor of this event. The rollover events may be counted to correctly determine
the overall elapsed time of an event.
5.4 APPLICATIONS
In this section, we consider some important uses of the timer system of a microcontroller to (1)
measure an input signal timing event, termed input capture, (2) count the number of external
signal occurrences, (3) generate timed signals---termed output compare, and, finally, (4) generate
PWM signals. We first start with a case of measuring the time duration of an incoming signal.
Microcontroller
External
Timer Output Port Device
FIGURE 5.3: Use of the timer I/O systems of a microcontroller. The signal on top is fed into a
timer input port. The captured signal is subsequently used to compute the input signal frequency. The
signal on the bottom is generated using the timer output system. The signal is used to control an
external device.
example, we should capture two consecutive rising edges or falling edges of the incoming signal.
Again, the programming portion is done by storing an appropriate setup value to a special
register.
Now that the input timer system is configured appropriately, you now have two options to
accomplish the task. The first one is the use of a polling technique; the microcontroller
continuously polls a flag, which holds a logic high signal when a programmed event occurs on
the physical pin. Once the microcontroller detects the flag, it needs to clear the flag and record
the time when the flag was set using another special register that captures the time of the
associated free-running counter value. The program needs to continue to wait for the next flag,
which indicates the end of one period of the incoming signal. A programmer then needs to record
the newly acquired captured time represented in the form of a free-running counter value again.
The period of the signal can now be computed by computing the time difference between the
two captured event times, and based on the clock speed of the microcontroller, the programmer
can compute the actual time changes and consequently the frequency of the signal.
In many cases, a microcontroller cannot afford the time to poll for one event. Such
situation introduces the second method: interrupt systems. Most microcontroller manufacturers
have developed built-in interrupt systems with their timer input modules. Instead of continuously
polling for a flag, a microcontroller performs other tasks and relies on its interrupt system to
detect the programmed event. The task of computing the period and the frequency is the same
as the first method, except that the microcontroller will not be tied down constantly checking
the flag, increasing the efficient use of the microcontroller resources. To use interrupt systems,
of course, we must pay the price by appropriately configuring the interrupt systems to be
triggered when a
desired event is detected. Typically, additional registers must be configured, and a special
program called an ISR must be written.
Suppose that for an input capture scenario, the two captured times for the two rising edges are
$1000 and $5000, respectively. Note that these values are not absolute times but the
representations of times reflected as the values of the free-running counter. The period of the
signal is $4000, or
16384 in a decimal form. If we assume that the timer clock runs at 10 MHz, the period of the
signal is 1.6384 ms, and the corresponding frequency of the signal is approximately 610.35 Hz.
Time
Pulse Width Modulated Signal
GND "
FIGURE 5.4: The figure shows the speed profile of a DC motor over time when a pulse-width-
modulated signal is applied to the motor.
Each timing channel has the capability to generate PWM signals, generate a periodic
signal with a specific frequency, count events, and generate a precision signal using the output
compare channels. Additionally, Timer 1 is equipped with the Input Capture feature.
All of the timing channels may be configured to operate in one of four operational modes
designated : Normal (Mode 0), Clear Timer on Compare Match (CTC) (Mode 1), Fast PWM
(mode 2), and Phase Correct PWM (mode 3). We provide more information on these modes
shortly.
fclk_I/O 3 bottom
=0
Timer/Counter
Register (TCNT0) = 0xFF
8
8 2 2
WGM0[1:0] COM0[1:0]
Output Compare
Register (OCR0)
also contains the WGM0[1:0] and the COM0[1:0] bits, which are used to select the mode of
operation for Timer 0 as well as tailor waveform generation for a specific application.
The timer clock source (clkTn ) is fed to the 8-bit Timer/Counter Register (TCNT0). This
register is incremented (or decremented) on each clkTn clock pulse. Timer 0 is also equipped
with an 8-bit comparator that constantly compares the counts of TCNT0 to the Output
Compare Register (OCR0). The compare signal from the 8-bit comparator is fed to the waveform
generator. The waveform generator has a number of inputs (top, bottom, WGM0[1:0], and
COM0[1:0]) to perform different operations with the timer system.
The BOTTOM signal for the waveform generation and the control logic, shown in Figure
5.6, is asserted when the timer counter TCNT0 reaches all 0’s (0x00). The MAX signal for
the control logic unit is asserted when the counter reaches all 1’s (0xFF). The TOP signal for
the waveform generation is asserted by either reaching the maximum count values of 0xFF on the
TCNT0 register or reaching the value set in the OCR0. The setting for the TOP signal will be
determined by the timer’s mode of operation.
Timer 0 also uses certain bits within the Timer/Counter Interrupt Mask Register (TIMSK)
and the Timer/Counter Interrupt Flag Register (TIFR) to signal interrupt-related events. Timer 0
shares these registers with the other two timer channels.
TCNT0
TOP OCR0
TCNT0 OCR0 OCR0
BOTTOM OC0 OC0 OC0
OC0
5.6.1.1 Normal Mode. In the normal mode, the timer will continually count from 0x00 (BOT-
TOM) to 0xFF (TOP). When the TCNT0 returns to 0 on each cycle of the counter, the
Timer/Counter Overflow Flag (TOV0) will be set.
The normal mode is useful for generating a periodic ‘‘clock tick’’ that may be used to
calculate elapsed real time or provide delays within a system. We provide an example of this
application in Section 5.9.
5.6.1.2 Clear Timer on Compare Match. In the CTC modem, the TCNT0 timer is reset to
0 every time the TCNT0 counter reaches the value set in OCR0. The Output Compare Flag 0
(OCF0) is set when this event occurs. The OCF0 flag is enabled by asserting the
Timer/Counter
0 Output Compare Math Interrupt Enable (OCIE0) flag in the TIMSK and when the I-bit in the
Status Register is set to 1.
The CTC mode is used to generate a precision digital waveform such as a periodic signal
or a single pulse. The user must describe the parameters and key features of the waveform in
terms of Timer 0 ‘‘clock ticks.’’ When a specific key feature is reached within the waveform, the
next key feature may be set into the OCR0 register.
5.6.1.3 Phase Correct PWM Mode. In the Phase Correct PWM mode, the TCNT0 register
counts from 0x00 to 0xFF and back down to 0x00 continually. Every time the TCNT0 value
matches the value set in the OCR0 register, the OCF0 flag is set and a change in the PWM
signal occurs.
5.6.1.4 Fast PWM. The fast PWM mode is used to generate a precision PWM signal of a
desired frequency and duty cycle. It is called the fast PWM because its maximum frequency is
twice that of the Phase Correct PWM mode. When the TCNT0 register value reaches the
value set in the OCR0 register, it will cause a change in the PWM output as prescribed by the
system designer. It continues to count up to the TOP value, at which time the Timer/Counter
0 Overflow Flag (TOV0) is set.
7 0
Output Compare Register (OCR0)
7 0
Timer/Counter Interrupt Mask Register (TIMSK)
OCIE2
7 0
Timer/Counter Interrupt Flag REgister (TIFR)
OCF2
7 0
5.6.2.1 Timer/Counter Control Register 0. The TCCR0 register bits are used to
• select the operational mode of Timer 0 using the Waveform Mode Generation
(WGM0[1:0]) bits,
• determine the operation of the timer within a specific mode with the Compare Match
Output Mode (COM0[1:0]) bits, and
• select the source of the Timer 0 clock using CS0[2:0] bits.
The bit settings for the TCCR0 register are summarized in Figure 5.9.
5.6.2.2 Timer/Counter Register. The TCNT0 is the 8-bit counter for Timer 0.
5.6.2.3 Output Compare Register. The OCR0 register holds a user-defined 8-bit value that is
continuously compared with the TCNT0 register.
CS0[2:0]
000
001
010
011
100
101
110
111
Normal, CTC
Mode
COM0[1:0]
Fast PWM
COM0[1:0]
5.7 TIMER 1
Timer 1 is a 16-bit timer/counter. It shares many of the same features of the Timer 0 channel.
Because of limited space, the shared information will not be repeated. Instead, we concentrate on
the enhancements of Timer 1, which include an additional output compare channel and also the
capability for input capture. The block diagram for Timer 1 is shown in Figure 5.10.
As discussed earlier in the chapter, the input capture feature is used to capture the
characteristics of an input signal, including period, frequency, duty cycle, or pulse length. This is
accomplished by monitoring for a user-specified edge on the ICP1 microcontroller pin. When
the desired edge occurs, the value of the Timer/Counter 1 (TCNT1) register is captured and
stored in the Input Capture Register 1 (ICR1).
5.7.1.1 TCCR1A and TCCR1B Registers. The TCCR1 register bits are used
to
• select the operational mode of Timer 1 using the Waveform Mode Generation
(WGM1[3:0]) bits,
• determine the operation of the timer within a specific mode with the Compare Match
Output Mode (Channel A, COM1A[1:0]; Channel B, COM1B[1:0]) bits, and
• select the source of the Timer 1 clock using CS1[2:0] bits.
The bit settings for the TCCR1A and TCCR1B registers are summarized in
Figure 5.12.
7 0
Timer/Counter 1 Control Register B (TCCR1B)
ICNC1
7 0
Timer Counter1 (TCNT1H/TCNT1L)
15
7
Clock Select
Timer/Counter 1 Control Register B (TCCR1B)
ICNC1 ICES1
7 0
Timer/Counter 1 Control Register A (TCCR1A)
COM1A1 COM1A0
7 0
Waveform Generation Mode Normal, CTC
Mode
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1110 when up-counting. Set OC0
Fast PWM
15 1111 on compare match when
Fast PWM
11 down counting
Set OC0 on compare match
when up-counting. Clear OC0
on compare match when
down counting.
Fast PWM
COMx[1:0]
00 Description
01 Normal, OC1A/1B disconnected
WGM1[3:0] = 15, toggle OC1A on
compare match OC1B disconnected
WGM1[3:0] = other settings,
10 OC1A/1B disconnected
Clear OC1A/1B on compare match,
11 set OC1A/1B at TOP
Set OC1A/1B on compare match,
clear OC1A/1B at TOP
5.7.1.4 Output Compare Register 1 Channel B (OCR1BH/ OCR1BL). The OCR1B register
holds a user-defined 16-bit value that is continuously compared with the TCNT1 register when
Channel B is used.
5.7.1.5 Input Capture Register 1 (ICR1H/ICR1L). ICR1 is a 16-bit register used to capture
the value of the TCNT1 register when a desired edge on ICP1 pin has occurred.
5.7.1.6 Timer/Counter Interrupt Mask Register (TIMSK). The TIMSK register is used by
all three timer channels. Timer 1 uses the OCIE1A/1B bits, the Timer/Counter 1 Overflow
Interrupt Enable (TOIE1) bit, and the Timer/Counter 1 Input Capture Interrupt Enable
(TIC1E1) bit. When the OCIE1A/B bit and the I-bit in the Status Register are both set to 1, the
Timer/Counter
1 Compare Match interrupt is enabled. When the TOIE1 bit and the I-bit in the Status Register
are both set to 1, the Timer/Counter 1 Overflow interrupt is enabled. When the TIC1E1 bit and
the I-bit in the Status Register are both set to 1, the Timer/Counter 1 Input Capture interrupt is
enabled.
5.7.1.7 Timer/Counter Interrupt Flag Register (TIFR). The TIMSK register is used by all
three timer channels. Timer 1 uses the OCF1A/B, which sets for an output compare A/B match.
Timer 1 also uses the Timer/Counter 1 Overflow Flag (TOV1), which sets when Timer/Counter
1 overflows. Timer Channel 1 also uses the Timer/Counter 1 Input Capture Flag (ICF1), which
sets for an input capture event.
5.8 TIMER 2
Timer 2 is another 8-bit timer channel similar to Timer 0. The Timer 2 channel block diagram is
provided in Figure 5.13. Its registers are summarized in Figure 5.14.
• select the operational mode of Timer 2 using the Waveform Mode Generation
(WGM2[1:0]) bits,
FIGURE 5.13: Timer 2 block diagram. Figure used with permission of Atmel.
• determine the operation of the timer within a specific mode with the Compare Match
Output Mode (COM2[1:0]) bits, and
• select the source of the Timer 2 clock using CS2[2:0] bits.
The bit settings for the TCCR2 register are summarized in Figure 5.15.
7 0
Output Compare Register (OCR2)
7 0
Timer/Counter Interrupt Mask Register (TIMSK)
OCIE2
7 0
Timer/Counter Interrupt Flag REgister (TIFR)
OCF2
7 0
Normal, CTC
Mode
COM2[1:0]
Fast PWM
COM2[1:0]
//Function prototypes
void delay(unsigned int number_of_6_55ms_interrupts);
void init_timer0_ovf_interrupt(void);
void timer0_interrupt_isr(void);
//interrupt handler
//definition
#pragma interrupt_handler timer0_interrupt_isr:10
//door profile data
//****************************************************************
//int_timer0_ovf_interrupt(): The Timer0 overflow interrupt is
//being employed as a time base for a master timer for this
//project. The ceramic resonator operating at 10 MHz is divided
//by 256. The 8-bit Timer0 register (TCNT0) overflows every 256
//counts or every 6.55 ms.
//****************************************************************
void init_timer0_ovf_interrupt(void)
{
TCCR0 = 0x04; //divide timer0 timebase by 256, overflow occurs
//every 6.55ms
TIMSK = 0x01; //enable timer0 overflow interrupt
asm("SEI"); //enable global interrupt
}
//****************************************************************
//****************************************************************
//timer0_interrupt_isr:
//Note: Timer overflow 0 is cleared by hardware when executing the
//corresponding interrupt handling vector.
//****************************************************************
void timer0_interrupt_isr(void)
{
input_delay++; //input delay processing
}
//****************************************************************
//****************************************************************
//delay(unsigned int num_of_6_55ms_interrupts): this generic delay
//function provides the specified delay as the number
//of 6.55 ms "clock ticks" from the Timer0 interrupt.
//Note: this function is only valid when using a 10 MHz crystal or
// ceramic resonator
//****************************************************************
//****************************************************************
//Function Prototypes
void PWM(unsigned int PWM_incr)
100100100ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
TIMING SUBSYSTEM
AND 100
INTERFACING
{
unsigned int Open_Speed_int;
float Open_Speed_float;
int gate_position_int;
PWM_duty_cycle = 0;
InitADC(); //Initialize ADC
//Read "Open Speed" volt
//setting PA3
Open_Speed_int = ReadADC(0x03); //Open Speed Setting
//unsigned int
//Convert to max duty
//cycle setting 0 VDC =
//50% = 127, 5 VDC =
//100% = 255
Open_Speed_float = ((float)(Open_Speed_int)/(float)(0x0400));
//convert volt to
//PWM constant 127-255
Open_Speed_int = (unsigned int)((Open_Speed_float * 127) + 128.0);
//Configure PWM clock
TCCR1A = 0xA1; //freq = resonator/510
// = 10 MHz/510
//freq = 19.607 kHz
TCCR1B = 0x01; //no clock source
//division
//Initiate PWM duty cycle
//variables
PWM_duty_cycle = 0;
OCR1BH = 0x00;
OCR1BL = (unsigned char)(PWM_duty_cycle);//set PWM duty cycle CH
//B to 0%
//Ramp up to Open Speed
//in 1.6s
OCR1BL = (unsigned char)(PWM_duty_cycle);//set PWM duty cycle CH
//B
while (PWM_duty_cycle < Open_Speed_int)
{
if(PWM_duty_cycle < Open_Speed_int) //increment duty cycle
PWM_duty_cycle=PWM_duty_cycle + PWM_open_incr;
//****************************************************************
//****************************************************************
//initialize_ICP_interrupt: Initialize Timer/Counter 1
//for input capture
//****************************************************************
void initialize_ICP_interrupt(void)
{
TIMSK=0x20; //Allows input capture
//interrupts
SFIOR=0x04; //Internal pull-ups disabled
TCCR1A=0x00; //No output comp or waveform
//generation mode
TCCR1B=0x45; //Capture on rising edge,
//clock prescalar=1024
TCNT1H=0x00; //Initially clear timer/
//counter 1
TCNT1L=0x00;
asm("SEI"); //enable global interrupts
}
//****************************************************************
void Input_Capture_ISR(void)
{
if(first_edge==0)
{
ICR1L=0x00; //clear ICR1 and TCNT1
//on first edge
ICR1H=0x00;
TCNT1L=0x00;
TCNT1H=0x00;
first_edge=1;
}
else
{
ICR1L=TCNT1L; //capture time from TCNT1
ICR1H=TCNT1H;
TCNT1L=0x00;
TCNT1H=0x00;
first_edge=0;
}
5.10 SUMMARY
In this chapter, we considered a microcontroller timer system, associated terminology for timer-
related topics, discussed typical functions of a timer subsystem, studied timer hardware operations,
and considered some applications where the timer subsystem of a microcontroller can be used.
We then took a detailed look at the timer subsystem aboard the ATmega16 and reviewed the
features, operation, registers, and programming of the three timer channels.
5. Question: Program the output compare system of the ATmega16 to generate a 1-kHz
signal with a 10% duty cycle.
6. Question: Design a microcontroller system to control a sprinkler controller that performs
the following tasks. We assume that your microcontroller runs with a 10-MHz clock and
it has a 16-bit free-running counter. The sprinkler controller system controls two different
zones by turning sprinklers within each zone on and off. To turn on the sprinklers of a
zone, the controller needs to receive a 152.589-Hz PWM signal from your
microcontroller. To turn off the sprinklers of the same zone, the controller needs to receive
the PWM signal with a different duty cycle.
a. Your microcontroller needs to provide the PWM signal with 10% duty cycle for 10 ms
to turn on the sprinklers in zone 1.
b. After 15 min, your microcontroller must send the PWM signal with 15% duty cycle
for
10 ms to turn off the sprinklers in zone 1.
c. After 15 min, your microcontroller must send the PWM signal with 20% duty cycle
for
10 ms to turn on the sprinklers in zone 2.
d. After 15 min, your microcontroller must send the PWM signal with 25% duty cycle
for
10 ms to turn off the sprinklers in zone 2.
• • • •
105
CHAPTER 6
• describe the voltage and current parameters for the Atmel AVR HC CMOS-type
microcontroller,
• apply the voltage and current parameters toward properly interfacing I/O devices to the
Atmel AVR microcontroller,
• interface a wide variety of I/O devices to the Atmel AVR microcontroller,
• describe the special concerns that must be followed when the Atmel AVR microcontroller
is used to interface to a high-power DC or AC device,
• discuss the requirement for an optical-based interface,
• describe how to control the speed and direction of a DC motor, and
• describe how to control several types of AC loads.
Our first textbook for M&C, Microcontrollers Fundamentals for Engineers and Scientists,
contained a chapter entitled ‘‘Operating Parameters and Interfacing’’ [1]. With M&C’s permission,
we have repeated this chapter here for your convenience. However, we have personalized the
information provided to the Atmel AVR line of microcontrollers. We have also expanded the
coverage of the chapter to include interface techniques for a number of additional I/O devices.
In this chapter, we introduce you to the extremely important concepts of the operating
envelope for a microcontroller. We begin by reviewing the voltage and current electrical
parameters for the HC CMOS-based Atmel AVR line of microcontrollers. We then show
how to apply this information to properly interface I/O devices to the ATmega16
microcontroller. We then discuss the special considerations for controlling a high-power DC or
AC load such as a motor and introduce the concept of an optical interface. Throughout the
chapter, we provide a number of detailed examples.
106106106ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING
PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
INTERFACING 106106106
6.1 OPERATING PARAMETERS
The microcontroller is an electronic device that has precisely defined operating conditions. As
long as the microcontroller is used within its defined operating parameter limits, it should
continue to operate correctly. However, if the allowable conditions are violated, spurious results
may result.
Any time a device is connected to a microcontroller, careful interface analysis must be
performed. Most microcontrollers are members of the ‘‘HC,’’ or high-speed CMOS family of
chips. As long as all components in a system are also of the ‘‘HC’’ family, as is the case for the
Atmel AVR line of microcontrollers, electrical interface issues are minimal. If the microcontroller
is connected to some component not in the HC family, electrical interface analysis must be
completed. Manufacturers readily provide the electrical characteristic data necessary to complete
this analysis in their support documentation.
To perform the interface analysis, there are eight different electrical specifications required
for electrical interface analysis. The electrical parameters are
• VOH : the lowest guaranteed output voltage for a logic high,
• VOH : the highest guaranteed output voltage for a logic low,
• IOH : the output current for a VOH logic high,
• IOH : the output current for a VOH logic low,
• VIH : the lowest input voltage guaranteed to be recognized as a logic high,
• VIL : the highest input voltage guaranteed to be recognized as a logic low,
• IIH : the input current for a VIH logic high, and
• IIL : the input current for a VIL logic low.
These electrical characteristics are required for both the microcontroller and the
external components. Typical values for a microcontroller in the HC CMOS family assuming
VDD = 5.0
V and VSS = 0 V are provided below. The minus sign on several of the currents indicates a
current
flow out of the device. A positive current indicates current flow into the
device.
• VOH = 4.2 V,
• VOL = 0.4 V,
• IOH = −0.8 mA,
• IOL = 1.6 mA,
• VIH = 3.5 V,
• VIL = 1.0 V,
• IIH = 10 µA, and
• IIL = −10 µA.
107107107 ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
It is important to107107107
INTERFACING realize that these are static values taken under very specific operating
conditions. If external circuitry is connected such that the microcontroller acts as a current
source
(current leaving microcontroller) or current sink (current entering microcontroller), the voltage
parameters listed above will also be affected.
In the current source case, an output voltage VOH is provided at the output pin of the
microcontroller when the load connected to this pin draws a current of IOH . If a load draws
more current from the output pin than the IOH specification, the value of VOH is reduced. If
the load current becomes too high, the value of VOH falls below the value of VIH for the
subsequent logic circuit stage and not be recognized as an acceptable logic high signal. When
this situation occurs, erratic and unpredictable circuit behavior results.
In the sink case, an output voltage VOL is provided at the output pin of the microcontroller
when the load connected to this pin delivers a current of IOL to this logic pin. If a load delivers
more current to the output pin of the microcontroller than the IOL specification, the value of VOL
increases. If the load current becomes too high, the value of VOL rises above the value of VIL for
the subsequent logic circuit stage and not be recognized as an acceptable logic low signal. As
before, when this situation occurs, erratic and unpredictable circuit behavior results.
For convenience, this information is illustrated in Figure 6.1. In Figure 6.1(a), we have
provided an illustration of the direction of current flow from the HC device and a comparison
of voltage levels. As a reminder, current flowing out of a device is considered a negative current
(source case), whereas current flowing into the device is considered positive current (sink
case). The magnitude of the voltage and current for HC CMOS devices are shown in Figure
6.1(b). As more current is sunk or sourced from a microcontroller pin, the voltage will be
pulled up or pulled down, respectively, as shown in Figure 6.1(c). If I/O devices are improperly
interfaced to the microcontroller, these loading conditions may become excessive, and voltages
will not be properly interpreted as the correct logic levels.
You must also ensure that total current limits for an entire microcontroller port and
overall bulk port specifications are complied with. For planning purposes, the sum of current
sourced or sunk from a port should not exceed 100 mA. Furthermore, the sum of currents for all
ports should not exceed 200 mA. As before, if these guidelines are not complied with, erratic
microcontroller behavior may result.
The procedures presented in the following sections when followed carefully will ensure the
microcontroller will operate within its designed envelope. The remainder of the chapter is
divided into input device interface analysis followed by output device interface analysis.
**
*% #*
#%
# $ ' #" # $ ' #"
+# ! ! !
% ) * )
#*& $ . #
#%& $ #
#* $ ' #
#% $ ' #
**& $ ' µ
*%& $ , '
** $ , ' µ
*% $ -
/+ & % !
0 , !
1 2
1 2
*
*
' '
' # 1#2 # 1#2 '
!+ % !
FIGURE 6.1: Electrical voltage and current parameters: (a) voltage and current electrical
parameters, (b) HC CMOS voltage and current parameters, and (c) CMOS loading curves.
6.2.1 Switches
Switches come in a variety of types. As a system designer, it is up to you to choose the
appropriate switch for a specific application. Switch varieties commonly used in microcontroller
applications are illustrated in Figure 6.2(a). Here is a brief summary of the different types:
• Slide switch: A slide switch has two different positions: on and off. The switch is
manually moved to one position or the other. For microcontroller applications, slide
switches are
"*) 6 !4 5 ! 6 !4 ) 6 !4 & 9 !
: 6 !4
+ 6 !4
#""
304
5 ! !
, ! 64 6 !4
, ! 64 6 !4 !
/+ 6 !4 7 !
#""
30 4 3 &
3' 0 4
' µ8
FIGURE 6.2: Switch interface: (a) switch varieties, (b) switch interface, and (c) switch interface
equipped with debouncing circuitry.
110110110ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING
PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
INTERFACING 110110110
available that fit in the profile of a common integrated circuit size DIP. A bank of four
or eight DIP switches in a single package is commonly available.
• Momentary contact push-button switch: A momentary contact push-button switch
comes in two varieties: normally closed (NC) and normally open (NO). A NO switch,
as its name implies, does not normally provide an electrical connection between its
contacts. When the push-button portion of the switch is depressed the connection
between the two switch contacts is made. The connection is held as long as the switch is
depressed. When the switch is released, the connection is opened. The converse is true
for an NC switch. For microcontroller applications, push-button switches are available
in a small tact type switch configuration.
• Push on/push off switches: These type of switches are also available in an NO or NC
configuration. For the NO configuration, the switch is depressed to make connection
between the two switch contacts. The push button must be depressed again to release the
connection.
• Hexadecimal rotary switches: Small profile rotary switches are available for
microcontroller applications. These switches commonly have 16 rotary switch positions.
As the switch is rotated to each position a unique 4-bit binary code is provided at the
switch contacts.
A common switch interface is shown in Figure 6.2(b). This interface allows a logic 1 or 0
to be properly introduced to a microcontroller input port pin. The basic interface consists of the
switch in series with a current limiting resistor. The node between the switch and the resistor is
provided to the microcontroller input pin. In the configuration shown, the resistor pulls the
microcontroller input up to the supply voltage VDD . When the switch is closed, the node is
grounded, and a logic 0 is provided to the microcontroller input pin. To reverse the logic of the
switch configuration, the position of the resistor and the switch is simply reversed.
6.2.3 Keypads
A keypad is simply an extension of the simple switch configuration. A typical keypad
configuration and interface are shown in Figure 6.3. As you can see, the keypad is simply multiple
switches in the same package. A hexadecimal keypad is provided in the figure. A single row of
keypad switches is asserted by the microcontroller, and then the host keypad port is immediately
read. If a switch has been depressed, the keypad pin corresponding to the column the switch is in
will also be asserted. The combination of a row and a column assertion can be decoded to
determine which key has been pressed as illustrated in the table. Keypad rows are continually
asserted one after the other in sequence. Because the keypad is a collection of switches,
debounce techniques must also be employed.
The keypad may be used to introduce user requests to a microcontroller. A standard
keypad with alphanumeric characters may be used to provide alphanumeric values to the
microcontroller such as providing your personal identification number (PIN) for a financial
transaction. However, some keypads are equipped with removable switch covers such that any
activity can be associated with a key press.
6.2.4 Sensors
A microcontroller is typically used in control applications where data are collected, assimilated,
and processed by the host algorithm and a control decision and accompanying signals are
provided by the microcontroller. Input data for the microcontroller are collected by a
complement of input sensors. These sensors may be digital or analog in nature.
6.2.4.1 Digital Sensors. Digital sensors provide a series of digital logic pulses with sensor data
encoded. The sensor data may be encoded in any of the parameters associated with the digital
pulse
0 1 2 3 assert
0 keypad row 0
PORTx[0]
4 5 6 7 assert
1 keypad row 1
PORTx[1]
8 9 A B assert
2 keypad row 2
PORTx[2]
C D E F assert
3 keypad row 3
Microcontroller PORTx
Vcc PORTx[3]
10K
4 5 6 7
stationary optical
source and detector
rotating pair
disk D
Detector output
Ch A
Ch B
FIGURE 6.4: Optical encoder: (a) incremental tachometer encoder and (b) incremental quadrature
encoder.
used to monitor the gate position. An incremental encoder is used in applications where a
velocity or a velocity and direction information is required.
The incremental encoder types may be further subdivided into tachometers and quadrature
encoders. An incremental tachometer encoder consists of a single track of etched opaque lines as
shown in Figure 6.4(a). It is used when the velocity of a rotating device is required. To calculate
velocity, the number of detector pulses is counted in a fixed amount of time. Because the number
of pulses per encoder revolution is known, velocity may be calculated.
The quadrature encoder contains two tracks shifted in relationship to one another by 90◦ .
This allows the calculation of both velocity and direction. To determine direction one would
monitor the phase relationship between Channel A and Channel B as shown in Figure 6.4(b).
The absolute encoder is equipped with multiple data tracks to determine the precise location
of the encoder disk (SICK Stegmann [2]).
6.2.4.2 Analog Sensors. Analog sensors provide a DC voltage that is proportional to the
physical parameter being measured. As discussed in the ADC chapter, the analog signal
may be first preprocessed by external analog hardware such that it falls within the voltage
references of the conversion subsystem. The analog voltage is then converted to a corresponding
binary representation.
An example of an analog sensor is the flex sensor shown in Figure 6.5(a). The flex
sensor provides a change in resistance for a change in sensor flexure. At 0◦ flex, the sensor
provides 10 kΩ of resistance. For 90◦ flex, the sensor provides 30--40 kΩ of resistance. Because
the microcontroller cannot measure resistance directly, the change in flex sensor resistance
must be converted to a change in a DC voltage. This is accomplished using the voltage divider
network shown in Figure
6.5(c). For increased flex, the DC voltage will increase. The voltage can be measured using the
ATmega16’s ADC subsystem.
The flex sensor may be used in applications such as virtual reality data gloves, robotic
sensors, biometric sensors, and in science and engineering experiments (Images Company [3]).
One of the coauthors used the circuit provided in Figure 6.5 to help a colleague in zoology
monitor the movement of a newt salamander during a scientific experiment.
VDD = 5 VDC
10K fixed
resistor
flex sensor:
-- 0 degree flex, 10K
-- 90 degree flex, 30-40K
b) flex action
c) equivalent circuit
FIGURE 6.5: Flex sensor: (a) flex sensor’s physical dimensions, (b) flex action, and (c) equivalent
circuit.
I R R2
+ +
from I
from
7404 micro
micro
R1
a) interface to an LED
DIP common cathode
VOH: 2.0 VDC resistor 7-segment display
(Vf 1.85 VDC @ If 12mA)
IOH : 15 mA
a
a
microcontroller port
b
f b
c 74LS244
d octal buffer/
e g
line driver
f
g e c
R = (VOH - Vf) / If d
common
R = (2.0 - 1.85)/ 12 mA
cathode
R = 12.5 ohms
a a a a
f b b f b
g g
e c e c e c e
d d d d
MPQ2222
segment
select
FIGURE 6.6: LED display devices: (a) interface to an LED, (b) seven-segment display interface, and
(c) quad seven-segment display interface.
value can be calculated using R = (VDD − VDIODE )/IDIODE . It is important to note that a
7404 inverter must be used because its capability to safely sink 16 mA of current. Alternately, an
NPN transistor such as a 2N2222 (PN2222 or MPQ2222) may be used in place of the inverter as
shown in the figure.
47 G
R
microcontroller port
47 G
47 G
47 G
47 G
47 G
47 G
VDD
VDD -
+ 2N2222
3.0 K
3.0 K LM324 2N2907
column
C1 circuitry
C0
microcontroller
R6
R5
row select
R4
interface
R3
R2
R1
R0
5 x 7 dot
matrix display
a) dot matrix display layout
74HC137
column
C2:C1:C0
3 1:8 decoder
R6
5 VDC
row select
R0
5 VDC
FIGURE 6.8: Dot matrix display: (a) dot matrix display and (b) dot matrix interface details.
120120120ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING AND
INTERFACING
6.3.4 Dot Matrix Display
The dot matrix display consists of a large number of LEDs configured in a single package. A
typical
5 × 7 LED arrangement is a matrix of five columns of LEDs with seven LEDs per row as
shown in Figure 6.8. Display data for a single matrix column [R6-R0] is provided by the
microcontroller. That specific row is then asserted by the microcontroller using the column
select lines (C2--C0). The entire display is sequentially built up a column at a time. If the
microcontroller sequences through each column fast enough (greater than 30 Hz), the matrix
display appears to be stationary to a human viewer.
In Figure 6.8(a), we have provided the basic configuration for the dot matrix display for
a single-display device. However, this basic idea can be expanded in both dimensions to provide
a multicharacter, multiline display. A larger display does not require a significant number of
microcontroller pins for the interface. The dot matrix display may be used to display
alphanumeric data as well as graphics data. In Figure 6.8(b), we have provided additional detail
of the interface circuit.
Vcc
10K
GND-1
VDD-2
line1
AND671GST
PORTB
4-(AIN1) PB3 PA3 (ADC3)-37
M
h 5-(SS) PB4 PA4 (ADC4)-36 47 G E
eq 4.7K 6-(MOSI) PB5 PA5 (ADC5)-35 L
ui VDD 1M 7-(MISO) PB6 PA6 (ADC6)-34 R
A
1.0 uF 8-(SCK) PB7 PA7 (ADC7)-33
pp SW7 470K sys reset 9-RESET
AREF-32 47 G V
ed 0.1 uF 10-Vcc AGND-31
VDD
R
R
wi 11-GND AVCC-30 O
PORTD PORTC
12-XTAL2 PC7 (TOSC2)-29
th 13-XTAL1 PC6 (TOSC1)-28 47 G P
an 14-(RXD) PD0 PC5-27 R E
L 15-(TXD) PD1
16-(INT0) PD2
PC4-26 R
PC3-25
C 17-(INT1) PD3 PC2-24 47 G A
18-(OC1B) PD4 PC1-23 TI
19-(OC1A) PD5 PC0-22 8 N
20-(ICP) PD6 PD7 (OC2)-21
ZTT 10MHz G
R
command/data P
Vcc A
data
10K R
8 3.0 K
A
- 2N2222
M
GND-1
+
LM324 E
VDD-2
2N2907
T
line1 line2 E
AND671GST
R
S
A
N
D
12
1
122122122ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING
PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
INTERFACING 122122122
an 8-bit data path and two lines are required between the microcontroller and the LCD. A small
microcontroller mounted to the back panel of the LCD translates the ASCII data characters and
control signals to properly display the characters. LCDs are configured for either parallel or
serial data transmission format. In the example provided, we use a parallel-configured display. In
Figure
6.10, we have included the LCD in the Testbench hardware
configuration.
Some sample C code is provided below to send data and control signals to an LCD.
In this specific example, an AND671GST 1 × 16 character LCD was connected to the Atmel
ATmega16 microcontroller [4]. One 8-bit port and two extra control lines are required to
connect the microcontroller to the LCD. Note: The initialization sequence for the LCD is
specified within the manufacturer’s technical data.
//***************************************************************
//LCD_Init: initialization for an LCD connected in the following
//manner:
//LCD: AND671GST 1x16 character display
//LCD configured as two 8 character lines in a 1x16 array
//LCD data bus (pin 14-pin7) ATMEL ATmega16: PORTC
//LCD RS (pin 4) ATMEL ATmega16: PORTD[7]
//LCD E (pin 6) ATMEL ATmega16: PORTD[6]
//***************************************************************
void LCD_Init(void)
{ delay_5ms(
);
delay_5ms();
delay_5ms();
// output command string to
// initialize LCD
putcommand(0x38); //function set 8-bit
delay_5ms();
putcommand(0x38); //function set 8-bit
putcommand(0x38); //function set 8-bit
putcommand(0x38); //one line, 5x7 char
putcommand(0x0C); //display on
putcommand(0x01); //display clear-1.64 ms
putcommand(0x06); //entry mode set
putcommand(0x00); //clear display, cursor at home
putcommand(0x00); //clear display, cursor at home
}
//***************************************************************
//putchar:prints specified ASCII character to LCD
//***************************************************************
//***************************************************************
//performs specified LCD related command
//***************************************************************
//***************************************************************
6.3.6 High-Power DC Devices
A number of direct current devices may be controlled with an electronic switching device such as
a MOSFET. Specifically, an N-channel enhancement MOSFET (metal oxide semiconductor
field effect transistor) may be used to switch a high-current load on and off (such as a motor)
using a low-current control signal from a microcontroller as shown in Figure 6.11(a). The low-
current control signal from the microcontroller is connected to the gate of the MOSFET. The
MOSFET switches the high-current load on and off consistent with the control signal. The high-
current load is connected between the load supply and the MOSFET drain. It is important to
note that the load supply voltage and the microcontroller supply voltage do not have to be at
the same value. When the control signal on the MOSFET gate is logic high, the load current
flows from drain to source. When the control signal applied to the gate is logic low, no load
current flows. Thus, the high-power load is turned on and off by the low-power control signal
from the microcontroller.
Often the MOSFET is used to control a high-power motor load. A motor is a notorious
source of noise. To isolate the microcontroller from the motor noise, an optical isolator may be
used as an interface as shown in Figure 6.11(b). The link between the control signal from the
microcontroller to the high-power load is via an optical link contained within an SSR. The SSR
is properly biased using techniques previously discussed.
VDD
load
Drain Iload
Gate
from
micro Source
FIGURE 6.11: MOSFET circuits: (a) N-channel enhance MOSFET and (b) solid-state relay (SSR)
with optical interface.
6.4 DC MOTOR SPEED AND DIRECTION CONTROL
Often, a microcontroller is used to control a high-power motor load. To properly interface the
motor to the microcontroller, we must be familiar with the different types of motor
technologies. Motor types are illustrated in Figure 6.12.
• DC motor: A DC motor has a positive and negative terminal. When a DC power supply
of suitable current rating is applied to the motor, it will rotate. If the polarity of the
supply is switched with reference to the motor terminals, the motor will rotate in the
opposite direction. The speed of the motor is roughly proportional to the applied voltage
up to the
rated voltage of the motor.
#
;
# 77
# 77 $ # 9 : !:! 1<2 ,
+ "
,
/+
! 7 !
! ! :
6
!+
FIGURE 6.12: Motor types: (a) DC, (b) servo, and (c) stepper.
• Servo motor: A servo motor provides a precision angular rotation for an applied
PWM duty cycle. As the duty cycle of the applied signal is varied, the angular
displacement of the motor also varies. This type of motor is used to change mechanical
positions such as the steering angle of a wheel.
• Stepper motor: A stepper motor, as its name implies, provides an incremental step
change in rotation (typically 2.5◦ per step) for a step change in control signal sequence.
The motor is typically controlled by a two- or four-wire interface. For the four-wire
stepper motor, the microcontroller provides a 4-bit control sequence to rotate the
motor clockwise. To turn the motor counterclockwise, the control sequence is reversed.
The low-power control signals are interfaced to the motor via MOSFETs or power
transistors to provide for the proper voltage and current requirements of the pulse
sequence.
6.4.2 AC Devices
In a similar manner, a high-power AC load may be switched on and off using a low-power
control signal from the microcontroller. In this case, an SSR is used as the switching device.
SSRs are available to switch a high-power DC or AC load (Crydom) [7]. For example, the
Crydom 558-CX240D5R is a printed circuit board mounted, air-cooled, single-pole, single-throw
(SPST), NO SSR. It requires a DC control voltage of 3--15 VDC at 15 mA. However, this
small
DC motor
supply voltage
VDD M protection
diode
I R
D
MOSFET
ILOAD
G
S
7404 RG
from Solid State Relay
micro
Joystick
Status Panel
(PB5) (PB6)
(PB3) (PB4)
(PB2)
(PB1)
MAIN
Trip PWR CB
Duration (PB0)
AUX
SYS O2 FUEL CB
Reset CB
DB2-9
DB3-10
Vcc = 5 VDC
cuit Breaker
line1 trip duration pot
Vcc Vcc
E-6
RS-4
VDD-2
GND-1
DB1-8
DB0-7
LED A-15
LED K-16
DB7-14
DB6-13
DB5-12
DB4-11
R/W-5
Vo-3
data E
5V
Vcc
3850 Hz buzzer
LED6 piezo buzzer DB5
O2
Cir
AUX
13
0
FI A
G T
U M
R initialize_timer E
E L
6. initialize_ports A
16 V
: initialize_ADC R
So M
ft initialize_LCD
IC
wa R
re TRIP TIME 0-60m
SET MAIN PWR CB O
flo C
w main pwr O
no
for N
set?
the yes T
fli read_ADC R
gh O
t calculate_trip_inc (25...)
L
si perform_countdown L
m LED_blastoff_seq E
ula R
tor delay(3s) P
pa RI
nel SYSTEMS A-OK
M
E
while(1) R:
flt25_actions no
actions_complete? yes
P
flash_LED_panel ***LOW O2*** SYS A-OK reset_alarm restore_panel
sound_alarm R
25% trip time? RESET O2 CB
O
no flt50_actions G
R
50% trip time? sound_alarm
***LOW FUEL***
actions_complete?
yes
SYS A-OK reset_alarm restore_panel A
flash_LED_panel
ASSERT AUX FUEL M
no
flt75_actions M
ENGINE OVERHEAT yes IN
75% trip time? sound_alarm flash_LED_panel actions_complete? SYS A-OK reset_alarm restore_panel
POWER DOWN 30S G
no flt100_actions A
no FUEL EXPENDED LED_power_down_seq N
100% trip time? sound_alarm flash_LED_panel
MISSION ABORT
131131131ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING
PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
INTERFACING 131131131
alert students to changing status. There is also a complement of other status indicators. From
left to right is the Trip Duration potentiometer. At the beginning of the flight episode, students
are prompted to set this from 0 to 60 min to communicate to the microcontroller the length of
the flight episode. These data are used to calculate different flight increments. There are also a
series of simulated circuit breakers: system reset (SYS Reset), oxygen (O2 CB), auxiliary fuel
(AUX FUEL CB), and the main power circuit breakers (MAIN PWR CB). These are not actual
circuit breakers but NO SPST momentary push-button switches that allow the students to
interact with the microcontroller. There are also a series of LEDs that form a Y pattern on the
panel face. They are also used to indicate status changes.
To interface the flight simulator panel to the microcontroller, a number of different
techniques previously discussed in the book were employed. The interface diagram is shown in
Figure 6.15. Pin 1 is a reset for the microcontroller. When the switch is depressed, pin 1 is taken
low and resets the microcontroller. Port D of the microcontroller (pins 2--6, 11--13) forms the
data connection for the LCD. Pin 9 is used to turn the buzzer on and off. This pin is routed
through a transistor interface described earlier in the text. Port B[5:0] (pins 14--19) are used to
control the LEDs on the front panel. Each individual LED is also supported with a transistor
interface circuit. Conveniently, these small NPN signal transistors come in fours to a 14-pin DIP
package (MPQ2222). Port C [0] (pin 23) is used as an analog input pin. It is connected to the
trip duration potentiometer. Port C pins [3:1] (pins 24--26) are used to connect the NO SPST
tact switches to the microcontroller. Port C pins [4:5] (pins 27 and 28) are used for the LCD
control signals.
The software flowchart is shown in Figure 6.16. After startup the students are prompted
via the LCD display to set the trip duration and then press the main power circuit breaker.
This potentiometer setting is then used to calculate four different trip increments. Countdown
followed by blastoff then commences. At four different trip time increments, students are
presented with status that they must respond to. Real clock time is kept using the TCNT0
timer overflow configured as a 65.5 ms ‘‘clock tick.’’ The overall time base for the
microcontroller was its internal
1 MHz clock that may be selected during programming with the STK500.
Provided below is the code listing for the flight simulator
panel.
//***************************************************************
//file name: flight_sim.c
//author: Steve Barrett, Ph.D., P.E.
//created: August 1, 2007
//last revised: August 19, 2007
//function: Controls Flight Simulator Control Panel for Larimer
// County School District #1
//
//Compiler settings:
// Paths: c:\icc\include\
// Lib: c:\icc\lib
// Output Directory: c:\output\
//Compiler Options:
// Accept Extensions
// Optimizxations: Default
// AVR Studio Version: Studio 4.06
// ATmega8
// printf: small
// Return Stack: 16
//
//AVR Program Tab Settings
//Program:
// Select device: ATmega8
// Programming mode: ISP, Erase Device Before Programming,
// Verify Device After Programming
// Flash: Input HEX file, Browse and find machine code file:
// flight_sim.hex
// EEPROM: Input HEX file, Browse and find machine code file:
// flight_sim.EEP
//Fuses: Set the following fuses
// Boot flash section size = 128
// Brown out detection at Vcc = 4.0V
// Internal Oscillator: 1 MHz
//Lock bits:
// Mode 1
// Application Protection Mode 1
// Boot loader Protection Mode 1
//Advanced: N/A
//Board: N/A
//Auto:
// Erase Device
// Program Flash
// Verify Flash
// Program Fuses
// Verify Fuses
// Read Fuses
//
//ATMEL AVR ATmega8
//Chip Port Function I/O Source/Dest Asserted Notes
//***************************************************************
//Pin 1: /Reset
//Pin 2: PD0 to DB0 LCD
//Pin 3: PD1 to DB1 LCD
//Pin 4: PD2 to DB2 LCD
//Pin 5: PD3 to DB3 LCD
//Pin 6: PD4 to DB4 LCD
//Pin 7: Vcc
//Pin 8: Gnd
//Pin 9: PB6 to LED6
//Pin 10: PB7 to piezo buzzer
//Pin 11: PD5 to DB6 LCD
//Pin 12: PD6 to DB6 LCD
//Pin 13: PD7 to DB7 LCD
//Pin 14: PB0 to LED0
//Pin 15: PB1 to LED1
//Pin 16: PB2 to LED2
//Pin 17: PB3 to LED3
//Pin 18: PB4 to LED4
//Pin 19: PB5 to LED5
//Pin 20: AVCC to Vcc
//Pin 21: AREF to Vcc
//Pin 22 Gnd
//Pin 23 ADC0 to trip duration potentiometer
//Pin 24 PC1 Engine Power Switch
//Pin 25 PC2 AUX Fuel circuit breaker
//Pin 26 PC3 O2 circuit breaker
//Pin 27 PC4 to LCD Enable (E)
//Pin 28 PC5 to LCD RS
//
//include files**************************************************
//function prototypes********************************************
void delay(unsigned int number_of_65_5ms_interrupts);
void init_timer0_ovf_interrupt(void);
void InitADC(void); //initialize ADC
void initialize_ports(void); //initializes ports
void power_on_reset(void); //returns system to
//startup state
unsigned int ReadADC(unsigned char chan);//read value from ADC
//results
void clear_LCD(void); //clears LCD display
void LCD_Init(void); //initialize AND671GST
//LCD
void putchar(unsigned char c); //send character to LCD
void putcommand(unsigned char c); //send command to LCD
unsigned int ReadADC(unsigned char chan);//read value from ADC
//results
void timer0_interrupt_isr(void);
void flt25_actions(void);
void flt50_actions(void);
void flt75_actions(void);
void flt100_actions(void);
void sound_alarm(void);
void turn_off_LEDs(void);
void reset_alarm(void);
void restore_panel(void);
void LED_blastoff_sequence(void);
void LED_power_down_sequence(void);
void monitor_main_power_CB(void);
void monitor_O2_CB_reset(void);
void monitor_aux_fuel_CB(void);
void perform_countdown(void);
void print_LOWO2(void);
void print_LOW_FUEL(void);
void print_fuel_expended(void);
void print_OVERHEAT(void);
void print_trip_dur(void);
void flash_LED_panel(void);
void clear_LCD(void);
void calculate_trip_int(void);
void systems_A_OK(void);
//program constants
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
//main program***************************************************
//global variables
unsigned int flt_25, flt_50, flt_75, flt_100;
unsigned int action25_done=NO, action50_done=NO;
unsigned int action75_done=NO, action100_done=NO;
unsigned int achieved25=NO, achieved50=NO;
unsigned int achieved75=NO, achieved100=NO;
unsigned int flt_timer=0;
unsigned int trip_duration_volt;
unsigned char PORTC_pullup_mask = 0x0e;
unsigned int flash_timer;
unsigned int PORTB_LEDs;
unsigned int flash_panel=NO;
unsigned int delay_timer;
unsigned int troubleshooting = 1;
void convert_display_voltage_LCD(int trip_duration_volt);
void convert_int_to_string_display_LCD(unsigned int
total_integer_value);
void main(void)
{
init_timer0_ovf_interrupt(); //initialize Timer0 to
//serve as elapsed
initialize_ports(); //initialize ports
InitADC(); //initialize ADC
LCD_Init(); //initialize LCD
print_trip_dur(); //prompt user to enter trip
//duration
monitor_main_power_CB();
clear_LCD();
while(1)
{
if(flt_timer > flt_25) achieved25 = YES;
if(flt_timer > flt_50) achieved50 = YES;
if(flt_timer > flt_75) achieved75 = YES;
if(flt_timer > flt_100) achieved100 = YES;
//function definitions*******************************************
//***************************************************************
//initialize_ports: provides initial configuration for I/O ports
//
//Note: when the RSTDISBL fuse is unprogrammed, the RESET
// circuitry is connected to the pin, and the pin cannot be
// used as an I/O pin.
//***************************************************************
void initialize_ports(void)
{
DDRB = 0xff; //PORTB[7:0] as output
PORTB= 0x00; //initialize low
DDRC = 0xb0; //set PORTC as output OROO_IIII
// 1011_0000
PORTC= PORTC_pullup_mask; //initialize pullups PORTC[3:1]
DDRD = 0xff; //set PORTD as output
PORTD =0x00; //initialize low
}
//***************************************************************
//delay(unsigned int num_of_65_5ms_interrupts): this generic
//delay function
//provides the specified delay as the number of 65.5 ms
//"clock ticks" from the
//Timer0 interrupt.
//Note: this function is only valid when using a 1 MHz crystal or
//ceramic resonator
//***************************************************************
void delay(unsigned int number_of_65_5ms_interrupts)
{
TCNT0 = 0x00; //reset timer0
delay_timer = 0;
while(delay_timer <= number_of_65_5ms_interrupts)
{
;
}
}
//***************************************************************
//InitADC: initialize ADC converter
//***************************************************************
void InitADC( void)
{
ADMUX = 0; //Select channel 0
ADCSRA = 0xC3; //Enable ADC & start 1st
//dummy conversion
//Set ADC module prescalar
//to 8
//critical for accurate ADC results
while (!(ADCSRA & 0x10)); //Check if conversation is
//ready
ADCSRA |= 0x10; //Clear conv rdy flag-set
//the bit
}
//***************************************************************
//ReadADC: read analog voltage from ADC - the desired channel for
//conversion
//is passed in as an unsigned character variable. The result is
//returned
//as a left justified, 10 bit binary result. The ADC prescalar
//must be set to 8 to slow down the ADC clock at higher external
//clock frequencies (10 MHz) to obtain accurate results.
//***************************************************************
140140140ATMEL AVR MICROCONTROLLER
ATMEL AVR OPERATING
PRIMER:
PARAMETERS
PROGRAMMING
AND INTERFACING
AND
INTERFACING 140140140
unsigned int ReadADC(unsigned char channel)
{
unsigned int binary_weighted_voltage, binary_weighted_voltage_low;
unsigned int binary_weighted_voltage_high; //weighted binary
//voltage
//***************************************************************
//int_timer0_ovf_interrupt(): The Timer0 overflow interrupt is
//being employed as a time base for a master timer for this
//project. The internal time base is set to operate at 1 MHz and
//then is divided by 256. The 8-bit Timer0 register (TCNT0)
//overflows every 256 counts or every 65.5 ms.
//***************************************************************
void init_timer0_ovf_interrupt(void)
{
TCCR0 = 0x04; //divide timer0 timebase by 256, overflow occurs
//every 65.5ms
TIMSK = 0x01; //enable timer0 overflow interrupt
asm("SEI"); //enable global interrupt
}
//***************************************************************
//LCD_Init: initialization for an LCD connected in the following
//manner:
//LCD: AND671GST 1x16 character display
//LCD configured as two 8 character lines in a 1x16 array
//LCD data bus (pin 14-pin7) ATMEL 8: PORTD
//LCD RS (pin 28) ATMEL 8: PORTC[5]
//LCD E (pin 27) ATMEL 8: PORTC[4]
//***************************************************************
void LCD_Init(void)
{ delay(1
);
delay(1);
delay(1);
// output command string to initialize LCD
putcommand(0x38); //function set 8-bit
delay(1);
putcommand(0x38); //function set 8-bit
putcommand(0x38); //function set 8-bit
putcommand(0x38); //one line, 5x7 char
putcommand(0x0C); //display on
putcommand(0x01); //display clear-1.64 ms
putcommand(0x06); //entry mode set
putcommand(0x00); //clear display, cursor at home
putcommand(0x00); //clear display, cursor at home
}
//***************************************************************
//putchar:prints specified ASCII character to LCD
//***************************************************************
void putchar(unsigned char c)
{
DDRD = 0xff; //set PORTD as output
DDRC = DDRC|0x30; //make PORTC[5:4] output
PORTD = c;
PORTC = (PORTC|0x20)|PORTC_pullup_mask; //RS=1
PORTC = (PORTC|0x10)|PORTC_pullup_mask;; //E=1
PORTC = (PORTC&0xef)|PORTC_pullup_mask;; //E=0
delay(1);
}
//***************************************************************
//putcommand: performs specified LCD related command
//***************************************************************
//***************************************************************
//clear_LCD: clears LCD
//***************************************************************
void clear_LCD(void)
{
putcommand(0x01);
}
//***************************************************************
//*void calculate_trip_int(void)
//***************************************************************
void calculate_trip_int(void)
{
unsigned int trip_duration_sec;
unsigned int trip_duration_int;
trip_duration_sec=(unsigned int)(((double)(trip_duration_volt)/
1024.0)*60.0*60.0);
trip_duration_int = (unsigned int)((double)(trip_duration_sec)/
0.0655);
flt_25 = (unsigned int)((double)(trip_duration_int) * 0.25);
flt_50 = (unsigned int)((double)(trip_duration_int) * 0.50);
flt_75 = (unsigned int)((double)(trip_duration_int) * 0.75);
flt_100 = trip_duration_int;
}
//***************************************************************
//void timer0_interrupt_isr(void)
//***************************************************************
void timer0_interrupt_isr(void)
{
delay_timer++;
flt_timer++; //increment flight timer
if(flash_panel==YES)
{
if(flash_timer <= 8)
{
flash_timer++;
}
else
{
flash_timer = 0;
if(PORTB_LEDs == OFF)
{
PORTB = 0xff;
PORTB_LEDs = ON;
}
else
{
PORTB = 0x00;
PORTB_LEDs = OFF;
}
}
}
else
{
flash_timer = 0;
}
}
//***************************************************************
//void flt25_actions(void)
//***************************************************************
void flt25_actions(void)
{ sound_alarm();
flash_LED_panel();
print_LOWO2();
monitor_O2_CB_reset();
reset_alarm();
restore_panel();
action25_done = YES;
}
//***************************************************************
//void flt50_actions(void)
//***************************************************************
void flt50_actions(void)
{ sound_alarm();
flash_LED_panel();
print_LOW_FUEL();
monitor_aux_fuel_CB();
reset_alarm();
restore_panel();
action50_done = YES;
}
//***************************************************************
//void flt75_actions(void)
//***************************************************************
void flt75_actions(void)
{ sound_alarm();
flash_LED_panel();
print_OVERHEAT();
delay(458); //delay 30s
monitor_main_power_CB();
reset_alarm();
restore_panel();
action75_done = YES;
}
//***************************************************************
//void flt100_actions(void)
//***************************************************************
void flt100_actions(void)
{ sound_alarm();
flash_LED_panel();
print_fuel_expended();
turn_off_LEDs();
action100_done = YES;
}
//***************************************************************
//void sound_alarm(void)
//***************************************************************
void sound_alarm(void)
{
PORTB = PORTB | 0x80;
}
//***************************************************************
//void turn_off_LEDs(void)
//***************************************************************
void turn_off_LEDs(void)
{
PORTB = PORTB & 0x80;
}
//***************************************************************
//void reset_alarm(void)
//***************************************************************
void reset_alarm(void)
{
PORTB = PORTB & 0x7F;
}
//***************************************************************
//void restore_panel(void)
//***************************************************************
void restore_panel(void)
{
flash_panel = NO;
PORTB = PORTB | 0x7F;
}
//***************************************************************
//void LED_blastoff_sequence(void)
//***************************************************************
void LED_blastoff_sequence(void)
{
PORTB = 0x00; //0000_0000
delay(15); //delay 1s
PORTB = 0x01; //0000_0001
delay(15); //delay 1s
PORTB = 0x03; //0000_0011
delay(15); //delay 1s
PORTB = 0x07; //0000_0111
delay(15); //delay 1s
PORTB = 0x1F; //0001_1111
delay(15); //delay 1s
PORTB = 0x7F; //0111_1111
delay(15); //delay 1s
}
//***************************************************************
//void LED_power_down_sequence(void)
//***************************************************************
void LED_power_down_sequence(void)
{
PORTB = 0x7F; //0111_1111
delay(15); //delay 1s
PORTB = 0x1F; //0001_1111
delay(15); //delay 1s
PORTB = 0x07; //0000_0111
delay(15); //delay 1s
PORTB = 0x03; //0000_0011
delay(15); //delay 1s
PORTB = 0x01; //0000_0001
delay(15); //delay 1s
PORTB = 0x00; //0000_0000
delay(15); //delay 1s
}
//***************************************************************
//void monitor_main_power_CB(void)
//***************************************************************
void monitor_main_power_CB(void)
{
while((PINC & 0x02) == 0x02)
{
; //wait for PC1 to be exerted low
}
}
//***************************************************************
//void monitor_O2_CB_reset(void)
//***************************************************************
void monitor_O2_CB_reset(void)
{
while((PINC & 0x08) == 0x08)
{
; //wait for PC3 to be exerted low
}
}
//***************************************************************
//void monitor_aux_fuel_CB(void)
//***************************************************************
void monitor_aux_fuel_CB(void)
{
while((PINC & 0x04) == 0x04)
{
; //wait for PC2 to be exerted low
}
}
//***************************************************************
//void perform_countdown(void)
//***************************************************************
void perform_countdown(void)
{
clear_LCD();
putcommand(0x01); //cursor home
putcommand(0x80); //DD RAM location 1 - line 1
putchar(’1’); putchar (’0’); //print 10
delay(15); //delay 1s
putcommand(0x01);
putcommand(0x80);
putchar(’5’);
delay(15);
putcommand(0x01);
putcommand(0x80);
putchar(’4’);
delay(15);
putcommand(0x01);
putcommand(0x80);
putchar(’3’);
delay(15);
putcommand(0x01);
putcommand(0x80);
putchar(’2’);
delay(15);
putcommand(0x01);
putcommand(0x80);
putchar(’1’);
delay(15);
//BLASTOFF!
putcommand(0x01); //cursor home
putcommand(0x80); //DD RAM location 1 - line 1
putchar(’B’); putchar(’L’); putchar(’A’); putchar(’S’); putchar
(’T’);
putchar(’O’); putchar(’F’); putchar(’F’); putchar(’!’);
}
//***************************************************************
//void print_LOWO2(void)
//***************************************************************
void print_LOWO2(void)
{
clear_LCD();
putcommand(0x01); //cursor home putcommand(0x80);
//DD RAM location 1 - line 1 putchar(’L’); putchar(’O’);
putchar(’W’); putchar(’ ’); putchar
(’O’);
putchar(’2’);
//***************************************************************
//void print_LOW_FUEL(void)
//***************************************************************
void print_LOW_FUEL(void)
{
clear_LCD();
putcommand(0x01); //cursor home
putcommand(0x80); //DD RAM location 1 - line 1
putchar(’L’); putchar(’O’); putchar(’W’); putchar(’ ’); putchar
(’F’);
putchar(’U’); putchar(’E’); putchar(’L’);
putcommand(0xC0);//DD RAM location 1 - line 2
putchar(’A’); putchar(’S’); putchar(’S’); putchar(’E’); putchar
(’R’);
putchar(’T’); putchar(’ ’); putchar(’A’); putchar(’U’); putchar
(’X’);
putchar(’F’); putchar(’U’); putchar(’E’); putchar(’L’); putchar
(’C’);
putchar(’B’);
}
//***************************************************************
//void print_fuel_expended(void)
//***************************************************************
void print_fuel_expended(void)
{
clear_LCD();
putcommand(0x01); //cursor home putcommand(0x80);
//DD RAM location 1 - line 1 putchar(’F’); putchar(’U’);
putchar(’E’); putchar(’L’); putchar
(’ ’);
putchar(’E’); putchar(’X’); putchar(’P’); putchar(’E’); putchar
(’N’);
putchar(’D’); putchar(’E’); putchar(’D’);
void print_trip_dur(void)
{
clear_LCD();
putcommand(0x01); //cursor home putcommand(0x80);
//DD RAM location 1 - line 1 putchar(’T’); putchar(’R’);
putchar(’I’); putchar(’P’); putchar(’T’); putchar(’I’);
putchar(’M’); putchar(’E’); putchar
(’:’);
putchar(’0’); putchar(’-’); putchar(’6’); putchar(’0’);
//***************************************************************
//void print_OVERHEAT(void)
//***************************************************************
void print_OVERHEAT(void)
{
clear_LCD();
putcommand(0x01); //cursor home putcommand(0x80);
//DD RAM location 1 - line 1 putchar(’E’); putchar(’N’);
putchar(’G’); putchar(’I’); putchar
(’N’);
putchar(’E’); putchar(’ ’); putchar(’O’); putchar(’V’); putchar
(’E’);
putchar(’R’); putchar(’H’); putchar(’E’); putchar(’A’); putchar
(’T’);
//***************************************************************
//void systems_A_OK(void)
//***************************************************************
void systems_A_OK(void)
{
clear_LCD();
putcommand(0x01); //cursor home putcommand(0x80);
//DD RAM location 1 - line 1 putchar(’S’); putchar(’Y’);
putchar(’S’); putchar(’T’); putchar
(’E’);
putchar(’M’); putchar(’S’); putchar(’ ’); putchar(’A’); putchar
(’-’);
putchar(’O’); putchar(’K’); putchar(’!’); putchar(’!’); putchar
(’!’);
}
//***************************************************************
//void flash_LED_panel(void)
//***************************************************************
void flash_LED_panel(void)
{
flash_panel = YES;
flash_timer = 0;
PORTB = 0x00;
PORTB_LEDs = OFF;
}
//***************************************************************
//convert_display_voltage_LCD: converts binary weighted voltage
//to ASCII representation and prints result to LCD screen
//***************************************************************
void convert_display_voltage_LCD(int binary_voltage)
{
float actual_voltage; //voltage between 0 and
//5 V
int all_integer_voltage; //integer representation
//of voltage
//int representation of
//voltage
int hundreths_place, tens_place, ones_place;
//char representation of
//voltage
char hundreths_place_char, tens_place_char, ones_place_char;
//***************************************************************
//convert_int_to_string_display_LCD: converts 16 bit to unsigned
//integer
//values range from 0 to 65,535
//prints result to LCD screen
//***************************************************************
//***************************************************************
//end of file: flight_sim.c
//***************************************************************
6.6 SUMMARY
In this chapter, we have discussed the voltage and current operating parameters for the Atmel
HC CMOS-type microcontroller. We discussed how this information may be applied to properly
design an interface for common I/O circuits. It must be emphasized that a properly designed
interface allows the microcontroller to operate properly within its parameter envelope. If, because
of a poor interface design, a microcontroller is used outside its prescribed operating parameter
values, spurious and incorrect logic values will result. We provided interface information for a
wide range
of I/O devices. We also discussed the concept of interfacing a motor to a microcontroller using
PWM techniques coupled with high-power MOSFET or SSR switching devices.
7. Question: What is the difference between an incremental encoder and an absolute encoder?
APPEND IX A
During C programming, the contents of a specific register may be referred to by name when an
appropriate header file is included within your program. The header file provides the link
between the register name used within a program and the hardware location of the register.
Provided below is the ATmega16 header file from the ICC AVR compiler. This header
file was provided courtesy of ImageCraft.
#ifndef
iom16v_h
#define
iom16v_h
/* ADC */
#define ADC (*(volatile unsigned int *)0x24)
#define ADCL (*(volatile unsigned char *)0x24)
#define ADCH (*(volatile unsigned char *)0x25)
#define ADCSR (*(volatile unsigned char *)0x26)
#define ADCSRA (*(volatile unsigned char *)0x26)
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define ADMUX (*(volatile unsigned char *)0x27)
#define
#define
#define
#define
#define
#define
#define
#define
163163163ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
ATMEGA16 HEADER
AND FILE
INTERFACING 163
/* Analog Comparator */
#define ACSR (*(volatile unsigned char *)0x28)
#define ACD 7
#define ACBG 6
#define ACO 5
#define ACI 4
#define ACIE 3
#define ACIC 2
#define ACIS1 1
#define ACIS0 0
/* USART */
#define UBRRHI (*(volatile unsigned char *)0x40)
#define UBRRH (*(volatile unsigned char *)0x40)
#define URSEL 7
#define UBRR (*(volatile unsigned char *)0x29)
#define UBRRL (*(volatile unsigned char *)0x29)
#define UCSRC (*(volatile unsigned char *)0x40)
#define URSEL 7
#define UMSEL 6
#define UPM1 5
#define UPM0 4
#define USBS 3
#define UCSZ1 2
#define UCSZ0 1
#define UCPOL 0
#define UCSRB (*(volatile unsigned char *)0x2A)
#define RXCIE 7
#define TXCIE 6
#define UDRIE 5
#define RXEN 4
#define TXEN 3
#define UCSZ2 2
#define RXB8 1
#define TXB8 0
#define UCSRA (*(volatile unsigned char *)0x2B)
#define RXC
#define TXC
#define UDRE
#define FE
#define DOR
#define OVR
#define PE
#define U2X
#define MPCM
#define UDR (*(volatile unsigned char *)0x2C)
/* SPI */
#define SPCR (*(volatile unsigned char *)0x2D)
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 4
#define CPOL 3
#define CPHA 2
#define SPR1 1
#define SPR0 0
#define SPSR (*(volatile unsigned char *)0x2E)
#define SPIF 7
#define WCOL 6
#define SPI2X 0
#define SPDR (*(volatile unsigned char *)0x2F)
/* Port D */
#define PIND (*(volatile unsigned char *)0x30)
#define DDRD (*(volatile unsigned char *)0x31)
#define PORTD (*(volatile unsigned char *)0x32)
/* Port C */
#define PINC (*(volatile unsigned char *)0x33)
#define DDRC (*(volatile unsigned char *)0x34)
#define PORTC (*(volatile unsigned char *)0x35)
/* Port B */
#define PINB (*(volatile unsigned char *)0x36)
#define DDRB (*(volatile unsigned char *)0x37)
#define PORTB (*(volatile unsigned char *)0x38)
/* Port A */
#define PINA (*(volatile unsigned char *)0x39)
#define DDRA (*(volatile unsigned char *)0x3A)
#define PORTA (*(volatile unsigned char *)0x3B)
/* EEPROM */
#define EECR (*(volatile unsigned char *)0x3C)
#define EERIE 3
#define EEMWE 2
#define EEWE 1
#define EERE 0
#define EEDR (*(volatile unsigned char *)0x3D)
#define EEAR (*(volatile unsigned int *)0x3E)
#define EEARL (*(volatile unsigned char *)0x3E)
#define EEARH (*(volatile unsigned char *)0x3F)
/* Timer/Counter 2 */
#define ASSR (*(volatile unsigned char *)0x42)
#define AS2 3
#define TCN2UB 2
#define OCR2UB 1
#define TCR2UB 0
#define OCR2 (*(volatile unsigned char *)0x43)
#define TCNT2 (*(volatile unsigned char *)0x44)
#define TCCR2 (*(volatile unsigned char *)0x45)
#define FOC2 7
#define WGM20 6
#define COM21 5
#define COM20 4
#define WGM21 3
#define CS22 2
#define CS21 1
#define CS20 0
/* Timer/Counter 1 */
#define ICR1 (*(volatile unsigned int *)0x46)
#define ICR1L (*(volatile unsigned char *)0x46)
#define ICR1H (*(volatile unsigned char *)0x47)
#define OCR1B (*(volatile unsigned int *)0x48)
#define OCR1BL (*(volatile unsigned char *)0x48)
#define OCR1BH (*(volatile unsigned char *)0x49)
#define OCR1A (*(volatile unsigned int *)0x4A)
#define OCR1AL (*(volatile unsigned char *)0x4A)
#define OCR1AH (*(volatile unsigned char *)0x4B)
#define TCNT1 (*(volatile unsigned int *)0x4C)
#define TCNT1L (*(volatile unsigned char *)0x4C)
#define TCNT1H (*(volatile unsigned char *)0x4D)
#define TCCR1B (*(volatile unsigned char *)0x4E)
#define ICNC1 7
#define ICES1 6
#define WGM13 4
#define WGM12 3
#define CS12 2
#define CS11 1
#define CS10 0
#define TCCR1A (*(volatile unsigned char *)0x4F)
#define COM1A1 7
#define COM1A0 6
#define COM1B1 5
#define
#define
#define
#define
#define
/* Oscillator Calibration */
#define OSCCAL (*(volatile unsigned char *)0x51)
/* On-Chip Debug register */
#define OCDR (*(volatile unsigned char *)0x51)
/* Timer/Counter 0 */
#define OCR0 (*(volatile unsigned char *)0x5C)
#define TCNT0 (*(volatile unsigned char *)0x52)
#define TCCR0 (*(volatile unsigned char *)0x53)
#define FOC0 7
#define WGM00 6
#define COM01 5
#define COM00 4
#define WGM01 3
#define CS02 2
#define CS01 1
#define CS00 0
/* MCU general */
#define MCUCSR (*(volatile unsigned char *)0x54)
#define MCUSR (*(volatile unsigned char *)0x54)
#define JTD 7
#define ISC2 6
#define JTRF 4
#define WDRF 3
#define BORF 2
#define EXTRF 1
#define PORF 0
#define MCUCR (*(volatile unsigned char *)0x55)
#define
#define
#define
#define
#define
#define
#define
#define
/* Timer/Counter Interrupts */
#define TIFR (*(volatile unsigned char *)0x58)
#define
#define
#define
#define
#define
#define TOV1 2
#define OCF0 1
#define TOV0 0
#define TIMSK (*(volatile unsigned char *)0x59)
#define OCIE2 7
#define TOIE2 6
#define TICIE1 5
#define OCIE1A 4
#define OCIE1B 3
#define TOIE1 2
#define OCIE0 1
#define TOIE0 0
/* General Interrupts */
#define GIFR (*(volatile unsigned char *)0x5A)
#define INTF1 7
#define INTF0 6
#define INTF2 5
#define GICR (*(volatile unsigned char *)0x5B)
#define INT1 7
#define INT0 6
#define INT2 5
#define IVSEL 1
#define IVCE 0
/* Stack Pointer */
#define SP (*(volatile unsigned int *)0x5D)
#define SPL (*(volatile unsigned char *)0x5D)
#define SPH (*(volatile unsigned char *)0x5E)
/* Status REGister */
#define SREG (*(volatile unsigned char *)0x5F)
/* Port A bits */
#define PORTA7 7
170170170ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
ATMEGA16 HEADER
AND FILE
INTERFACING 170
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
/* Port
#define
#define
#define
171171171ATMEL AVR MICROCONTROLLER PRIMER: PROGRAMMING
ATMEGA16 HEADER
AND FILE
#define
INTERFACING 171
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
/* Port
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
/* Port
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
/* fuses
#define
#define
#define
#define
#define
#define
#define
#define
#define iv_RESET 1
#define iv_INT0 2
#define iv_INT1 3
#define iv_TIMER2_COMP 4
#define iv_TIMER2_OVF 5
#define iv_TIMER1_CAPT 6
#define iv_TIMER1_COMPA 7
#define iv_TIMER1_COMPB 8
#define iv_TIMER1_OVF 9
#define iv_TIMER0_OVF 10
#define iv_SPI_STC 11
#define iv_USART_RX 12
#define iv_USART_RXC 12
#define iv_USART_DRE 13
#define iv_USART_UDRE 13
#define iv_USART_TX 14
#define iv_USART_TXC 14
#define iv_ADC 15
#define iv_EE_RDY 16
#define iv_EE_READY 16
#define iv_ANA_COMP 17
#define iv_ANALOG_COMP 17
#define iv_TWI 18
#define iv_TWSI 18
#define iv_INT2 19
#define iv_TIMER0_COMP 20
#define iv_SPM_RDY 21
#define iv_SPM_READY 21
/* */
#endif
177
Author Biography
Steven F. Barrett received his bachelor of science degree in electronic enginnering technology
from the University of Nebraska at Omaha in 1979, a Master of engineering in electrical
engineering from the University of Idaho at Moscow in 1986, and a doctor of philosophy degree
from the University of Texas at Autin in 1993. He was formally an active-duty faculty
member with the U.S. Air Force Academy, Colorado, and is now an associate professor of
electrical and computer engineering in the University of Wyoming. He is a member of IEEE
(senior), Tau Beta Pi (chief faculty advisor), and the American Society for Engineering
Education. His research interests include digital and analog image processing, computer-
assisted laser surgery, and embedded controller systems. He is a registered professional engineer
in Wyoming and Colorado. He cowrote with Dr. Pack Microcontroller Theory and Application:
HC12 and S12, second edition, Pearson Prentice-Hall,
2008; Embedded Systems Design and Applications with the 68HC12 and HS12, Pearson Prentice-
Hall,
2005; and Microcontroller Fundamentals for Engineers and Scientists, Morgan and Claypool, 2006.
In 2004, Barrett was named Wyoming Professor of the Year by the Carnegie Foundation for the
Advancement of Teaching. E-mail: [email protected].
Daniel J. Pack is a professor in the Department of Electrical Engineering at the U.S. Air Force
Academy, Colorado. He received his bachelor of science degree in electrical engineering in 1988
from Arizona State University, a master of science degree in engineering sciences in 1990 from
Harvard University, and a doctor of philosophy degree in electrical engineering in 1995 from
Purdue University. He was a visiting scholar at Massachusetts Institute of Technology--Lincoln
Laboratory. He coauthored five textbooks on microcontrollers and embedded systems and
authored more than
70 journal and conference papers. He is a member of Eta Kappa Nu, Tau Beta Pi (faculty
advisor), IEEE (senior), and American Society for Engineering Education. He is a registered
professional engineer in Colorado. In 2005, Dr. Pack was named Colorado Professor of the Year
by the Carnegie Foundation for the Advancement of Teaching. His research interests include
cooperative UAVs, intelligent control, automatic target recognition, and robotics. E-mail:
[email protected].
179
Index
AC device control, 114 digital sensor, 101
AC interfacing, 114 dot matrix display, 107
ADC, 35 duty cycle, 68
ADC conversion, 35 dynamic range, 42
ADC process, 43
analog sensor, 104 electrical specifications, 96
analog vs digital signal, 36 encoding, 38, 40
ASCII, 23
ATmega16 ADC, 46 fast PWM timer mode, 78
ATmega16 interrupt system, 57 Flash EEPROM, 4
ATmega16 timers, 74 flight simulator panel, 115
ATmega16 timing system, 67 frequency measurement, 72
full duplex, 22
Baud rate, 22
Bell Laboratory, 38 Harry Nyquist, 38
HC CMOS, 96
counter-based ADC, 46
counting events, 72 ImageCraft ICC AVR compiler, 60
crystal time base, 68 input capture, 71
CTC timer mode, 78 input capture programming, 91
current sink, 97 input devices, 97
current source, 97 integration ADC, 46
internal interrupt, 62
DAC converter, 53 interrupt theory, 57
data rate, 42
DC motor, 114 keypad, 101
DC motor control, 112
DC motor speed control, 73 LED biasing, 105
decibel (dB), 42 light emitting diode (LED), 105
180 ATMEL AVR MICROCONROLLER PRIMER: PROGRAMMING AND INTERFACING
liquid crystal display (LCD), 107 SPI, 29
stepper motor, 114
MAX232, 23 successive-approximation ADC, 45
MOSFET, 112 switch debouncing, 99
motor operating parameters, 114 switch interface, 99
switches, 97
normal timer mode, 77
NRZ format, 22 time base, 7
Nyquist sampling rate, 38 Timer 0, 75
Timer 1, 81
operating parameters, 95 Timer 2, 85
output compare, 73 timer applications, 71
output device, 105 timer modes, 77
output timer, 70 timer system programming, 87
timing system, 67
parallel ADC, 46 transducer interface, 43
parity, 23 tri-state LED indicator, 107
period, 68 TWI, 33
phase correct timermode, 78
photodiode, 44 USART, 23
PWM, 73
PWM programming, 90 volatile, 4
quantization, 38
RAM, 4
resolution, 41
RS-232, 23
sampling, 38
sensors, 101
serial communications, 21
servo motor, 114
signal conditioning, 43
signal generation, 73
solid state relay (SSR), 112