program firmware;
{$mode ObjFPC}
{ Demo program to switch an LED on or off based on text commands received
over serial. This code is written for an atmega328p and should be compatible with the
Arduino Uno/Nano boards.
Written for the Free Pascal compiler. Compiler command line
(requires ppcrossavr compiler to be installed):
$ fpc -Tembedded -Pavr -Wpatmega328p -O3 firmware.pp
Note on Linux it may be necessary to specify the binutils prefix: -XPavr-
Upload firmware.hex to Arduino:
$ avrdude -P /dev/ttyACM0 -p m328p -c arduino -v -e -U flash:w:firmware.hex }
type
// State machine for parsing input strings
TCmdState = (csNone, csO, csOf, csOff, csOn);
const
F_CPU = 16000000;
baud = 9600;
LEDPin = 1 shl 5;
var
c: char;
state: TCmdState;
LEDport: byte absolute PORTB;
LEDdir: byte absolute DDRB;
procedure uartInit;
begin
// Baud rate setting
// Formula for X2 option with rounding
UBRR0 := ((F_CPU + 4*baud) shr 3) div baud;
// Set U2X as specified
UCSR0A := 1 shl U2X0;
// Enable receiver and transmitter
UCSR0B := (1 shl RXEN0) or (1 shl TXEN0);
// Set frame format: 8data, 1stop bit, no parity
UCSR0C := (3 shl UCSZ0);
end;
procedure uartTransmitChar(const data: byte);
begin
// Wait for empty transmit buffer
while ((UCSR0A and (1 shl UDRE0)) = 0) do;
// Put data into buffer, sends the data
UDR0 := data;
end;
procedure uartTransmitString(const s: shortstring);
var
c: char;
begin
for c in s do
uartTransmitChar(ord(c));
end;
function uartReceive: char;
begin
// Wait for data to be received
while ((UCSR0A and (1 shl RXC0)) = 0) do;
// Get and return received data from buffer
result := char(UDR0);
end;
begin
// Switch LED pin to output
LEDdir := LEDPin;
uartInit();
// Transmit help message
uartTransmitString('Enter any of the following commands:'#10);
uartTransmitString(' on - switch LED on'#10);
uartTransmitString(' off - switch LED off'#10);
state := csNone;
repeat
c := uartReceive(); // blocking
// Feed character into state machine
case state of
csNone:
begin
if c in ['o', 'O'] then
state := csO
else
state := csNone;
end;
csO:
begin
if c in ['n', 'N'] then
state := csOn
else if c in ['f', 'F'] then
state := csOf
else if not(c in ['o', 'O']) then // Ignore repeated 'o' characters
state := csNone;
end;
csOf:
begin
if c in ['f', 'F'] then
state := csOff
else
state := csNone;
end;
end;
if state > csOf then
begin
if state = csOff then
LEDport := LEDport and not(LEDPin)
else
LEDport := LEDport or LEDPin;
state := csNone;
end;
until false;
end.