Задача: разработаем устройство которое должно обеспечивать движение огня в двух разных направлениях. Переключение направления движения будет осуществляться с помощью переключателя S1. В соответствие с поставленной задачей наше устройство должно управлять восемью светодиодами HL1-HL8. Подключим восемь светодиодов к порту D микроконтроллера через токоограничительные резисторы по 220 Ом. Переключатель подключим к младшему разряду порта C.

Бегущие огни.

Алгоритм программы будет такой:

1. Читаем состояние переключателя управления;
2. Если контакты разомкнуты переходим к процедуре сдвига вправо;
3. Если контакты замкнуты переходим к сдвигу влево;
4. После окончания полного цикла сдвига (8 шагов) переходим к началу алгоритма.

Алгоритм сдвига:

1. Записываем в рабочий регистр начальное значение, это будет двоичное число, у которого один из разрядов равен единице. Для сдвига вправо нам нужно число с единицей в старшем самом разряде(0b10000000). Для сдвига влево в единицу устанавливаем младший разряд(0b00000001);
2. Выводим значение рабочего регистра в порт D;
3. Вызываем подпрограмму задержки, чтобы скорость бега огней была нормальная т.е. видима человеческим глазом;
4. Сдвигаем содержимое рабочего регистра вправо(влево на один разряд);
5. Проверка конца полного цикла сдвига (8 шагов);
6. Если полный цикл сдвига не закончен переходим к пункту 2 данного алгоритма.

В этой программе мы впервые будем использовать переменную. Так как сдвигаемых битов должно быть 8 используем тип переменной – unsigned char. Переменная такого типа имеет длину в 1 байт. Второй однобайтовый тип (char) в данном случае не подходит, т. к. представляет собой число со знаком, у которого старший разряд интерпретируется как знак, остальные разряды используются для хранения значений. Записывается так:

unsigned char temp; //вводим переменную temp

Настроим порты ввода-вывода:

DDRC = 0x00; //порт С на вход
PORTC |= (1 << PC0); //подключаем нагрузочный резистор к PC0
DDRD = 0xFF; //порт D на выход
PORTD = 0x00; //устанавливаем нули на выходе

Телом основного цикла является оператор сравнения (if-else), проверяющий состояние бита к которому подключен переключатель. Бит PC0 проверяется на равенстве единице. Если он равен единице то выполняется сдвиг вправо, если не равен то выполняется сдвиг влево.

while(1)
{
if ((PINC&(1 << PC0)) == 0) //проверяем нажатие кнопки
{                                       //сдвиг вправо
temp = 0x80; //записываем начальное значение 0b10000000
while (temp != 0)
{
PORTD = temp; //запишем temp в порт D
temp = temp >> 1; //сдвигаем разряды
_delay_ms(200); //задержка 200 мс
}
}

Для того чтобы цикл повторялся только 8 раз, используется оператор цикла while (temp!=0) , в качестве условия, при котором цикл выполняется, используется выражение temp!=0 . Выражение “!=” на языке Си означает неравно.

Для сдвига разрядов используется оператор “>>”. Результатом выражения temp >> 1 является число, полученное путем сдвига всех разрядов переменной temp на одну позицию вправо. Число 1 справа от оператора сдвига означает количество разрядов, на которое нужно сдвинуть число.

temp = temp >> 1;

Выражение означает: присвоить переменной temp значение этой же переменной сдвинутое на один разряд вправо. Можно записать и так:

temp >> = 1;

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

/***************Занятие №4. Бегущие огни*****************/
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
unsigned char temp;
DDRC = 0x00;
PORTC |= (1 << PC0); // подключаем нагрузочный резистор к PC0
DDRD = 0xFF;
PORTD = 0x00;

while(1){
if ((PINC&(1 << PC0)) == 0) // проверяем нажатие кнопки
{
// сдвиг вправо
temp = 0x80; // записываем начальное значение 0b10000000
while (temp != 0) // пока temp не равно нулю
{
PORTD = temp; // запишем temp в порт D
temp = temp >> 1; // сдвигаем разряды
_delay_ms(100); // задержка 100 мс
}
}
else
{
//сдвиг влево
temp = 0x01; // записываем начальное значение 0b00000001
while (temp != 0) // пока temp не равно нулю
{
PORTD = temp; // запишем temp в порт D
temp = temp << 1; // сдвигаем разряды
_delay_ms(100); // задержка 100 мс
}
}
}
}

