AVR® 8-bit microcontrollers control applications through their digital Input and Output (I/O) pins. These pins can monitor any voltage present as a high impedance input and supply or sink current as a high or low voltage digital output. These pins are usually organized in groups of eight and referred to as a port. The AVR uses the alphabet to name these ports, for example: PortA, PortB, etc. The pins of PortA are referred to as PA0 - PA7.
Overview
All AVR ports have true Read-Modify-Write functionality when used as general digital I/O ports. This means that the direction of one port pin can be changed without unintentionally changing the direction of any other. The same applies when changing drive value (if configured as an output) or enabling/disabling of pull-up resistors (if configured as an input). Each output buffer has symmetrical drive characteristics with both high sink and source capability.
The pin driver is robust enough to drive LED displays directly. All port pins have individually selectable pull-up resistors with a supply-voltage invariant resistance. All I/O pins have protection diodes to both VCC and Ground as indicated in the figure.
Brief AVR I/O Port Summary
Configuring the I/O Digital Pins
Each port consists of three registers:
- DDRx – Data Direction Register
- PORTx – Pin Output Register
- PINx – Pin Input Register
where x = Port Name (A, B, C or D)
These registers determine the setup of the digital inputs and outputs. I/O pins can also be shared with internal peripherals. For example, the Analog to Digital (ADC) converter can be connected to the I/O pin instead of being a digital pin. In this case the I/O pin registers set it up as a tri-state high impedance input.
Register Bits
- DDxn bits are accessed at the DDRx I/O address
- PORTxn bits at the PORTx I/O address
- PINxn bits at the PINx I/O address
Where n = pin bit number in the Port Register
DDxn
The DDxn bits in the DDRx Register select the direction of this pin. If DDxn is written to '1', Pxn is configured as an output pin. If DDxn is written to '0', Pxn is configured as an input pin.
PORTxn
The PORTxn bits in the PORTx register have two functions. They can control the output state of a pin and the setup of an input pin.
As an Output:
If a '1' is written to the bit when the pin is configured as an output pin, the port pin is driven high. If a ‘0’ is written to the bit when the pin is configured as an output pin, the port pin is driven low.
As an Input:
If a '1' is written to the bit when the pin is configured as an input pin, the pull-up resistor is activated. If a ‘0’ is written to the bit when the pin is configured as an input pin, the port pin is tri-stated.
PINxn
The PINxn bits in the PINx register are used to read data from port pin. When the pin is configured as a digital input (in the DDRx register), and the pull-up is enabled (in the PORTx register) the bit will indicate the state of the signal at the pin (high or low).
Note: If a port is made an output, then reading the PINx register will give you data that has been written to the port pins.
As a Tri-State Input:
When the PORTx register disables the pull-up resistor the input will be tri-stated, leaving the pin left floating. When left in this state, even a small static charge present on surrounding objects can change the logic state of the pin. If you try to read the corresponding bit in the pin register, its state cannot be predicted.
Examples
All PORTA pins set as inputs with pull-ups enabled and then read data from PORTA:
DDRA = 0x00; //make PORTA all inputs
PORTA = 0xFF; //enable all pull-ups
data = PINA; //read PORTA pins into variable data
PORTB set to tri-state inputs:
DDRB = 0x00; //make PORTB all inputs
PORTB = 0x00; //disable pull-ups and make all pins tri-state
PORTA lower nybble set as outputs, higher nybble as inputs with pull-ups enabled:
DDRA = 0x0F; //lower pins output, higher pins input
PORTA = 0xF0; //output pins set to 0, input pins enable pull-ups
Example Project controlling an I/O pin along with simple debugging is available.
Digital I/O Project on AVR Xplained 328PB
Example Project mentioned in the video
[| Video Referenced I/O Example]]
Tips and Tricks
Switching Between Input and Output
When switching between tri-state ({DDxn, PORTxn} = 0b00) and output high ({DDxn, PORTxn} = 0b11), an intermediate state with either pull-up enabled {DDxn, PORTxn} = 0b01) or output low ({DDxn, PORTxn} = 0b10) must occur.
Normally, the pull-up enabled state is fully acceptable, as a high impedance environment will not notice the difference between a strong high driver and a pull-up. If this is not the case, the PUD bit in the MCUCR Register can be set to disable all pull-ups in all ports.
Switching between input with pull-up and output low generates the same problem. You must use either the tri-state
({DDxn, PORTxn} = 0b00) or the output high state ({DDxn, PORTxn} = 0b11) as an intermediate step.
Disable Pull-Ups Over-ride
The PUD Pull-up Disable bit in the MCUCR register can over-ride the DDRx and PORTx pull-up settings.
When this bit is written to one, the pull-ups in the I/O ports are disabled even if the DDxn and PORTxn Registers are configured to enable the pull-ups ({DDxn, PORTxn} = 0b01).
Toggling an I/O Pin
Writing a '1' to PINxn toggles the value of PORTxn independent of the value of DDRxn. The SBI assembly instruction can be used to toggle one single bit in a port.
Unconnected Pins
If some pins are unused, we recommend that you ensure that these pins have a defined level, even though most of the digital inputs are disabled in the deep sleep modes. Floating inputs should be avoided to reduce current consumption in all other modes where the digital inputs are enabled (Reset, Active Mode and Idle Mode).
The simplest method to ensure a defined level of an unused pin is to enable the internal pull-up. In this case, the pull-up will be disabled during reset. If low power consumption during reset is important, we recommend you use an external pull-up or pull-down. Connecting unused pins directly to VCC or GND is NOT recommended, since this may cause excessive currents if the pin is accidentally configured as an output.