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

Привет самоделкины!
В данной статье вашему вниманию предлагается небольшой приборчик, который поможет отсчитать нужное время во многих сферах вашей деятельности. Конечно, сейчас имеется огромное количество подобных приспособлений. даже в наших смартфонах есть подобное приложение. Но намного приятней изготовить самому и использовать его в быту. Что бы он был всегда под рукой и его легко можно было бы использовать.
Кухонный таймер Для реализации проекта потребуются:
— Микропроцессор ATtiny32161шт,
Поворотный энкодер ec12e24204a8 (24 импульса / оборот, с ручкой 12 мм) 1шт,
4-х разрядный 7-ми сегментный индикатор без шины I2C 0,36 дюйма1шт,
Кнопка для монтажа на плату 1шт,
Зуммер высотой 5мм 1шт,
Интегральная микросхема 74HC14 1шт,
— Резистор SMD (0805) 2 кОм 2шт,
— Резистор SMD (0805) 10 кОм 2шт,
— Керамический конденсатор (1206) 10 мкФ 1шт,
— Arduino IDE
— 3D-принтер
— Паяльник
В данном проекте в качестве считывателя использован механический энкодер. Конкретно модель EC12E24204A8 с высотой ручки 12мм.
Кухонный таймерИменно такой элемент больше всего подходит для реализации проекта. Под его контакты на монтажной плате имеются отверстия. И рассчитано положение для свободной шестеренчатой передачи внутри корпуса для изменения значений на цифровом дисплее.
Кухонный таймерПосмотреть ознакомительное видео с работой готового устройства можно на канале YouTube. Как можно заметить — градация отсчета и индикации составляет 1 секунду, а управление сведено к минимуму, что очень удобно.
Что касается схемы приборчика, то там сложного ничего нет. Как и писалось выше основным инструментом для считывания поворота части корпуса и задания времени срабатывания сигнала зуммера используется механический энкодер. Но все таки основным элементом является программируемый микроконтроллер ATtiny3216. У него имеется достаточное количество контактов, что бы использовать их для подключения напрямую к дисплею, не используя шину I2C. Это довольно таки распространенный микроконтроллер, поэтому найти его не составит труда.
Если посмотреть на схему, станет понятным использование микросхемы 74HC14. В спящем режиме она блокирует контакты энкодера для экономии расхода заряда источника питания.
Кухонный таймерПосле распечатки деталей корпуса (ссылка для скачивания будет в конце статьи) и травления платы (так же оригинальная плата будет предоставлена для скачивания). можно приступать к сборке прибора.
Плата для монтажа будет выглядеть вот так:
Кухонный таймерНачать электромонтаж лучше с мелких деталей. Первым делом установите SMD компоненты микросхему 74HC14 и микроконтроллер ATtiny3216.
Кухонный таймерДальше можно припаять пару разъемов. Это будет разъем для программатора и разъем для батарейки. Можно установить кнопку с обратной стороны платы.
Кухонный таймерДальше можно установить индикатор со стороны где установлена кнопка.
Кухонный таймерПочти последней припаянной деталькой будет поворотный энкодер. Он устанавливается со стороны, где расположены микросхемы. Пропаивать деталь не спешите, сначала примерьте. Проверьте как будет сидеть на месте и в корпусе. Все таки в дальнейшем на него будет механическое воздействие.
Кухонный таймерСо стороны индикатора и кнопки установите зуммер. Вот теперь смонтированы все радиокомпоненты!
Кухонный таймерНачинаем сборку.
Первым делом нужно установить распечатанную на принтере шестеренку (в скачанных файлах будет Twist — Pinion) на поворотный вал энкодера. Зафиксировать можно с помощью клея.
Кухонный таймерГотовую плату нужно вставить в верхнюю часть корпуса (Twist — Top). Закрепить ее можно с помощью пары винтиков М3.
Кухонный таймерКухонный таймерДальше распечатанные на принтере детали нужно скомпоновать между собой. Сначала надо склеить шестерню с внутренними зубьями (Twist — Ring) и внешний обод (Twist — Rim).
Кухонный таймерКухонный таймерТеперь важная часть сборки прибора. При установке на место сборки деталей с внутренней шестерней на сборку верхней части и платы, важно обратить внимание на свободный ход (поворот) большой шестерни относительно шестеренки, закрепленной на валу энкодера. Усилий не должно быть никаких и вращение малой шестеренки должно быть легким и свободным.
Кухонный таймерСледующим шагом к нижней части корпуса (Twist — Bottom) нужно установить контакты в батарейном отсеке и припаять к ним провода питания с установленным встречным разъемом что был припаян к плате.
Кухонный таймерКухонный таймерЕсли вращение частей корпуса и поворот вала энкодера свободные, без «затираний» и тем более усилий, можно приступить к следующей части. А именно программирование микроконтроллера. В случае если механическому движению частей что мешает, воспользуйтесь надфилями и припИлите проблемные зоны.
Для заливки кода в микроконтроллер вам понадобится UPDI программатор. О его постройке самому на основе Arduino есть множество статей в свободном доступе нашего интернета. Имеются и готовые решения, поэтому на этом вопросе останавливаться долго не стоит.
Кухонный таймерДля проверки работоспособности прибора осталось вставить пару батареек в отсек и включить прибор.
Кухонный таймерФайлы для скачивания:
— Файлы корпуса (формат .STL)
— Схема (формат.PNG)
— Печатная плата (формат .JPG)
— Схема и печатная плата в формате Eagle (форматы .SCH и .BRD)
— Код программы (формат .INO)
Так же можно скачать текст программы из спойлера ниже:

