- •Chapter 1: Introduction
- •Goals
- •Chapter 2: Quick Start Guide
- •Software
- •WinAVR – Oh, Whenever…
- •Programmers Notepad
- •AVRStudio – FREE and darn well worth it.
- •Br@y++ Terminal:
- •Hardware
- •Constructing Your Development Platform
- •Blinking LEDs – Your First C Program
- •Write it in Programmers Notepad
- •Download to the Butterfly with AVRStudio
- •Blinky Goes Live
- •Simulation with AVRStudio
- •GOOD GRIEF!
- •Comments
- •Include Files
- •Expressions, Statements, and Blocks
- •Operators
- •Flow Control
- •Functions
- •The Main() Thing
- •Chapter 4: C Types, Operators, and Expressions
- •Data Types and Sizes
- •Seen on a shirt at a Robothon event:
- •Bits
- •Bytes
- •The long and short of it
- •Variable Names
- •Constants
- •Declarations
- •Arithmetic Operators
- •Relational and Logical Operators
- •Bitwise Operators
- •Testing Bits
- •Assignment Operators and Expressions
- •Conditional Expressions
- •Precedence and Order of Evaluation
- •Projects
- •Port Input and Output
- •Cylon Eye Speed and Polarity Control
- •Chapter 5: C Control Flow
- •Statements and Blocks
- •If-Else and Else-If
- •Switch
- •Loops – While, For and Do-while
- •Break and Continue
- •Goto and Labels
- •A few practical examples: strlen, atoi, itoa, reverse
- •Chapter 6: C Functions and Program Structures
- •Function Basics
- •Returns
- •Variables External, Static, and Register
- •Scope
- •Headers
- •Blocks
- •Initialization
- •Recursion
- •Preprocessor
- •Macro Substitution
- •Conditional Inclusion
- •Projects
- •Is anybody out there? Communicating with a PC
- •Demonstrator
- •PC_Comm
- •Using CommDemo:
- •Chapter 7: Microcontroller Interrupts and Timers
- •Interrupts
- •Projects
- •Grab your joystick – and test your interrupts
- •Using joystick
- •Timers/Counters
- •Calibrating the Butterfly oscillator:
- •OSCCAL_calibration() function – detailed explanation
- •ALL THIS AND WE HAVEN’T EVEN STARTED CALIBRATING YET!
- •Projects
- •Precision Blinking
- •Using Precision Blinking:
- •Pulse Width Modulation – LED Brightness Control
- •Pulse Width Modulation - Motor Speed Control
- •Speedometer
- •Chapter 8: C Pointers and Arrays
- •Addresses of variables
- •Function Arguments
- •Arrays
- •FIFOs and LIFOs: Stacks and Queues (Circular Buffers)
- •Stacks
- •Queues (Circular Buffers)
- •Function Pointers
- •Complex Pointer and Array Algorithms
- •Projects
- •Messenger
- •Arrays in RAM and ROM
- •Does anybody know what time it is? A Real Time Clock.
- •A one second interrupt
- •Converting Computer Time to Human Readable Time
- •The Real Timer Clock Software
- •Music to my ears. “Play it again Sam.”
- •More on pointers to arrays
- •Setting the frequency
- •Setting the duration
- •An example song array – Fur Elise
- •Using the Piezo-element to make sound
- •Initializing the Timer1 for PWM to the piezo-element.
- •Generating the tone using PWM from Timer1
- •Using the Timer0 interrupt to play a tune
- •Chapter 9 – Digital Meets Analog – ADC and DAC
- •But First - A Debugging Tale
- •Analog to Digital Conversion
- •What is Analog to Digital Conversion?
- •Analog to Digital Conversion by Successive Approximation
- •Analog to Digital Conversion with the ATMEGA169
- •Starting a Conversion
- •Conversion Timing
- •Changing Channels
- •Digital Noise Reduction
- •Conditioning the Analog Input Signal
- •Accuracy
- •Projects
- •Initializing the ADC
- •Reading the ADC
- •Light Meter
- •Temperature Meter
- •The @#%#&*#!!!! Volt Meter
- •Using ADC
- •DAC and ADC - Function Generator / Digital Oscilloscope
- •Chapter 10: C Structures
- •Structure Basics
- •Structures and Functions
- •Structure Arrays
- •Typedef
- •Unions
- •Bit-fields
- •Bit-Fields the C-way
- •Bit-fields the masking-way
- •Projects
- •Finite State Machine
- •Chapter 11 The Butterfly LCD
- •PC to LCD test program
- •Conclusion
- •Appendix 1: Project Kits
- •Data I/O
- •PWM Motor Control
- •Appendix 2: Soldering Tutorial
- •Appendix 3: Debugging Tale
- •Appendix 4: ASCII Table
- •Appendix 5: Decimal, Hexadecimal, and Binary
- •Appendix 6: Motor Speed Control Wheel
- •Appendix 7: HyperTerminal
- •Index
Chapter 7: Microcontroller Interrupts and Timers
Projects
Precision Blinking
Let’s use interrupts and timers to provide precise control over the blink rate for an LED. We’ll let the PC send data as a character string to the microcontroller and let the microcontroller set a timer interrupt to trip at the specified rate and toggle an LED.
First Let’s think about setting a timer to throw an interrupt every millisecond. The USART initialization sets the system oscillator to 2 MHz. We set the Timer0 prescaler
to clk/8 which gives a 250 kHz input to the timer/counter. Then we set a compare value of 250 so the timer throws an interrupt every 250 counts: 250000/250 = 1000, and we get interrupted a thousand times a second, almost like having a toddler around.
We set timer0 to do a compare interrupt:
TIMSK0 = (1<<OCIE0A);
Then we set the timer0 compare register to 250:
OCR0A = 250;
Finally we set the Timer/Counter Control Register A to the Clear Timer on Compare waveform and the prescaler to divide the clock by 8:
// Set Clear on Timer Compare (CTC) mode, CLK/8 prescaler TCCR0A = (1<<WGM01)|(0<<WGM00)|(1<<CS01);
But, heck Let’s get fancy and allow ourselves to change the compare value by sending data from the PC. We write the MilliSec_init and the set_OCR)A functions:
void MilliSec_init(unsigned char count)
{
// Initialize Timer0.
128
Chapter 7: Microcontroller Interrupts and Timers
// Enable timer0 compare interrupt TIMSK0 = (1<<OCIE0A);
//Sets the compare value set_OCR0A(count);
//Set Clear on Timer Compare (CTC) mode, CLK/8 prescaler TCCR0A = (1<<WGM01)|(0<<WGM00)|(1<<CS01);
}
void set_OCR0A(unsigned char count)
{
// Sets the compare value OCR0A = count;
}
Now we can initialize the timer when the program starts and change the compare value when we feel like it. Let’s reuse the PC_Comm code to generate an annoying LED precision blinker that’s actually an 8-bit counter. As you will see, or rather won’t see, you can’t see the LED blinking at the fastest rates in the lower 4 bits, but you can see blinking in the slower upper 4 bits. The lowest bit toggles the LED 1000 times a second, it is on for 1000th of a second then off for 1000th of a second, which yields a blink period of 500 Hz. Each LED blinks at half the rate of the prior LED, so the blink periods for each LED are:
LED0 = 500 Hz.
LED1 = 250 Hz.
LED2 = 125 Hz.
LED3 = 62.5 Hz.
LED4 = 31.25 Hz.
LED5 = 15.625 Hz.
LED6 = 7.8125 Hz.
LED7 = 3.90625 Hz.
If we tell the Butterfly to set the compare to 125, then the interrupt occurs at 2000 Hz and the fastest blink period becomes 1000 Hz.
129
Chapter 7: Microcontroller Interrupts and Timers
What happens if we send it 100? Well, 250000/100 = 2500, so we would get a 1250 Hz blink.
How do we get a 60 Hz blink? We can get LED3 to blink at 60 Hz if the base rate is 480 Hz, which we can get from 960 interrupts per second, which we could get from a compare count of 260.41666… and we ain’t gonna get that for two reasons: one, the count overflows at 255 and two, we are dealing with integers. If we set the compare to 130 we get a rate of 1923.076923 which yields 60.096…Hz on LED5, pretty darn close, but we have an error of 1 – (60/60.09615385 ) * 100 = 0.16 %, not bad at all. But is it close enough? Only you can decide that
Create a new directory Precision Blinking and copy the PC_Comm. and Demonstrator .c and .h files from the PC_Comm. directory.
In Programmers Notepad change Demonstrator.h to:
// Demonstrator.h Precision Blinking version
#include <avr/signal.h> #include <inttypes.h>
void initializer(void); void parseInput(char *);
int parse_ctc(char *); void set_ctc(int);
void MilliSec_init(unsigned char count); void set_OCR0A(unsigned char count);
In Programmers Notepad change Demonstrator.c to:
// Demonstrator.c Precision Blinking version
#include "PC_Comm.h" #include "Demonstrator.h"
unsigned char milliseconds = 0;
void initializer()
{
// Calibrate the oscillator:
130
Chapter 7: Microcontroller Interrupts and Timers
OSCCAL_calibration();
//Initialize the USART USARTinit();
//set PORTD for output DDRD = 0xFF;
MilliSec_init(250); // default to 1000 Hz
// say hello
sendString("\rPC_Comm.c ready to communicate.\r"); // identify yourself specifically
sendString("You are talking to the Precision Blinking demo.\r");
}
void parseInput(char s[])
{
// parse first character switch (s[0])
{
case 'c':
if( (s[1] == 't') && (s[2] == 'c')) parse_ctc(s);
break; case 'd':
if((s[1]=='e')&&(s[2]=='m')&&(s[3]=='o')&&(s[4]=='?')) sendString("You are talking to the Precision Blinking demo.\r"); break;
default:
sendString("\rYou sent: '"); sendChar(s[0]);
sendString("' - I don't understand.\r"); break;
}
s[0] = '\0';
}
int parse_ctc(char s[])
{
char ctc[11];
unsigned char i = 3, j = 0;
while( (s[i] != '\0') && (j <= 11) )
{
if( (s[i] >= '0') && (s[i] <= '9') )
{
131
Chapter 7: Microcontroller Interrupts and Timers
ctc[j++] = s[i++];
}
else
{
sendString("Error - Parse_ctc received a non integer: "); sendChar(s[i]);
sendChar('\r'); return 0;
}
}
ctc[j] = '\0';
if(j>4)// must be < 256
{
sendString("Error - Parse_ctc number too large"); return 0;
}
else
{
set_ctc(atoi(ctc));
}
return 1;
}
void set_ctc(int count)
{
char ctc[11];
sendString("Setting the Compare Timer Count to: "); itoa(count,ctc,10);
sendString(ctc);
sendChar('\r');
MilliSec_init(count);
}
/*
The USART init set the system oscillator to 2 mHz. We set the Timer0 prescaler to clk/8 which gives a 250 kHz input to the timer/counter. A compare of 250 throws an interrupt every millisecond.
*/
void MilliSec_init(unsigned char count)
{
// Initialize Timer0.
//Enable timer0 compare interrupt TIMSK0 = (1<<OCIE0A);
132