Кухонный таймер

Rate this item
(8 votes)

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Кухонный таймер. Что это? сколько стоит?

На рынке существует очень много различных видов кухонных таймеров. Мы будем рассматривать только электронные варианты (еще есть механические). Основное применение данный прибор нашёл на кухне. Отсюда идёт и его название — кухонный таймер. Допустим, вы готовите какое-то блюдо, варите картошку. Через 20 минут после закипания, надо ее выключить — она готова. Можно, конечно запомнить по часам этот промежуток времени, но делать это с помощью таймера гораздо удобнее. Установили нужный интервал времени — нажали кнопку, начался обратный отсчёт времени. Через 20 минут кухонный таймер громко просигналит, обычно в течение 1 минуты. Вот такой простой прибор.

Купить электронный кухонный таймер на рынке можно по цене от 200 до 2000 рублей. Как правило, они отличаются дизайном, размерами и функциями. Все они умеют выполнять основную функцию — таймер обратного отсчёта. Интервал времени почти у всех моделей ограничен 99 минутами (4 разряда цифр — 2 на минуты и 2 на секунды). Дополнительные функции, которые можно встретить:

  • магнитное крепление, крепление на ремень

  • секундомер

  • быстрая установка времени (покрути корпус)

Все рыночные приборы, питаются от батареек, имеют, как правило, ЖК дисплей. Батареек хватает больше чем на 2-3 месяца регулярного использования.

Мы будем делать самодельный кухонный таймер, по функциям превосходящий продаваемые на рынке. Отметим, что этот прибор — отличный радиоконструктор для всех желающих познакомится с микроконтроллерами.

{product id=32}

Постановка задачи, требования к прибору

Основные требования к нашему кухонному таймеру.

  • Компактный размер

  • Питание от аккумулятора, длительная работа от одного заряда

  • Зарядка от micro usb

  • Индикатор как минимум на 3 разряда, лучше 4-е

  • Низкая стоимость

  • Громкий сигнал

  • Широкий набор функций — Таймер, Секундомер, Игры: игральная кость, лото, бомба, возможность программирования.

Подбор компонентов

Компоненты будем подбирать самые простые, недорогие, и доступные на рынке.

Индикатор

Это самый сложный вопрос. На рынке есть следующие виды индикаторов:

  • LCD, TFT дисплей — дорого, большой размер




  • ЖК сегментный индикатор — на 3-4 цифры — вполне подойдёт, но тяжело купить (больше распространён китае), большой плюс — низкое энергопотребление.


  • Светодиодный сегментный индикатор — отличный, недорогой вариант, минусом является высокое энергопотребление, но с аккумулятором это не так страшно. За счет яркости, можно снизить энергопотребление до 2ма. Его несложно купить. Наш таймер будем делать на данном виде индикатора.


Данные индикаторы могут иметь прямое управление каждым светодиодом, но в этом случае у них будет много выводов. Мы выберем 3-х сегментный светодиодный индикатор красного цвета с общим анодом. У каждой цифры аноды светодиодов соединены вместе и выведены на один вывод. На таком индикаторе можно в одном время показать только одну цифру! Как же задействовать все три? Очень просто. Будем использовать динамическую индикацию, то есть очень быстро показывать первую цифру, потом вторую, потом третью. Глаз не успеет заметить этого подвоха, и будет складываться впечатление, что горят одновременно все три цифры! Такая схема очень часто используется в индикаторах, в том числе и в ЖК. Поэтому вам просто необходимо освоить модель программирования таких индикаторов.

Интерфейс общения

Для управления прибором, будем использовать две тактовые кнопки. Прибор будет постоянно «спать» и выходить из сна по нажатию кнопок. Для подачи сигнала будем использовать уже знакомый по прибору Велокомпьютер излучатель HC0903A. Он очень громкий и компактный.

