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

Проблема

Я остался один дома. То есть совсем один. Практически безвылазно сижу дома. Целый месяц. Работы нет, семьи нет, ничего нет.

Хочу жрать. Ставлю на газ чайник и ухожу продолжать писать прогу.

Через час в квартире становится как-то тепло и влажно… Чайник!!! Почти выкипел. И это случалось много раз.

Оставаться на кухне на 5-10 минут, чтобы караулить чайник, как-то не правильно. А при работе на компе или с паяльником, так ухожу в это дело с головой, что на долгое время забываю, что недавно хотел есть.

Я думаю, что подобные проблемы имеются не только у меня.

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

Нужен какой-то таймер, который поставил, скажем, на 3 минуты, и ушел по своим делам. Таймер отсчитает время и начнет своим громким пиканием капать на мозг. То есть, заставит вернуться на кухню.

Отсюда вытекает

Техническое задание

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

Устройство должно быть простым, иметь автономное питание (батарейку) и очень громко орать по окончании заданного времени.

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

Времена выдержек — фиксированные:

1 минута,
2 минуты,
3 минуты,
5 минут,
10 минут,
15 минут,
20 минут,
30 минут,

Всего — восемь вариантов.

Нажатие на кнопку должно перебирать варианты циклически. После выбора варианта 30 минут таймер должен перейти в отключенное состояние. Из отключенного состояния при нажатии на кнопку должен выбираться вариант выдержки 1 минута.

Нажатие на кнопку должно сопровождаться коротким звуковым сигналом смены варианта выдержки времени.

Вариант выдержки времени должен индицироваться с помощью (точечного) светодиода. В режиме выборки, светодиод соответствующего варианта, должен гореть непрерывно.

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

При переходе из режима выборки варианта в режим отсчета времени таймер должен произвести два коротких звуковых сигнала.

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

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

В первом случае, переход из режима отсчета времени осуществляется в режим отключения и сопровождением короткого звукового сигнала в момент нажатия на кнопку.

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

В режиме оповещения светодиоды погашены. Период подачи серии звуковых сигналов равен 30 секунд.

Серия звуковых сигналов представляет собой следующий набор:

…00010010010101000…

Здесь символом «0» обозначен промежуток времени молчания, а символом «1» — промежуток времени излучения звукового сигнала.

Длительность промежутка времени равна 50 мс.

Длительность режима оповещения либо равна бесконечности, либо ограничивается нажатием на кнопку,

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

Таймер должен быть оформлен в виде коробочки, на передней панели у которой расположены 8 светодиодов и кнопка. У коробки должны быть предусмотрены отверстия для выхода звукового сигнала.

Реализация проекта

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

Особых вычислительных мощностей для задач таймера не требуется, поэтому выбираю самый простой и самый дешевый  микроконтроллер (из тех, которые я знаю) — MSP430F2001.

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

IMG_0845

Как видно — ничего заумного нет. Микроконтроллер, керамический конденсатор, 8 светодиодов, буззер, кнопка и «Крона.» С другой стороны платы находятся пара резисторов, SMD-транзистор 2N7002 и стабилизатор на 3.3В TPS71533.

Cхема

ct-kicad

Схема Кухонного Таймера выполнена на базе микроконтроллера MSP430F2001. Сейчас этот МК в корпусе DIP, но в конечном устройстве он будет в корпусе TSSOP14.

Порт P1 микроконтроллера отдан полностью для светодиодной индикации. Порт P2 в этом микроконтроллере (MSP430F2001) не полный, состоит всего из двух линий. Одна линия нагружена на звуковой буззер, к другой подключена кнопка.

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

Буззер типа EMF-472A, сам вырабатывает звуковой сигнал при подаче на него напряжения. Поскольку буззер запитан от +9В, то управлять им непосредственно от выводов МК нельзя. Поэтому в схеме используется транзистор Q1 типа 2N7002. Резистор в цепи затвора имеет сопротивление 0 Ом. Резистор нужен на тот случай, если вместо полевого транзистора будет использоваться биполярный, например, типа BC547C. В этом случае нужно ограничить ток базы, что осуществляется увеличением сопротивления резистора до 1 кОм.

