Vývojová deska Arduino Uno s mikrokontrolérem ATMega328 je primárně zaměřena na začátečníky, kteří elektronice nebo mikrokontrolérům vůbec nerozumí. Internetový odborníci na slovo vzatí :) se ale různě po diskusích dohadují, že je Arduino nepoužitelné, že neučí začátečníka ty správné návyky™, že je vývojář až příliš odříznut od hardawe a podobně. Dva hlavní argumenty těchto diskutujících jsou — Arduino používá vlastní jazyk a ne standardní C. A že vývojové prostředí je pro pokročilejší věci nepoužitelné.
V tomto článku bych chtěl oba tyto argumenty vyvrátit a dokázat, že Arduino je pouze ATMega328 a že lze Arduino IDE obejít.
Na následujících řádcích se budu odkazovat na nástroje make
, avr-gcc
, avr-objcopy
, avrdude
a stty
. Předpokládám alespoň základní znalost práce v Unixovém terminálu a znalost jazyka C pro mikrokontroléry Atmel. Pokud nerozumíte co to všechno znamená, pak mám pro vás dobrou zprávu — tento článek ještě číst nemusíte, vystačíte si s Arduino IDE :)
Jak to dělá Arduino IDE
Arduino není nic jiného, že deska s ATMega328 (mluvíme o Arduino Uno). Tento mikrokontrolér má již naprogramovaný bootloader, který umí programovat flash paměť skrz rozhraní UART. Aby bylo možné Arduino programovat pomocí avrdude
, obsahuje deska i převodník USB-UART, který je realizován mikrokontrolérem ATMega8U2 (nebo ATMega16U2).
Po připojení k PC se Arduino hlásí jako sériový port, na Unixových systémech většinou /dev/tty.usbmodem*
, /dev/tty.usbserial*
, /dev/ttyACM*
nebo /dev/ttyUSB*
. Záleží na operačním systému a verzi Arduina.
Pokud spustíte Arduino IDE a přeložíte libovolný kód, na pozadí se nejdříve spustí překladač avr-gcc
. Jakmile chcete kód do Arduina nahrát, na pozadí nejdříve ATMega328 restartuje a pak se spustí avrdude
.
Tímto víme vše potřebné, abychom obešli vývojové prostředí a napsali si vlastní makefile
a kód přímo v jazyce C.
Kód blink.c
Nejdříve jednoduchý kód, který bude blikat LEDkou na pinu číslo 13. V Arduino IDE by nám stačilo napsat něco takového:
void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); }
My ale nemáme k dispozici žádné Arduino funkce, vše si musíme napsat sami.
Při pohledu do schématu Una zjistíme, že pin číslo 13 je připojen na PB5
. Náš kód bude vypadat třeba takto:
#include <avr/io.h> #include <util/delay.h> // Nastaví bit 'b' bajtu 'B' na log. nulu. #define LOW(B, b) (B &= ~_BV(b)) // Nastaví bit 'b' bajtu 'B' na log. jedničku. #define HIGH(B, b) (B |= _BV(b)) // Pin 13 je na 5. bitu portu B. #define P13 (5) void setup() { // Všechny piny portu B budou výstupní. DDRB = 0xFF; } /** * Hlavní smyčka programu */ static void loop() { LOW(PORTB, P13); _delay_ms(500); HIGH(PORTB, P13); _delay_ms(500); } int main(void) { setup(); for (;;) loop(); return 0; }
Programování Arduina
Pro překlad .c
do .hex
použijeme avr-gcc
:
$ avr-gcc -g -Os -mmcu=atmega328p -DF_CPU=16000000 -c blink.c $ avr-gcc -g -mmcu=atmega328p -o blink.elf blink.o $ avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex
Nejdříve přeložíme do objektového kódu. Musíme definovat frekvenci krystalu (Arduino používá 16MHz) a cílový mikrokontrolér (ATMega328P). Jelikož v kódu používáme funkci _delay_ms()
, musíme kód optimalizovat pomocí přepínače -Os
. Pokud bychom tuto optimalizaci nezapli, zmíněná funkce by nebyla přesná a blikání by mělo jinou frekvenci.
Teď již zbývá .hex
nahrát do Arduina. To provedeme např.:
$ stty -f /dev/tty.usbmodem441 hupcl $ avrdude -p atmega328p -P /dev/tty.usbmodem441 -c arduino -U flash:w:blink.hex
Prvním příkazem Arduino restartujeme. Přepínač -f
funguje pouze pro BSD verzi stty, pokud máte GNU verzi, použijte -F
. Pokud z nějakého důvodu nechcete použít stty
, lze Arduino restartovat i tímto jednoduchým kódem v Pythonu:
import serial, time s = serial.Serial('/dev/tty.usbmodem441', 57600) s.setDTR(True) time.sleep(1) s.setDTR(False)
Druhým příkazem se Arduino naprogramuje. Avrdude
lze použít i pro přečtení obsahu paměti. V případě, že chcete přečíst celou flash paměť Arduina, můžete použít toto:
$ avrdude -p atmega328p -P /dev/tty.usbmodem441 -c arduino -U flash:r:blink.hex:i
Pokud byste chtěli měnit i fuses a bootloader, již budete potřebovat externí programátor.
Makefile
A takto nějak může vypadat náš Makefile
:
MCU = atmega328p F_CPU = 16000000 FORMAT = ihex CC = avr-gcc FLAGS = -std=c99 -g -mmcu=$(MCU) OBJCOPY = avr-objcopy FILE = blink PORT ?= /dev/tty.usbmodem* STTY = stty AVRDUDE = avrdude PROGRAMMER = arduino programme: $(FILE).hex $(STTY) -f $(PORT) hupcl $(AVRDUDE) -p $(MCU) -P $(PORT) -c $(PROGRAMMER) -U flash:w:$(FILE).hex $(FILE).hex: $(FILE).elf $(OBJCOPY) -j .text -j .data -O $(FORMAT) $(FILE).elf $(FILE).hex $(FILE).elf: $(FILE).o $(CC) $(FLAGS) -o $(FILE).elf $(FILE).o $(FILE).o: $(FILE).c $(CC) $(FLAGS) -Os -DF_CPU=$(F_CPU) -c $(FILE).c clean: rm -f *.elf *.o *.hex
A to je vše. Teď již pro programování Arduina stačí spustit make
:
$ ls blink.c Makefile $ make
Závěr
V tomto článku jsem chtěl připomenout, že Arduino není nic jiného, než ATMega328 a pár součástek okolo. Pokud vám z nějakého důvodu vadí Arduino IDE, není nic jednoduššího, než jej obejít a využívat překladač gcc
a avrdude
.