Изменения частоты мигания светодиода на avr. Мигаем светодиодами на AVR без Arduino

16.01.2024

На этом уроке Вы научитесь программировать свою плату Arduino на примере мигания встроенным светодиодом.

Необходимые элементы

Для данного примера Вам понадобится плата Arduino (в данном случае – Arduino Uno R3 , но Вы сможете проработать данный пример, имея в наличии и другую плату) и кабель USB (типа A (4х12 мм) – B (7х8 мм) – более подробно можно почитать на Вики).

Что такое ” L” светодиод


На Arduino Uno присутствуют ряды коннекторов типа мама по бокам платы, которые используются для подключения периферийных электронных устройств или “шилдов” .

Кроме того, на плате присутствует встроенный светодиод (англ. – LED), которым Вы можете управлять с помощью скетчей. Этот встроенный светодиод условно назовем “L” светодиод, как это принято на многих англоязычных ресурсах.

Расположение данного светодиода на плате отмечено на фото снизу.


Загрузка примера “Blink” (мигание) в Arduino IDE

При подключении новой платы к персональному компьютеру, обратите внимание, что светодиод начинает мигать, так как все платы от производителей поступают с уже “залитым” скетчем “Blink ”.

На этом уроке мы перепрограммируем нашу плату, изменив частоту мигания светодиода. Не забудьте настроить оболочку Arduino IDE и выбрать нужный серийный порт, по которому Вы подключили Вашу плату.

Пришло время проверить Ваше подключение и запрограммировать плату.

В оболочке Arduino IDE существует большая коллекция скетчей, которые уже готовы к использованию. Среди них находится и пример, который заставляет мигать “L” светодиод.

Откройте пример “Blink”, который находится в пункте меню File – Examples – 01.Basics

После открытия, расширьте окно оболочки Arduino IDE, чтобы Вы могли весь скетч в одно окне.

Скетчи из примеров, включенные в Arduino IDE предусматривают режим “только чтение” (“read only”). То есть, загрузить их на плату Вы сможете, но после изменения кода, Вы не сможете их сохранить в том же файле.

Мы будем изменять скетч, так что в первую очередь Вам необходимо сохранить собственную копию, которую Вы сможете изменять.

Вы сохранили копию скетча “Blink” в Вашей библиотеке. Теперь открыть этот файл Вы можете в любой момент, перейдя по вкладке File – Scetchbook.

Загрузка примера “Blink” (мигание) на плату

Подключите свою плату Arduino к компьютеру с помощью USB и проверьте тип платы (“Board type”) и серийный порт (“Serial Port”), по которому она подключена.

Текущие настройки отображаются внизу окна оболочки Arduino IDE

Кликните на кнопку “Загрузить” (“Upload”)

Во время загрузки в нижней части окна IDE появятся ползунок загрузки и сообщения. Вначале появляется фраза “Компилирование” (“Compiling scetch..”), что означает процесс конвертирования Вашего скетча в формат, подходящий для загрузки на плату Arduino.

В конце статус сменится на ”Загрузка завершена” (“Done uploading”). В сообщении, которое появится в текстовой строке отобразится информация о том, что загруженный скетч занимает 1,084 байта из 32,256 доступных.

Иногда при компиляции у Вас может возникнуть подобная ошибка:

Причин может быть несколько: Вы не подключили плату к компьютеру; Вы не установили необходимые драйвера; Вы выбрали некорректный серийный порт.

Пояснения к скетчу “Blink”

Ниже представлен код скетча “Blink”.

Turns on an LED on for one second, then off for one second, repeatedly.

This example code is in the public domain.

// Pin 13 has an LED connected on most Arduino boards.

// give it a name:

pinMode(led, OUTPUT);

delay(1000); // wait for a second

