Урок 6
Бегущие огни
Сегодня мы немного усовершенствуем наш проект, заодно и повторим битовые сдвиги, и не только повторим, а и увидим их смысл в деле. Мы применим данные сдвиги для того, чтобы наши светодиоды, находящиеся в матрице, мигали один за другим поочерёдно, за счёт чего наша схемка приобретёт ещё более живой вид.
Для этого нам потребуется уже не один светодиод. У меня на этот счёт имеется светодиодная планка или матрица. Я её поместил в беспаечную макетную плату, катоды всех светодиодов соединил вместе и подключил к общему проводу, а аноды каждый через токоограничивающий резистор подключил к соответствующим ножкам порта D. Вот так это всё выглядит (нажмите на картинку для увеличения изображения)
Поэтому, как обычно, по старой доброй традиции мы запускаем Atmel Studio, создаём в ней проект, выбрав тот же самый микроконтроллер Atmega8a, назовём проект Test03. Таким же образом в качестве отладчика выберем simulator, и также, чтобы сэкономить наше драгоценное время, скопируем весь код из файла main.c прошлого занятия.
Начнём писать код. Сначала мы в функции main() создадим целочисленную короткую беззнаковую переменную
int main(void)
{
unsigned char i;
Порт также оставляем на выход, и сразу на данном порте включим нулевую ножку в 1
DDRD = 0xFF;
PORTD = 0b00000001;
А в бесконечном цикле мы создадим цикл другого типа — типа for. Данный цикл уже является конечным и работает он следующим образом
Данный цикл немного сложнее и условие в скобках здесь уже состоит из трёх частей, но я думаю, мы разберёмся. Мы ещё не с таким впоследствии разберёмся. Применим цикл данного типа в нашем коде:
while(1)
{
for(i=0;i<=7;i++)
{
_delay_ms(500);
}
}
В данном цикле у нас будет пока только задержка, остальной код мы уберём. То есть тело нашего цикла будет у нас выполняться до тех пор, пока переменная i у нас не достигнет значения, большего или равного 7. То есть получится, что наше тело будет выполняться ровно 8 раз, затем мы выйдем из данного цикла и благодаря бесконечному циклу заново в него войдём и наш восьмикратный процесс повторится сначала.
А вот теперь сдвиг. Вставим его до задержки
PORTD = (1<<i);
_delay_ms(500);
Как мы видим, данный сдвиг мы применяем к регистру, отвечающему за состояния порта D, и в нём мы будем сдвигать единичку влево на величину нашей переменной i, а так как данная переменная с каждым циклом увеличивается на 1 (или инкрементируется), то, соответственно, наша единичка постепенно раз в полсекунды будет двигаться влево, также как и лапки порта, за которые отвечает каждый бит нашего регистра. И тем самым мы и получим эффект бегущего огня.
Давайте соберём наш проект. И, также как и на прошлом занятии скопируем файл протеуса с прошлого занятия и переименуем его в Test03. Откроем его, заменим файл прошивки в свойствах контроллера.
Также добавим ещё 7 светодиодов и 7 резисторов, так как показано на схеме. Можно применять операцию копирования. Как это делается, показано в видеоуроке.
Запустим проект в протеусе и увидим, что наши светодиоды мигают поочерёдно, создавая впечатление эффекта бегущего огня
Теперь прошьём настоящий контроллер и увидим уже результат на практике. Это, конечно, намного интереснее, чем в протеусе. Как всё это выглядит, можно увидеть в видеоверсии урока, ссылка на который находится ниже и доступна с помощью нажатия на картинку.
На следующем занятии мы уже поработаем с ножкой порта не на выход, а на вход. Так как мы уже знаем, что порт — это такая шина, которая умеет работать в разных направлениях. Мы подключим кнопку и попытаемся отследить её состояние. То есть наша задача — узнать в какой-то определённый момент, нажата наша кнопка или отжата. Так что будет интересно.
Предыдущий урок Программирование МК AVR Следующий урок
Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером
Смотреть ВИДЕОУРОК
еременная i у нас не достигнет значения, меньшего или равного 7
Еще как достигнет, она же инкрементируется.
Добрый день! Что за «L» после частоты? В предыдущем проекте её нет.
long. Иногда интерпретатору так понятней, что за величина.
Здравствуйте ! Попробовал развернуть бегущий огонь в другую сторону, код не работает. Не могу понять в чем проблема, по идее должно все работать, но не работает …
int main(void)
{
unsigned char i;
DDRD = 0xFF;
PORTD = 0b10000000;
while(1)
{
for (i=7; i>=0; i—)
{
PORTD = (1>>i);
_delay_ms(500);
}
}
}
Переменная i объявлена как бес знаковая. А выход из цикла когда она станет меньше 0. Что не может быть выполнено.
Выход из цикла, когда она станет больше 7.
У тебя в коде много ошибок. Изначально код должен выглядеть как-то так.
#include
int main(void)
{
unsigned char i;
DDRD = 0xFF;
PORTD = 0b00000001;
while(1)
{
for (i=0; i<=7; i++)
{
PORTD = (1<<i);
}
}
_delay_ms(500);
}
Проверил лично код рабочий компилил в AtmelStudio 6.2, проверял в Протеусе на At mega8 с частотой 8 mhz.
Если код будет для кого-то кривой, то прошу сильно не пинать, я только учусь. 🙂
В начале должно быть #include , а то не дописал.
Здравствуйте! На AVR Studio собрал такую программу (выложена часть). Принцип работы следующий: изначально при подачи напряжения на МК светодиоды на портах B и D горят, затем постепенно гаснут. Можно как-то уменьшить программу в плане написания кода.
#include
#include
void main(void)
{
mainendloop:
DDRB=0xFF;
PORTB=(255);
DDRD=0xFF;
PORTD=(255);
while (1)
{
PORTB=(255);
_delay_ms(255);
PORTB=(PORTB&0xFE)|(0);
_delay_ms(255);
PORTB=(PORTB&0xFC)|(0);
_delay_ms(255);
PORTB=(PORTB&0xF8)|(0);
_delay_ms(255);
PORTB=(PORTB&0xF0)|(0);
_delay_ms(255);
PORTB=(PORTB&0xE0)|(0);
_delay_ms(255);
PORTB=(PORTB&0xC0)|(0);
_delay_ms(255);
PORTB=(PORTB&0x80)|(0);
_delay_ms(255);
PORTB=(PORTB&0x00)|(0);
_delay_ms(255);
Не могу добиться бесконечного цикла,с остальными параметрами разобрался.
Хотел поменять направление и ограничиться пятью ледами.
Если не трудно -где ошибка?
Спасибо.
#define F_CPU 8000000
#include
#include
int main(void)
{ unsigned char i;
DDRD = 0xFF;
PORTD = 0b00100000;
while(1)
{
{
for(i=5;i>=0;i—)
{
PORTD = (1<<i);
_delay_ms(500);
}
}
}
}
Непонятно, для чего после while(1) стоят сразу две открывающие скобки
int main(void)
{
/* Replace with your application code */
unsigned char i;
DDRD = 0xFF;
while (1)
{
PORTD = 0b10000000;
for (i=0;i> 1);
}
_delay_ms(500);
}
}
int main(void)
{
unsigned char i;
DDRD = 0xFF;
while (1)
{
PORTD = 0b10000000;
for (i=0;i> 1);
}
_delay_ms(500);
}
}
а что за глюк? не могу нормально код вставить.
попытка номер 3:
int main(void)
{
/* Replace with your application code */
unsigned char i;
DDRD = 0xFF;
while (1)
{
PORTD = 0b10000000;
for (i=0;i> 1); // пропихиваем 1 с каждой итерацией цикла на 1 двоичный разряд
}
_delay_ms(500);
}
}
У тебя в коде переменная i не учавствует в качестве аргумента какой либо фунции. Она только определена и создано условие. А что использует данную переменную i может быть какой то порт или задержка ?
Понял,спасибо.
А зачем мы изначально нулевой бит порта D в единицу опускаем, если PORTD = (1<<i); единица в этой записи означает то же самое?
Не уверен что все сделал правильно, но в протеусе работает. Гирлянда на 16 портах.
#define F_CPU 8000000
#include
#include
int main(void)
{
unsigned char i;
unsigned char a;
DDRB = 0b11111111;
DDRD = 0b11111111;
while (1)
{
PORTB = 0b00000001;
for(i=1;i<=8;i++)
{
_delay_ms(20);
PORTB = (1<=7)
PORTD = 0b00000001;
{
for (a=1;a<=8;a++)
{
_delay_ms(20);
PORTD = (1<<a);
}
}
}
}
}
PORTD сдвигай а не сравнивай
PORTB = (1 << i);
Вернулся,после некоторого обучения,благодаря этим урокам.
Спасибо за учебу.
int main(void)
{
DDRB=0x00;
PORTB=0x01;
DDRD=0xFF;
PORTD=0x00;
unsigned char i;
DDRD = 0xFF;
PORTD = 0b00000000;
while(1)
{
for(i=7;i>0;i—)
{
PORTD = (1<<i);
_delay_ms(500);
}
}
}
Зачем ты два раза до цикла написал DDRD=0xFF; Там наверное должно быть DDRB=0xFF; и потом в цикеле дописать PORTB = (1<<i);
Даже текст программы скопировал из прикрепленного к уроку файла, думал, может ошибку не нахожу. компилирую в Atmel studio. При включенной оптимизации-01 компилятор ошибок не видит и удаляет переменную i, (в окошке Quick watch пишет optimized away) при этом отладка останавливается в функции delay (появляется файл, delay.h, содержащий её описание). При отключении оптимизации (оптимизация-00) компилятор говорит, что функция delay корректно работать не будет, отладка зависает также при обработке задержки, только в другом месте. Что надо сделать, чтобы компилятор нормально обработал текст. квалификатор volatile не помог.
отладчик виснет в delay на второй итерации цикла for.
при исключении задержки из кода и оптимизации-01 компилятор также не видит ошибок, в окне Watch1 видно сообщение об удалении компилятором глобальной переменной (optimized away), но программа в отладчике работает, в окне IO View видно, как происходит сдвиг активного бита порта D.
#define F_CPU 8000000L
#include
int main(void)
{
unsigned char i;
DDRD = 0xFF;
PORTD = 0b00000001;
while(1)
{
for( i=0;i<=7;i++)
{
PORTD = (1<<i);
}
}
}
Вопрос снят. Не обратил внимания, что при входе в delay индикатор состояния отладчика в левом нижнем углу показывает running. Почему-то задержка длительностью в пол секунды отрабатывается за минуту сорок секунд (засекал по секундомеру), после этого в окне IO View показывается сдвиг бита и индикация состояния отладчика меняется на Ready.
Может кто-нибудь ответить, почему так долго отрабатывается задержка?
В протеус если записывать файл прошивки с расширением .hex задержка игнорируется, если указать прошивку с расширением .elf задержка отрабатывается как требуется, по 0,5 секунды (видимо учитываются биты фьюзов тактовой частоты). Получается что-то нехорошее с режимом отладки в atmel studio 6.2 .
Вопрос таков: почему не объявляются типы переменных и почему нельзя написать в цикле вот так: for(int i=0; i<=7; i++)
{
PORTD=(1<<PORTD)
}
?
Спасибо!!!
Еще один вариант
#define F_CPU 8000000L
#include
#include
int main(void)
{
int i;
DDRD = 0xFF;
PORTD = 0x08;
while(1)
{
for(i=7;i>=0;i—)
{
PORTD = ((1<<i));
_delay_ms(500);
}
}
}
добрый день!
начинаю только изучать программирование на AVR.
при попытке «прогона» программы она всегда выскакивает на надпись:
__builtin_avr_delay_cycles(__ticks_dc);
попытки что-либо изменять (в пределах того, что я понял из Ваших предыдущих уроков) ни к чему не привели :(.
прогу открыл (и пишу) в MicroChip Studio.
эмулирую в Proteus. после загрузки проги в чип и её запуске, светодиоды не переключаются, горит только первый.
понимаю, что проблема в задержке (_delay), но что именно не так и как исправить — к сожалению, не знаю.
прошу помочь.
А почему нельзя заменить «PORTD = (1<<i)" на "PORTD = (PORTD<<1)"??
Можно. Только нужно внимательно начальное значение записывать в PORTD тогда, чтобы при уходе на второй круг, единичка не убежала.
Можно, только осторожно. Чтобы единичка не потерялась на следующем круге.