Установка
программного обеспечения.
Запускаем AVR Studio 4.
Почему компилятор AVR GCC?
Вообще существует
несколько компиляторов языка С для микроконтроллеров AVR. Наиболее используемые из других
компиляторов – IAR и Code vision AVR.
Основными
достоинствами AVR GCC являются следующие: только он бесплатный, только он
встраивается в AVR Studio, генерирует самый компактный код, особенно при использовании чисел с плавающей точкой.
К
достоинствам IAR следует отнести то, что только он полностью
поддерживает С++, AVR GCC поддерживает C++, но не полностью.
К
достоинствам Code vision AVR следует отнести наличие в нём генератора начального кода, который
облегчает конфигурирование микроконтроллера и написание некоторых функций,
например для интерфейса 1-Wire или модулей ЖКИ. Кроме того, в Code vision AVR есть возможность подключить отладчики AVR Studio (но не все).
Таким образом,
основными недостатками AVR GCC являются – отсутствие полной поддержки C++ и отсутствие
генератора начального кода. Отсутствие полной поддержки C++ для
микроконтроллеров не очень важно, а генератор начального кода можно с успехом
заменить развитием библиотечных функций WinAVR, дополнять её можно
самостоятельно.
Приступаем к написанию исходного
кода. Структура программы на языке С.
Напишем программу для микроконтроллера ATmega16, которая будет
формировать на всех выводах порта B сигнал «SOS». Если к любому выводу порта B подключить катод
светодиода, а анод подключить к плюсу, через резистор на 560 Ом, то он будет
мигать, передавая сигнал SOS азбукой Морзе.
Программы
обычно начинаются с директив
препроцессора (начинаются с символа "#"), которые, по сути, не
являются конструкциями языка C и обрабатываются
до фактической компиляции программы. Их смысл — подстановка некоторого кода в
программу. Так, к примеру, очень часто используется директива #include, которая включает в файл с исходным кодом программы
текст внешнего заголовочного файла (с расширением .h). Заголовочные
файлы содержат определения глобальных типов, констант, переменных и
функций.
#include <avr/io.h> // Подключение
устройств ввода/вывода в зависимости от типа МК AVR.
#include <avr/delay.h> // Подключаем функции
циклов задержки.
//
Процедура «Пауза», время паузы задаётся из процедур «Точка» и «Тире» параметром
ms.
void Pause(unsigned char ms) // Тип переменной
ms - unsigned char, то есть от 0 до 255.
{
PORTB = 0xFF; // Устанавливаем на всех выводах
порта B лог. 1.
_delay_ms(ms); // Задержка
}
//
Процедура «Точка»
void P(void)
{
PORTB
= 0; //
Устанавливаем на всех выводах порта B лог. 0.
_delay_ms (5); // Короткая задержка.
Pause(5); // Вызов функции Pause, с
параметром 5ms
}
//
Процедура «Тире»
void D(void)
{
PORTB
= 0; //
Устанавливаем на всех выводах порта B лог. 0.
_delay_ms (20); // Длинная задержка.
Pause(5); // Вызов функции Pause, с
параметром 5ms
}
/* Главная
функция программы, отсюда начинает исполняться исходный код, в компиляторе AVR – GCC должна всегда иметь тип возвращения int */
int main (void)
{
DDRB = 0xFF; // Настройка порта B как выхода
while(1) /* Бесконечный цикл (это основная часть программы, она будет крутиться в
этом цикле, поочерёдно вызывая функции точки и тире. */
{
//
Вызываем поочерёдно процедуры «Точка» и «Тире», формируем сигнал SOS.
P(); P(); P();
D(); D(); D();
P(); P(); P();
Pause(100); // Вызываем процедуру «Пауза» с параметром 100
}
}
Комментарий — поясняющий
текст, который при компиляции не учитывается, например:
/*
Многострочный комментарий часто
размещают в начале
файла, где он содержит
имя автора и
описание программы */
#include <avr/io.h> //Подключаем заголовочный
файл io.h
Идентификатор — это
последовательность букв, цифр и символов подчеркивания "'_", которая
не должна начинаться с цифры, используемая для именования различных программных
элементов, - переменных, констант, функций, типов и т.д. Регистр букв имеет
значение. Например, в нашей программе – это - переменная ms, и названия процедур.
Ключевое слово — это
зарезервированное слово четко определенного назначения. Ключевые слова не
могут использоваться в качестве идентификаторов:
asm, auto; bit, bool, break; case, char, const, continue; default, defined, do, double;
else, enum, explicit, extern; false, float, for; goto; if, inline, int; long; register, return;
short, signed, sizeof, static, struct, switch; true,
typedef; union, unsigned; void; while.
Например, в нашей программе – это - char, void и while.
Литерал
— постоянное значение некоторого типа, используемое в выражениях.
Примеры
числовых литералов:
10 — число 10 в десятичной форме;
0хА — число 10 в шестнадцатеричной форме (префикс
0х);
0b1010 — число
10 в двоичной форме (префикс 0b);
012 — число 10 в восьмеричной форме (префикс 0);
10.5 — число с плавающей точкой;
105е-1 — число 10,5 в экспоненциальной форме (105 *
10**-1);
10U —
беззнаковая константа (суффикс U);
10L — знаковая
константа (суффикс L).
Символьные
литералы заключаются в одинарные кавычки, например, 'В', '*'. Для обозначения
непечатаемых и специальных символов в литералах используются так называемые escape-последовательности:
'\а'— звуковой сигнал;
'\b' — клавиша
<Backspace>;
'\f' — прогон
листа;
'\n'— символ
перевода строки;
'\r'— возврат
каретки;
'\t'—
горизонтальная табуляция;
'\v' —
вертикальная табуляция;
'\0'— нулевой символ;
'\\'— обратная косая;
'\''— апостроф.
Кроме
того, любой символ можно представить с помощью литерала по его ASCII-коду, например, литерал '\t' равнозначен '\х09'.
Строковые
литералы ограничиваются двойными кавычками, а в памяти хранятся как
последовательности символов, заканчивающиеся нулевым символом '\0'. Специальные
символы внутри строки должны предваряться обратной косой ("\").
Примеры строковых литералов:
""
— пустая строка: один символ '\0';
"В"
— два символа: 'В' и '\0';
"A\tB\n" — пять символов: 'А', табуляция, 'В', перевод
строки, '\0'.
Например, в нашей программе –
значения пауз, числа 5, 20 и 100 в десятичной форме.
Оператор
— это символ, указывающий компилятору, какие действия выполнить над
операндами. Некоторые символы могут трактоваться по-разному в зависимости от
контекста. Например, знак "-" может использоваться для изменения
знака числа или в качестве оператора вычитания. Операторы, соединяющие операнды,
представляют собой выражения. Выражения могут быть заключены в круглые скобки и
отделяются друг от друга символом точки с запятой (";").
Приоритет
(по убыванию) выполнения операторов
в выражениях языка C указан ниже.
Уровень |
Операторы |
Категория |
Описание |
1 |
( ) |
|
Круглые скобки |
[ ] |
|
Элемент массива |
|
. |
Доступ к данным |
Обращение к элементу структуры, например: portb .
1 — разряд 1 порта В. |
|
-> |
|
Обращение к элементу структуры, определенной указателем, например: pStruct -> x — элемент х структуры, на которую указывает pStruct |
|
++, --(постфиксы) |
Арифметические |
Операторы автоинкремента и автодекремента после того как выражение, в котором задействованы соответствующие операнды, вычислено. Примеры: а = b++; равнозначно а = b; b = b+1; а = b—; равнозначно а = Ь; b = b-1; |
|
2 |
++, --(префиксы) |
|
Операторы автоинкремента и автодекремента перед тем как выражение, в котором задействованы соответствующие операнды, будет вычислено. Примеры: а = ++Ь; равнозначно b = b+1; a = b;
а = —b;
равнозначно b = b-1; a = b; |
! |
Логические |
Логическое (унарное) отрицание |
|
~ |
Поразрядные |
Поразрядное отрицание |
|
& |
Доступ к данным |
Адрес |
|
3 |
+, -(унарные) |
Арифметические |
Изменение знака операнда |
*
(унарный) |
Доступ к данным |
Разыменование указателя |
|
4 |
*
(бинарные) |
Арифметические |
Умножение |
/ |
|
Деление |
|
% |
|
Остаток от деления |
|
5 |
+, -(бинарные) |
|
Сложение и вычитание |
6 |
<< |
Поразрядные |
Поразрядный сдвиг влево |
>> |
|
Поразрядный сдвиг вправо |
|
7 |
<, >, <=, >= |
Сравнения |
Меньше, больше и т.д. |
8 |
==, ! = |
|
Равно, не равно |
9 |
& |
Поразрядные |
Поразрядное "И" |
10 |
^ |
Поразрядные |
Поразрядное "Исключающее ИЛИ" |
11 |
| |
Поразрядные |
Поразрядное "ИЛИ" |
12 |
&& |
Логические |
Логическое "И" |
13 |
|| |
Логические |
Логическое "ИЛИ" |
14 |
= |
Присваивание |
Возможны также сочетания оператора присваивания с арифметическими и поразрядными операторами, например: а += Ь; равнозначно а = а + b; а *= b+с; равнозначно а = а * (b + с) ; |
С
оператором присваивания используются вот такие сокращения:
ДЛИННАЯ ЗАПИСЬ |
СМЫСЛ |
СОКРАЩАЕТСЯ ДО |
x = x + 1; |
добавить 1 |
x++; или ++x; или x += 1; |
x = x - 1; |
вычесть 1 |
x--; или --x; или x -= 1; |
x = x + y; |
прибавить y |
x += y; |
x = x - y; |
вычесть y |
x -= y; |
x = x * y; |
умножить на y |
x *= y; |
x = x / y; |
поделить на y |
x /= y; |
x = x % y; |
остаток от деления |
x %= y; |
Кроме
знаков +,-,*,/,% могут стоять поразрядные и побитные операторы. При сокращённой записи между знаками нельзя ставить
пробел!
Когда
инкремент или декремент используется в выражении то важно где стоят два знака +
или - перед переменной или после
переменной:
a=4, b=7;
a = b++; /*
Эта строчка на Си означает: взять значение переменной b присвоить его
переменной a затем добавить 1 к переменной b
и сохранить результат в b. Теперь a = 7; b = 8 */
a=4, b=7;
a = ++b; /* Эта строчка на Си означает: взять значение
переменной b затем добавить к нему 1 и сохранить результат в b и этот же
результат присвоить переменной a. Теперь
a = 8, b = 8. */
Объединенные
по некоторому признаку последовательности выражений заключаются в фигурные
скобки:
{
PORTB = 0xFF; // Устанавливаем на всех выводах
порта B лог. 1.
_delay_ms(ms); // Задержка
}.
Так,
к примеру, обозначаются границы функций, а также блоки выражений в циклических
и условных конструкциях (см. ниже соответствующие разделы).