Тестирование прототипа схема показало, что потребление тока в выключенном режиме составляет 6-8 мкА. Это очень малое значение. Во всяком случае, светодиоды и буззер «пожирают» энергию примерно на три порядка больше. Грубо говоря, одна минута пикания и моргания светодиодом соответствует примерно 16 часам нахождения Таймера в выключенном режиме.

Ну, можно оценить степень воздействия на батарейку зуммер и светодиодов по другому. Ориентировочно батареи должно хватать Таймеру, находящемуся в выключенном режиме, на полгода. Или на 5-6 часов непрерывной сигнализации. То есть один час пиликания соответствует одному месяцу бездействия.

Программное обеспечение

Программную часть проекта составляют несколько файлов.

Makefile
kt.h
hal.c
hal.h

и некоторые другие файлы, которые не принимают непосредственного участия в компиляции и сборке. Это такие файлы как README, в котором находится краткое описание проекта, файлы системы контроля версий git, и некоторые другие.

Содержимое файла Makefile

PROJ=kt

CPU=msp430f2001

CC=msp430-gcc
SZ=msp430-size

CFLAGS=-Os -Wall -c -mmcu=$(CPU)
LFLAGS=-mmcu=$(CPU)

$(PROJ).elf : $(PROJ).o hal.o
    $(CC) $(LFLAGS) -o $(PROJ).elf $(PROJ).o hal.o
    $(SZ) $(PROJ).elf

$(PROJ).o : $(PROJ).c hal.h
    $(CC) $(CFLAGS) -o $(PROJ).o $(PROJ).c

hal.o : hal.c hal.h
    $(CC) $(CFLAGS) -o hal.o hal.c

load:
    mspdebug uif "prog $(PROJ).elf"

clean:
    rm -rf *.o $(PROJ).elf

(Здесь, при публикации Makefile, я использовал символы пробела для отступа строк. Но это не правильно. По правилам нужно использовать табуляцию. Не забывайте об этом, если будете копировать текст файла!)

Файл kt.c

// kt.c


/*
Project: kt
Кухонный таймер
*/



#include <stdint.h>
#include <msp430f2001.h>
#include "hal.h"


int main(void)
{
  InitSystem();

  // Вывыод на P1OUT тактовой частоты SMCLK
  // P1DIR |= BIT4;
  // P1SEL |= BIT4;  // SMCLK

  __bis_SR_register(GIE);
  while (1)
  {
    if (fTestButton == 1)
    {
      testButton();
    }
    
    LPM3; // Включаем режим LPM3
  }

  return 0;
}

Файл hal.c

// hal.c

/*
Project: kt
Кухонный таймер
*/


#include <stdint.h>
#include <msp430f2001.h>
#include "hal.h"


enum mode_t {modeIdle, modeSelect, modeWait, modeAlarm};
enum period_t {p1, p2, p3 ,p5, p10, p15, p20, p30};

// Глобальные переменные
volatile uint8_t fTestButton = 0;  // Флаг необходимости проверить нажатие на кнопку
enum mode_t mode;
enum period_t period;

volatile uint8_t  tBeep1;  // Переменная короткого бипа при нажатии на кнопку
volatile uint8_t  tBeep2;  // Переменная для двух коротких бипов
volatile uint8_t  t2s;     // Переменная для паузы перед стартом отсчета времени
volatile uint16_t tPeriod; // Переменная, отвечающая за длительность выбранного периода

volatile uint8_t led;      // Светодиод выбранного периода
volatile uint16_t tmpPeriod;  // Временная переменная длительности выбранного периода

/*
// Прерывание возникает при нажатии на кнопку
void port2_handler(void) __attribute__((interrupt(PORT2_VECTOR)));
void port2_handler(void)
{
  P2IFG = 0;
}
*/