Первое, на что стоит обратить внимание: в данном скетче множество “комментариев”. Обратите внимание, что комментарии не являются инструкцией по работе программы. Это исключительно пояснения отдельных функций и задач, которые выполняются на определенном этапе кода. Это не обязательная часть кода. Все между символами /* и */ в верхней части скетча – это комментарии, в которых описаны задачи программы. Так же есть комментарии, которые ограничиваются одной строкой. Они начинаются с символов // и заканчиваются по умолчанию в конце строки. Первая важная, по сути, часть данного кода это строка:

В комментариях над строкой указано, что мы присваиваем имя пину, к которому подключен светодиод. На большинстве плат Arduino это будет 13 пин. Дальше используется функция “Setup”. Опять-таки, в комментариях указано, что функция срабатывает после нажатия кнопки “reset”. Также эта функция срабатывает, когда плата перезагрузится по каким-либо другим причинам. Например, подача питания или после загрузки скетча.

// the setup routine runs once when you press reset:

// initialize the digital pin as an output.

pinMode(led, OUTPUT);

Каждый скетч Arduino обязан включать в себя функцию “setup” и часть, в которую вы можете добавлять собственные инструкции, заключенные между { }. В нашем примере в функции присутствует только одна команда, в которой указано, что пин, который мы используем, настраивается на “вывод” (“Output”). Также обязательным для любого скетча является функция цикла “Loop”. В отличие от функции “Setup ”, которая отрабатывает один раз после перезагрузки, функция “Loop” после окончания работы команд, вновь запустится.

// the loop routine runs over and over again forever:

digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)

delay(1000); // wait for a second

digitalWrite(led, LOW); // turn the LED off by making the voltage LOW

delay(1000); // wait for a second

В теле функции “Loop” светодиод включается (HIGH), данное значение задерживается на 1000 миллисекунд (1 секунда), светодиод отключается (LOW) и остается выключенным на 1 секунду, после чего цикл повторится.

Изменение частоты мигания светодиода

Для того, чтобы обеспечить более частое мигание светодиода, необходимо изменить параметр, указываемый в скобках () в команде “delay ”.

Как уже было указано, период задержки указывается в миллисекундах. То есть, для того, чтобы заставить светодиод мигать в два раза чаще, необходимо изменить значение с 1000 на 500. В результате, пауза между включением/выключением светодиода составит половину секунды и светодиод будет мигать быстрее.

Для проверки, не забудьте загрузить измененный скетч на плату Arduino.

В статье будет рассмотрено подключение светодиодов к микроконтроллеру, работа с портами и написание программы на СИ. Статья, прежде всего, предназначена новичкам, которые только взялись за микроконтроллеры AVR.

Для начала нужно выбрать микроконтроллер. В моем случае это ATmega8535. В данном случае микроконтроллер можно брать любой, так как данная задача легко реализуется под любой МК. Писать программу для микроконтроллера можно на Ассемблере, СИ, Pascal-е и Bascom. Я использовал язык СИ, все эти языки разные.
Конкретную разницу между Си и Паскалем можно увидеть ниже.

//Мигающий светодиод void main() { ddrB = 0b11111111; //задаём порты B на выход portB = 0b11111111; //по умолчанию всё выключено while(1) { portB = ˜portB; //переключаем состояние светодиода на обратное delay_ms(100); //делаем задержку на 100 миллисекунд } }

Program First; begin ddrB:= $FF; //задаём порт B на выход portB:= $FF; //по умолчанию ничего не горит while(1) do begin portB:= not(portB); //переключаем состояние светодиода на обратное delay_ms(100); //делаем небольшую задержку end; end.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
U1 МК AVR 8-бит

ATmega8535

1 В блокнот
R1-R8 Резистор

220 Ом - 1 кОм

8 В блокнот
R9-R11 Резистор

10 кОм

3 В блокнот
V1-V8 Светодиод 8 В блокнот
Тактовая кнопка 3

