В этом примере мы напишем нашу первую программу на Си для микроконтроллера ATtiny13. Предполагается, что у нас уже подготовлено к работе всё необходимое: среда разработки, компилятор и т.д. Подопытным у меня будет самодельная отладочная плата, соответственно весь код буду приводить применительно к ней.
В качестве тестовой программы напишем классический, простейший пример «blink», который будет мигать светодиодом с определённой частотой.
Итак, создаём новый проект и приступаем. Приведу сразу полный код программы, а затем поясню всё более подробно:
/*
* tiny13_board_blink
* Демо-прошивка отладочной платы на ATtiny13
* с целью проверки работоспособности МК.
* Мигаем светодиодом.
*/
#define F_CPU 1200000UL // Указываем тактовую частоту МК
#define LED PB2 // Используем светодиод, подключенный к PB2 (7 пин)
#include <avr/io.h> // Подключаем определения ввода/вывода
#include <util/delay.h> // Подключаем библиотеку функций задержки
int main(void)
{
// Светодиод
DDRB |= (1<<LED); // конфигурируем пин как выход
PORTB &= ~(1<<LED); // по умолчанию светодиод выключен
// Основной цикл
while (1)
{
_delay_ms (500); // задержка 500 мс
PORTB ^= (1<<LED); // инвертируем состояние пина
}
}
В самом начале задаём значения констант и подключаем заголовочные файлы и библиотеки.
Файл avr/io.h подключает определения ввода/вывода для конкретного типа микроконтроллера (тип МК указывается в виде опции для компилятора).
Библиотеку util/delay.h подключаем для использования функций задержки, в нашем случае: _delay_ms(). Для работы функций задержки мы должны указать тактовую частоту процессора. Поэтому ДО подключения util/delay.h определяем константу F_CPU (в данном случае — 1,2МГц).
Затем у нас идёт основная функция main — это, собственно, тело нашей программы. Здесь мы должны сначала описать все действия, которые будут происходить при старте микроконтроллера, а затем, в бесконечном цикле запустить выполнение основной программы:
while (1) { ... }
Для начала, мы должны сконфигурировать порт ввода/вывода. В МК AVR старших моделей портов в/в может быть несколько (A, B, C, D). К каждому порту может быть подключено до восьми ножек. Каждая из ножек может быть настроена как на вход, так и на выход. ATtiny13 имеет только один порт (B), к которому подключены шесть ножек (PB0-PB5, см. datasheet). По умолчанию все ножки настроены на вход, а чтобы управлять светодиодом, мы должны использовать соответствующую ножку как выход. В микроконтроллерах AVR вся аппаратная часть настраивается посредством восьмибитных регистров. Направление (вход-выход) устанавливается битами регистров DDRx (где x — буква порта, в нашем случае B). Значение бита «0» — соответствует входу, «1» — выходу. Таким образом, чтобы использовать ножку PB2, как выход, мы должны установить второй бит регистра DDRB в единицу:
DDRB |= (1<<PB2);
Для управления состоянием выхода предназначены регистры PORTx. Например, чтобы выключить светодиод, подключенный к ножке PB2 (подать низкий уровень сигнала), мы должны записать ноль во второй бит регистра PORTB:
PORTB &= ~(1<<PB2);
Чтобы включить (подать высокий уровень сигнала) — соответственно, записываем единицу:
PORTB |= (1<<PB2);
Теперь, когда порт в/в сконфигурирован, мы запускаем основной цикл, в котором будем инвертировать состояние выхода PB2 (чередовать высокий и низкий уровень сигнала) с задержкой 500мс. Таким образом, светодиод у нас будет мигать с частотой 1 раз в секунду.
Полезные ссылки:
ATtiny13 Datasheet (официальный)
ATtiny13 Datasheet (урезанный вариант)
Доступ к портам I/O AVR на языке C (GCC, WinAVR)
Операторы управления битами