Интерфейс общения должен быть интуитивно понятным. Кухонный таймер будет иметь три режима, изменяемые, например, долгим нажатием первой кнопки.

  • Таймер

  • Секундомер, с возможностью учета рабочего времени

  • Игры

При включении после сна, прибор автоматически возвращается в последний режим, в котором он был до сна.

В режиме таймера:

  • Отображается предустановленное значение таймера в минутах, первая кнопка перебираем предустановленные значения, которые можно запрограммировать

  • Вторая кнопка начинает Отсчет, при окончании раздаётся сигнал

  • Долгое нажатие второй кнопки позволяет поменять значение и запрограммировать новое предустановленное значение

В режиме Секундомера

  • Вторая кнопка старт/пауза

  • Первая кнопка выбор режима — простой секундомер или с подтверждением. В режиме с подтверждением, каждые 5 минут необходимо нажимать кнопку, если не нажали, то секундомер пищит и встаёт на паузу. Так можно измерять рабочее время, когда вы часто отвлекаетесь от рабочего процесса.

В режиме игр

  • Первая кнопка выбор игры

  • Вторая кнопка ход в игре

Конечно, вы можете сами написать свою программу, и сделать совершенно другие комбинации и режимы — это же ваш кухонный таймер — вы его создатель!

Микроконтроллер

Выберем микроконтроллер. Какие требования к микроконтроллеру в нашем проекте?

  • считывать показания 2 кнопок

  • наличие спящего режима для энергосбережения

  • для более полного погружения в программирование, необходим полноценный отладчик

  • удобный корпус для пайки

  • точный внутренний генератор частоты, кварц использовать не будем

  • EEPROM память для хранения настроек

  • достаточное количество выводов для управления индикатором — нужно 11 выводов.

Выберем уже знакомую серию STM8, исключительно по цене. Дополнительно она имеет отличный отладчик ST-Link по 2-ум проводам, симулятор и всю необходимую периферию. Программа будет небольшая, выберем самый дешёвую модель - наш выбор STM8S003F3P6. Можно выбрать серию STM8L — с низким энергопотреблением, но на выбранном микроконтроллере прибор будет работать больше месяца. Этого вполне достаточно.

Аккумулятор

В этот раз будем использовать литиевый аккумулятор меньшего размера — LIR2032, ёмкостью 45 mAh, для того чтобы прибор поместился в небольшой корпус. Схема заряда аналогично велокомпьютеру. Дополнительно будем использовать схему защиты аккумулятора от глубокого разряда из данной статьи.

Составляем схему

Схема зарядки аккумулятора и обвязки МК будет очень похожа на велокомпьютер, так что, не будем повторяться. Для защиты аккумулятора от разряда добавим схему аналогично данной статьи. Для отображения информации добавим ещё светодиодный индикатор — это по сути просто набор светодиодов. При управлении индикатором будем использовать посегментное сканирование — одновременно может светиться только один сегмент из цифры. В этом случае управление сегментом напрямую можно подключить к выводу МК. Резисторы нужны только на общих выводах анода. Резисторы можно использовать 200 Ом, при этом ток свечения одного светодиода будет около 6мА, яркости будет достаточно. Дополнительно ее можно будет снизить за счет динамической индикации для уменьшения потребления. Итак, вот финальная схема.


Вторая часть схемы — зарядка и защита аккумулятора от разряда. Отметим, что резистор R7 здесь не нужен!! При его установке будет только увеличено потребление тока во сне до 50 мкА. Запаивать его не надо!!




Корпус

Подберём небольшой корпус для нашего прибора. Компания SANHE выпускает много универсальных корпусов. Нам подойдет корпус 20-31 размером 30х40мм. Данный корпус очень приятный на ощупь и совсем небольшой.


При трассировке платы будем учитывать необходимые размеры. В корпусе необходимо будет прорезать отверстия под экран и usb разъем. Также нужно будет просверлить отверстия под кнопки. Вот как выглядит собранный прибор в этом корпусе.




