Attiny85 Watchdog срабатывает только один раз
Я делаю что-то вроде фонарика с разными модами. Судя по аппаратному сайту, он очень похож на Nanjg105c. Существует Attiny85, который генерирует ШИМ-сигнал для AMC7135.
У меня есть одна кнопка, если я нажму на нее, Аттини заснет, если я удержу кнопку, Аттини изменит свой режим. Для проверки напряжения батареи я использую сторожевой таймер, который выполняет преобразование АЦП каждые 8 секунд.
#include "OneButton.h"
#include <avr/sleep.h> // Спящие режимы
#include <avr/power.h> // Управление энергопотреблением
#include <avr/wdt.h> // Сторожевой таймер
#include <util/delay.h>
#define mid 4000 // Средний уровень заряда батареи
#define low 3200 // Низкий уровень заряда батареи, мигание и затемнение светодиода
#define crit 2600 // Критический уровень заряда батареи, выключение
const byte LEDr = 1; // контакт 1
const byte LEDw = 4; // контакт 4
const byte ModeNr = 3;
volatile bool WDR_flag = false;
bool PWR_flag = false;
OneButton button1(2, true);
int count = 1;
int flag = 0;
long Vcc;
int PWMr = 255;
int PWMw_l = 50;
int PWMw_h = 255;
ISR(PCINT0_vect)
{
// делаем здесь что-нибудь интересное
}
ISR(WDT_vect){
WDR_flag=true;
}
void setup()
{
pinMode(3, OUTPUT);
pinMode(LEDr, OUTPUT); // включаем светодиод (HIGH - уровень напряжения)
pinMode(LEDw, OUTPUT);
digitalWrite(LEDr, HIGH); // включаем светодиод (HIGH - уровень напряжения)
digitalWrite(LEDw, HIGH);
delay(1000);
button1.attachClick(sleep);
button1.attachLongPressStart(changeMode);
WDT_on();
}
void loop()
{
uint8_t i = 0;
button1.tick(); // продолжаем следить за кнопками:
if(WDR_flag == true){ // делаем каждые 8 секунд
WDR_flag = false; //сбросить флаг WDT
digitalWrite(3, HIGH); // отладка с третьим светодиодом
delay(250);
digitalWrite(3, LOW);
WDT_off();
//ADC_on();
/*Vcc = readVcc(); //чтение напряжения батареи
if(Vcc < low && count == 3){
if(PWMw_h <= PWMw_l){ // изменить режим на низкий, когда выход ШИМ меньше, чем низкий ШИМ
count = 2;
}else
{
i = 0;
while (i++<3 && PWR_flag == false) { //мигаем 3 раза красным светодиодом перед затемнением белого светодиода
analogWrite(LEDr, PWMr);
_delay_ms(500);
digitalWrite(LEDr, LOW);
_delay_ms(250);
PWR_flag = true;
}
PWMw_h = PWMw_h / 2; // уменьшите мощность ШИМ белого светодиода вдвое
}
if(Vcc <= crit){ // переходим в спящий режим, когда батарея разряжена
sleep();
}
}
if(Vcc < low && count == 1){
i = 0;
while (i++<3) {
digitalWrite(LEDr, LOW);
_delay_ms(250);
analogWrite(LEDr, PWMr);
_delay_ms(500);
}
PWMr = PWMr / 2;
if(Vcc <= crit){
sleep();
}
}*/
//ADC_off(); //экономим энергию
WDT_on; // снова запускаем сторожевой таймер
}
switch (count) {
case 1: //режим красного светодиода
analogWrite(LEDr, PWMr);
digitalWrite(LEDw, LOW);
break;
case 2: //низкий режим белого светодиода
digitalWrite(LEDr, LOW);
analogWrite(LEDw, PWMw_l);
break;
case 3: // белый светодиод высокого режима
digitalWrite(LEDr, LOW);
analogWrite(LEDw, PWMw_h);
break;
}
}
void sleep() // Эта функция будет вызвана, когда кнопка 1 была нажата 1 раз
{
digitalWrite(LEDr, LOW);
digitalWrite(LEDw, LOW);
//готовим сон
WDT_off();
GIFR |= bit(PCIF); // очищаем все необработанные прерывания
GIMSK |= _BV(PCIE); // Включить прерывания смены контакта
PCMSK |= _BV(PCINT2); // Использовать PB2 в качестве вывода прерывания
ADC_off();
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // заменяет указанное выше выражение
sleep_enable(); // Устанавливает бит разрешения спящего режима в регистре MCUCR (SE BIT)
sei(); // Разрешить прерывания
sleep_cpu(); // спать
cli(); // Отключить прерывания
PCMSK &= ~_BV(PCINT2); // Отключаем PB2 как вывод прерывания
sleep_disable(); // Очистить бит SE
WDT_on();
flag = 1; //устанавливаем флаг, uc до этого был в спящем режиме
}
void changeMode() // Эта функция будет вызываться один раз при длительном нажатии.
{
if (flag == 1) {
flag = 0;
}
else {
if (count < ModeNr) {
count++;
}
else {
count = 1;
}
}
}
void WDT_on() {
// Настраиваем сторожевой таймер только на прерывание, а не на сброс
cli(); // Отключить прерывания
wdt_reset(); // Сброс WDT
WDTCR |= (1 << WDCE) | (1 << WDE); // Запустить временную последовательность
WDTCR = (1 << WDIE) | (1 << WDP3) | (1<<WDP0); // Цикл сторожевого таймера = 8 с
//WDTCR = (1 <<WDIE); // Включение сторожевого прерывания
sei(); // Разрешить прерывания
}
void WDT_off(){
cli(); // Отключить прерывания
wdt_reset(); // Сброс WDT
MCUSR &= ~(1<<WDRF); // Очистить флаг сброса сторожевого таймера
WDTCR |= (1<<WDCE) | (1<<WDE); // Запустить временную последовательность
WDTCR = 0x00; // Отключить WDT
sei(); // Разрешить прерывания
}
void ADC_on() {
ADCSRA = (1 << ADEN ); // питание АЦП включено
}
void ADC_off() {
ADCSRA &= ~(1<<7); // АЦП выключен
}
long readVcc() {
// Чтение ссылки 1,1 В относительно AVcc
// установить ссылку на Vcc и измерение на внутреннюю ссылку 1,1 В
ADMUX = _BV(MUX3) | _BV(MUX2);
delay(2); // Подождите, пока Vref установится
ADCSRA |= _BV(ADSC); // Начать преобразование
while (bit_is_set(ADCSRA,ADSC)); // измерение
uint8_t low_adc = ADCL; // сначала нужно прочитать ADCL - затем он блокирует ADCH
uint8_t high_adc = ADCH; // разблокирует оба
long result = (high_adc<<8) | low_adc;
result = 1126400L / result; // Рассчитать Vcc (в мВ); 1126400 = 1,1*1024*1000
int x = 0;
/*while (x++<2) { //отладка с третьим светодиодом
digitalWrite(3, HIGH);
_delay_ms(500);
digitalWrite(3, LOW);
_delay_ms(250);
} */
return result; // Vcc в милливольтах
}
Моя проблема в том, что сторожевой таймер срабатывает только один раз. после усыпления attiny сторожевой таймер также срабатывает только один раз.
Я думаю, проблема в функции WDT_off()...
@Fredo, 👍1
1 ответ
▲ 2
В приведенной ниже строке отсутствуют скобки ()
, что делает ее вызовом функции; на самом деле он не вызывает WDT_on
.
WDT_on; // снова запускаем сторожевой таймер
должно быть:
WDT_on(); // снова запускаем сторожевой таймер
,
@Curt Nichols
Смотрите также:
- PCINT0, PCINT1, PCINT2 и т. д. на ATtiny45/85
- Как назначить прерывание на нажатие кнопки с помощью ATtiny? (прерывание не срабатывает с моим кодом)
- Прерывание переполнения таймера AVR не работает
- ATtiny85 AC Phase Control для регулировки яркости лампочки
- Прерывать каждую секунду на ATTiny84 (и спать все остальное)
- Attiny85 Таймер 1 компаратор B не работает должным образом (в то время как A работает)
- ATtiny85 со сном и последовательным портом
- Arduino для ATtiny изменения поведения pin-прерывания?