As with most ”Hello World” programs; this one is very short. It will be presented in its entirety and then broken down piece by piece. A basic understanding of the C programming language will be helpful, though not necessary for this. Before jumping in and using peripherals in a microcontroller, one should first look at the datasheet, read about the operation of the device and learn what each of the associated registers are for. On the ATmega644p, digital I/O utilizes three types of registers, with each of the four 8-bit ports requiring one of each type, plus an additional register relating to pull-up resisters for a total of 13 registers. Port designations have been generalized to ’x’ here. Section 4 of this chapter contains further information on how these registers operate and interact in the hardware.
PORTx - Port x Data Register
The four PORTx registers control the signals being generated for digital output. Each bit corresponds to a separate pin on the microcontroller. If the port is set for any or all pins to be input, a 1 in the corresponding bit(s) of this register will enable a pull-up resistor on that pin. For more
information about controlling the pull-up resistors and their purpose, refer to section 3.4 later in this chapter.
DDRx - Portx Data Direction Register
These registers control whether a given pin on the port is an input or an output. If the bit in the register is high, the corresponding pin is configured as an output. The default when the ATmega644p is powered on is that all pins are inputs.
PINx - Port x Input Pins Address
This register reads the current value of the pin, regardless of the data direction. When a pin is set to input, the pin is not connected to anything else and the pull-up resistor is off, the value of the corresponding bit may randomly change. If the pull-up resistor is turned on, the pin will read high when it is not connected. If the data direction is set to output, this register will match PORTx.
MCUCR - MCU Control Register
Only bit four of this register matters to the digital I/O. This pin, PUD is a global disable for the pull-up resistor. When set to 1, the pull-ups are disabled even if DDRx and PORTx are configured to use them.
Now, knowing what each of the register do, they can be used in an applica- tion. # i n c l u d e < avr / io . h > int m a i n ( v o i d ) { D D R A = 0 xff ; P O R T A = 0 xfe ; r e t u r n 0; }
This program will turn on an LED connected to pin 40 of the ATmega644p and then ends (pin configuration is shown in figure 1 in the Preface). Due to the nature of microcontrollers this LED will remain on as long as power is supplied to both the microcontroller and the LED. In order to better understand how this program works, each line is explained below.
# i n c l u d e < avr / io . h >
This line tells the compiler to include the specified header file (avr/io.h). Almost every program written for any AVR series processor will include this line, as it in turn includes additional files that define much of the memory structure such as the names of all the registers. Most microcontroller manufacturers or compilers will include such a header file to define names for all the registers in their microcontrollers Did this not exist, the programmer would be forced to address the registers by memory address, rather than by name.
This is the main function. Every program must have exactly one main function and it is where program execution starts. This line also specifies that the program does not take any information as input (void), but it does return an integer upon completion (int).
D D R A = 0 xff ;
This sets the contents of the register DDRA to the hex (0x) value ff, which turns all 8 pins to output. Only one of the pins is actually used, but setting them all does not cause any issues in this case.
Whenever there are several registers serving the same purpose for multiple devices, the actual register names are often generalized by replacing the dis- tinguishing character, in this case A, with a generic character indicating that it could be any of the possibilities. This generic character is generally a lower case ‘n’ for numerical distinguishers or ‘x’ for alphabetic. Therefore, when some reference is made to DDRx, it is referring to any or all of the data direction registers rather than a specific one. This ‘x’ means something different when preceded by a ‘0’ and followed by a string of numbers or letters a-e. In this case the ‘0x’ is a designator that the following value is in hexadecimal (base 16). P O R T A = 0 xfe ;
This sets all of the bits in the data register to high except for bit 0. As the circuit is using active-low logic, with the microcontroller acting as a sink, this turns the LED on. As a value of 0 is default here this line could be left out, however including this line will cause any LEDs attached to the other pins on the port to be off. Additionally, the value 0xfe can be replaced by any syntax that gives the same value. This syntax is for hexadecimal, other options include binary (0b11111110) or decimal (254). Hexadecimal is commonly used due to its compactness and easy conversion to and from binary (each character in hexadecimal corresponds to a block of four bits).
r e t u r n 0;
The final line of code supplies the integer requested as the return value in the function declaration. The return statement has the added effect of exiting the function immediately. While not necessary in this application, many compilers will throw errors or warnings if the main function does not have a return type of int or if execution of the function can reach the end of the function without encountering the return command.
}
While the return statement tells the program to exit the function, this bracket signifies that the definition of the function is complete, and any further lines belong to some other aspect of the code.