Шаг 2. "Бегающая" световая дорожка

Продолжаем играться.
Попробуем сделать "бегающую" световую дорожку. Для этого, помимо всего прочего, нам потребуются штук этак восемь светодиодов, девять резисторов (у нас - на 220 Ом), ну и кнопка, при нажатии на которую дорожка (два «огонька» подряд) будет двигаться.
Вот схема:

Рисунок 1. Принципиальная схема
Рис. 1. Принципиальная схема.

Помимо всего прочего, в этот раз мы задействовали новый вывод - A.2, он же RESET, судя по описанию. По умолчанию, он подключён к «фазе» (это которая +5 В), но как только мы заземлим его, микросхема отключится. Таким образом можно перезагрузить микроконтроллер при неожиданных (ну и при ожидаемых, в принципе, тоже) глюках. Ну а резистор нужен, как всегда, чтобы ограничить силу тока).
Теперь посмотрим, как вообще это может работать:

  1. Сначала включаем наши «бегунки» - пару светодиодов - и ждём, пока будет дан старт, то есть будет нажата кнопка
  2. Как только кнопка нажата, мы начинаем сдвигать наши включённые огоньки
  3. Как только мы отпускаем кнопку, дорожка опять замирает

Разберёмся с моментом включения-выключения: кнопка у нас подключена одним концом к микросхеме, другим - к "земле", поэтому если на вывод «входа», к которому подключена кнопка, приходит 0 - кнопка нажата - то мы запускаем цикл «движения» светодиодов, если приходит 1 - то просто ждём. Единица на входе обеспечивается тем, что ножку мы настраиваем на "вход с подтяжкой" - то есть если на ножку не поступает "0", она внутри микросхемы подключается к питанию.
Теперь будем думать, как же нам сдвигать нашу «дорожку»: для начала вспомним, что если на вывод, к которому подключён светодиодик, подать 0, то он загорится, если 1 - погаснет. Посмотрим, как оно должно бегать: 11111100 - 11111001 - 11110011 и так далее. Получается циклический сдвиг - крайний левый битик становится крайним правым.
Теперь самое время вспомнить об операциях сдвига! Итак, выхватим значение крайнего левого бита - состояние светодиода у вывода B.7: PORTB >> 7 или, если думать на Паскале, PORTB shr 7. Отлично, теперь сдвинем нашу дорожку на один огонёк влево PORTB << 1, оно же PORTB shl 1. Наконец, нужно разобраться с первым светодиодом - B.0. Снова обращаем взор на побитовые операции, выбираем на этот раз побитовое ИЛИ. При сдвиге значение B.0 автоматически оказалось ноликом, и нам известно, что 0 | x = x.
Вот оно, решение: PORTB = (PORTB >> 7) | (PORTB << 1)!
Оформляем программу:
На С:

typedef unsigned char byte;

//"Бегающая" световая дорожка
void main()
{
  //переменные и константы
  const byte ddrLED_RoadInit = 0xFF;                                            //настройка порта со светодиодами - на выход и
  const byte portLED_RoadInit = 0xFC;                                           //два светодиода включены (на ноль)
  const byte ddrButtonInit = 0;                                                 //настройка порта с кнопкой - кнопка на вход с подтяжкой
  const byte portButtonInit = 0x1;
  const byte ButtonOutputNumber = 0;                                            //номер вывода для кнопки
  const byte DelayTimeMs = 100;                                                  //время задержки дорожки в одном состоянии в мс

  //инициализация портов
  DDRB = ddrLED_RoadInit;
  PORTB = portLED_RoadInit;
  DDRD = ddrButtonInit;
  PORTD = portButtonInit;

  while(1)
  {
    if(PIND.ButtonOutputNumber == 0)                                            //если кнопка нажата
    {
      PORTB = (PORTB >> 7) | (PORTB << 1);                                      //циклический сдвиг на один бит влево
      Delay_ms(DelayTimeMs);                                                    //задержка
    }
  }
}

На Паскале:

 program Road;
{ "Бегающая" световая дорожка }
const
   ddrLED_RoadInit = $FF;                                                       //настройка порта со светодиодами - на выход и
   portLED_RoadInit = $FC;                                                      //два светодиода включены (на ноль)
   ddrButtonInit = 0;                                                           //настройка порта с кнопкой - кнопка на вход с подтяжкой
   portButtonInit = $01;
   ButtonPortNumber = 0;
   DelayTimeMs = 100;                                                           //время задержки дорожки в одном состоянии в мс

begin
   //инициализация портов
   DDRB := ddrLED_RoadInit;
   PORTB := portLED_RoadInit;
   DDRD := ddrButtonInit;
   PORTD := portButtonInit;
   
   while(true) do
   begin
      if(PIND.ButtonPortNumber = 0) then                                        //если кнопка нажата
      begin
         PORTB := (PORTB shr 7) or (PORTB shl 1);                               //циклический сдвиг на один бит влево
         Delay_ms(DelayTimeMs);                                                 //задержка
      end;
   end;
end.

Конечно, реализовать эту задачу можно бессчётным количеством способов - пробуйте, выдумывайте)))
А вот готовая программка для прошивки)
Ну а вот как примерно это выглядит в жизни:


Дорожка в результате.

Заковырки на этот раз: возникли проблемки с кнопкой - уж никак она Проблемы с кнопкойне хотела работать, как будто её и не было… Стали разбираться: у нашей кнопки четыре ножки, и дело оказалось в том, что в действительности они по две соединены. Если попытаться изобразить, то будет как-то так.
Тогда если мы соединим ножки 1 и 2 или 3 и 4, то будет всё замечательно, все счастливы, а вот если 1-4 или 2-3, то вместо нормальной кнопки получим просто проводок, вот. В общем, если её повертеть по-всякому, будет понятно)


Автор - Moriam
Обсудить на форуме