Задача: Разработаем программу управления одним светодиодом. При нажатии на кнопку светодиод горит, при отпускании гаснет.
Для начала разработаем принципиальную схему устройства. Для подключения к микроконтроллеру любых внешних устройств используются порты ввода-вывода. Каждый из портов способен работать как на вход так и на выход. Подключим светодиод к одному из портов, а кнопку к другому. Для этого опыта мы будем использовать контроллер Atmega8. Эта микросхема содержит 3 порта ввода-вывода, имеет 2 восьмиразрядных и 1 шестнадцатиразрядный таймер/счетчик. Также на борту имеется 3-х канальный ШИМ, 6-ти канальный 10-ти битный аналого-цифровой преобразователь и многое другое. По моему мнению микроконтроллер прекрасно подходит для изучения основ программирования.
Для подключения светодиода мы будем использовать линию PB0, а для считывания информации с кнопки воспользуемся линией PD0. Схема приведена на рис.1.
Через резистор R2 на вход PD0 подается плюс напряжения питания, что соответствует сигналу логической единице. При замыкании кнопки напряжение падает до нуля, что соответствует логическому нулю. В дальнейшем R2 можно исключить из схемы, заменяя его на внутренний нагрузочный резистор, введя необходимые настройки в программе. Светодиод подключен к выходу порта PB0 через токоограничивающий резистор R3. Для того чтобы зажечь светодиод надо подать в линию PB0 сигнал логической единицы. Задающий тактовый генератор будем использовать внутренний на 4MHz, так как в устройстве нет высоких требований к стабильности частоты.
Теперь пишем программу. Для написания программ я использую программную среду AVR Studio и WinAvr. Открываем AVR Studio, всплывает окошко приветствия, нажимаем кнопку "Создать новый проект" (New project), далее выбираем тип проекта - AVR GCC, пишем имя проекта например "cod1", ставим обе галочки "Создать папку проекта" и "Создать файл инициализации", нажимаем кнопку "Далее", в левом окошке выбираем "AVR Simulator", а в правом тип микроконтроллера "Atmega8", нажимаем кнопку "Финиш", открывается редактор и дерево категорий проекта - начальные установки закончены.
Для начала добавим стандартный текст описаний для Atmega8 с помощью оператора присоединения внешних файлов: #include
синтаксис директивы #include
#include <имя_файла.h>
#include “имя_файла.h”
Угловые скобки < и > указывают компилятору, что подключаемые файлы нужно сначала искать в стандартной папке WinAvr с именем include. Двойные кавычки “ и “ указывают компилятору начинать поиск с директории, в которой хранится проект.
Для каждого типа микроконтроллера есть свой заголовочный файл. Для ATMega8 этот файл называется iom8.h, для ATtiny2313 – iotn2313.h. В начале каждой программы мы должны подключать заголовочный файл того микроконтроллера, который мы используем. Но есть и общий заголовочный файл io.h. Препроцессор обрабатывает этот файл и в зависимости от настроек проекта включает в нашу программу нужный заголовочный файл.
Для нас первая строчка программы будет выглядеть вот так:
#include <avr/io.h>
Любая программа на языке Си должна обязательно содержать одну главную функцию. Она имеет имя main. Выполнение программы всегда начинается с выполнения функции main. У функции есть заголовок – int main(void) и тело – оно ограниченно фигурными скобками {}.
int main(void)
{
тело функции
}
В тело функции мы и будем добавлять наш код. Перед именем функции указывается тип возвращаемого значения. Если функция не возвращает значение – используется ключевое void.
int – это целое 2-х байтное число, диапазон значений от – 32768 до 32767
После имени функции в скобках () указываются параметры, которые передаются функции при ее вызове. Если функция без параметров – используется ключевое слово void. Функция main содержит в себе набор команд, настройки системы и главный цикл программы.
Далее настраиваем порт D на вход. Режим работы порта определяется содержимым регистра DDRD(регистр направления передачи информации). Записываем в этот регистр число "0x00" (0b0000000 – в двоичном виде), кроме кнопки к этому порту ничего не подключено, поэтому настраиваем весь порт D на вход. Настроить порт поразрядно можно записав в каждый бит регистра числа 0 или 1 (0-вход, 1-выход), например DDRD = 0x81 (0b10000001) - первая и последняя линия порта D работают на выход, остальные на вход. Необходимо также подключить внутренний нагрузочный резистор. Включением и отключением внутренних резисторов управляет регистр PORTx, если порт находится в режиме ввода. Запишем туда единицы.
Настраиваем порт B на выход. Режим работы порта определяется содержимым регистра DDRB. Ничего кроме светодиода к порту B не подключено, поэтому можно весь порт настроить на выход. Это делается записью в регистр DDRB числа "0xFF". Для того чтобы при первом включении светодиод не загорелся запишем в порт B логические нули. Это делается записью PORTB = 0x00;
Для присвоения значений используется символ "=" и называется оператором присваивания, нельзя путать со знаком "равно"
Настройка портов будет выглядеть так:
DDRD = 0x00;
PORTD = 0xFF;
DDRB = 0xFF;
PORTB = 0x00;
Пишем основной цикл программы. while ("пока" с англ.) - эта команда организует цикл, многократно повторяя тело цикла до тех пор пока выполняется условие, т. е пока выражение в скобках является истинным. В языке Си принято считать , что выражение истинно, если оно не равно нулю, и ложно, если равно.
Команда выглядит следующим образом:
while (условие)
{
тело цикла
}
В нашем случае основной цикл будет состоять лишь из одной команды. Эта команда присваивает регистру PORTB инвертируемое значение регистра PORTD.
PORTB = ~PIND; //взять значение из порта D, проинвертировать его и присвоить PORTB (записать в PORTB)
// выражения на языке Си читаются справа налево
PIND регистр ввода информации. Для того, чтобы прочитать информацию с внешнего вывода контроллера, нужно сначала перевести нужный разряд порта в режим ввода. То есть записать в соответствующий бит регистра DDRx ноль. Только после этого на данный вывод можно подавать цифровой сигнал с внешнего устройства. Далее микроконтроллер прочитает байт из регистра PINx. Содержимое соответствующего бита соответствует сигналу на внешнем выводе порта. Наша программа готова и выглядит так:
#include <avr/io.h> int main (void) { DDRD = 0x00; //порт D - вход PORTD = 0xFF; //подключаем нагрузочный резистор DDRB = 0xFF; //порт B - выход PORTB = 0x00; //устанавливаем 0 на выходе while(1) { PORTB = ~PIND; //~ знак поразрядного инвертирования } }
В языке Си широко используются комментарии. Есть два способа написания.
/*Комментарий*/
//Комментарий
При этом компилятор не будет обращать внимание на то что написано в комментарии.
Если используя эту же программу и подключить к микроконтроллеру 8 кнопок и 8 светодиодов, как показано на рисунке 2, то будет понятно что каждый бит порта D соответствует своему биту порта B. Нажимая кнопку SB1 - загорается HL1, нажимая кнопку SB2 - загорается HL2 и т.д.
Рисунок 2
В статье были использованы материалы из книги Белова А.В. "Самоучитель разработчика устройств на AVR"
Комментарии
Можно так
Код:
if((PIND&(1 << PD0)) == 0) // Если кнопка нажата
{
PORTB |= (1 << PB0); // Зажигаем светодиод
_delay_ms(1000); // Ждем 1 сек.
PORTB &= ~(1 << PB0); // Гасим светодиод
while((PIND&(1 << PD0)) == 0); // Ждем отпускания кнопки
}
ну и добавить заголовочный файл util/delay.h
DDRD=0x00(0b00000000)
после х первый ноль старший байт, потом младший байт? и в двоичной форме биты в байтах слева направо от младшего или наоборот?
Счет идет справа налево, сначала младшие байты(биты) потом старшие байты(биты)
Пишите, обсудим vk.com/antonchip