AVR GPIO
From OpenAVR
Contents |
[edit] Introduction
The term General Purpose Input/Output (GPIO) is typically used for pins of a microcontroller, which can be configured for either digital input or digital output.
Different devices of the AVR family offer different number of GPIO ports, each of which is typically 8 bit wide. The currently largest AVR, the ATmega2560, got 11 ports, named PORT A to PORT L. However, not all 8 bits of each port may be available. Some ports may provide input only or output only. Furthermore, most GPIO pins provide special function. If such functions are activated, the related GPIO bits usually are no more available. You need to check the datasheet of your microcontroller.
Software can control or monitor ports by reading from or writing to specific registers. On the AVR three registers are provided:
- PORTx Output register
- PINx Input register
- DDRx Data direction register
Note, that the naked GPIO pin of your microcontroller is quite limited. Before attaching any hardware, check the electrical characteristics in the datasheet. Otherwise you may destroy the chip.
[edit] Using the Runtime Library
With AvrLibC, port registers can be used like any other global variable. To make use of it, we need to include the related header file.
#include <avr/io.h>[edit] GPIO Configuration
As stated above, typical GPIO ports may be configured as digital inputs or digital outputs. This is controlled by the data direction register. For example, DDRB specifies, which pin will be used for input or output. Setting the related bit to 1, will enable output mode. If the bit is cleared, the pin can be used as an input.
If configured as an input, most ports allow to activate an internal pull-up resistor by setting the related bit in the port output register.
[edit] Reading Inputs
In order to read an input, make sure that the related bit is properly configured. To set bit 4 of PORT B to input mode, use
DDRB &= ~_BV(4);
Reading the input can be done this way
unsigned char val; val = PINB & _BV(4); if (val) { /* Bit 4 at Port B is high. */ } else { /* Bit 4 at Port B is low. */ }
A common pitfall is to use register PORTx instead of PINx.
[edit] Writing Outputs
In order to drive a GPIO line high or low, we set the related bit to output mode. Setting the related bit in the port output register to 1 will raise the pin level to high. When clearing the bit, the output pin level will be pulled low.
The following function will set the output at bit 5 of Port B to low (ground level), if the parameter high is zero. Otherwise the output pin will be set to the level of the supply voltage.
void SetPB5(int high) { /* Test the parameter and accordingly set the bit in the output register. */ if (high) { PORTB |= _BV(5); } else { PORTB &= ~_BV(5); } /* Set PB5 to output mode. */ DDRB |= _BV(5); }
[edit] Simple Square Wave Generator
The following application will generate a square wave at Port B, bit 5. It's very simple and doesn't care about frequency or duty cycle.
Adjust the SWG_ macros, if this pin is not available for output on your hardware.
#include <avr/io.h> #define SWG_PORT PORTB #define SWG_DDR DDRB #define SWG_BIT 5 int main(void) { /* Initialize port direction. */ SWG_DDR |= _BV(SWG_BIT); for (;;) { /* Set port pin to high. */ SWG_PORT |= _BV(SWG_BIT); /* Reset port pin to low. */ SWG_PORT &= ~_BV(SWG_BIT); } return 0; }
A more advanced version would use PWM, for example.