Магнитная щетка для мытья окон: что это...
9 часов назад
Развивающий детский конструктор с шуруповертом + 2 подарка
7 часов назад

/**************************************************************************
TWIST-TO-SET KITCHEN TIMER
New mechanics, electronics and software for «an Attiny85 Twist-to-Set Kitchen Timer» by bobson.h
(https://www.instructables.com/an-Attiny85-Twist-to-Set-Kitchen-Timer/)

2027-04-20 V1 John Bradnam (jbrad2089@gmail.com)
— Replaced optical rotary encoder with a mechanical rotary encoder
— Designed new hardware around ATtiny3216 microprocessor
— Initial code base

—————————————————————————
Arduino IDE:
—————————————————————————
BOARD: 20pin tinyAVR 0/1/2 Series
Chip: ATtiny3216
Clock Speed: 5MHz Internal
Programmer: jtag2updi (megaTinyCore)
ATtiny3216 Pins mapped to Ardunio Pins
_____
VDD 1|* |20 GND
(nSS) (AIN4) PA4 0~ 2| |19 16~ PA3 (AIN3)(SCK)(EXTCLK)
(AIN5) PA5 1~ 3| |18 15 PA2 (AIN2)(MISO)
(DAC) (AIN6) PA6 2 4| |17 14 PA1 (AIN1)(MOSI)
(AIN7) PA7 3 5| |16 17 PA0 (AIN0/nRESET/UPDI)
(AIN8) PB5 4 6| |15 13 PC3
(AIN9) PB4 5 7| |14 12 PC2
(RXD) (TOSC1) PB3 6 8| |13 11~ PC1 (PWM only on 1-series)
(TXD) (TOSC2) PB2 7~ 9| |12 10~ PC0 (PWM only on 1-series)
(SDA) (AIN10) PB1 8~ 10|_____|11 9~ PB0 (AIN11)(SCL)

PA0 to PA7, PB0 to PB5, PC0 to PC3 can be analog or digital
PWM on D0, D1, D7, D8, D9, D10, D11, D16

**************************************************************************/
#include
#include
#include
//Pins
#define SPEAKER 12 //(PC2)
#define SWITCH 16 //(PA3)
#define SEG_A 1 //(PA5)
#define SEG_B 15 //(PA2)
#define SEG_C 10 //(PC0)
#define SEG_D 8 //(PB1)
#define SEG_E 7 //(PB2)
#define SEG_F 0 //(PA4)
#define SEG_G 9 //(PB0)
#define SEG_DP 11 //(PC1)
#define DIG_1 2 //(PA6)
#define DIG_2 3 //(PA7)
#define DIG_3 14 //(PA1)
#define DIG_4 6 //(PB3)
#define ENC_A 4 //(PB5)
#define ENC_B 5 //(PB4)
#define PA0_bm PIN0_bm
#define PA1_bm PIN1_bm
#define PA2_bm PIN2_bm
#define PA3_bm PIN3_bm
#define PA4_bm PIN4_bm
#define PA5_bm PIN5_bm
#define PA6_bm PIN6_bm
#define PA7_bm PIN7_bm
#define PB0_bm PIN0_bm
#define PB1_bm PIN1_bm
#define PB2_bm PIN2_bm
#define PB3_bm PIN3_bm
#define PB4_bm PIN4_bm
#define PB5_bm PIN5_bm
#define PC0_bm PIN0_bm
#define PC1_bm PIN1_bm
#define PC2_bm PIN2_bm
#define PC3_bm PIN3_bm
#define TCB_COMPARE 150 //Refresh value for 7 segment display (1000@20MHz, 100@4MHZ)
#define BRIGHTNESS 2 //Initial brightness level (0 to 15)
#define DIGITS 4 //Number of digits in display
uint8_t digits[DIGITS]; //Holds the current digits to display
uint8_t nextDigit = 0; //Holds next digit to display
uint8_t brightness = BRIGHTNESS; //Current Brightness level (0 to 15)
uint8_t bamCounter = 0; //Bit Angle Modulation variable to keep track of things
uint8_t bamBit; //Used to store bit to test against brightness value
//Digit array
#define SPACE 10
uint8_t segments[11] = {
// abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg
B01111110,B00110000,B01101101,B01111001,B00110011,B01011011,B01011111,B01110000,
B01111111,B01111011,B00000000
};
//EEPROM handling
#define EEPROM_ADDRESS 0
#define EEPROM_MAGIC 0x0BAD0DAD
typedef struct {
uint32_t magic;
int countdownTime;
} EEPROM_DATA;
EEPROM_DATA volatile EepromData; //Current EEPROM settings

