AVR Embedded Tutorial - Simple GPIO on and off output
│ Deutsch (de) │ English (en) │
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;
Blink example
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.
pinMode
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;
Digital write
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;
Digital switch
Switches the pin, there is no equal function from the Arduino.
procedure WritePortD(Pin: byte);
begin
PORTD := PORTD xor (1 shl pin);
end;
Digital read
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.
Bitpacked array
var
LEDPort: bitpacked array[0..7] of boolean absolute PORTD;
begin
LEDPort [0] := True;
LEDPort [1] := True;
LEDPort [2] := False;
LEDPort [3] := False;
Bitpacked record
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;
Set
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).
See also
- AVR Embedded Tutorials - Overview