Стойки крепления платы необходимо будет убрать — это можно сделать пассатижами. Чтобы отделить аккумулятор от платы необходимо вырезать прокладку из толстого полиэтилена или плотной изоленты.

Программа

Программа, как обычно, для STM8, написана в среде ST Visual develop IDE. Заготовку проекта вы можете скачать с github данного прибора, папка timer. Мы специально не выкладываем полную программу! В этом приборе вы должны сделать ее сами! Только так вы научитесь программировать МК. В заготовке проекта мы сделали самую сложную часть — инициализация, динамическая индикация, спящий режим, обработка кнопок. Вот это мы и разберём в этой статье. В кухонном таймере будем использовать все виды нажатий кнопки — одиночное, двойное, долгое. Такие режимы обработки кнопок очень часто используются в различных устройствах. Читайте внимательно!

Если вы делаете подарок, то вы можете запрограммировать при включении какую-то небольшую мелодию. Это не сложно. В интернет есть много примеров. Заодно поработаете со звуком.

Структура файлов проекта

Проект создан на основе библиотеки SPL для STM8 от ST. Подробное описание, как развернуть проект, вы найдёте в этой статье. Вся программа содержится в файле main.c, обработка прерываний перенесена в этот файл.

Общее описание программы

Упрощённый алгоритм работы программы.

  1. При включении производится настройка всей периферии, тактирование от внутреннего генератора на частоте 2 МГц. Читаем данные из EEPROM. Сразу переходим в спящий режим.

  2. Прибор может находится в одном из трёх режимов — Игры, Таймер, Секундомер, перебор по долгому нажатию первой кнопки. Выбор подрежимов, по обычному нажатию первой кнопки. Запуск и остановка второй кнопкой.

  3. Индикация

    1. Если прибор в режиме игры — то левый сегмент индикация игры — L — лото, Б — бомба, Н — игральная кость. Остальные два разряда для игры.

    2. В режиме таймера. Таймер запущен — мигает точка в такт секундам. Таймер остановлен точка не горит. Таймер может отображать от 999 минут до 0. На экране всегда отображаем значащие разряды, точка разделитель секунд и минут. Например, 900 минут = 900. , 10 минут 15 секунд = 10.1, 1 минута 25 секунд = 1.25.

    3. В режиме секундомера. Запущен — мигает точка в такт секундам. Отображение как в таймере. При остановке секундомера, например на 10 мин 35 сек, показывает целую часть 10. 1сек потом дробную часть .35 1сек и так попеременно.

  4. Таймер

    1. Когда таймер не запущен. Первая кнопка выбираем предустановленные значения.

    2. Вторая кнопка старт таймера из предустановленного значения. Таймер в минутах.

    3. Долгое нажатие второй кнопки переходит в режим настройки значения. В этом режиме вторая кнопка и первая кнопка работают как плюс минус 1 минута. Долгое нажатие Второй кнопки записывает значение в настройку. Быстрое нажатие на кнопки прибавляет по 5 минут.

    4. При достижении конца таймера играем мелодию каждые 60с в течение 5 мин. Пока не остановим кнопкой.

    5. Когда таймер запущен — вторая кнопка долгое нажатие — сброс, первая кнопка - пауза

  5. Секундомер

    1. Когда запущен — мигает точка

    2. Вторая кнопка старт/пауза секундомера

    3. Первая кнопка выбор режима — с подтверждением или без. Когда выбран режим с подтверждением, то горит дополнительно первая точка

    4. Вторая кнопка долгое нажатие сброс

  6. Лото

    1. Игра не началась. Отображаем две тире

    2. Вторая кнопка следующее значение и выдаем звуковой сигнал

    3. Вторая кнопка долгое нажатие начать сначала

    4. в конце игры выдаем мелодию переливы и начинаем сначала

  7. Бомба

    1. Игра не началась — две тире

    2. Вторая кнопка — начать игру. Засекаем случайное время

    3. Игра идет — каждую секунду мигают нули и идет звук как часы пикают. Звук ускоряется каждые 10% оставшегося времени

    4. Когда время вышло — то звучит звук низкого тона — взрыв. У кого в руками остался прибор — тот проиграл. Игра начинается сначала.

  8. Спящий режим

    1. Если ничего не запущено, то через 30с неактивности — глубокий сон

    2. Если запущен таймер или секундомер — то через 30с гасим экран — остаётся только точка мигать каждую сек на 200мс. По кнопке показываем время. Когда осталось 30 сек. Кнопки работают как обычно. Но сначала будят как бы. То есть пробуждение не срабатывает как нажатие кнопки. Будить можно любой кнопкой.

    3. Если запущен секундомер, и про него забыли, не было активности 3ч, то заснуть совсем, а таймер оставить на моменте когда заснули.