В данном уроке мы научимся программировать в цикле, а также использовать задержку исполнения кода, в результате чего наш светодиод станет более живым. Также мы поработаем с некоторыми логическими операциями и с операциями сдвига бита в байте.

Для начала мы создадим новый проект. Создадим мы его приблизительно по той же схеме, как и напрошлом занятии, за исключением только лишь, того, что назовём мы его Test02 .

Также после запуска настроим в качестве отладчика симулятор. Также, чтобы нам не мучиться с кодом и не вводить его заново, мы его скопируем с прошлого занятия, открыв в проекте с прошлого занятия файл main.c в любом редакторе и скопировав весь код в буфер обмена. Удалим весь код из файла main.c в новом проекте и вставим из буфера обмена код.

Теперь начнем исправления. То есть мы создадим новый код, а старый у нас будет нетронутым в прошлом проекте. Порт D мы полностью весь установим в 0, изменив 1 на 0 в следующей строке

PORTD = 0b00000000;

В принципе, у нас уже все ножки порта по умолчанию установлены в ноль, но все равно сделаем это для порядка.

Дальнейший код мы уже будем писать в теле бесконечного цикла и весь этот код, который мы там напишем будет выполняться постоянно и циклично.

Но прежде, чем мы туда начнем писать код, я хотел бы немного рассказать вам о логических операциях, без которых в наш век никуда. Также они нам пригодятся и в коде. Первым делом мы расмотрим четыре основные операции.

Логические операции мы будем производить над восьмибитовыми числами или байтами, которые мы представим в виде прямоугольников, состоящих из восьми ячеек. Первые три операции будут выполняться над двумя числами. Возьмём, к примеру вот такие:

Все три операции делаются побитно, то есть логически сравниваются одноимённые биты — нулевой с нулевым, первый с первым и так далее.

Первая — это операция "И ", обозначаемая в языке C/C++ знаком "& ". Любой бит в результате будет установлен в единицу только в том случае, если оба соответствующих ему бита в операндах будут единицами . В любом другом случае мы получаем ноль .

Поэтому результат у нас будет следующий

То есть в единицу у нас установлен в нашем случае только пятый бит, потому что пятый бит установлен в единицу как в первом операнде, так и во втором.

Сделующая логическая операция — это операция "ИЛИ ", обозначаемая вертикальной чертой "| ". В результате данной операции мы получим единицу , если хотя бы один бит в сравниваемых одноименных битах будет установлен в единицу . Таким образом, ноль мы получим только тогда, когда в обеих сравниваемых битах будет ноль .

Поэтому здесь будет уже вот такой результат

Третий вид операции — операция "Исключающее ИЛИ ". Эта операция обозначается знаком "^ ". Здесь шансы у бита стать нулём или единицей уравниваются. Единицей результирующий бит станет тогда, когда сравниваемые биты обязательно будут разными — один будет нулём , другой — единицей . А нулём будет результирующий бит тогда, когда сравниваемые биты будут одинаковыми.

Итак, получим следующий результат

А четвертая операция — операция "НЕ ", обозначаемая знаком тильда — "~ ", проделывается над одним байтом. В результате данной операции все биты меняются обратный. То есть ноль становится единицей , а единица нулём . Данную операцию ещё называют операцией инвертирования .

Вот такой вот получим результат

Теперь вернёмся к коду. Напишем следующую очень непонятную на первый взгляд команду

while (1)

PORTD |=(1<<(PORTD0 ));

Первый непонятный оператор в данной команде — это сдвоенный оператор "|= ". Такого рода операторов существует несколько. В данном случае сначала результат, который получится в правой части, сразу не присваивается переменной. которая находится в правой части, а складывается логически по "ИЛИ " со значением, хранящемся до этого в перменной, которая находится справа. Затем уже результат, полученный после применения данной логической операции, присваивается переменной, находящейся в правой части. Также существуют подобные операции типа "+= и "-= ", которыми мы в дальнейшем будем очень часто пользоваться.

