Задача: разработаем устройство которое должно обеспечивать движение огня в двух разных направлениях. Переключение направления движения будет осуществляться с помощью переключателя 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"