Конечно, это один из возможных вариантов работы программы. Вы можете придумать свой собственный вариант. Это же ваш кухонный таймер.

Инициализация, прерывания

Первоначальная инициализация довольно простая.

  1. CLK->PCKENR1 = CLK_PCKENR1_TIM4+CLK_PCKENR1_TIM2;
  2. CLK->PCKENR2 = 0b01110111;
  3.  
  4. CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);
  5.  

Выключаем лишнюю периферию, оставляем только таймер 4 и 2. Тактирование от внутреннего генератора 16 МГц, с делителем 8, для пониженного энергопотребления. В итоге, работаем на частоте 2 МГц. При тактировании от внутреннего генератора, периферия работает на частоте центрального процессора — то есть таймеры будут работать тоже на частоте 2Мгц, имейте это ввиду при настройке счетчиков таймеров.

  1. TIM4_TimeBaseInit(TIM4_PRESCALER_8, 249);
  2. TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  3. TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
  4. TIM4->IER |= (uint8_t)TIM4_IT_UPDATE;
  5.  
  6. TIM2_TimeBaseInit(TIM2_PRESCALER_32, 50);
  7. TIM2_ClearFlag(TIM2_FLAG_UPDATE);
  8. TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
  9. TIM2->IER |= (uint8_t)TIM2_IT_UPDATE;
  10.  

TIM4 будем использовать для миллисекундного отсчета, а TIM2 для динамической индикации. Для TIM2 частота нужна повыше, чтобы не было заметно мерцания, также она не должна быть пропорциональна 50 Гц (частота мерцания лампочек в сети 220В). С другой стороны слишком высокая частота будет больше тратить энергии.

  1. EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA,EXTI_SENSITIVITY_FALL_ONLY);
  2. EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB,EXTI_SENSITIVITY_RISE_ONLY);
  3.  

Кнопки в этот раз будем обрабатывать методом опроса, но не в основном цикле, а в обработчике прерывания миллисекундного таймера. Но прерывания все равно настроить надо, для выхода из спящего режима. Достаточно будет падающего сигнала для прерывания для одной кнопки и возрастающего для другой (так как она включена через подтяжку к VDD).

  1. GPIO_Init(GPIOA,GPIO_PIN_2,GPIO_MODE_IN_PU_IT);//кнопки
  2. GPIO_Init(GPIOB,GPIO_PIN_5,GPIO_MODE_IN_FL_IT);//кнопки
  3.  
  4. GPIO_Init(GPIOD,GPIO_PIN_4,GPIO_MODE_OUT_PP_LOW_SLOW);//пищалка
  5.  
  6. GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_HIGH_SLOW);//индикатор
  7. GPIO_Init(GPIOA,GPIO_PIN_1,GPIO_MODE_OUT_PP_HIGH_SLOW);//
  8. GPIO_Init(GPIOB,GPIO_PIN_4,GPIO_MODE_OUT_PP_HIGH_SLOW);//
  9. GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_HIGH_SLOW);
  10.  
  11. halt();
  12.  

Настраиваем все выводы, так чтобы ничего не светилось и не тратило энергию, и ложимся спать. Такая инициализация необходима для возможности зарядки сильно «просаженного» аккумулятора.