Теперь нам осталось этот результат получить. А мы даже не знаем, что за оператор у нас в правом выражении в виде стрелочек. А это один из двух вариантов битовых сдвигов, которые могут осуществляться над числами.

Битовые сдвиги бывают двух видов:

"<< " — сдвиг влево,

">> " — сдвиг враво.

Давайте остановимся на них немного поподробнее.

Битовый сдвиг сдвигает все биты числа вправо или влево на количество положений, находящемся в числе справа. Число может быть разное. В результате сдвига самые крайние биты, находящиеся в стороне, в которую сдвигаем исчезают вникуда, а биты, находящиеся в противоположной стороне, в которые сдвигаться нечему, то есть они самые крайние, заполняются нулями.

Давайте проделаем данные операции над определённым байтом

Ну, я думаю, со сдвигом всё ясно. Давайте проделаем данную операцию над нашим примером в коде

Единичка, стоящая слева — это число, над которым проводится операция, а не число, на которое мы сдвигаем байт побитно, как очень многие путают. Запомните это накрепко! То есть в нашем случае — это единица или в двоичном выражении 0b00000001 . А PORTD0 — это константа, которая определена в макросе в файле io.h . Вот разновидности данных констант

#define PORTD7 7

#define PORTD6 6

#define PORTD5 5

#define PORTD4 4

#define PORTD3 3

#define PORTD2 2

#define PORTD1 1

#define PORTD0 0

То есть в нашем случае — это ноль. Вот и получается, что мы единицу сдвигаем влево на ноль положений. В принципе, в результате операции ничего с нашей единицей не произойдёт и она также останется единицей, но зато код станет наглядным и мы будем видеть, что мы нулевую ножку порта установили в единицу.

Дальше мы делаем операцию "ИЛИ" между значением, находящимся в переменной PORTD и данным результатом, равным единице. Так как у нас в порте D в данный момент находится ноль на всех ножках, то мы только установим единицу на нулевой ножке, так как 0b00000000 и 0b00000001 в результате данной операции дадут на 0b00000001 . Но если бы в регистре порта D находилось бы какое-нибудь другое число, то мы также бы установили бы единицу в нулевом бите, а остальные биты бы не тронулись. То есть мы в результате команды получили и лояльную к остальным лапкам операцию, и в то же время эта операция у нас имеет очень наглядный и читабельный вид.

Вообще, зажгли мы данный светодиод. Но прежде чем нам его погасить, мы обязаны применить соответствующую задержку, так как если нам сразу написать команду, обнуляющую бит, то она его обнулит практически мгновенно. Для задержки имеются две команды

Delay_ms (число в милисекундах )

Delay_us (число в микросекундах )

Также чтобы воспользоваться функциями задержки, нам необходимо подключить ещё один заголовочный файл в начале модуля

#include

#include

Мы воспользуемся первой командой и применим задержку на 500 милисекунд

PORTD |=(1<<(PORTD0 ));

_delay_ms (500);

Теперь можно погасить светодиод. Делается это с помощью следующей команды

Delay_ms (500);

PORTD &=~(1<<(PORTD0 ));

Здесь мы видим, что у нас команда похожа на нашу предыдущую, хотя есть некоторые существенные изменения. Во-первых наш логический оператор превратился в "И ", а также мы применили инверсию результата справа.

Давайте разберём данную команду. Результат справа нам известен — это 0b00000001 , если мы его инвертируем то получим соответственно 0b11111110 . Тепрь его нужно умножить логически на значение в переменной справа. В данный момент там у нас также 0b00000001 . Соответственно получим мы все нули, так как сравниваемые биты в операндах у нас разные. А если бы было какое-то другое чесло в переменной PORTD, то у нас бы сбросился только нулевой бит, остальные бы не тронулись. Поэтому вот такой операцией в будущем мы и будем сбрасывать определенные биты в регистрах и переменных. Также можно сбрасывать сразу несколько битов или устанавливать, но об этом позже, а то и так мы слишком много уже узнали. Осталось нам добавить ещё такую же задержку, чтобы светодиод находился в погасшем состоянии столько же. сколько и в светящемся