#define COLON_FLASH_RATE 500;
unsigned long colonTimeout;
bool colonOn = false;
#define SLEEP_TIMEOUT 10000 //Amount of time no switch is pressed before going to sleep
uint32_t sleepTimeout = 0; //Used to timeout mode switch function to sleep function
bool volatile ignoreNextPress = false;
int8_t volatile rotaryDirection = 0;
bool volatile lastRotA = false;
bool volatile timeChanged = false;
bool volatile inCoundownMode = false;
bool volatile alarmOn = false;
//————————————————————————-
//Initialise Hardware
void setup()
{
pinMode(SWITCH, INPUT_PULLUP);
pinMode(ENC_A, INPUT);
pinMode(ENC_B, INPUT);
pinMode(SPEAKER, OUTPUT);
digitalWrite(SPEAKER, LOW);
readEepromData();

Мужской триммер для бороды и волос. -50%!
9 часов назад
Набор для быстрого ремонта стекла своими руками
8 часов назад

//Initialise digits
memset(&digits[0],SPACE,4);
//Set up 7 segment display refresh timer
TCB1.CCMP = TCB_COMPARE;
TCB1.INTCTRL = TCB_CAPT_bm;
TCB1.CTRLA = TCB_ENABLE_bm;
//Interrupt handers for rotary encoder
attachRotaryPinChangeInterrupt();
//Attach interrupt handler to wake up from sleep mode
attachInterrupt(SWITCH, switchInterrupt, CHANGE);

// Initialize RTC
while (RTC.STATUS > 0); // Wait until registers synchronized
RTC.PER = 1023; // Set period 1 second
RTC.CLKSEL = RTC_CLKSEL_INT32K_gc; // 32.768kHz Internal Oscillator
RTC.INTCTRL = RTC_OVF_bm; // Enable overflow interrupt
RTC.CTRLA = RTC_PRESCALER_DIV32_gc | RTC_RTCEN_bm;// Prescaler /32 and enable
//Force a display update
inCoundownMode = false;
timeChanged = true;
sleepTimeout = millis() + SLEEP_TIMEOUT;
//Enable interrupts
sei();
}
//———————————————————
// Attach the pin change interrupts for the rotary encoder
void attachRotaryPinChangeInterrupt()
{
attachInterrupt(ENC_A, rotaryInterrupt, CHANGE);
}
//———————————————————
// Detach the pin change interrupts for the rotary encoder
void detachRotaryPinChangeInterrupt()
{
detachInterrupt(ENC_A);
}
//————————————————————————-
// Main loop
void loop()
{
if (buttonPressed())
{
if (inCoundownMode)
{
//Stop countdown
inCoundownMode = false;
displayTime(EepromData.countdownTime, true);
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
else
{
//Start countdown
writeEepromData(); //Save last time
colonTimeout = millis() + COLON_FLASH_RATE;
colonOn = false;
timeChanged = true;
inCoundownMode = true;
}
}

if (inCoundownMode)
{
//Handle flashing colon
if (colonTimeout < millis())
{
colonTimeout = millis() + COLON_FLASH_RATE;
colonOn = !colonOn;
timeChanged = true;
}
if (timeChanged)
{
displayTime(EepromData.countdownTime, colonOn);
timeChanged = false;
}
if (EepromData.countdownTime == 0)
{
displayTime(EepromData.countdownTime, true);
soundAlaram();
inCoundownMode = false;
readEepromData(); //Pull last time used
displayTime(EepromData.countdownTime, true);
}
}
else if (timeChanged || rotaryDirection != 0)
{
if (rotaryDirection == 1 && EepromData.countdownTime < 3600)
{
EepromData.countdownTime += 1;
}
else if (rotaryDirection == -1 && EepromData.countdownTime > 0)
{
EepromData.countdownTime -= 1;
}
rotaryDirection = 0;
displayTime(EepromData.countdownTime, true);
timeChanged = false;
sleepTimeout = millis() + SLEEP_TIMEOUT;
}
else if (!inCoundownMode && millis() >= sleepTimeout)
{
gotoSleep();
}
else
{
delay(100);
}
}
//————————————————————————————
//Display a number on the 7 segment display
void displayTime(int secs, bool colon)
{
displayNumber(secs / 60, colon, true, 2);
displayNumber(secs % 60, colon, true, 0);
}
//————————————————————————————
//Display a number on the 7 segment display
void displayNumber(int number, bool colon, bool leading, int pos)
{
for (uint8_t i = 0; i < 2; i++)
{
if (number > 0 || leading || i == 0)
{
digits[pos + i] = number % 10;
}
else
{
digits[pos + i] = SPACE;
}
if (colon && pos == 2 && i == 0)
{
digits[pos + i] |= 0x80;
}
number = number / 10;
}
}
//————————————————————————————
//Turn off display
void displayOff()
{
//Turn off display timer
TCB1.CTRLA = TCB1.CTRLA & ~TCB_ENABLE_bm;

//Set all digit cathodes HIGH and all segment anodes LOW
PORTA.OUT = PORTA.IN & ~(PA2_bm | PA4_bm | PA5_bm) | PA1_bm | PA6_bm | PA7_bm; //(B, F, A), 3, 1, 2
PORTB.OUT = PORTB_IN & ~(PB0_bm | PB1_bm | PB2_bm) | PB3_bm; //(G, D, E), 4
PORTC.OUT = PORTC.IN & ~(PC0_bm | PC1_bm); //(C, DP)
}
//————————————————————————————
//Turn on display
void displayOn()
{
//Turn on display timer
TCB1.CTRLA = TCB1.CTRLA | TCB_ENABLE_bm;
}
//—————————————————————
// Test if button pessed
bool buttonPressed()
{
bool down = false;
if (digitalRead(SWITCH) == LOW)
{
delay(10);
if (digitalRead(SWITCH) == LOW)
{
while (digitalRead(SWITCH) == LOW)
{
yield();
}
down = !ignoreNextPress;
ignoreNextPress = false;
}
}
return down;
}
//————————————————————————————
// Sound alarm
#define NOTE_A2 110
#define NOTE_B2 123
#define NOTE_G2 98
#define NOTE_G1 49
#define NOTE_D2 73
#define NUM_NOTES 5
const int closeEncounters[] PROGMEM = { // notes in the melody:
NOTE_A2, NOTE_B2, NOTE_G2, NOTE_G1, NOTE_D2 // «Close Encounters» tones
};
#define NOTE_DURATION 800

//Play the «Close Encounters» melody
void soundAlaram()
{
detachRotaryPinChangeInterrupt();
int thisNote;
alarmOn = true;
while (alarmOn)
{
displayOff();
thisNote = 0;
while (alarmOn && (thisNote < NUM_NOTES))
{
tone(SPEAKER, pgm_read_byte(closeEncounters + thisNote) * 4);
delay(NOTE_DURATION);
thisNote++;
}
noTone(SPEAKER);
displayOn();
long timeout = millis() + 2000;
while (alarmOn && (millis() < timeout))
{
yield();
}
}
attachRotaryPinChangeInterrupt();
ignoreNextPress = true;
}
//———————————————————————
//Write the EepromData structure to EEPROM
void writeEepromData(void)
{
//This function uses EEPROM.update() to perform the write, so does not rewrites the value if it didn’t change.
EEPROM.put(EEPROM_ADDRESS,EepromData);
}
//———————————————————————
//Read the EepromData structure from EEPROM, initialise if necessary
void readEepromData(void)
{
#ifndef RESET_EEPROM
EEPROM.get(EEPROM_ADDRESS,EepromData);
if (EepromData.magic != EEPROM_MAGIC)
{
#endif
EepromData.magic = EEPROM_MAGIC;
EepromData.countdownTime = 0;
writeEepromData();
#ifndef RESET_EEPROM
}
#endif
}
//———————————————————
// Shut down display and put ATtiny to sleep
// Will wake up when SWITCH is pressed
void gotoSleep()
{
displayOff();
detachRotaryPinChangeInterrupt();
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System actually sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
attachRotaryPinChangeInterrupt();
displayOn();
timeChanged = true; // Force a screen update
sleepTimeout = millis() + SLEEP_TIMEOUT;
ignoreNextPress = true;
}
//=========================================== ISR Routines =======================================
//————————————————————————-
//Timer B Interrupt handler interrupt each mS — output segments
ISR(TCB1_INT_vect)
{
//This is 4 bit ‘Bit Angle Modulation’ or BAM,
if (bamCounter == (DIGITS * 1) || bamCounter == (DIGITS * 3) || bamCounter == (DIGITS * 7))
{
bamBit = bamBit 0)
{
EepromData.countdownTime—;
}
timeChanged = true;
}
RTC.INTFLAGS = RTC_OVF_bm; // Reset overflow interrupt
}

У меня всё. Вссем добра!!!

Эффективное средство для борьбы с алкогольной зависимостью
9 часов назад
Видеорегистратор Full HD и камера заднего вида по цене...
9 часов назад

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