phreaking АЛЕКСЕЙ «CLUSTER» АВДЮХИН / CLUSTERRR@CLUSTERRR.COM / ВЫСОКИЙ УРОВЕНЬ ПРОГРАММИРОВАНИЯ Пишем на Си под AVR Программисты микроконтроллеров всегда делились на тех, кто пишет на ассемблере, и тех, кто предпочитает высокоуровневые языки программирования. Обе группы готовы бесконечно доказывать, что их язык лучше. И каждая права по-своему. Ассемблер обычно используют профессионалы, которые давно знакомы с микроконтроллерами. Но зачем учить язык тем, кто только начинает осваивать новую архитектуру? Я расскажу, как программировать на Си под микроконтроллеры AVR. >> phreaking ВЫБОР КОМПИЛЯТОРА Существует несколько компиляторов Си под AVR, включая официальный от Atmel. Я предпочитаю использовать WinAVR (произносится, как «whenever»). Этот пакет представляет набор бесплатных утилит под винду, включая компилятор AVR-GCC, консольный отладчик и даже софт для прошивки, который умеет работать с самыми разными программаторами. Далее я буду рассматривать именно WinAVR, поэтому рекомендую установить его. Домашняя страничка проекта находится по адресу: http://winavr.sourceforge.net, но ты можешь взять свежую версию на нашем диске. Обрати внимание, что почти все утилиты в этом пакете консольные. Если ты уже знаком с GCC, то тебе не привыкать. Можно использовать для него соответствующую оболочку-редактор. Именно для таких целей в комплекте идет Programmer’s Notepad. Я же предпочитаю писать код в обычном текстовом редакторе и компилировать его командой «make». Это дело вкуса и привычки. РЕГИСТРЫ, РЕГИСТРЫ, РЕГИСТРЫ... Неоспоримое преимущество Си в переносимости. Один и тот же код зачастую можно легко скомпилировать под разные платформы. Однако программе нужно как-то взаимодействовать с внешним миром, которым является операционная система или аппаратная часть. В случае с софтом под Windows и *nix для этого используются вызовы системных функций. В микроконтроллерах же нет операционной системы, и мы будем напрямую взаимодействовать с железом. Делается это с помощью 104 регистров, которые, по сути, являются ячейками в памяти микроконтроллера. Так, если ты хочешь работать с модулями микроконтроллера, будь то таймеры, компараторы, USART или просто ноги, тебе придется писать данные в регистры. Этим я хочу сказать, что если ты уже сейчас без проблем кодишь на Си, то единственное, что тебе осталось изучить — это регистры микроконтроллера. У каждой АВРки они свои. Cписок и подробное описание ты сможешь найти в соответствующем даташите. Однако базовые принципы для каждой модели очень похожи. Давай рассмотрим основные регистры, с которыми ты, наверняка, будешь играться в первую очередь: DDRx, PORTx и PINx. Отвечают они непосредственно за управление ногами микроконтроллера. Немного поясню для тех, кто не в теме. В каждой АВРке все ноги делятся на порты, которые обозначаются латинскими буквами A, B, C и т.д. Каждый может содержать до восьми ног, которые номеруются цифрами от 0 до 7. Скачай даташит к своему микроконтроллеру. На первых страницах ты найдешь рисунок с распиновкой, где подписано, какая нога за что отвечает. Обрати внимание на надписи типа PB0, PC1 и т.п. Именно они указывают букву порта и номер ноги. Например, строка «PA7» означает, что мы имеем дело с седьмой ногой на порту A. Существует набор регистров DDRx, PORTx и PINx, которые у каждого порта свои. Соответственно, вместо «x» нужно подставить соответствующую букву. Например, для управления портом «B» используются регистры DDRB, PORTB и PINB. Каждый из них размером всего в 1 байт. Нетрудно догадаться, что каждый бит при этом отвечает за соответствующую ногу. XÀÊÅÐ 07 /127/ 09
phreaking «ПИШЕМ НА СИ ПОД AVR» УСТРОЙСТВО С ДИСПЛЕЕМ В ДЕЙСТВИИ Итак, DDRx регистры определяют направление данных — ввод или вывод. PORTx позволяют задать состояние ноги — логическая единица или логический ноль, а также включать подтягивающий резистор. Регистры PINx рассчитаны только на чтение и позволяют определить уровень на ноге, когда она работает на ввод. Ну, хватит нудной теории. Рекомендую внимательно почитать даташиты, а пока разберем простейший пример: Моргаем светодиодом #define F_CPU 8000000UL #include #include int main (void) { DDRB |= (1