AVR Embedded Tutorial - Simple GPIO on and off output
Easy GPIO input and output
Direct port manipulation
Before you can switch a GPIO pin x to HIGH, you have to configure it as an output. This is done using DDRx.
- Configure pin as an output:
DDRx := DDRx or (1 shl Pinx);
- Set pin to be HIGH:
PORTx := PORTx or (1 shl Pinx);
- Set pin to be LOW:
PORTx := PORTx and not (1 shl Pinx);
- Switch pin (high to low or low to high):
PORTx := PORTx xor (1 shl Pinx);
If you leave DDRx LOW, a pull-up resistor is enabled using PORTx. This is needed to connect a push button to GND. So you can do without an external pull-up resistor.
The status of the GPIO pin x can be queried using PINx.
if PINx and (1 shl Pinx) > 0 then Pin_is_HIGH;
This example shows how to address a GPIO with an ATtiy2313. For this, two LEDs are connected to pins 0 and 1 of Port D.
Alternating indicator ATtiny2313
program Project1; const DP0 = 0; // Pin 0 PortD DP1 = 1; // Pin 1 PortD sl = 150000; // Delay procedure mysleep(t: int32); // A simple delay var i: Int32; begin for i := 0 to t do asm nop end; end; begin // Configure pin 0 and 1 of Port D as output DDRD := DDRD or (1 shl DP0) or (1 shl DP1); repeat // change LED PORTD := PORTD or (1 shl DP0); // Pin 0 on (high) PORTD := PORTD and not (1 shl DP1); // Pin 1 off (low) mysleep(sl); // Delay // change LED PORTD := PORTD or (1 shl DP1); // Pin 1 on (high) PORTD := PORTD and not (1 shl DP0); // Pin 0 off (low) mysleep(sl); // Delay until 1 = 2; end.
Toggle pin ATtiny2313
If you want to switch the pin, no matter what its original state, you can use an xor operator. This also works for an alternating high/low signal. DP0 is first set to HIGH.
begin // Configure Pin 0 and 1 of Port D as output DDRD := DDRD or (1 shl DP0) or (1 shl DP1); PORTD := PORTD or (1 shl DP0); // Pin 0 on (high) repeat // Blink LED PORTD := PORTD xor (1 shl DP0); // Switch pin 0 PORTD := PORTD xor (1 shl DP1); // Switch pin 1 mysleep(sl); // Delay until 1 = 2; end.
Simplify port access
If you access ports and do not always want to write the and, or 'and xor operators, you can also use the following procedures/functions. The examples below show this for PORT D. You can easily adjust these for other ports.
This corresponds roughly to pinMode(... from the Arduino.
procedure ModePortD(Pin: byte; Value: Boolean); begin if Value then begin DDRD := DDRD or (1 shl pin); end else begin DDRD := DDRD and not (1 shl pin); end; end;
This corresponds approximately to digitalWrite(... from the Arduino.
procedure WritePortD(Pin: byte; Value: Boolean); begin if Value then begin PORTD := PORTD or (1 shl pin); end else begin PORTD := PORTD and not (1 shl pin); end; end;
Switches the pin, there is no equal function from the Arduino.
procedure WritePortD(Pin: byte); begin PORTD := PORTD xor (1 shl pin); end;
This corresponds approximately to digitalRead(... from the Arduino.
function ReadPortD(bit: byte): Boolean; begin Result := PIND and (1 shl bit) <> 0; end;
Address pin directly
If you connect an absolute bit-packed array, record or set to the port, you can access each pin directly, without annoying or and and not' operators.
The compiled code is exactly the same size as the conventional method with or and and not. It could hardly be more elegant.
The following three examples address the first 4 pins from PORT D which control 4 LEDs.
var LEDPort: bitpacked array[0..7] of boolean absolute PORTD; begin LEDPort  := True; LEDPort  := True; LEDPort  := False; LEDPort  := False;
var LEDPort: bitpacked record red, green, yellow, blue: boolean; end absolute PORTD; begin LEDPort.red := True; LEDPort.green := True; LEDPort.yellow := False; LEDPort.blue := False;
var LEDPortS: set of (green, yellow, red, blue) absolute PORTD; begin LEDPortS := [yellow, red]; // yellow, red on LEDPortS := LEDPortS + [green, blue] - [red]; // green, blue on; red off LEDPortS := LEDPortS - [green, blue] + [red]; // green, blue off; red on
DDR and PORT
DDRx can be solved in a similar way to PORTx. It is best to declare the LEDs as a type:
Type TLed = bitpacked record green, yellow, red, blue: boolean; end; var LedPORT: TLed absolute PORTD; LedDDR: TLed absolute DDRD; begin LedDDR.green := True; LedDDR.red := True; repeat LedPORT.green := True; LedPORT.red := False; ...
PINx can be solved in a similar way.
Arduino pins PD0 and PD1
This description refers to the Arduino Uno/Nano, other AVRs may also be affected.
The PORTD PD0 and PD1 pins are also used for the UART interface by default and are therefore not usable. If you still want to use these pins, you have to disable their UART functions.
UCSR0B := 0; // Disable UART functions
Note: The LEDs RX and TX will light in the opposite way because the anode of these LEDs is directly connected to Vcc.
For more information about the UART, see UART - serial input and output via UART (COM port).
- AVR Embedded Tutorials - Overview