- •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 9 – Digital Meets Analog – ADC and DAC
Projects
We will write code to allow us to use HyperTerminal to request a reading from the light, temperature and voltage sensors of the Butterfly. You’ve already seen the debugging tale above so you know how much fun I had writing this stuff, so enjoy it or else.
Initializing the ADC
The Butterfly has the ATmega169 pin 62, (AREF) connected to a bypass capacitor to help lessen noise on the ADC, so we set the ADMUX bits 6 and 7 to 0 to select the 'use external reference' option. We use the ‘input’ variable to set the multiplexer. to connect the ADC to pin 61 (ADC0) using the ADMUX register (data book p 207).
ADMUX = input; |
// external AREF and ADCx |
Next we set the ADC Control and Status Register A. The ADEN bit enables the ADC. The ADPSx bits select the prescaler.
// set ADC prescaler to , 1MHz / 8 = 125kHz ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
Finally we take a dummy reading, which basically allows the ADC to hack up any hairballs before we take any real readings
input = ADC_read();
void ADC_init(char input)
{
ADMUX = input; |
// external AREF and ADCx |
// set ADC prescaler to , 1MHz / 8 = 125kHz ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
input = ADC_read(); // clear hairballs
}
216
Chapter 9 – Digital Meets Analog – ADC and DAC
Reading the ADC
We save power by turning off the voltage on the light and temperature sensors when they are not used, so now we turn them on, in case they are being used.
sbi(PORTF, PF3); sbi(DDRF, DDF3);
Next we enable the ADC.
sbi(ADCSRA, ADEN); |
// Enable the ADC |
Then we do another hairball clearing dummy read.
ADCSRA |= (1<<ADSC); |
// do single conversion |
And we wait till the conversion is complete.
while(!(ADCSRA & 0x10));//wait for conversion done, ADIF flag active
Now we repeat this 8 times for better accuracy.
// do the ADC conversion 8 times for better accuracy for(i=0;i<8;i++)
{
ADCSRA |= (1<<ADSC); // do single conversion
// wait for conversion done, ADIF flag active while(!(ADCSRA & 0x10));
ADC_temp = ADCL; // read out ADCL register ADC_temp += (ADCH << 8); // read out ADCH register
// accumulate result (8 samples) for later averaging ADCr += ADC_temp;
}
We divide by 8, which conveniently is done by left shifting 3 bits. Weren’t we lucky that we chose to do 8 samples and save processing time by avoiding a division?
ADCr = ADCr >> 3; // average the 8 samples
217
Chapter 9 – Digital Meets Analog – ADC and DAC
We turn the sensors off to save power.
cbi(PORTF,PF3); // mt cbi(PORTF, PORTF3); // disable the VCP cbi(DDRF,DDF3); // mt cbi(DDRF, PORTF3);
And we disable the ADC and return the calculated value.
cbi(ADCSRA, ADEN); |
// disable the ADC |
return ADCr;
Giving us the ADC_read function:
int ADC_read(void)
{
char i;
int ADC_temp;
//mt int ADC = 0 ; int ADCr = 0;
//To save power, the voltage over the LDR and the NTC is
//turned off when not used. This is done by controlling the
//voltage from an I/O-pin (PORTF3)
sbi(PORTF, PF3); // Enable the VCP (VC-peripheral) sbi(DDRF, DDF3); // sbi(DDRF, PORTF3);
sbi(ADCSRA, ADEN); |
// Enable the ADC |
//do a dummy readout first |
|
ADCSRA |= (1<<ADSC); |
// do single conversion |
//wait for conversion done, ADIF flag active while(!(ADCSRA & 0x10));
//do the ADC conversion 8 times for better accuracy for(i=0;i<8;i++)
{
ADCSRA |= (1<<ADSC); |
// do single conversion |
// wait for conversion done, ADIF flag active |
|
while(!(ADCSRA & 0x10)); |
|
ADC_temp = ADCL; |
// read out ADCL register |
218
Chapter 9 – Digital Meets Analog – ADC and DAC
ADC_temp += (ADCH << 8); |
// read out ADCH register |
// accumulate result (8 samples) for later averaging ADCr += ADC_temp;
}
ADCr = ADCr >> 3; // average the 8 samples
cbi(PORTF,PF3); // disable the VCP cbi(DDRF,DDF3); // mt cbi(DDRF, PORTF3);
cbi(ADCSRA, ADEN); |
// disable the ADC |
return ADCr;
}
Light Meter
The Butterfly has a Light Dependent Resistor, LDR, connected to ADC channel 2. The resistance of the LDR decreases as the light increases, so the voltage measured will decrease as light decreases.
We write the getLight function:
void getLight()
{
char light[]= {'0','0','0','\0'}; int ADCresult = 0;
// Initialize the ADC to the light sensor channel ADC_init(2);
ADCresult = ADC_read();
itoa(ADCresult, light, 10);
// Send the temperature to the PC sendString("The light reading is "); sendString(light);
sendString(" somethings.\r");
}
This is straightforward and returns a value for the light. The light units ‘somethings’ is a precise scientific measure that means: ‘I don’t have a clue as to
219