Динамическая индикация

Настройка динамической индикации не очень сложная. Для удобства, необходимо сделать несколько дефайнов:

  1. #define ON1 GPIO_WriteHigh(GPIOC,GPIO_PIN_3)
  2. #define ON2 GPIO_WriteHigh(GPIOD,GPIO_PIN_5)
  3. #define ON3 GPIO_WriteHigh(GPIOD,GPIO_PIN_6)
  4.  
  5. #define OFF1 GPIO_WriteLow(GPIOC,GPIO_PIN_3)
  6. #define OFF2 GPIO_WriteLow(GPIOD,GPIO_PIN_5)
  7. #define OFF3 GPIO_WriteLow(GPIOD,GPIO_PIN_6)
  8.  
  9. #define AON GPIO_WriteLow(GPIOB,GPIO_PIN_4)
  10. #define BON GPIO_WriteLow(GPIOA,GPIO_PIN_1)
  11. #define CON GPIO_WriteLow(GPIOC,GPIO_PIN_6)
  12. #define DON GPIO_WriteLow(GPIOD,GPIO_PIN_3)
  13. #define EON GPIO_WriteLow(GPIOD,GPIO_PIN_2)
  14. #define FON GPIO_WriteLow(GPIOC,GPIO_PIN_4)
  15. #define GON GPIO_WriteLow(GPIOC,GPIO_PIN_5)
  16. #define TON GPIO_WriteLow(GPIOC,GPIO_PIN_7)
  17.  
  18. #define ALLOFFGPIO_WriteHigh(GPIOC,GPIO_PIN_6|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7);GPIO_WriteHigh(GPIOD,GPIO_PIN_2|GPIO_PIN_3);GPIO_WriteHigh(GPIOA,GPIO_PIN_1|GPIO_PIN_3);GPIO_WriteHigh(GPIOB,GPIO_PIN_4);
  19.  

