В этой статье я расскажу о том, как программировать микроконтроллеры без использования Arduino. Мы будем использовать программатор AvrISP STK500 для программирования контроллера ATtiny84.
Arduino мы не используем, поэтому обо всем нам придется думать самостоятельно. И первое, с чем необходимо разобраться — питание. Мы будем использовать преобразователь L7805, обладающей следующими характеристиками:
Теперь нам надо узнать схему подключения этого преобразователя. Ее мы найдем на странице 3 даташита.
Помимо самого преобразователя, мы видим еще 2 конденсатора — входной Сi и выходной Сo. Входной конденсатор необходим для того, чтобы сгладить пульсации на входе в случае удаленности L7805 от источника. В нашем случае длина соединительных проводов не будет превышать 15 см, поэтому входного конденсатора у нас не будет. Зато будет выходной, поскольку мы хотим «кормить» наш контроллер стабильным питанием.
В качестве программатора мы использовали AvrISP STK500 от Seeed Studio. Для его работы под Windows и Mac OS необходимы драйверы. Их можно скачать с официального сайта. Пользователям Linux устанавливать ничего не нужно — программатор будет сразу готов к работе.
Распиновка разъема программатора такова:
Важно! Это распиновка разъема программатора, если смотреть на него сверху (отверстиями от себя). Не перепутайте!
Разъем программатора необходимо подключить к микроконтроллеру. Можно использовать как 10-пиновый разъём, так и 6-пиновый. Без разницы. Соединим проводами соответствующие пины, т.е:
10-пиновый ICSP | ATtiny84 | |
---|---|---|
Reset | 5 | 4 |
MOSI | 1 | 7 |
MISO | 9 | 8 |
SCK | 7 | 9 |
Напишем код прошивки на чистом «C», которая заставит светодиод мигать. Использование ШИМ-сигналов и считывание аналоговых сигналов на чистом «C» не так тривиальна, и может являться темой отдельной статьи, поэтому остановимся пока на простейшем примере.
#include <avr/io.h> #include <util/delay.h> 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()
.
Далее начинается самое интересное. Нам нужно скомпилировать и загрузить прошивку. Однако, в зависимости от вашей операционной системы, методика будет различаться.
Первым делом необходимо скачать и установить CrossPack for AVR Development. Это даст нам все необходимые инструменты. CrossPack состоит из двух частей.
Первая нам нужна для написания кода и создания файла прошивки, а вторая — для заливки прошивки в контроллер.
Проект создается в три шага.
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-битов может привезти к тому, что микроконтроллер перестанет работать и вернуть его к нормальной жизни может быть либо очень сложно либо невозможно! Воспользеумся сайтом AVR Fuse Calcuator.
Сначала из выпадающего списка выберем нужный нам контроллер (ATtiny84).
И затем укажем необходимые опции, которые нам нужны. Сейчас для нас важны 2 вещи: сохранение возможности прошивать контроллер через SPI и сохранение его работоспособности без внешнего резонатора, поэтому выбираем соответствующие пункты, а остальные оставляем по умолчанию.
Видим, как поменялись сгенерированные значения.
Внесем изменения в 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.
Все, прошивка контроллера завершена.
Здесь все проще.
Первым делом необходимо скачать и уствновить среду разработки для AVR — Atmel AVR Studio 4. А вторым — Atmel AVR Toolchain.
После запуска среды, необходимо создать новый проект.
Затем указать имя, расположение и то, что мы хотим использовать С (GCC
).
Третий шаг — настройка отладчика.
На этом все, проект готов к использованию. Теперь необходимо написать и сохранить исходник, который мы уже обсудили.
В результате общий вид среды разработки выглядит вот так:
Теперь необходимо подключиться к программатору. Делается это с помощью нажатия на кнопку con
.
В качестве Platform
выбираем STK500
, а в Port
— Auto
. Затем нажимаем Connect.
Если все правильно, то в открывшемся окне выбираем вкладку Main
и нажимаем в ней на кнопку Read Signature
.
Строка Reading signature from device .. 0x1E, 0x93, 0x0C .. OK!
говорит о том, что все хорошо и сигнатура успешно прочиталась. Сигнатура — это своего рода позывной микроконтроллера, которым он сообщает собственную модель.
Это окно нельзя закрывать, иначе соединение с программатором будет потеряно. Просто сверните его.
Теперь нажмем Build → Build
. Это заставит программу скомпилироваться.
Прошьем контроллер с помощью кнопки Write Flash Memory Using Current Settings
— это заставит скомпилированную программу загрузиться в память микроконтроллера.
Мы собрали простейшее устройство мигалку, но сделали это на низком уровне. С использованием программатора и «продвинутой» среды разработки, а не Arduino.
Разобравшись в премудростях программирования микроконтроллеров на чистом «Си», вы сможете выжимать из них максимум возможности, затрачивая при этом минимум места и денег.