// Прерывание возникает с частотой 100 Гц, период 10 мс
void timerA0_handler(void) __attribute__((interrupt(TIMERA0_VECTOR)));
void timerA0_handler(void)
{
  static uint8_t t05s;
  static uint8_t t01s;
  static uint8_t phaseAlarm = 0;
  
  fTestButton = 1;

  if (tBeep1 == 1)
  {
    tBeep1 = 0;
    P2OUT &amp;= ~BUZZER;  // Выключить короткий бип
  }
  
  if (mode == modeSelect)
  {
    if (t2s != 0) 
    { // Идет отсчет времени
      if (--t2s == 0)
      { // Пауза закончилась
        tBeep2 = 40;  // Формируем два коротких бипа
      }
    }
  }
  
  if (tBeep2 != 0)
  { // Фаза двух коротких бипов
    tBeep2--;
    switch (tBeep2)
    {
      case 0:
        P2OUT &amp;= ~BUZZER;  // Выключить буззер (два коротких бипа)
        // Запустить отсчет времени выбранного периода
        tPeriod = tmpPeriod;        
        mode = modeWait;
        break;

      case 15:
        P2OUT &amp;= ~BUZZER;  // Выключить буззер (два коротких бипа)
        break;
      
      case 5:
      case 20:
        P2OUT |= BUZZER;  // Включить буззер (два коротких бипа)
        break;
    }
  }
  
  if (++t05s >= 50)
  { // Сюда попадаем каждые полсекунды
    t05s = 0;  // Инициализируем новый полусекундный интервал
    if (tPeriod != 0)
    { // Таймер запущен
      if (--tPeriod == 0)
      { // Период звкончился
        // Переходим к в режим сигнализации
        mode = modeAlarm;
        phaseAlarm = 0;
      }
      else
      { // Продолжаем отсчет времени
        // Моргаем светодиодом
        P1OUT ^= led;
      }
    }
  }
  
  if (mode == modeAlarm)
  {
    if (++t01s >= 10)
    { // Сюда попадаем каждые 100 мс
      t01s = 0;
      switch (++phaseAlarm)
      {
        case 1:
        case 4:
        case 7:
        case 9:
        case 11:
          P2OUT |= BUZZER;  // Включить буззер
          break;
        
        case 2:
        case 5:
        case 8:
        case 10:
        case 12:
          P2OUT &amp;= ~BUZZER;  // Выключить буззер
          break;
        
        case 100:
          phaseAlarm = 0;
          break;
      }
      
    }
  }
  
  LPM3_EXIT; // Включаем режим AM (Active Mode)
}


// Инициализация системы
void InitSystem(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // Останавливаем собаку

  // Инициализируем MCLK
  DCOCTL  = CALDCO_8MHZ;
  BCSCTL1 = CALBC1_8MHZ;
  BCSCTL3 = LFXT1S_2;     // Выбираем для ACLC генератор VLO
  
  // Устанавливаем источник частоты для таймера Timer_A
  TACTL  = 0;  // Останавливаем таймер
  TACTL |= ID_3 + TASSEL_1 + TACLR;  //  ACLK / 8 = 12 kHz / 8 = 1.5 kHz
  TACCR0 = 13;  // 1500 kHz / 15 = 100 Hz, T = 10 мc
    
  TACCTL0 = CCIE;
  TACTL |= MC_1;
    
  // Инициализируем порты
  P1DIR = 0xFF;   // Все ноги на выход
  P1OUT = 0x00;   // Все светодиоды погашены

  P2DIR = BUZZER;  // Ногу на выход
  
  P2REN = BUTTON;  // Разрешим подтяжку
  P2OUT = BUTTON;  // Подтяжка вверх
//  P2IES = BUTTON;  // Прерывание по ниспадающему фронту
//  P2IFG = 0;       // Флаги могут установиться при конфигурирования порта
//  P2IE  = BUTTON;  // Разрешить прерывание
  P2SEL = 0;       // Отключим ноги от генератора
  
  // Инициализируем системные переменные
  fTestButton = 0;
  mode = modeIdle;
  tBeep1 = 0;
  tBeep2 = 0;
  t2s = 0;
}


// Выбор периода
void selectPeriod(enum period_t per)
{
  period = per;

  switch (per)
  {
    case p1:
      led = LED1;
      tmpPeriod = T1M;
      break;
      
    case p2:
      led = LED2;
      tmpPeriod = T2M;
      break;

    case p3:
      led = LED3;
      tmpPeriod = T3M;
      break;

    case p5:
      led = LED5;
      tmpPeriod = T5M;
      break;

    case p10:
      led = LED10;
      tmpPeriod = T10M;
      break;

    case p15:
      led = LED15;
      tmpPeriod = T15M;
      break;

    case p20:
      led = LED20;
      tmpPeriod = T20M;
      break;

    case p30:
      led = LED30;
      tmpPeriod = T30M;
      break;
  }
  P1OUT = led; // Зажечь соответствующий светодиод
  t2s = 200;
}


