Гирлянда на МК Tiny 2313 и 4 светодиодах

01.12.2015 19:41

"Нажата ли ты, наша кнопочка, или отжата?", - именно таким вопросом мы задавались в прошлой статье. И в зависимости от состояния кнопки мы делали эффект из 4 светодиодов. В этой статье мы с вами разберем похожую ситуацию. Итак, погнали!

 

 

Помните китайскую гирлянду за 100 рублей?)

 

Нажимаем кнопочку  и эффект моргания становится абсолютно другой ;-) Именно этим мы с вами и займемся в этой статье ;-)

 

Мы не будем делать китайску гирлянду с N-ным количеством лампочек, а сделаем упрощенную схему такой гирлянды на МК AVR Tiny2313 и четырех светодиодах. С помощью кнопки мы будем менять эффект моргания.

 

Итак, наша задача буквально звучит так:

Создать гирлянду на МК AVR Tiny2313 из четырех светодиодов и одной кнопки с самовозвратом (кнопка, которую нажал и сама отжимается). Нажимаем один раз кнопку - появляется первый эффект моргания кнопки, нажал второй раз кнопку - появился второй эффект моргания и тд. Всего у нас будет семь эффектов. Условие такое, что пока светодиоды переливаются морганием, у нас МК не реагирует на кнопку. То есть пока не прошел эффект, нажатие на кнопку никак не отображается на эффекте. Эффект НЕ прерывается. Когда эффект закончится, только тогда МК будет обрабатывать нажатие на кнопку.

 

Задача вроде бы ясна. Для начала составим простенькую схемку в Proteus. Схемка будет выглядеть примерно как-то так (кликните для увеличения, откроется в новом окне):

 

