Универсальный сторожевой таймер на ATtiny13

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

Тем более встроенный WDT имеется у большинства современных микроконтроллеров.

Но бывают случаи, когда приходится иметь дело с готовой платой или модулем с определенными проблемами. Свой первый WDT я сделал для борьбы с редкими, но все же иногда происходящими зависаниями ESP8266. Причем софтовый ресет тогда не спасал и ESP-шка не хотела переподключаться к WiFi. Передергивание питания внешним WDT решило проблему.

Вторая проблема возникла с GSM контроллером Elecrow ATMEGA 32u4 A9G. Здесь имели место быть очень редко случающиеся зависание SIM-карты. (Кстати эту же проблема бывает и с USB-модемами 3G и 4G). Для борьбы с таким зависанием нужно передернуть питание на SIM-ке. И вроде даже вывод у GSM модема для этого есть, но в схемотехнику устройства данная возможность не заложена. И для достижения максимальной надежность пришлось снова обращаться к внешней сторожевой собаке.

Схему на таймере 555 я не стал повторять. Слишком много недостатков у нее выявилось:

  • Большие габариты и довольно много обвязки
  • Неудобная установка времени срабатывания подстроечным резистором
  • Довольно длительное время сброса (необходима разрядка конденсатора)
  • Ну и потенциальное зависание МК с низким уровнем на выходе таймера, когда таймер просто перестает срабатывать.
  • А проектов OpenSource в интернете, полностью соответствующих моим требованиям, я не нашел.

Требования к новому WDT


  • Низкая цена устройства, простота изготовления и малые габариты
  • Управление периодической сменой логического уровня 0/1 на входе
  • Простая настройка времени срабатывания (как вариант выбор из предустановленных интервалов)

Разработка железа


В качестве основной микросхемы выбрал микроконтроллер ATtiny13. Его возможностей оказалось более чем достаточно для моей задачи. А цена, с учетом уменьшения элементов обвязки — практически такая же как у 555 микросхемы.
6bdzeyh1bowur2gidmkemmap2lc.jpeg

Пять выводов МК (RESET решил не трогать) распределились следующим образом:

  1. Выход таймера
  2. Вход для сброса
  3. Три оставшихся вывода — задания времени срабатывания

Для коммутации питания используется P-канальный MOSFET. Подойдет любой совместимый по корпусу, но желательно брать с так называемым «логическим уровнем управления» — то есть полностью открывающийся от низкого напряжения 3–5В: IRLML2502, AO3415 и т.п. Несмотря на малые размеры, данный транзистор способен управлять нагрузкой в 4А. Если нужно коммутировать что-то другое, к этому выходу можно напрямую подключить реле на 5В.

Светодиод загорается в момент срабатывания таймера и отключения основного устройства.

Основной разъем для подключения к плате микроконтроллера имеет четыре вывода

  1. Общая шина
  2. Вход — сброс таймера
  3. Выход +5В (управляется таймером)
  4. Вход +5В

Два разъема — ICSP программатор и джамперы питания можно не устанавливать на плате. Микроконтроллер прошить в программаторе заранее, а время срабатывания задать постоянной перемычкой.

Список комплектующих


Изготовление


Платы получились маленькие — 18×22 мм. Я развел два варианта:

Для одностороннего изготовления ЛУТом
khyp26ytvqxcj437volrrhkfcuw.jpeg
8dylefeebfvbkrpf2iaqymdhvh4.jpeg
И для заказа на заводе с улучшенным дизайном и переходами меж сторонами. (Закажу у китайцев, при случае)
5hs4eynikwmqazhhyix7oljkb2a.jpeg
fdffgubsoonrbwva_lc_noy7mao.jpeg
Домашние технологии дают примерно такой прототип.
axcdirbr10irmp46awb4gnlrytg.jpeg
84fzissob7kg5rq24f7qhwe-az4.jpeg
_dzpyzgeqzjau8szktiqfcwqplc.jpeg

Прошивка


Для прошивки использовал самодельный программатор на баз Arduino Nano
uslsfxv9iq2s3ex0vgflqyedsbs.jpeg
Программировал я в среде Arduino IDE с установленной поддержкой Attiny13 — MicroCore. В последней версии IDE были проблемы программатора ArduinoISP, но нормально заработало в версии Arduino IDE 1.6.13. Разбираться, что там накосячила наизменяла дружная команда arduino.cc желания не возникло)))

