
- •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 6: C Functions and Program Structures
One possible source of problems occurs when you reuse a token. You might write:
#define Up 0
And come back a month later, when your header file has 500 lines and forget that you have already defined Up and add:
#define Up 1
The preprocessor uses the last #define and you won’t get any warnings, other than this one. But you probably will get some mysterious bugs that you’ll blame on the hardware until much later you finally see what you’ve done and apply a welldeserved boink to your own head.
Macro Substitution
We can use #define to make a simple token that replaces a complex, or frequently used expression. For example we may want to determine the larger of two variables:
#define larger( x, y) ( (x)>(y) ? (x) : (y) )
Which we would use as:
int a= 9; int b = 7; int c = 0;
c = larger( a, b);
The preprocessor replaces the last statement with:
c = ( (a)>(b) ? (a) : (b) );
Which is what the compiler sees.
The expression larger( a, b) looks like a function but isn’t. A macro is substituted in the code anywhere that it is used, while a function is located in only one place and is called each time it is used. The big difference from a microcontroller perspective is that nothing is pushed on the stack when a macro is used, unlike
95
Chapter 6: C Functions and Program Structures
functions, which use extra RAM. Also macros create in-line code that can be faster than function calls (no processor overhead). And finally, macros don’t require formally declared data types:
double da = 12; double db = 14; double dc = 7; double dd = 0;
dd = larger( (db-da), dc);
If larger() was a function, the parameters require a data type such as int or double, but couldn’t use both (okay, there is casting, but that’s another topic).
Conditional Inclusion
Often microcontrollers come in families that differ only in a few features, pinouts, memory size, and register locations. You can write C code for the entire family if you substitute alias for the things that differ. Let’s say that SuprMic16 uses pins 12 and 13 for USART transmit and receive, while SuprMic8 uses pins 6 and 14, and SuprMic4 uses pins 1 and 2. We put the following in our SuprMic.h file:
#if SuprMicX == 16
#define TXD 12
#define RXD 13 #elif SuprMicX == 8
#define TXD 6
#define RXD 14 #elif SuprMicX = 4
#define TXD 1
#define RXD 2
#else
#error “No definition for SuprMicX TXD and RXD pins." #endif
If we are using the SuprMic8 in our Killer Cylon Robot project we should put the following in our CylonKillerRobot.h file:
#ifndef SuprMicX
#define SuprMicX = 8
#include <SuprMic.h>
96
Chapter 6: C Functions and Program Structures
#endif
The ifndef means ‘if not defined’ so that the preprocessor will use the #define SuprMicX = 8 and #include <SuprMic.h> lines only the first time it sees the #ifndef SuprMicX line. This prevents the preprocessor from attaching the contents of SuprMic.h in each file that uses CylonKillerRobot.h
As a matter of standard practice, always begin a header file with an #ifndef statement and a #define so that the preprocessor will only use that header’s data once in a project. If you put the header data in more than once you may get a lot of compiler errors about multiple declarations.
97