ONx.. OFFx — позволяют включить и выключить 1 цифру. AON..TON — один сегмент в цифре. ALLOFF — выключить все сегменты. Далее, нам нужна вспомогательная функция — cifraS(), которая будет отображать в одной цифре нужный сегмент для выбранного символа (например буквы L, прочерка и т. д.). В функцию передаем нужный сегмент. Информация о том, что необходимо выводить содержится в массиве ind[] и tchk[] для символов и точек.

  1. void cifraS(u8 seg){
  2. u8 j=0;
  3.  
  4. if(seg==0) AON;
  5. if(seg==1) BON;
  6. if(seg==2) CON;
  7. if(seg==3) DON;
  8. if(seg==4) EON;
  9. if(seg==5) FON;
  10. if(seg==6) GON;
  11. if(seg==7) TON;
  12.  
  13. for (j=0;j<3;j++) {
  14. u8 num;
  15. u8 flag=0;
  16.  
  17. if (seg==7) {
  18. if (tchk[j] * tchkmig) flag = 1;
  19. } else {
  20.  
  21. num = ind[j];
  22.  
  23.  
  24. if (num==0) {
  25. //AON;BON;CON;DON;EON;FON;
  26. if(seg==0) flag=1;
  27. if(seg==1) flag=1;
  28. if(seg==2) flag=1;
  29. if(seg==3) flag=1;
  30. if(seg==4) flag=1;
  31. if(seg==5) flag=1;
  32. }
  33. if (num==1) {
  34. //BON;CON;
  35. if(seg==1) flag=1;
  36. if(seg==2) flag=1;
  37.  
  38. }
  39. if (num==2) {
  40. //AON;BON;GON;EON;DON;
  41. if(seg==0) flag=1;
  42. if(seg==1) flag=1;
  43. if(seg==3) flag=1;
  44. if(seg==4) flag=1;
  45. if(seg==6) flag=1;
  46. }
  47. if (num==3) {
  48. //AON;BON;CON;DON;GON;
  49. if(seg==0) flag=1;
  50. if(seg==1) flag=1;
  51. if(seg==2) flag=1;
  52. if(seg==3) flag=1;
  53. if(seg==6) flag=1;
  54. }
  55. if (num==4) {
  56. //FON;GON;BON;CON;
  57. if(seg==1) flag=1;
  58. if(seg==2) flag=1;
  59. if(seg==5) flag=1;
  60. if(seg==6) flag=1;
  61.  
  62. }
  63. if (num==5) {
  64. //AON;FON;GON;CON;DON;
  65. if(seg==0) flag=1;
  66. if(seg==2) flag=1;
  67. if(seg==3) flag=1;
  68. if(seg==5) flag=1;
  69. if(seg==6) flag=1;
  70. }
  71. if (num==6) {
  72. //AON;EON;FON;GON;CON;DON;
  73. if(seg==0) flag=1;
  74. if(seg==2) flag=1;
  75. if(seg==3) flag=1;
  76. if(seg==4) flag=1;
  77. if(seg==5) flag=1;
  78. if(seg==6) flag=1;
  79. }
  80. if (num==7) {
  81. //AON;BON;CON;
  82. if(seg==0) flag=1;
  83. if(seg==1) flag=1;
  84. if(seg==2) flag=1;
  85. }
  86. if (num==8) {
  87. //AON;BON;CON;GON;DON;EON;FON;
  88. if(seg==0) flag=1;
  89. if(seg==1) flag=1;
  90. if(seg==2) flag=1;
  91. if(seg==3) flag=1;
  92. if(seg==4) flag=1;
  93. if(seg==5) flag=1;
  94. if(seg==6) flag=1;
  95. }
  96. if (num==9) {
  97. //AON;BON;CON;GON;DON;FON;
  98. if(seg==0) flag=1;
  99. if(seg==1) flag=1;
  100. if(seg==2) flag=1;
  101. if(seg==3) flag=1;
  102. if(seg==5) flag=1;
  103. if(seg==6) flag=1;
  104. }
  105.  
  106. if (num==14) {
  107. //-
  108. if(seg==6) flag=1;
  109. }
  110.  
  111. if (num==11) {
  112. //L
  113. if(seg==3) flag=1;
  114. if(seg==4) flag=1;
  115. if(seg==5) flag=1;
  116. }
  117.  
  118. if (num==12) {
  119. //K
  120. if(seg==0) flag=1;
  121. if(seg==3) flag=1;
  122. if(seg==4) flag=1;
  123. if(seg==5) flag=1;
  124. }
  125.  
  126. if (num==15) {
  127. //K
  128. if(seg==0) flag=1;
  129. if(seg==3) flag=1;
  130. if(seg==4) flag=1;
  131. if(seg==5) flag=1;
  132. }
  133. }
  134.  
  135. if (flag==1 && j==0 ) ON1;
  136. if (flag==1 && j==1 ) ON2;
  137. if (flag==1 && j==2 ) ON3;
  138.  
  139.  
  140. }
  141. }
  142.  

С дефайнами она выглядит симпатично. Активируем нужный сегмент и проверем в каких из трех цифр он активен. Там где активен — включаем общий анод. Если вам нужны другие символы на индикаторе, то надо добавить еще условия, например, (num==11) — вывести на индикатор L.

Для того, чтобы вывести что-то на индикатор, достаточно положить в массивы ind[] и tchk[] нужные нам значения, остальное будет сделано в прерываниях. Вот так можно вывести число от 0 до 999.

  1. void shownumber(u16 num){
  2. ind[0]=num/100;
  3. ind[1]=num/10-ind[0]*10;
  4. ind[2]=num - ind[0]*100 - ind[1]*10;
  5. }
  6.  