// Переход к выбору следующего периода
void nextPeriod(void)
{
  switch (period)
  {
    case p1:
      selectPeriod(p2);
      break;
      
    case p2:
      selectPeriod(p3);
      break;

    case p3:
      selectPeriod(p5);
      break;

    case p5:
      selectPeriod(p10);
      break;

    case p10:
      selectPeriod(p15);
      break;

    case p15:
      selectPeriod(p20);
      break;

    case p20:
      selectPeriod(p30);
      break;

    case p30:
      mode  = modeIdle;      
      P1OUT = 0;  // Погасить все светодиоды
      break;
  }
}


// Обработчик нажатие на кнопку
void EventButton(void)
{
  switch (mode)
  {
    case modeIdle:
      mode = modeSelect;
      selectPeriod(p1);
      break;
      
    case modeSelect:
      nextPeriod();
      break;
      
    case modeWait:
      tPeriod = 0;
      P1OUT = 0;  // Погасить все светодиоды      
      mode = modeIdle;
      break;
      
    case modeAlarm:
      mode = modeIdle;
      P1OUT = 0;  // Погасить все светодиоды
      break;
  }
}


// Проверить нажатие на кнопку
void testButton(void)
{
  // Текущее и предыдушее состояния кнопки: 0 - свободна, 1 - нажата
  static uint8_t fButton, fPrevButton;
  
  fTestButton = 0;
  fButton = ((P2IN &amp; BUTTON) == BUTTON) ? 0 : 1;
  
  if ((fButton == 1) &amp;&amp; (fPrevButton == 0))
  { // Произошло нажатие на кномпку  
    tBeep1 = 1;
    P2OUT |= BUZZER;  // Включить короткий бип
    EventButton();
  }
  
  fPrevButton = fButton;  // Сохраним состояние кнопки
}

Файл hal.h

// hal.h


/*
Project: kt
Кухонный таймер
*/

extern volatile uint8_t fTestButton;  // Флаг необходимости проверить нажатие на кнопку



#ifndef __HAL_H__
#define __HAL_H__

// Длительность выдержки в полусекундных долях
#define T1M   (120)
#define T2M   (240)
#define T3M   (360)
#define T5M   (600)
#define T10M (1200)
#define T15M (1800)
#define T20M (2400)
#define T30M (3600)


// Назначение линий портов
// Port 1
#define LED1   (BIT0)
#define LED2   (BIT1)
#define LED3   (BIT2)
#define LED5   (BIT3)
#define LED10  (BIT4)
#define LED15  (BIT5)
#define LED20  (BIT6)
#define LED30  (BIT7)

// Port 2
#define BUZZER  (BIT6)
#define BUTTON  (BIT7)


// Макросы управления сигналами портов
#define Buzzer_On()  (P2OUT |=  BUZZER)
#define Buzzer_Off() (P2OUT &amp;= ~BUZZER)


// Инициализация системы
void InitSystem(void);
void testButton(void);


#endif

Компиляция и сборка проекта дает следующий результат:

$ msp430-size kt.elf 
   text	   data	    bss	    dec	    hex	filename
    950	      0	     22	    972	    3cc	kt.elf

Вся работа по проекту в том числе рисование принципиальной схемы и разработка печатной платы осуществляется в Debian-8.1 Jessie, ядно ядро Linux 3.16.0-4-686-pae, графическая система MATE 1.8.1.

Версия msp430-gcc:

$ msp430-gcc --version
msp430-gcc (GCC) 4.6.3 20120301 (mspgcc LTS 20120406 unpatched)
Copyright (C) 2011 Free Software Foundation, Inc.

Физическая Реализация

Вид со стороны морды лица:

IMG_0851

И вид со стороны… ну, в общем, с другой стороны:

IMG_0852