PORTD &=~(1<<(PORTD0 ));

_delay_ms (500);

Но это ещё не всё. Чтобы задержка корректно работала, мы обязаны ещё в начале модуля или файла main.c написать макрос, говорящий компилятору о том, с какой частотой работает наш контроллер, иначе он неправлиьно применит задержку, и нам даст предупрежедение. Напишем данный макрос

#define F_CPU 8000000

#include

Соберём проект. У нас ошибок и предупреждений нет

Теперь мы можем посмотреть результат работы сначала в протеусе, затем на живом светодиоде и контроллере.

Чтобы нам заново не создавать схему, мы файл с проектом для проетуса из папки с проектом из прошлого урока скопируем в папку с новым проектом и переименуем в Test02.pdsprj .

Запустим его. Щёлкнем двойным щелчком по изображению контроллера и выберем там другую прошивку, соответствующую новому проекту, а также выставим в свойствах соответствующую частоту, иначе светодиод будет мигать в 8 раз медленнее

Запустим проект и увидим, что светодиод у нас мигает. На картинке я этого показать не смогу, поэтому лучше для лучшей визуализации посмотрите видеоверсию урока, ссылка на которую дана ниже.

Затем прошьём настоящий контроллер, и также убедимся, что светодиод мигает и там.

Смотреть ВИДЕОУРОК

Post Views: 11 097

  • Перевод

Дешевые электронные «свечи» в последнее время, кажется, повсюду. Я не обращал на них особого внимания, пока не заметил, что на самом деле в них используется особый светодиод - со встроенным «моргательным» контроллером. Теперь-то совсем другое дело: кому не нравятся таинственные светодиоды? Полчаса спустя я уже набрал охапку мерцающих светодиодов китайского производства.

Конечно, самый интересный вопрос - как они работают? Учитывая, что стоят они буквально по несколько центов за штуку, там внутри не может быть какой-то дорогой электроники. В связи с этим возникает еще один вопрос: правда ли эти светодиоды хуже, чем многочисленные «свечи» на микроконтроллерах, схем которых полно в интернете?

Устройство относительно простое. В стандартном 5-миллиметровом корпусе размещены кристалл светодиода и микросхема, которая чуть больше первого по размеру. Схема контроллера соединена как с положительным, так и с отрицательным выводами. Третьей перемычкой к ней подключен анод светодиода, в то время как катодом он «сидит» на отрицательном выводе.

В блоге Evil Mad Scientist недавно был рассказ о похожих светодиодах. Там было показано, как они «поют», если преобразовать изменения яркости в звук. А также - как с их помощью управлять более мощным диодом. Подобные трюки основаны на том, что светодиод потребляет больший ток в те моменты, когда контроллер зажигает его ярче. Обычный светодиод, включенный последовательно с мерцающим, показывает очень похожие изменения яркости. Иными словами, падение напряжения на добавочном резисторе изменяется пропорционально яркости.


Это я и использовал, чтобы извлечь управляющий сигнал контроллера и завести его на логический анализатор (см. схему выше). Подстройкой переменного резистора я добился того, чтобы анализатор воспринимал броски тока как «нули» и «единицы», а светодиод при этом нормально работал.


На диаграмме выше показаны изменения яркости диода в течение примерно минуты, записанные с частотой выборки 1 МГц. Заметны интервалы, когда светодиод непрерывно включен, и периоды, когда его яркость каким-то образом модулируется. Светодиод никогда не выключается надолго. Это разумно, ведь настоящая свеча тоже ярко светит большую часть времени, снижая яркость на короткие периоды мерцания.


