AVR Programming:
Programming is the simplest part in robotics. We will use avr-gcc version of ‘C’, which is specifically designed for avr based microcontrollers.
Before you start any of your projects:
1. Plan your actions and visualize your expectations and outcome of the project
2. When writing a program, it is always good to write a pseudo code of what you expect the code to do. Note down all steps in simple English, or in any other language you prefer
3. You do not need to learn complex software to create a simple circuit. A rough sketch on a paper or even a paint program on your desktop would suffice. Once you are comfortable, get into those advanced simulators and circuit design software.
4. Working with electricity and these tiny components can be dangerous. Be cautious.
5. Last but not the least, do not try to overdo anything in a single day. If you are stressed, go out and enjoy. Love what you do and be proud of your mistakes too.
Let’s get started. Here is the code required to turn on a LED. You can download a copy of this program with necessary comments and the makefile, upload it to your microcontroller and see the results (To upload the code, you need a programmer which connects your computer and the microcontroller). Later I will explain what each line means, why and how are they used.
/*
File Name : LEDON.c
Title : Basic LEDON Program.
Notes : This is the first program in Basic LED series.
All this program does is set DDR and Port registers to turn on a LED
*/
#ifndef F_CPU
#define F_CPU 1000000UL
#endif
#include <avr/io.h>
int main(void)
{
DDRC = 0xff;
while (1)
{
PORTC = 0xff;
}
return (0);
}
Now we will understand what each line means.
/* File … blah… blah… */
Anything between /* and */ is considered as comments and is ignored by the complier. It is always a good practice to include brief description of your program. This practice helps you in better identification and documentation of what the program does. For inline comments, you can use //.
// This is an example of inline comment
#ifndef F_CPU #define F_CPU 1000000UL #endif
F_CPU is used to define the clock frequency in Hertz. It is surrounded by #ifndef (If not defined) and #endif which means this code should be executed if F_CPU is not already defined. This is necessarily not required as we will define the clock frequency in makefile.
Makefile??? Now what is a makefile? makefile is a set of instructions for any specific project which directs 'make'(utility that builds executable programs and libraries using your source code) on how to compile and link a program. It supports in finding the target file and dependencies if any. It also specifies what avr device is being used. Since we are using AVRStudio, makefile is automatically generated.
WinAVR already has a template for makefile where you need to make minimal changes for your project to get it up and running. If you have installed WinAVR, then you are most likely to find the file at <install>\sample directory, where <install> is the directory where you have WinAVR installed.
#include <avr/io.h>
Programmers generally separate certain elements of code from the program’s source code which can be reused in other programs when required. #include is used to include these separate chunks of code from an external file into this program. avr/io.h is one such file which contains I/O definitions for the particular device we use. If we use Atmega8, then respective file is included. But how does the compiler know which device we use? Very simple; we define the type of device in the "makefile” and appropriate device file ioxxxx.h (where xxxx is the device name) is included. It further includes additional header files: #include <avr/sfr_defs.h>, #include <avr/portpins.h>, #include <avr/common.h>, #include <avr/version.h>. http://www.nongnu.org/avr-libc/user-manual/group__avr__io.html provides a complete description of io.h. If you have read the documentation, it clearly tells you not to include ioxxxx.h file directly and always get it called from io.h.
int main(void)
The actual processing starts from main() which is common in most programming languages
DDRC = 0xff;
To understand this line, you should have already referred to AVR basics. If not, take a break, read through the details in AVR Basics and return. Summarizing those details, all we do in this line is to set DDRC (Data-Direction-Register) as output. Be informed that 0xff (hexadecimal) is the same as 0b11111111 (binary), where "0x" refers to hexadecimal value, and “0b” refers to binary. You can as well write DDRC = 0b11111111;
If you are still not clear, refer to number-system tutorial for number conversion. In your program, you can either use binary or hexadecimal although I personally prefer hexadecimal values as it is easier to remember and write.
while(1)
Most of the time you want your microcontroller to do repetitive tasks. You do not want your robot to process an activity and then sit idle for the rest of its life. Hence we will put the entire code in an infinite loop. You can even use “for” loop for the same purpose. I generally use “for” loop when I know the number of iterations and “while” loop otherwise.
PORTC = 0xff;
DDRC = 0xff sets DDR as output. Each Port register is responsible for I/O pins for the respective port. So, PORTC controls the pins in PORTC. We can either set the pins to high or low. In the example, we have set all Pins in PORTC as output.
return(0);
Once all the processing is complete the control is returned. But do note that our program never reaches this line as we have the entire logic within an infinite loop.
Build this program using AVR Studio. If you are unsure, refer to software requirements under How-To section. Once you click build all, your program should compile without any errors. Locate the folder where you had saved this program and open “default” folder. Makefile, .hex file and other supporting files should be stored there. LEDON.hex is the file of interest.
Open this .hex file from PonyProg and upload it to your microcontroller. You should see that the LED is on.
Did the LED turn ON? Congratulations! You are successful. No? Don't worry, it is normal. Go back to the start of this tutorial and check if something has gone wrong. Check if:
1. You have powered up your microcontroller.
2. You are supposed to upload the hex code into your microcontroller. Did you successfully do that?
3. You have fried the poor LED. Test it by connecting it to a battery and a resistor in series and see if it still works.
4. If you still do not have any idea, upload your code, circuit diagram, and questions in the forum and you might find help.
Do not connect your LED to a battery without a resistor. It will almost instantly fry your LED as too much current flows through it.
If everything went well, you have a platform which can be upgraded further. We started with an intention to make a blinking LED circuit, not just an LED which turns ON and stays forever. Ofcourse we will do that too. If everything worked perfectly, all that is needed is to add few more lines to our program to achieve desired result. The concept is simple. Set Pins to High to turn on LED, wait for sometime and then set Pins to Low to turn it off. Wrap this in an infinite loop and you have your desired result.
Next you will see how to blink a LED. This tutorial is created not to just showcase a blinking LED but try to cover as much of details as possible which includes Programming Basics, AVR basics etc.,
Tutorial index:
Do you have anything to say?
Visit the Forum to discuss, learn and share anything related to robotics and electronics !!