====== Работа с микроконтроллерами: прошивка программатором и чистый «Си» ======
В этой статье я расскажу о том, как программировать микроконтроллеры без использования Arduino. Мы будем использовать программатор AvrISP STK500 для программирования контроллера ATtiny84.
===== Нам понадобится =====
{{ :программирование:hardcore2-avr-list3.jpg? |}}
* [[amp>product/avrisp-stk500-programmer|Программатор AvrISP STK500]]
* [[amp>product/led-5mm|Светодиоды]]
* [[amp>product/resistor|Резисторы]]
* [[amp>product/wire-mm|Провода «папа-папа»]]
* [[amp>product/avr-attiny84|Микроконтроллер ATtiny84]]
* [[amp>|Клеммник]]
* [[amp>|Батарейка «Крона»]]
* [[amp>|Преобразователь напряжения]]
===== Подключаем питание =====
Arduino мы не используем, поэтому обо всем нам придется думать самостоятельно. И первое, с чем необходимо разобраться --- питание. Мы будем использовать преобразователь L7805, обладающей следующими характеристиками:
* Выходной ток до 1.5 А
* Выходное напряжение — ровные 5 В
* Защита от перегрева
* Защита от короткого замыкания
Теперь нам надо узнать схему подключения этого преобразователя. Ее мы найдем на странице 3 [[http://files.amperka.ru/datasheets/l78xx.pdf|даташита]].
{{ :программирование:hardcore2-l7805-circuit.jpg? |}}
Помимо самого преобразователя, мы видим еще 2 конденсатора --- входной Сi и выходной Сo. Входной конденсатор необходим для того, чтобы сгладить пульсации на входе в случае удаленности L7805 от источника. В нашем случае длина соединительных проводов не будет превышать 15 см, поэтому входного конденсатора у нас не будет. Зато будет выходной, поскольку мы хотим «кормить» наш контроллер стабильным питанием.
==== Распиновка ====
Необходимо знать назначение ножек преобразователя. Это описано на 2-й странице даташита.
{{ :программирование:hardcore2-l7805-pinout.jpg? |}}
==== Схема ====
С учетом всего вышеописанного, получается схема для организации питания.
{{ :программирование:hardcore2-l7805-connected2.jpg? |}}
===== Программатор =====
В качестве программатора мы использовали AvrISP STK500 от Seeed Studio. Для его работы под Windows и Mac OS необходимы драйверы. Их можно скачать с [[http://prolificusa.com/pl-2303hx-drivers/|официального сайта]]. Пользователям Linux устанавливать ничего не нужно — программатор будет сразу готов к работе.
==== Подключение к контроллеру ====
Распиновка разъема программатора такова:
{{:программирование:avr_isp.jpg?nolink&}}
**Важно!**
Это распиновка разъема программатора, если смотреть на него сверху (отверстиями от себя). Не перепутайте!
{{ :программирование:hardcore2-connection3.jpg? |}}
Разъем программатора необходимо подключить к микроконтроллеру. Можно использовать как 10-пиновый разъём, так и 6-пиновый. Без разницы. Соединим проводами соответствующие пины, т.е:
| ^ 10-пиновый ICSP ^ ATtiny84 ^
^ Reset | 5 | 4 |
^ MOSI | 1 | 7 |
^ MISO | 9 | 8 |
^ SCK | 7 | 9 |
===== Прошивка =====
Напишем код прошивки на чистом «C», которая заставит светодиод мигать. Использование ШИМ-сигналов и считывание аналоговых сигналов на чистом «C» не так тривиальна, и может являться темой отдельной статьи, поэтому остановимся пока на простейшем примере.
#include
#include
int main(void) {
// номер пина 2 в порту А -- на выход
DDRA = 1 << 2;
// основной цикл
while (1==1) {
_delay_ms(500); // задержка 500 мс
PORTA ^= 1 << 2; // инвертирование значения на выводе
}
return 0;
}
После скетчей Arduino, код малопонятен, правда? Ничего, сейчас я объясню, что да как.
В первых двух строчках мы подключаем необходимые библиотеки, чтобы воспользоваться такими штуками, как ''DDRA'', ''PORTA'', ''_delay_ms''.
Что же такое ''DDRA''?
Это регистр микроконтроллера, управляющий направлением работы порта А. Он содержит в себе 8 бит. Если установить какой-то бит в 1, то пин с соответствующим номером станет выходом.
''PORTA'' --- тоже регистр, но он содержит в себе данные порта А. Если мы хотим на вывод номер 2 записать логическую единицу, то мы должны поместить 1 в соответсвующий бит регистра.
А ''_delay_ms'' --- функция задержки.
Исходя из этого можно составить таблицу соответствия:
| ^ Arduino ^ C ^
^ Направление | ''pinMode(led, OUTPUT);'' | ''DDRA = 1 %%<<%% 2;'' |
^ Значение | ''digitalWrite(led, HIGH);''| ''PORTA = 1 %%<<%% 2;'' |
^ Задержка | ''delay(1000); '' | ''_delay_ms(50); '' |
Однако, самым важным различием кода является то, что в программе на С нет разделений функций ''setup'' и ''loop''. За все это отвечает функция ''int main(void)''. И она выполняется всего 1 раз! А мы хотим, чтобы наш светодиод моргал не один раз, а постоянно. Как раз для этого и используется бесконечный цикл ''while (1==1)''.
Поэтому легко сделать вывод, что этот цикл и есть аналог функции ''loop()'' в Arduino. А то, что до него --- аналог функции ''setup()''.
Далее начинается самое интересное. Нам нужно скомпилировать и загрузить прошивку. Однако, в зависимости от вашей операционной системы, методика будет различаться.
==== Mac OS X ====
Первым делом необходимо [[http://www.obdev.at/products/crosspack/download.html|скачать]] и установить CrossPack for AVR Development. Это даст нам все необходимые инструменты.
CrossPack состоит из двух частей.
- AVR Libc --- a C library for GCC on AVR microcontrollers
- AVRDUDE --- AVR Downloader/Uploader
Первая нам нужна для написания кода и создания файла прошивки, а вторая --- для заливки прошивки в контроллер.
Проект создается в три шага.
- Запустите терминал
- Перейдите в нем в нужную папку
- Создайте проект с помощью команды ''avr-project''
$ mkdir ~/AVR
$ cd AVR
$ avr-project firstProject
Using template: /usr/local/CrossPack-AVR-20130212/etc/templates/TemplateProject
В результате будет создано следующее дерево файлов.
$ tree
.
|-- firmware
| |-- main.c
| `-- Makefile
`-- firstProject.xcodeproj
1 directory, 3 files
На данном этапе нас интересует содержимое файла ''Makefile''. В нем содержится информация о том, что вообще мы используем: какой контроллер, программатор. Это все описывается в строках с 20 по 24:
DEVICE = atmega8
CLOCK = 8000000
PROGRAMMER = #-c stk500v2 -P avrdoper
OBJECTS = main.o
FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
Пройдемся по строкам:
- ''DEVICE'' содержит в себе название контроллера, который мы программируем
- ''CLOCK'' --- частота работы
- ''PROGRAMMER'' --- используемый программатор
- ''OBJECTS'' --- какие объектные файлы будут сгененрированы
- ''FUSES'' --- конфигурация fuse-битов в микроконтроллере
Это автосгенерированный make-файл, поэтому нам необходимо вручную его подправить. Править будем строку ''DEVICE'' у нас же микроконтроллер ''attiny84'' и строку ''FUSES''. А вот с ней все сложнее.
Fuse-биты, или просто <<фьюзы>> --- два (иногда три) особых байта, в которых содержится фундаментальая конфигурация работы контроллера. Очень важно правильно их задать.
**Внимание!
Задание неверных fuse-битов может привезти к тому, что микроконтроллер перестанет работать и вернуть его к нормальной жизни может быть либо очень сложно либо невозможно!**
Воспользеумся сайтом [[http://www.frank-zhao.com/fusecalc/fusecalc.php?chip=attiny84&LOW=E2&HIGH=DF&EXTENDED=FF&LOCKBIT=FF|AVR Fuse Calcuator]].
Сначала из выпадающего списка выберем нужный нам контроллер (ATtiny84).
{{ :программирование:hardcore2-avr-fuse4.png? |}}
И затем укажем необходимые опции, которые нам нужны. Сейчас для нас важны 2 вещи: сохранение возможности прошивать контроллер через SPI и сохранение его работоспособности без внешнего резонатора, поэтому выбираем соответствующие пункты, а остальные оставляем по умолчанию.
{{ :программирование:hardcore2-avr-fuse6.png? |}}
Видим, как поменялись сгенерированные значения.
{{ :программирование:hardcore2-avr-fuse7.png?700 |}}
Внесем изменения в Makefile.
DEVICE = attiny84
CLOCK = 8000000
PROGRAMMER = -c stk500v2 -P /dev/tty.usbserial
OBJECTS = main.o
FUSES = -U lfuse:w:0xe2:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m
=== Прошивка ===
Она происходит в 2 этапа.
Сначала необходимо перейти в папку ''firmware'' и выполнить команду ''make''. Если ошибок нет, то результат выполнения команды будет таким:
$ make
avr-gcc -Wall -Os -DF_CPU=8000000 -mmcu=attiny84 -c main.c -o main.o
avr-gcc -Wall -Os -DF_CPU=8000000 -mmcu=attiny84 -o main.elf main.o
rm -f main.hex
avr-objcopy -j .text -j .data -O ihex main.elf main.hex
avr-size --format=avr --mcu=attiny84 main.elf
AVR Memory Usage
----------------
Device: attiny84
Program: 126 bytes (1.5% Full)
(.text + .data + .bootloader)
Data: 0 bytes (0.0% Full)
(.data + .bss + .noinit)
Эта команда сделает из нашего исходника ''main.c'' файл, пригодный для заливки в контроллер --- ''main.hex''.
Второй этап --- как раз заливка прошивки. Делается это с помощью команды ''make flash''. Ее нормальный вывод выглядит следующим образом:
$ make flash
avrdude -c stk500v2 -P /dev/tty.usbserial -p attiny84 -U flash:w:main.hex:i
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude: Device signature = 0x1e930c
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 "main.hex"
avrdude: writing flash (126 bytes):
Writing | ################################################## | 100% 0.10s
avrdude: 126 bytes of flash written
avrdude: verifying flash memory against main.hex:
avrdude: load data flash data from input file main.hex:
avrdude: input file main.hex contains 126 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 0.08s
avrdude: verifying ...
avrdude: 126 bytes of flash verified
avrdude: safemode: Fuses OK
avrdude done. Thank you.
Все, прошивка контроллера завершена.
==== Windows ====
Здесь все проще.
Первым делом необходимо скачать и уствновить среду разработки для AVR --- [[http://www.atmel.com/System/BaseForm.aspx?target=tcm:26-17924|Atmel AVR Studio 4]]. А вторым --- [[http://www.atmel.com/tools/ATMELAVRTOOLCHAINFORWINDOWS.aspx|Atmel AVR Toolchain]].
После запуска среды, необходимо создать новый проект.
{{ :программирование:hardcore2-avrstudio-project.png? |}}
Затем указать имя, расположение и то, что мы хотим использовать С (''GCC'').
{{ :программирование:hardcore2-avrstudio-project2.png? |}}
Третий шаг --- настройка отладчика.
{{ :программирование:hardcore2-avrstudio-project3.png? |}}
На этом все, проект готов к использованию.
Теперь необходимо написать и сохранить исходник, который мы уже обсудили.
В результате общий вид среды разработки выглядит вот так:
{{ :программирование:hardcore2-avrstudio-main.png?700 |}}
Теперь необходимо подключиться к программатору. Делается это с помощью нажатия на кнопку ''con''.
{{ :программирование:hardcore2-avrstudio-connection1.png? |}}
В качестве ''Platform'' выбираем ''STK500'', а в ''Port'' --- ''Auto''. Затем нажимаем Connect.
{{ :программирование:hardcore2-avrstudio-connection2.png? |}}
Если все правильно, то в открывшемся окне выбираем вкладку ''Main'' и нажимаем в ней на кнопку ''Read Signature''.
{{ :программирование:hardcore2-avrstudio-signature.png? |}}
Строка ''Reading signature from device .. 0x1E, 0x93, 0x0C .. OK!'' говорит о том, что все хорошо и сигнатура успешно прочиталась. Сигнатура — это своего рода позывной микроконтроллера, которым он сообщает собственную модель.
Это окно нельзя закрывать, иначе соединение с программатором будет потеряно. Просто сверните его.
Теперь нажмем ''Build -> Build''. Это заставит программу скомпилироваться.
Прошьем контроллер с помощью кнопки ''Write Flash Memory Using Current Settings'' — это заставит скомпилированную программу загрузиться в память микроконтроллера.
{{ :программирование:hardcore2-avrstudio-flash.png? |}}
===== Заключение =====
Мы собрали простейшее устройство мигалку, но сделали это на низком уровне. С использованием программатора и «продвинутой» среды разработки, а не Arduino.
{{ :программирование:hardcore2-result2.jpg?nolink& |}}
Разобравшись в премудростях программирования микроконтроллеров на чистом «Си», вы сможете выжимать из них максимум возможности, затрачивая при этом минимум места и денег.