Более пристальный взгляд покзывает, что сигнал имеет широтно-импульсную модуляцию. Это означает, что перед нами цифровая схема, без всяких аналоговых трюков.

Любопытно, что частота сигнала - примерно 440 Гц, как у стандартного камертона (нота Ля первой октавы - прим. перев. ). Совпадение? Или разработчик просто взял генератор из какой-то музыкальной схемы? Так что есть доля правды в рассказах о «музыкальности» этих светодиодов. Каждый «кадр» постоянной яркости составляет ровно 32 такта и длится около 72 мс. Это соответствует 13-14 кадрам в секунду.

Я написал небольшую программу для определения яркости в каждом кадре по коэффициенту заполнения ШИМ-сигнала. Программа читает поток отсчетов с логического анализатора и выводит серию вещественных чисел - по одному на каждый кадр.


График яркости в зависимости от времени наводит на некоторые мысли: изменения яркости случайны, дискретны и имеют неравномерное распределение. Кажется, существуют 16 уровней яркости, низшие 4 из которых используются очень редко. Им соответствуют только 13 из 3600 отсчетов.


Постороение гистограммы открывает всю картину: фактически используется только 12 уровней яркости. Ровно половина кадров имеет максимальную яркость, остальные значения распределены примерно поровну.

Как это может быть реализовано на аппаратном уровне? Вполне вероятно, используется генератор равномерно распределенных случайных чисел, которые пропускают через простую функцию-формирователь. Для того распределения, которое мы наблюдаем, требуется как минимум 12x2=24 дискретных уровня. Половина из них отображаются в один. Это весьма любопытно, так как генератор, скорее всего, выдает двоичные числа. Наиболее логичной была бы разрядность числа 5 бит, а это 32 состояния. Отобразить 32-уровневую дискретную случайную величину в 24 уровня, не изменив распределения, не так просто, как кажется. Не забываем также, что это совсем не критичная схема, и у разработчика, вероятно, не было много времени на красивое решение. Поэтому он применил самое простое, своего рода хак.

Единственный простой способ, что приходит на ум - просто отбрасывать неподходящие значения и брать следующее случайное число. Нежелательные значения можно легко отделить по битовой маске. Так как схема синхронная, есть только конечное число попыток, пока не начнется следующий кадр. Если контроллер не уложился в заданное количество попыток, он застрянет на «неправильном» значении. Помните редкие выбросы на графике яркости?

Реализация на ANSI-C могла бы выглядеть так:
char attempts=0; char out; while(attempts++15) out=15; // верхняя половина диапазона соответствует максимальной яркости

Можно узнать, сколько делается попыток? По статистике, доля a=0,25 всех чисел должн быть отброшена и сгенерирована заново. Вероятность того, что за n попыток не будет выбрано «правильное» число, равна a n .
n=1 0,25 n=2 0,0625 n=3 0,015625 n=4 0,003906

Доля аномально низких уровней яркости составляет 13/3600=0,0036 , что хорошо совпадает с вариантом n=4 . Таким образом, MAX_ATTEMPTS==4 .

Обратите внимание, что более простым решением было бы просто использовать значение из предыдущего кадра, если встретилось недопустимое число. Этот вариант можно было бы исключить, исходя из автокорреляции (см. ниже). Наиболее же простое, вероятно, решение - изменить схему ШИМ - не было здесь использовано.

Последний кусочек головоломки - это сам генератор случайных чисел. Типичным способом генерации случайных последовательностей в цифровых схемах является применение сдвиговых регистров с линейной обратной связью . Такой регистр выдает псевдослучайную битовую последовательность, которая повторится не позже, чем через 2 x -1 тактов, где x - разрядность регистра. Одной из особенностей таких последовательностей (и хороших псевдослучайных последовательностей в целом) является то, что их автокорреляционная функция равна единице только в точке 0 и в координатах, кратных длине последовательности. Во всех остальных интервалах она нулевая.


