
- •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
Chapter 6: C Functions and Program
Structures
Function Basics
About now you are probably wondering why you bought the Butterfly and all that cool hardware. Where are the projects? Let’s blow something up! Patience grasshopper, we’ll have a project at the end of this chapter and many more later. It will be worth it, I promise.
We’ve been using functions enough that by now you probably have a good intuitive feel for them, but Let’s be formal and define some things. First a ‘reuse’ of what was said earlier:
Encapsulation is a key idea in C programming and provides the possibility of making chunks of code convenient to use. And just as important, it provides a way to make tested code reusable while not allowing the programmer to mess with it and chance breaking something. These ideas are so important in software engineering that the C++ language was developed primarily to formalize these concepts and force their use.
One of the main functions of functions (har!) is to break computations up into logical chunks and separate them to help clarify the code. If you find yourself writing a function that seems to be doing two separable things, try separating it into two functions.
A function must be declared before it is defined somewhere, usually in a header file or before the main() function. For example:
void sendChar(char ) ;
Which tells the compiler that the sendChar() function takes a char as an argument and doesn’t return anything when finished. The compiler can use this information to make sure you are using it correctly when you make calls to the function.
A function definition is the function text as:
void sendChar(char myData)
87
Chapter 6: C Functions and Program Structures
{
// Do stuff with the variable ‘data’
}
Note that the argument now not only has the type ‘char’ but a specific variable ‘myData’. It doesn’t matter what you name the argument in the calling function, as long as the type matches, so:
sendChar(myByte);
This is just fine, since the sendchar function will use the data in ‘myByte’ as the data in ‘myData’ in the function definition. An important consideration is that the data in ‘myByte’ is copied to sendchar(myByte), but the variable ‘myByte’ is not sent. Think about this. In the calling function, ‘myByte’ is an alias for the address of some data, in this case a char. The called function takes that char and puts in memory at another address aliased, in this case, with the name ‘myData’. ‘myByte’ and ‘myData’ have the same value but are not stored in the same place. The function only sees a copy of ‘myByte’ not the actual ‘myByte’ itself. If the function chages the ‘myData’ variable, that change is not reflected in the calling functions ‘myByte’ variable. This is a source of a surprising number of bugs among novice C programmers. To clarify let’s make a function adder that adds two numbers.
void adder(unsigned char a1, unsigned char a2, unsigned char r)
{
r = a1 + a2;
if(r == 2) getrewarded(); else getboinked();
}
Let’s call it in main()
int main()
{
unsigned char add1 = 1; unsigned char add2 = 1; unsigned char results = 0;
adder(add1,add2,results);
88
Chapter 6: C Functions and Program Structures
if(results == 2) getrewardd(); else getboinked();
}
If you think 1 + 1 = 2 prepare to get boinked. You’ll getrewarded() in adder() and getboinked() in main(). In the adder function, r = 2, but this doesn’t change the ‘results’ in the parameter list in the function call to adder in the main() function.
Returns
Ouch! Boinking hurts, so Let’s make adder work right, we change the return type from void to char and declare r as an unsigned char:
char adder(unsigned char ad1, unsigned char a1)
{
unsigned char r;
r = a1 + a2;
if(r == 2) getrewarded(); else getboinked();
return r;
}
And in main we set ‘results’ equal to adder so it gets set to the data returned by adder:
int main()
{
unsigned char add1 = 1; unsigned char add2 = 1; unsigned char results = 0;
results = adder(add1,add2);
if(results == 2) getrewarded(); else getboinked();
}
Now we get two rewards. If we want to skip the reward we could write adder:
89
Chapter 6: C Functions and Program Structures
char adder(unsigned char ad1, unsigned char a1)
{
return a1 + a2;
}
And we have a concise and totally useless function. If we want to add 1 and 1, we just add them.
Variables External, Static, and Register
Another way to do the adder() thing would be to use and external variable (global). These are variables defined outside any function, usually in a header or before main() and are available for any function to use. We could have written:
void adder(unsigned char, unsigned char); unsigned char results = 0;
int main()
{
unsigned char add1 = 1; unsigned char add2 = 1;
adder(add1,add2);
if(results == 2) getrewarded(); else getboinked();
}
void adder(unsigned char ad1, unsigned char a1)
{
results = a1 + a2;
}
Which would work fine. Unless of course an interrupt triggered right after we set results in adder() and changed it to 3. Then when the interrupt finishes and we look at results in main() we get boinked again. This is a good reason to avoid external variables. You never know where they’ve been or what kind of nasty stuff they might track in. Also they permanently occupy memory, while defining ‘results’ in adder would only use memory when adder is called, and release the memory when finished.
90