Вообще пустая плата!

Кино

Видеоролик с работой Кухонного Таймера:

Копирайт

Поскольку проект потребовал небольших затрат времени, то я его выкладываю в общий доступ для свободного копирования и повторения.

А ТЕПЕРЬ РЖЁМ АКИ КОНИ

Давайте подсчитаем себестоимость изготовления.

Во внимание не берём стоимость несуществующего корпуса, не учитываем недорогие радиоэлементы. Кроме того, предполагаем, что разработчик и производитель работают за бесплатно, а государственный бюджет России тоже не претендует на налоги. Итак, считаем по ценам Промэлектроники:

Печатная плата : 50 руб.
Зуммер EMF-472A : 82 руб.
Микроконтроллер MSP430F2001 : 28 руб.
Стабилизатор TPS1533 : 30-50 руб.
Батарейка Крона : 55 руб.

По очень грубым оценкам себестоимость таймера составляет около 250 рублей. Если реально производить такие таймеры в России, то мне кажется, что они появятся в продаже по цене 500 рублей. Не меньше!

А теперь смотрим это видео:

(на вдохе):
— Сколько-сколько?!!!!!!!!!

Update 20.10.2015

Проект кухонного таймера я выложил на github. Чтобы получить его, наберите в консоли команду:

git clone git://github.com/zhevak/kt

После чего у вас в текущем директории появится поддиректорий kt с исходными файлами проекта.

Разумеется, у вас должна быть установлена система контроля версий git, и также вам будет нужен тулчейн для кросс-компиляции проекта и заливки его в микроконтроллер.

UPDATE 09.11.2015

Таймер в корпусе — http://wp.me/p1H7g0-1eS

 

Реклама

4 responses to “Кухонный таймер

  1. Если сходить в магазин ИКЕА, то можно взять там электронный таймер за 129 рублей.
    В Ашане можно взять механический таймер, не сильно дороже, я такой использую.
    А оставшиеся деньги потратить на дорогу туда и обратно.
    Но сделать свой таймер всё равно хочется… Интересно почему?

    • Почему? Да, как бы сказать…
      Есть несколько причин. Они персональные, и применительны только к моему случаю.

      1. Таймер для меня бесплатный. Я его сделал из того, что у меня есть в наличии. А поскольку я сижу без работы, то и стоимость моего рабочего времени тоже бесплатная.

      2. Покупной таймер стоит денег. Плюс дорога в Ашан, который находится на западе Е-бурга (я я живу в пригороде на востоке), — тоже не бесплатная. Работы у меня нет, поэтому неистово экономлю на всём.

      3. Я — мастер. Я родился в Советском Союзе, и моё мировоззрение сформировалось во времена совка. Я испытываю

      «чувство глубокого удовлетворения» (с) Л.И.Брежнев

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

      Люди, которые ничего сами делать не умеют, а все свои проблемы решают деньгами, меня не поймут.

      4. Таймер — полезная вещь. Когда сидишь без работы — чем-то ведь надо наполнять свою жизнь. Надо заполнять время какими-то делами. Ну, не водку же пить!

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

      Вы в гости к бабушке когда последний раз ходили? Она угощала вас своими грибочками, огурчиками, блинами… Вы сидели за столом все вместе и получали удовольствие от общения? Вот, это именно то, чего не купишь ни за какие деньги.

      Я не умею стряпать блины. Но зато я умею делать уникальные электронные гаджеты.

      А поскольку, я так думаю, я такой не один, то почему бы мне не поделиться с общественностью своим «рецептом приготовления» таймера?

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

      Человек не вечен. После меня останутся вещи, по которым люди будут вспоминать обо мне.

      Вот, как-то такушки.

  2. Хрень полная…

    • Ага. Но люди почему-то просят им тоже сделать.

      Жена постоянно использует: варит картошку, яйца — ставит таймер и не заботиться о времени, занимается другими кухонными делами. Не редко и я юзаю: когда хочется попить чайку-кофейку, а сидеть караулить чайник на газу нет желания.

      Да. Хрень полная. Но ведь, собака, работает! Приносит определённую пользу. Удобно с ним. А так — да. Хрень.

      Да, ну и ладно!

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s