Теперь, собственно сам вывод на индикатор. Вся работа ведётся в обработчике прерывания TIM2. Введём переменную numind, которая будет обозначать, какой сегмент показывать в данный вызов прерывания.

  1. INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
  2. {
  3. TIM2_ClearITPendingBit(TIM2_IT_UPDATE);
  4.  
  5. OFF1;
  6. OFF2;
  7. OFF3;
  8. ALLOFF
  9.  
  10. if (numind<8) {
  11. cifraS(numind);
  12. }
  13.  
  14. numind++;
  15.  
  16. if (numind==16) numind=0;
  17. }
  18.  

Очищаем бит контроля обработки прерывания. Далее выключаем все разряды. Выводим нужные сегменты по всех трех цифрах. А потом несколько раз ничего не выводим. Пропуски нужны для регулирования яркости. У нас получится такая картина

Первый Сегмент, Второй Сегмент, Третий Сегмент, Ничего не горит …. Ничего не горит, Первый сегмент и т.д….

и так, очень быстро. Чем больше мы выводим пустых разрядов — тем более тускло светится индикатор, и меньше тратит энергии.

Обработка кнопок

В кухонном таймере всего две кнопки. Нам надо нагрузить на них максимальный функционал. Поэтому будет нужна обработка одиночного, двойного и долгого нажатия кнопки. Напишем функцию которая сразу определит какой вид нажатия был и вернёт это в основной цикл. Там вы сможете обработать это как вам надо.

Для настройки процедуры обработки кнопок есть несколько дефайнов:

  1. #define KNNUM 2 //колво кнопок
  2. #define KNONE 4 //обычное нажатие
  3. #define KNLONG 5 //долгое
  4. #define KNTWO 6 //двойное
  5.  
  6. #define KNDTIME 50 //время в мс дребезга контактов
  7. #define KNTIMETWO 300 //время в мс двойногонажатия
  8. #define KNTIMELONG 1000 //время в мс долгогонажатия
  9.  

Количество кнопок, значения, которые возвращает функция определения кнопок, время необходимое для устранения дребезга, время в течение которого должно произойти двойное нажатие, время фиксации долгого нажатия. Для хранения обработанных данных используется массив kn[], для хранения предыдущего состояния кнопок массив knstatus[], времени, прошедшего с начала нажатия первой кнопки — kntime[]. При инициализации МК, необходимо очистить все эти массивы.

Сама процедура обработки кнопок вызывается из миллисекундного таймера каждые 50 мс (время нужное для устранения дребезга), так сразу решается проблема с дребезгом контактов.

  1. u8 i,pd;
  2.  
  3. if(kndtime) kndtime--;
  4. if (kndtime==0) {
  5. //опрос кнопок редко для избежаниядребезга
  6. kndtime = KNDTIME;
  7.  
  8. pa = GPIOA->IDR;//GPIO_ReadInputData(GPIOA);
  9. pb = ~(GPIOB->IDR);//_ReadInputData(GPIOB);
  10. knint(0, pa, GPIO_PIN_2);
  11. knint(1, pb, GPIO_PIN_5);
  12. }
  13. for (i=0;i<KNNUM;i++) if(kntime[i]) kntime[i]--;
  14.  

Предварительно считываем состояние порта, на котором висят кнопки. Далее, передаем это значение, номер кнопки, номер вывода кнопки в функцию, в которой будет вся обработка — knint(). Так как кнопка на порту B нажата когда там будет значение 0, то используем операцию инверсии битов.

В конце уменьшаем на единицу переменные таймеры кнопок.