ghcipvlpi0kom2xxlrrlwjqqbic.jpeg
Тиньку настроил на работу от внутреннего резонатора с частотой 1.2МГц. Программа простая — настраиваем входы/выходы, считываем PB2 -PB4 и определяем время срабатывания, настраиваем таймер и переходим в режим IDLE. По прерыванию по таймеру определяем состояние контрольного входа. Если состояние изменилось на противоположное, сбрасываем счетчик. Если показания счетчика превысило установленное время срабатывания — передергиваем питание на выходе.

#define F_CPU 1200000UL
#include 
#include 
#include 

boolean pb1_state; 
volatile uint16_t pb1_count;

// Оброботчик прерывания по таймеру TIMER0
ISR(TIM0_OVF_vect){
   pb1_count++;  
}

int main(){
// Устанавливаем выход PB0 
   DDRB |= (1 << PB0);      // pinMode(PB0, OUTPUT); 
   PORTB &= ~(1 << PB0);    // digitalWrite(PB0, LOW);}
// Устанавливаем вход PB1 с подтягиванием 
   DDRB &= ~(1 << PB1);    // pinMode(PB1, INPUT_PULLUP);   
   PORTB |= (1 << PB1);    
// Устанавливаем вход PB2 с подтягиванием 
   DDRB &= ~(1 << PB2);    // pinMode(PB2, INPUT_PULLUP);   
   PORTB |= (1 << PB2);    
// Устанавливаем входы PB3 с подтягиванием 
   DDRB &= ~(1 << PB3);    // pinMode(PB3, INPUT_PULLUP); 
   PORTB |= (1 << PB3);    
// Устанавливаем входы PB4 с подтягиванием 
   DDRB &= ~(1 << PB4);    // pinMode(PB4, INPUT_PULLUP);  
   PORTB |= (1 << PB4);    
// Определяам время срабатывание таймера по входам PB2,PB3,PB4 (перемычки подтягивают к земле) (период, сек = TM/4 )
   uint16_t TM = 0;
   bool pb2 = false;
   bool pb3 = false;
   bool pb4 = false;
   if( PINB & (1 << PINB2) )pb2 = true;
   if( PINB & (1 << PINB3) )pb3 = true;
   if( PINB & (1 << PINB4) )pb4 = true;

   if( pb2 == true  && pb3 == true  && pb4 == true )TM = 4;         //Таймаут 1 сек
   else if( pb2 == false && pb3 == true  && pb4 == true  )TM = 8;   //Таймаут 2 сек
   else if( pb2 == true  && pb3 == false && pb4 == true  )TM = 20;  //Таймаут 5 сек
   else if( pb2 == false && pb3 == false && pb4 == true  )TM = 40;  //Таймаут 10 сек
   else if( pb2 == true  && pb3 == true  && pb4 == false )TM = 80;  //Таймаут 20 сек
   else if( pb2 == false && pb3 == true  && pb4 == false )TM = 120; //Таймаут 30 сек
   else if( pb2 == true  && pb3 == false && pb4 == false )TM = 240; //Таймаут 60 сек
   else if( pb2 == false && pb3 == false && pb4 == false )TM = 480; //Таймаут 120 сек
   pb1_count = 0;
   pb1_state = false;
// Отключаем ADC
   PRR = (1<= TM ){
       PORTB |= (1 << PB0);    // digitalWrite(PB0, HIGH);}
       _delay_ms(1000);        // Ждем секунду
       PORTB &= ~(1 << PB0);   // digitalWrite(PB0, LOW);}
       pb1_count = 0;          // Сбрасываем счетчик
    }
    TIMSK0 = (1<

Весь код уместился в 340 байт — ровно треть от килобайта памяти тиньки. Работа таймера проверяется просто — в зависимости от времени установки — периодически загорается светодиод на 1 сек. В это время на выходе Vвых напряжение 5В пропадает. Если контакт «вход» с периодичностью 1 сек замыкать на землю — сброс не производится и светодиод не загорается.

Управление WDT в основной программе следующее

#define PIN_WDT 5 //GPIO контроллера, куда подключен WDT
bool WDT_flag = false;

// Инициализация порта таймера
void WDT_begin(){
   pinMode(PIN_WDT,OUTPUT);
   digitalWrite(PIN_WDT,WDT_FLAG);
}

// Сброс таймера (не реже чем 1 на время срабатывания WDT, установленное перемычкой)
void WDT_reset(){
   if( WDT_flag)WDT_flag = false;
   else WDT_flag = true;
   digitalWrite(PIN_WDT,WDT_FLAG);
}

Вот собственно, а все. Все исходные файлы, схемы и печатные платы можно скачать с GITHUBа
https://github.com/samopal-pro/wdt-tiny13

© Habrahabr.ru