- •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 8: C Pointers and Arrays
Music to my ears. “Play it again Sam.”
We are going to pillage the Butterfly code again and play some tunes to further illustrate the use of pointers and arrays.
More on pointers to arrays
In the original Butterfly code written with the IAR compiler, in sound.c, songs are selected using these definitions:
__flash int __flash |
*Songs[] |
= { FurElise, Mozart, /*Minuet, |
|
AuldLangSyne,*/ Sirene1, |
Sirene2, Whistle, 0}; |
||
int __flash *pSong; |
// |
pointer to the different songs in flash |
The __flash is not C, it is a special IAR modifier that allows access to Flash ROM as if it was regular C style RAM. In use:
pSong = Songs[song]; |
// point to this song |
Loads pSong with the pointer to the tune indicated by the song variable. All nice and C like. Unfortunately, the WinAVR compiler isn’t quite as C-like in the way it allows access to Flash ROM. Not that I’m criticizing, I think the WinAVR port of the gcc tools to the AVR platform is a miracle of dedication and technical prowess, not to mention: free. But I won’t mention free. Especially not repeatedly: free, free, free. So this is a miraculous little free compiler (send them some money at: http://www.sourceforge.net/donate.)
The port of the Butterfly code from not-free IAR compiler to the free WinAVR was done by:
Martin Thomas, Kaiserslautern, Germany mthomas@rhrk.uni-kl.de http://www.siwawi.arubi.uni-kl.de/avr_projects/
who did an outstanding job. When you finally learn enough to really evaluate the Butterfly code, you will come to appreciate the intelligence and hard work that this gentleman (my assumption) did for you. Yes, you. And for free. So when you see the way he translated the relatively simple appearing song selection statement, you can agree with his comment below: ‘// looks too complicated’, without getting fussy about it.
189
Chapter 8: C Pointers and Arrays
First look at his version of the definitions:
// pointer-array with pointers to the song arrays
const int *Songs[] PROGMEM = { FurElise, Mozart, Minuet, AuldLangSyne, Sirene1, Sirene2, Whistle, 0};
const int *pSong; // mt point to a ram location (pointer array Songs)
The __flash of the IAR compiler is replaced by the PROGMEM. And the actual use is as follows:
// mt pSong = Songs[song]; // point to |
this song |
pSong=(int*)pgm_read_word(&Songs[song]); |
// looks too |
complicated...
Yep, I agree: ‘// looks too complicated', but I have no intention to try to fix it and make it look more C-like. I doubt seriously that I have the time or the skill. In programming microcontrollers in C we sometimes have to dance lightly around ANSI C and use what works.
What the statement says is: we equate a constant integer pointer pointer to a cast of an integer pointer of the function pgm_read_word, which takes as a parameter the address of the song element of the Songs[] array. What we are doing is sending this address to a function that knows how to extract a pointer to Flash RAM. Looks too complicated… but so what, it works.
Setting the frequency
Tones are setup by putting an integer from the song table in the Timer1 Input Capture Register 1, ICR1, which in this case is used to set the counter top value. The values are taken from the Butterfly code and are based on a cpu clock running at 1 MHz. Since we are using a cpu clock of 2 MHz for the USART, adjustments are made that help but do not truly compensate for the difference.
We select a base frequency of 220Hz (the A note) and calculate the frequency for subsequent notes using the notes position on the musical scale following a. For instance, C0 is 3 after A:
190
Chapter 8: C Pointers and Arrays
Tone = 220*2^(NOTE/12)
When NOTE = C0 we get:
Tone = 220*2^(3/12) = 261.6256.
We get the frequency to generate for the tone with:
Timer value = 1Mhz / Tone / 2
For the C0 we would have:
Timer value = 1000000 / 261,6256... / 2 = 1911
So when we want to generate a C0 we set Timer1 to generate a phase/frequency correct PWM with a top value calculated as above. We then compensate for our using a 2Mhz cpu clock by doubling the value using a left bit shift of one position. (In case you didn’t get this earlier, left shifting a byte or integer doubles it if there is headroom. Headroom means the value is less than half the possible value, 256/2 for a byte.)
A few tones from the sound.h table:
#define a |
2273 |
// tone 0 |
|
#define xa |
2145 |
// tone 1 |
|
#define ax |
2145 |
// tone 1 |
|
#define b |
2024 |
// tone |
2 |
#define c0 |
1911 |
// tone |
3 |
Setting the tempo
The tempo, in this case, is the length of time we play the tone. The Timer0 calls the Play_Tune function at 10ms intervals. It begins by getting the tempo from the first position of the array and putting it into a Tempo variable. The next time Play_Tune is called, if Tempo is not 0, it decrements the tempo and exits. It continues to do this until the Tempo is 0, when it rereads the tempo and starts over.
191
Chapter 8: C Pointers and Arrays
Setting the duration
The duration and the frequency are paired values in the table. The duration is the length of time that the following tone should be played. Play_Tune gets the duration
and tone from the table and loads them into the Duration variable and the Timer1 top count. It starts the tone and then exits. When called again by Timer0, if the Duration is not 0, Duration is decremented and the function exits leaving the tone playing. When Duration is decremented to 0, Play_Tune gets the next set of values for the Duration and the timer and starts the next tone. If the Duration value read from the table is 0, this indicates that the tune has been played through, so it checks the next byte and if that byte is 1, it starts the tune over, if 0 it ends the tune. Clever, eh?
An example song array – Fur Elise
const int FurElise[] PROGMEM=
{
3,
8,e2, 8,xd2, 8,e2, 8,xd2, 8,e2, 8,b1, 8,d2, 8,c2, 4,a1, 8,p, 8,c1, 8,e1, 8,a1, 4,b1, 8,p, 8,e1, 8,xg1, 8,b1, 4,c2, 8,p, 8,e1, 8,e2, 8,xd2, 8,e2, 8,xd2, 8,e2, 8,b1, 8,d2, 8,c2, 4,a1, 8,p, 8,c1, 8,e1, 8,a1, 4,b1, 8,p, 8,e1, 8,c2, 8,b1, 4,a1,
0, 1 };
Using the Piezo-element to make sound
The piezo-element is the large black square on the back of the Butterfly. It contains a sheet of material that deforms when electricity is applied to it (the piezo electric effect). This deformation can be made at audio frequencies allowing the element to produce sound waves in the air. Our piezo-element is connected to PortB pin 5, which is also the OC1A pin that can be configured as an output for the Timer1 waveform generator. We will configure the Timer1 waveform generator so that it will use PWM to generate tones.
192