Я рассчитал автокорреляцию всей последовательности значений. Самоподобия не было найдено вплоть до 3500 кадров (на графике выше показано только 1200), что означает уникальность мерцания на протяжении по меньшей мере 4 минут. Неясно, наблюдалось ли дальнейшее повторение последовательности, или логический анализатор автора просто не позволял записывать дольше - прим. перев. Поскольку на каждый кадр нужно как минимум 5 бит случайных данных (а учитывая механизм отбрасывания нежелательных чисел - еще больше), псевдослучайная последовательность имеет длину по меньшей мере 17500 бит. Для этого потребуется регистр разрядности не менее 17, либо настоящий аппаратный генератор случайных чисел. В любом случае, интересно, как много внимания при разработке уделили тому, чтобы картина мерцания не повторялась.

В заключение ответим на вопросы, заданные в начале статьи. Мерцающий светодиод оказался гораздо сложнее, чем я ожидал (также я не ожидал потратить на него 4 часа). Многие микроконтроллерные реализации свечей просто подают биты с генератора псевдослучайных чисел на ШИМ-выход. Покупной светодиод использует более хитрый алгоритм изменения яркости. Безусловно, определенное внимание было уделено разработке алгоритма, и при этом использован кристалл почти минимально возможной площади. Доля цента потрачена не зря.

Каков же лучший алгоритм мерцания? Можно ли улучшить этот?

Дополнение: Я наконец нашел время написать эмулятор. Написанная на ANSI-C программа, эмулирующая поведение этого светодиода,