Рассмотрим саму функцию обработки кнопок.

  1. if (knstatus[knum] && ((zn&pin) == 0)) {//кнопкунажали
  2. knstatus[knum] = zn&pin;
  3. if (kn[knum]>=KNONE) return; //еще не обработалипредыдущее нажатие в основном циклепропустим это нажатие
  4.  
  5. kn[knum]++;//колво нажатий плюс один
  6. if (kn[knum]==1) kntime[knum] = KNTIMELONG;//первый разначнм замер времени
  7.  
  8. if (kn[knum]==2) {
  9. if (kntime[knum] > (KNTIMELONG-KNTIMETWO) ) kn[knum] =KNTWO;
  10. else kn[knum] = KNONE;
  11. }
  12. }
  13.  
  14. if ((kn[knum]==1) && (kntime[knum]==0)) kn[knum]=KNLONG;
  15. if ((kn[knum]==1) &&(kntime[knum]<(KNTIMELONG-KNTIMETWO)) && zn&pin)kn[knum]=KNONE;
  16.  
  17. knstatus[knum] = zn&pin;
  18.  

Чтобы определить, что мы нажали кнопку, сравним предыдущее состояние кнопки и состояние вывода. Если кнопка нажата, но мы еще не обработали в основном цикле значение кнопки, то делать ничего не будем. Каждое нажатие увеличиваем на один счётчик нажатий, он будет у нас хранится в элементе массива результата кнопки kn[]. Таким образом, пока мы не знаем точно, какой вид нажатия, то будем там хранить количество нажатий. Если это первое нажатие, то засекаем время определения долгого нажатия. Если это второе нажатие, то проверим уложились ли мы во время двойного нажатия — если да, то фиксируем двойное нажатие, если нет — то обычное.

Каждый раз проверяем, если время долгого нажатия было засечено и оно вышло, то это долгое нажатие кнопки. Если кнопку отпустили, время двойного нажатия вышло и у нас одинарное нажатие, то это обычное нажатие кнопки.

Все! Так несложно можно определить все нужные нам виды нажатия. В основном цикле вы можете обработать их

  1. if (kn[0] == KNONE) {
  2. secundomer = 0;
  3. sleeptime=30;
  4. kn[0]=0;
  5. }
  6. if (kn[0] == KNTWO) {
  7. secundomer = 100;
  8. sleeptime=30;
  9. kn[0]=0;
  10. }
  11. if (kn[0] == KNLONG) {
  12. secundomer = 200;
  13. sleeptime=30;
  14. kn[0]=0;
  15. }
  16.  

После обработки, необходимо очистить элемента массива kn[], для фиксирования нового нажатия. Вы можете использовать этот код в своих проектах, добавить количество кнопок, поменять время обработки различных ситуаций.

Начало положено, остальной код программы мы не приводим, так как это ваше творчество!

Как изготовить кухонный таймер самостоятельно

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

  4. Изготовить плату для прибора самостоятельно (это совсем несложно, в нашей инструкции все подробно описано).

  5. Приобрести все необходимые комплектующие.

  6. Запаять все компоненты на плату, смотри наше видео.

  7. Плата готова!

Для программирования вам понадобятся временно припаять провод выводу J3 (PRG). Питание можно подключить сразу с ST-Link в разъем аккумулятора.

Переходим к программированию

Данный прибор достаточно простой в программировании. В этой статье подробно разобрана самая сложная часть программы — динамическая индикация. Остальную программу вам надо написать самостоятельно. Только так вы сможете изучить программирование микроконтроллеров.

Рекомендуем написать программу совсем с нуля, с разворачивания проекта.

Приобретённые навыки

Пайка: пайка корпуса TTSOP, пайка корпуса SOT-23-5, пайка micro USB разъёма

Корпус: самодельный корпус из короба

Схемотехника: LDO, схема зарядки Liion аккумулятора, типовая схема подключения STM8, подключение пищалки, работа с кнопками.

Программирование: сложная обработка кнопок, миллисекундный таймер, динамическая индикация, спящий режим, работа с EEPROM

Самостоятельная работа

Прибор очень простой, но интересный и полезный. На github мы выкладываем только шаблон проекта. В данном шаблоне настроено энергопотребление, прерывания, таймеры, обработка кнопок, динамическая индикация с выводом трёх символов и точек. Остальное мы рекомендуем сделать самостоятельно. У вас получится отличный кухонный таймер, для себя или в подарок.

Read 11828 times

Media