Архитектура AVR в примерах/Простейшая программа
В данной работе мы рассмотрим два основных этапа разработки программ для микроконтроллеров семейства AVR — сборку кода и загрузку результата во встроенную Flash-память микроконтроллера — на примере простейшей программы на языке C.
Перед началом
[править]Для работы нам потребуются:
- простейшее устройство на МК ATmega8 (или подобном), или же плата Arduino Uno или Arduino Nano;
- среда разработки, включающая следующие программные пакеты:
- GCC и GNU Binutils для целевой архитектуры AVR;
- универсальный сборщик GNU Make;
- AVR Libc;
- загрузчик Avrdude;
- стандартные системные средства; так, мы будем предполагать использование командного интерпретатора GNU Bash и какого-либо инструмента редактирования кода (GNU nano, Vim, GNU Emacs, или иного);
- отметим, что установить специфичные для AVR инструменты в Debian (и производных системах) можно командой, подобной
# apt-get install -- avr-libc binutils-avr gcc-avr avrdude
.
Мерцание светодиода
[править]
/*** blink.c — Blink a LED at PB5, repeatedly -*- C -*- */
#include <avr/io.h> /* for DDRB, PORTB, etc. */
#include <util/delay.h> /* for _delay_ms () */
int
main ()
{
/* Arduino boards have a LED at PB5 */
DDRB |= ((1 << DDB5));
while (1) {
PORTB ^= ((1 << PB5));
_delay_ms (2718L); /* waste cycles for 2.71 s */
}
/* not reached */
/* . */
return 0;
}
/*** blink.c ends here */
### Makefile -*- Makefile -*-
MCU = atmega8
F_CPU = 7372800
CC = avr-gcc
CFLAGS = -O2 -Wall -std=gnu11 -mmcu=$(MCU)
CPPFLAGS = -DF_CPU=$(F_CPU)L
OBJCOPY = avr-objcopy
.PHONY: default
default: blink.hex blink
blink: blink.c
%.hex: %
$(OBJCOPY) -O ihex $< $@
### Makefile ends here
Чтение кода
[править]Рассмотрим код программы выше, начиная с его «полезной нагрузки».
Строка
PORTB ^= ((1 << PB5));
изменяет состояние вывода PB5 МК (D 13 платы Arduino Uno) на противоположное (на высокий уровень если был низкий и наоборот.)Следующий за ней вызов
_delay_ms (2718L);
приведет к выполнению «холостого цикла» в течение 2.718 с (при условии задания соответствующего действительной тактовой частоте процессора значения для макроопределенияF_CPU
.)Оба действия выше заключены в «основной цикл»
while (1) { }
. Условие продолжения цикла всегда выполняется, а значит цикл будет выполняться до момента потери питания или сброса МК.Строка
DDRB |= ((1 << DDB5));
настраивает вывод PB5 МК для использования в качестве выхода.В противном случае он будет настроен как вход и изменение его состояния будет приводить к подключению или отключению от вывода «подтягивающего резистора», ток через который может оказаться недостаточным для свечения подключенного к выводу светодиода.
Строки
int main ()
начинают определение «головной» функцииmain
, возвращающей значение типаint
(знаковое целое) и получающей неопределенное количество аргументов. Строкаreturn 0;
, идущая следом за «бесконечным» циклом, удовлетворяет формальное требование на возврат не-void
функцией некоторого значения.- Именно функции
main
передается управление после завершения инициализации служебными подпрограммами, обеспечивающими окружение этапа выполнения (англ. run-time environment) языка C. - Такое объявление функции
main
является одним из допускаемых стандартом.[1] - Возвращаемое значение 0 определено стандартом (для функции
main
) как код «успешного завершения».[2][3] - Фактически реализуемое GCC и AVR Libc окружение этапа выполнения не предполагает ни передачу функции
main
каких-либо аргументов, ни использование возвращаемого ею значения.
- Именно функции
Наконец, директивы препроцессора
#include
в самом начале кода подключают следующие заголовки (англ. header):avr/io.h
- включает используемые в коде макроопределения
DDRB
,DDB5
,PORTB
,PB5
; util/delay.h
- включает объявление (и определение) функции
_delay_ms ()
, также используемой в приведенном примере.
Сборка
[править]Создадим файлы
blink.c
иMakefile
приведенного выше содержания.Соберем рассматриваемый пример выполнив команду
make
:$ make avr-gcc -O2 -Wall -std=gnu11 -mmcu=atmega8 -DF_CPU=7372800 ../blink.c -o blink avr-objcopy -O ihex blink blink.hex $
- NB
При использовании микроконтроллера, отличного от ATmega8, или же кварцевого резонатора на частоту, отличную от 7.3728 MHz, следует явно указать параметры сборки
MCU
илиF_CPU
, соответственноТак, для платы Arduino Uno R3, поставляемой с МК ATmega328P и кварцевым резонатором на 20 MHz, команда сборки может быть следующей:
$ make MCU=atmega328p F_CPU=20000000
Удостоверимся в отсутствии ошибок сборки и в появлении файла
blink.hex
, содержащего результирующий машинный код в формате Intel hex.
Загрузка и проверка работоспособности
[править]Подключим устройство к USB-порту основной системы. Удостоверимся в появлении соответствующего файла устройства —
/dev/ttyUSB1
или подобного.Проверим возможность связи с загрузчиком Optiboot сохранив образ текущего состояния flash-памяти МК в файл формата Intel hex, подобно:
$ avrdude -P /dev/ttyUSB1 -c arduino -b 115200 -p atmega8 \ -U flash:r:"$(mktemp --suffix=.hex -- ./XXXX)":i avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e9307 avrdude: reading flash memory: Reading | ################################################## | 100% 1.02s avrdude: writing output file "96TF.hex" avrdude: safemode: Fuses OK avrdude done. Thank you. $
- NB
- Для запуска Optiboot, Avrdude пытается выполнить сброс МК кратковременно изменяя состояние линий RTS и DTR. Если эти линии не соединены с цепью Reset МК (так, на некоторых адаптерах эти линии не разведены вовсе), то сброс следует выполнить вручную, подобно:
- ввести команду выше, не завершая ее нажатием ⏎ Enter;
- нажать на кнопку сброса устройства;
- отпустить кнопку сброса и немедленно завершить ввод команды
avrdude
нажатием ⏎ Enter.
Загрузим полученный ранее образ в flash-память МК, подобно:
$ avrdude -P /dev/ttyUSB1 -c arduino -b 115200 \ -p atmega8 -U flash:w:blink.hex:i avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e9307 avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file "blink.hex" avrdude: writing flash (90 bytes): Writing | ################################################## | 100% 0.02s avrdude: 90 bytes of flash written avrdude: verifying flash memory against blink.hex: avrdude: load data flash data from input file blink.hex: avrdude: input file blink.hex contains 90 bytes avrdude: reading on-chip flash data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 90 bytes of flash verified avrdude: safemode: Fuses OK avrdude done. Thank you. $
- NB
- Замечание выше о сбросе устройства и запуске Optiboot остается справедливым и при загрузке образа в МК.
Удостоверимся в правильности работы программы и устройства оценив период вспышек светодиода и сопоставив его с заданным в исходном коде.
Примечания
[править]- ↑ 5.1.2.2.1 Program Startup. WG14 N1570 Committee Draft (2011-04-12). Проверено 19 ноября 2012.
- ↑ 5.1.2.2.3 Program termination. WG14 N1570 Committee Draft (2011-04-12). Проверено 19 ноября 2012.
- ↑ 7.22.4.4 The exit function. WG14 N1570 Committee Draft (2011-04-12). Проверено 19 ноября 2012.