На прошлых уроках мы с вами разобрались в том как устроен МК и посмотрели что такое порты ввода/вывода и их альтернативные функции. Давайте попробуем написать простенькую программу "Мигание светодиодом". Писать программу будем на языке С. Конечно многие начнут возмущаться, мол это жлобство, надо только на ассемблере, ну да и бог с ними. Если я начну рассказывать как писать программу на ассемблере, то скорее всего часть из вас просто подумает: "Как тут все заморочено! А ну его к черту". И от части будут правы. Для того чтобы писать программу, нам потребуется специальная программа. Я пользуюсь CodeVisionAVR V2.04.4a и найти его можно . Или прямо у нас на сайте, это . Надеюсь что с установкой вопросов не возникнет. Запускаем программу. Рисунок 1. Теперь давайте создадим новый проект. Для этого нажимаем File->New . Рисунок 2. Появится вот такое окно. Рисунок 3. Ну тут все понятно, выбираем Project и давим "Ок". И снова вопрос. Рисунок 4. Здесь программа предлагает вам запустить генератор кода. Для начала, а может и всегда, тут уж сами решайте, давим "Yes". Рисунок 5. Вот здесь мы с вами остановимся по подробнее. Это окно, как раз и есть тот самый генератор кода. Здесь мы выбираем что будет проинициализировано МК перед выполнением основной программы. Начнем с вкладки Chip . Ну тут я думаю все понятно. Выбираем наш контроллер, а именно как с вами договорились, ATmega8 и частоту кварца 4 МГц. Рисунок 6. Больше в этой вкладке ничего трогать не надо. Переходим в вкладку Ports . Рисунок 7. Здесь выбираем Port B и нулевой бит меняем с In на Out . Значение по умолчанию на выходе оставим 0. Это значит что при первом старте МК на порту B в нулевом разряде будет висеть логический ноль. В общем смотрите на рисунок выше. Более подробно по настройкам я напишу в отдельных статьях по программированию в среде CodeVisionAVR , а сейчас у нас задача поморгать светодиодом. Ну вроде ничего не забыли. Далее надо сохранить наш проект. Для этого жмем на иконку дискетки и выбираем путь куда сохраним наш проект. Я выбрал так: C:/my_cvavr/project_led , а проект назвал led . Получилось как-то так. Рисунок 8.
Но это еще не все. Теперь давайте попросим программу сгенерить нам наш стартовый код. Для этого жмем на иконку "шестеренка" и дважды под тем же именем, а именно led сохраняем проект. Все. Программа с генерировала нам код и теперь давайте взглянем на него. Расписывать весь код не буду, так как это другая тема, а вот на что мы обратим внимание. Смотрим на картинку ниже. Рисунок 9.
Строка: #include В этой строке мы просим компилятор подключить файл с описаниями всех регистров МК ATmega8. Это сделано для понимания. Что проще понять PORTB или 0x18 . По моему тут все очевидно. Просто в этом файле прописаны эквиваленты понятные простому человеку. Легче понять название порта не же ли его адрес. Строка: PORTB=0x00; Помним, мы хотели чтоб у нас был ноль на выходе по умолчанию, вот он. Правда здесь выстрел и пушки по воробьям, так как это выражение выводит нули в весь порт. А можно по проще PORTB.0=0x00; но это не суть важно. Строка: DDRB=0x01; Вспоминаем предыдущий урок, кто не читал вам сюда . Так как цифра 0x01 в hex равна 0b00000001 и bin. Учимся переводить из шестнадцатеричной системы в двоичную! То мы видим что в нулевой разряд регистра направления DDRB записали 1. То есть будем выводить данные через нулевой разряд порта В . Ну вот, просмотрев код мы убедились что генератор кода с генерировал код как нам надо. Заметьте, очень удобно и быстро. Теперь давайте посмотрим где же нам-то писать код. Для этого бежим вниз до вот этих строк. Рисунок 10.
Да, да. Внутри этого бесконечного цикла и будет наш код. О чем говорит коментарий написанный в теле цикла. Кажется мы хотели поморгать светодиодом. Ну давайте. Так как светодиодом мы будем управлять через нулевой разряд порта "В", то пишем вот такой код. PORTB.0 = 0x01; PORTB.0 = 0x00; Это самый простой способ. Сначала мы записываем в нулевой разряд порта, о чем говорит точка с нулем после порта, единицу, а затем ноль. Вроде светодиод сначала включится, а потом погаснет. А так как это все в бесконечном цикле, то все завертится по кругу. Но к сожалению если мы соберем схему и включим ее, наш светодиод будет гореть постоянно. А почему же, спросите вы. А вот почему. Помните мы выбрали частоту кварца 4 МГц. Во... 4 миллиона импульсов за секунду. И вы хотите уследить за ними. Не получится! Что же делать? А выход есть и даже не один. Вставить паузы длинной, ну к примеру в пол секунды. Вариант первый, использовать аппаратный таймер с прерыванием, но для нашего примера я думаю рановато. Вариант два, мы же работаем в такой замечательной программе как CodeVisionAVR . И для нас сделали хорошую библиотеку полезных функций. И одна из них пауза delay_ms(int x) или delay_us(int x) . Первая задает паузу длинной х миллисекунд, а вторая х микросекунд. Но чтоб ей воспользоваться давайте вернемся на самый верх и после строки #include и напишем под ней #include . Тем самым мы подключили библиотеку и можем смело пользоваться функциями пауз. Давайте допишем наш код. PORTB.0 = 0x01; delay_ms(500); PORTB.0 = 0x00; delay_ms(500); Теперь собираем наш проект. Project->Build All После сборки мы увидим окно Рисунок 11. в котором говорится, что все сделано без ошибок и нет предупреждений. Две строки No errors No warnings Рисунок 12. Вот и все. Для тех кто все же не понял что куда подключать. Рисунок 13.
На схеме отсутствуют питание, кварц и конденсаторы. Я их не стал рисовать так как мы про них уже распинались в предыдущих уроках. Просто эта обвязка обязательна в любом проекте и в дальнейшем не будем рисовать, а при сборке не забудем о них. В следующем уроке мы сваяем программатор и прошьем наш МК.

© autonomichouse.ru, 2024
Автономный дом