В статье были использованы материалы из книги Белова А.В. "Самоучитель разработчика устройств на AVR"

Комментарии  

-1 #1 AndriY_GTI 17.02.2013 04:33
Код:((PINC&(1 << PC0)) == 0)
условие работает наоборот
Сообщить модератору
+1 #2 AndriY_GTI 17.02.2013 04:35
должно быть
Код:((PINC&(1 << PC0)) == 1)
Сообщить модератору
0 #3 kantraler 20.07.2013 13:58
добрый... код вижен ругает функцию TEMP че делать???
Сообщить модератору
0 #4 SENDEJ 04.10.2013 22:14
ЭТО ПРОГРАММА НА АССЕМБЛЕРЕ. А ЕСТЬ ЭТА ЖЕ ПРОГРАММА НА "С"?
Сообщить модератору
+1 #5 AntonChip 04.10.2013 22:26
Цитирую SENDEJ:
ЭТО ПРОГРАММА НА АССЕМБЛЕРЕ. А ЕСТЬ ЭТА ЖЕ ПРОГРАММА НА "С"?

Эта программа на "Си", на ассемблере нету
Сообщить модератору
0 #6 Максим 23.10.2013 22:04
строка 33 ошибка в комментарии, влево ведь двигаем*
Сообщить модератору
0 #7 AntonChip 23.10.2013 22:48
Цитирую Максим:
строка 33 ошибка в комментарии, влево ведь двигаем*

Спасибо, исправил
Сообщить модератору
0 #8 Alyes 23.10.2013 23:56
Цитирую kantraler:
добрый... код вижен ругает функцию TEMP че делать???

Заменить имя переменной TEMP другим... это слово уже используется в *.H -- файле.
Сообщить модератору
0 #9 mastech 21.05.2014 01:02
"Занятие №4. Бегущие огни" в строчку, поправте.
Сообщить модератору
0 #10 maryana 28.02.2015 00:28
скажите а как сделать чтобы после включения 8 бита порта D включился 0 порт B - т.е увеличить количество бегущих огней
Сообщить модератору
0 #11 AntonChip 28.02.2015 10:17
Цитирую maryana:
скажите а как сделать чтобы после включения 8 бита порта D включился 0 порт B - т.е увеличить количество бегущих огней

Например так:
Код:
if ((PINC&(1 << PC0)) == 0) //проверяем нажатие кнопки
{ //сдвиг вправо
temp = 0x80; //записываем начальное значение 0b10000000
while (temp != 0) //пока temp не равно нулю
{
PORTB = 0;
PORTD = temp; // запишем temp в порт D
temp = temp >> 1; // сдвигаем разряды
_delay_ms(100); // задержка 100 мс
if(PIND&(1 << PD0)) // Если PD0 = 1
{
PORTD = 0;
temp = 0x80;
while (temp != 0) // пока temp не равно нулю
{
PORTB = temp; // запишем temp в порт D
temp = temp >> 1; // сдвигаем разряды
_delay_ms(100); // задержка 100 мс
}
}
}
}
else
{
// аналогично
}
Сообщить модератору
0 #12 maryana 04.03.2015 22:08
большое спасибо, что занимаетесь таким хорошим делом - помогаете людям учиться. Думал, что сайт уже не работает, а вопросов у меня много. По данному вопросу сам сделал - методом тыка - получилось почти как у вас. СПАСИБО!!!!!!
Сообщить модератору
+2 #13 Julia 19.12.2016 18:47
Как объединить бегущие и мигающие под кнопку?
Чтоб одним нажатием была бегущиен огни ,со вторым мигающие огни??? Мигающие не идёт что то
Сообщить модератору
0 #14 sergey 11.06.2017 20:50
здрвсствуйте
Изучал урок 4 бегущие огни на языке си
программа не реагирует на кнопку и виснит где ошибка,?
с уважением.
Сообщить модератору
0 #15 uuu000 08.04.2019 00:32
Не пойму почему глючит комментарии
Почему в строке 13 ==0,а не ==1?
Сообщить модератору
0 #16 AntonChip 08.04.2019 17:36
Цитирую uuu000:
Не пойму почему глючит комментарии
Почему в строке 13 ==0,а не ==1?

код выделяйте тегом code
Сообщить модератору