Все? Нет не все! Теперь шьем наш МК HEX-файлом. А где его взять? Из Atmel Studio 6. Но чтобы его создать, нам потребуется для начала написать программу, по которой будет работать наш МК. Как все это сделать, смотрим в этой статье.  Ниже приведен текст программы, справа  - комментарии.  Я пытался подробно расписать каждую строчку кода.

 

 А вот собственно и программка в  AVR Studio 6:

  1. #include       //Подключаем библиотеки
  2. #define F_CPU 8000000UL //Устанавливаем частоту 8 МегаГерц
  3. #include //Подключаем библиотеки
  4. int main(void)          //открываем основное тело программы
  5. {
  6.     PORTB=0b00000000;   //Притягиваем все 8 выводов порта В к 0
  7.     DDRB=0b00001111;    // Конфигурируем 0-4 на выход
  8.                         //а выход а 5-8 на вход
  9.                         //думаю, вы не забыли
  10.                         //что счет идет СПРАВА-НАЛЕВО
  11.     PORTA=0b00000000;   //Притягиваем все 8 выводов порта А к 0
  12.     DDRA=0b00000000;    //Конфигурируем все выводы порта А на вход
  13.     unsigned char k=0; //Объявляем переменную "К"
  14.                         //и присваиваем ей ноль
  15.                         //то есть в данный момент K - это НОЛЬ.
  16.  
  17.     while(1)            //Открываем бесконечный цикл
  18.     {
  19.         M5:             //Метка для перехода М5.
  20.                         //То есть объявляем метку
  21.                         //и ставим двоеточие после нее.
  22.  
  23.  if (PINA&(1<
  24.                        //если на ножке PA0 есть единичка
  25.                        //то переходим по коду ниже
  26.                        //Не спрашивайте меня,
  27.                        //почему такая запись.
  28.                        //Я сам  не знаю))
  29.      {_delay_ms(50);   //включаем задержку 50 миллисекунд для антидребезга
  30.            
  31.      k=k+1;            //Увеличиваем значение переменной "К" на единицу
  32.                        // то есть "новое К", которое слева
  33.                        //от знака "=" высчитывается по формуле справа.
  34.             if (k==8// Проверяем, НЕ РАВНЯЕТСЯ ЛИ "K" восьми???
  35.                        //если да, то переходим по коду ниже
  36.             {
  37.             k= 0; goto M5;// если "К" равно восьми
  38.                           // то устанавливаем значение переменной "К" равным нулю.
  39.                           // и переходим по метке M5
  40.             }
  41.             else          //"иначе", если не равняется
  42.                           //то переходим по коду ниже
  43.                           // то есть к метке M6
  44.             {
  45.                 goto M6;  // описание метки М6 ниже
  46.             }
  47.         }
  48.         else              //если же кнопка ВАЩЕ не нажималась
  49.                           // ни разу, то переходим к метке M5
  50.         {
  51.             goto M5;    //Если кнопка не была нажата
  52.                         // крутим бесконечный цикл
  53.                         // и все время опрашиваем кнопку
  54.                         //то есть ждем, когда на PA0 будет единичка
  55.         }
  56.         M6:             //а вот и метка М6
  57.         if (k==1)       // РАВНЯЕТСЯ ЛИ НОВОЕ "К" ЕДИНИЦЕ? Да?
  58.                         //Если да, то выполняем код ниже
  59.         {
  60.             PORTB=0b00000001; //*******************************       
  61.             _delay_ms(30);    //                              *
  62.             PORTB=0b00000000; //                              *
  63.             _delay_ms(30);    //                              *
  64.             PORTB=0b00000010; //                              *
  65.             _delay_ms(30);    //                              *
  66.             PORTB=0b00000000; //                              *
  67.             _delay_ms(30);    //                              *
  68.             PORTB=0b00000100; //     Крутим первый эффект     *
  69.             _delay_ms(30);    //                              *
  70.             PORTB=0b00000000; //                              *
  71.             _delay_ms(30);    //                              *
  72.             PORTB=0b00001000; //                              *
  73.             _delay_ms(30);    //                              *
  74.             PORTB=0b00000000; //                              *
  75.             _delay_ms(30);    // ******************************
  76.                        
  77.         goto M5;} //Покрутили? Возвращаемся к опросу кнопки, то есть к метке М5
  78.         if (k==2) //Равняется ли "К" двум?
  79.                   // Да?
  80.                   //Здесь уже к новому значению К по формуле
  81.                   //K=K+1 суммируется еще единичка
  82.                   //Получаем что-то типа счетчика.
  83.                   //То есть уже будет ДВА
  84.                   // Крутим эффект ниже.
  85.         {
  86.                   //Все остальные эффекты
  87.                   //я сделал на свой вкус
  88.                   //Вы можете сделать
  89.                   //другие эффекты.
  90.             PORTB=0b00000001;
  91.             _delay_ms(100);
  92.             PORTB=0b00000000;
  93.             _delay_ms(100);
  94.             PORTB=0b00000010;
  95.             _delay_ms(100);
  96.             PORTB=0b00000000;
  97.             _delay_ms(100);
  98.             PORTB=0b00000100;
  99.             _delay_ms(100);
  100.             PORTB=0b00000000;
  101.             _delay_ms(100);
  102.             PORTB=0b00001000;
  103.             _delay_ms(100);
  104.             PORTB=0b00000000;
  105.             _delay_ms(100);
  106.             PORTB=0b00000100;
  107.             _delay_ms(100);
  108.             PORTB=0b00000000;
  109.             _delay_ms(100);
  110.             PORTB=0b00000010;
  111.             _delay_ms(100);
  112.             PORTB=0b00000000;
  113.             _delay_ms(100);
  114.             PORTB=0b00000001;
  115.             _delay_ms(100);
  116.             PORTB=0b00000000;
  117.             _delay_ms(100);
  118.         goto M5; }
  119.         if (k==3)
  120.         {
  121.             PORTB=0b00000101;
  122.             _delay_ms(400);
  123.             PORTB=0b000001010;
  124.             _delay_ms(400);
  125.             PORTB=0b00000000;
  126.             goto M5;
  127.         }
  128.         if (k==4)
  129.         {
  130.             PORTB=0b00001111;
  131.             _delay_ms(500);
  132.             PORTB=0b00000000;
  133.             _delay_ms(50);
  134.             goto M5;
  135.         }
  136.         if (k==5)
  137.         {
  138.             PORTB=0b00000001;
  139.             _delay_ms(200);
  140.             PORTB=0b00000011;
  141.             _delay_ms(200);
  142.             PORTB=0b00000111;
  143.             _delay_ms(200);
  144.             PORTB=0b00001111;
  145.             _delay_ms(200);
  146.             PORTB=0b00000000;
  147.             goto M5;
  148.         }
  149.         if (k==6)
  150.         {
  151.             PORTB=0b00000001;
  152.             _delay_ms(10);
  153.             PORTB=0b00000010;
  154.             _delay_ms(10);
  155.             PORTB=0b00000100;
  156.             _delay_ms(10);
  157.             PORTB=0b00001000;
  158.             _delay_ms(10);
  159.             PORTB=0b00000000;
  160.             goto M5;
  161.         }
  162.         if (k==7)
  163.         {
  164.             PORTB=0b00000001;
  165.             _delay_ms(20);
  166.             PORTB=0b00000000;
  167.             _delay_ms(20);
  168.             PORTB=0b00000001;
  169.             _delay_ms(20);
  170.             PORTB=0b00000000;
  171.             _delay_ms(20);
  172.             PORTB=0b00000010;
  173.             _delay_ms(20);
  174.             PORTB=0b00000000;
  175.             _delay_ms(20);
  176.             PORTB=0b00000010;
  177.             _delay_ms(20);
  178.             PORTB=0b00000000;
  179.             _delay_ms(20);
  180.             PORTB=0b00000100;
  181.             _delay_ms(20);
  182.             PORTB=0b00000000;
  183.             _delay_ms(20);
  184.             PORTB=0b00000100;
  185.             _delay_ms(20);
  186.             PORTB=0b00001000;
  187.             _delay_ms(20);
  188.             PORTB=0b00000000;
  189.             _delay_ms(20);
  190.             PORTB=0b00001000;
  191.             _delay_ms(20);
  192.             PORTB=0b00000000;
  193.             _delay_ms(20);
  194.             goto M5;
  195.         }
  196.     }
  197. }

 

 

Обратите внимание также на строчку кода под номером 30:

{_delay_ms(50);   //включаем задержку 50 миллисекунд для антидребезга

Программа Proteus спокойно бы работала и без этой строчки кода. Зачем мы тогда ее вставили? Дело все в том, что реальное положение дел чуточку хуже. Козлом отпущения в данном случае будет самая безобидная кнопка, которую мы поставим в схему на переключение гирлянд, собрав ее на макетной плате.

Что делает кнопка в схеме согласно схемотехнике МК? Подает логический ноль или единицу на ножку МК. Так? Так. Но в реальной схеме она не сразу замыкает и размыкает цепь. При замыкании или размыкании кнопки у нас нет четкого переключения уровней сигнала с логической единицы на ноль и наоборот. Переключение с помощи кнопки выглядит примерно вот так:

 

С логической единицы на ноль:

 

 

С логического ноля на единицу:

 

Вот эта билиберда при переключении кнопки носит название дребезг контактов и мешает разработчикам логических устройств. Дело в том, что эти хаотические импульсы МК может посчитать как логический ноль или как единичку.  То есть нажатие на кнопку в таком случае приведет к ложным срабатываниям всей схемы на МК. В настоящее время это недоразумение  благополучно устранено. Сначала  научились убирать дребезг с помощью нехитрых схем, ну а потом просто тупо вставляя строчку кода в программе, что мы с вами и сделали в нашей программе ;-)

 

Программку можно было написать и красивее, но для наглядности я ее изобразил обычным столбом, так как ширина моей колонки на сайте ограничена. После того, как скомпилировали нашу программку и получили HEX-файл, мы скармливаем его нашему виртуальному МК в программе Proteus и проверяем в деле. Прикрепляю в архиве файл Сишник, HEX и файл Протеуса.

 

А вот и видео работы нашего проекта:

 

Читайте также:

Подключение кнопки к МК AVR

 

Как прошить микроконтроллер AVR?

 

Эмуляция проекта на МК AVR в программе Proteus