ЭЛЕКТРОНИКА Прерывания сторожевого таймера не вызываются

Mark_gresh

✩✩✩✩✩✩✩
28 Янв 2026
32
1
Здравствуйте! Я программирую под тини2313а, в Ардуино ИДИ. Неодобрительные взгляды за использование "Абдурины" просьба перевести в спящий режим - я программирую только на регистрах, даже либы каталога avr/ скуплюсь подключать. Неодобрительные взгляды за то,что ленюсь спросить у ИИ, просьба перевести в спящий режим - ИИ нынче тупой пошёл,и хоть он и лез в Интернет,всё равно приплетает несуществующие регистры и прочую бурду. Так вот,я настраиваю сторожевой таймер как будильник из глубокого сна, но прерывание почему-то вышло на прогулку из МК,оно не вызывается. Пробовал не 8 секунд, а 16 мс - то же самое.Убирал бит прерывания из настройки - ждёт 8-9 секунд, ресетится вместе с прескалером и начинает дискотеку в стиле "а-ля бутлуп". То есть сброс работает. Но в прерывании - нет.
Мой код в майнере -
C++:
int main(){

  DDRB |= (...);

  DDRA |= (...);

  DDRD |= (...);

  PORTB |= (1<<DIOD);

  _my_delay_ms(100);

  PORTB &= ~(1<<DIOD);

  USICR |= 0B00100010;

  MCUSR &= ~(1<<WDRF);
  WDTCSR |= (1<<WDE)|(1<<WDCE);
    WDTCSR |= (1<<WDIE)|(1<<WDP0)|(1<<WDP3);
    MCUCR = 0B00110011;
    GIMSK |= (1<<INT0);
    lable:
    asm volatile("sleep");
    goto lable;
}
В самом начале прерывания я моргаю диодом,как на первых строчках. Стартовое моргание нормально, в прерывании не происходит. В чём может быть проблема?
 

Bruzzer

★★★★✩✩✩
23 Май 2020
848
263
Желательно приводить короткий код целиком.
В том коде, что вы показали я не увидел глобальное разрешение прерываний.
И мне кажется, что с регистром WDTCSR вы работаете неправильно (не по даташиту, но не уверен, т.к. сам не пробовал).
 
Изменено:

Mark_gresh

✩✩✩✩✩✩✩
28 Янв 2026
32
1
Желательно приводить короткий код целиком.
извините, просто спешил сильно.
В том коде, что вы показали я не увидел глобальное разрешение прерываний.
пробовал и с sei() в начале, тот же результат.
И мне кажется, что с регистром WDTCSR вы работаете неправильно (не по даташиту, но не уверен, т.к. сам не пробовал).
Я думал,что так по даташиту. Как минимум,я его с десяток раз в день перечитываю по частям. И сброс при такой же настройке, только без бита WDIE, работает. Но может и что-то забыл. Буду очень рад,если поправите.
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,333
969
@Mark_gresh, Вот так нужно инициализировать wdt таймер:
C++:
__asm__ __volatile__ ("WDR"); //сброс таймера wdt
MCUSR = 0x00; //очистка флагов сброса мк
WDTCSR = (1<<WDCE) | (1<<WDE); //разрешили изменения wdt
WDTCSR = (1<<WDIE) | (1<<WDP0) | (1<<WDP3); //установили режим прерывания по таймауту в ~8сек
sei(); //разрешили прерывания глобально
При этом вектор прерывания должен быть обязательно объявлен, или пустой(EMPTY_INTERRUPT) или с обработчиком(ISR).
 
  • Лойс +1
Реакции: Mark_gresh

Mark_gresh

✩✩✩✩✩✩✩
28 Янв 2026
32
1
@Sergo_ST, всё заработало, спасибо большое!

@Mark_gresh, извините, опять придётся обратиться. Раз в 8 секунд МК просыпается,как и надо,но вместо вектора прерывания сбрасывается. И это софт ресет,ибо прескалер не падает в 16 мс, и товарищ MCUSR всегда, кроме запуска от подачи питания,показывает нули,то есть аппаратного сброса не было. Больше нету ни одного прерывания,которое как-то могло помешать. asm jmp 0 тоже явно не вызываю. В чём может быть дело?
 

Mark_gresh

✩✩✩✩✩✩✩
28 Янв 2026
32
1
@Sergo_ST, вектор прерывания объявлен, вот его начало:
C++:
ISR(WDT_vect){
    signal(500); //macrofunction PORTB|=(1<<DIOD); _delay_ms(n); PORTB &= ~(1<<DIOD)
    _delay_ms(500);
    signal(500);
    if(isActive){...}else{...};
}
, но вместо короткого двойного мигания происходит длинное одинарное,как в main(), то есть main начинается сначала, ещё до прерывания.
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,333
969
@Mark_gresh, Лучше выложите полностью код, без упрощения, сокрытия кусков и тд, тк явно есть что-то другое что вызывает подобное поведение(например другое прерывание без обработчика или отсутствие зацикливания в main()).
 

Mark_gresh

✩✩✩✩✩✩✩
28 Янв 2026
32
1
@Sergo_ST, ладно,вот весь код:
500+ строк:
#define signal(del) BUZZERPORT |= (1<<BUZZERPIN); _delay_ms(del); BUZZERPORT &= ~(1<<BUZZERPIN)
#define setCursor(pos, row) lcdSendByte(0x80|(0x40*row)|(pos), 0)
#define displayOn() PORTA |= (1<<LCDPOWER); _delay_ms(50); displayInit()
#define displayOff() PORTA &= ~(1<<LCDPOWER);
#define lcd_print(str) _lcd_print_P((const char*)(str))
#define DEC_TO_BCD(d) ((uint8_t)((((d) / 10u) << 4u) | ((d) % 10u)))
#define BCD_TO_DEC(b) ((uint8_t)(((((b) >> 4u) & 0x0Fu) * 10u) + ((b) & 0x0Fu)))
#define isFrontButton (pastButton < (PIND & (1<<ENCBUTTON)))
#define isFrontChSet (pastChSet < (PIND & (1<<CHANNEL_SET)))
#define lcdClear() lcdSendByte(0x01, 0); _delay_ms(2)
#define WDTFCHECK() \
    do { \
        if (WDT_flag) { \
            uniBoolFlag &= ~(1<<3); \
            return; \
        } \
    } while(0)

#define BUZZERPORT PORTB
#define BUZZERPIN PB6
#define COMPPLUS PB0
#define COMPMINUS PB1
#define SDA PB7
#define SCL PB5
#define ENCBUTTON PD2
#define MOSFET_A PD3
#define CHANNEL_A_PIN PD4
#define CHANNEL_B_PIN PD5
#define ENC_A PB4
#define ENC_B PB3
#define CHANNEL_SET PD6
#define MOSFET_B PB2
#define SELFLOCK PA0
#define LCDPOWER PA1

#define BIT_REGSET 0
#define BIT_READWRITE 1
#define BIT_ENABLE 2
#define BIT_BACKLIGHT 3

/[I]reserved or unused[/I]/
#define UART_RX PD0
#define UART_TX PD1
/**/
//display strings
const char STR_CH_A[] PROGMEM = "KAH A";
const char STR_CH_B[] PROGMEM = "KAH B";
const char STR_SET[] PROGMEM = "HACTPO\001KA";
const char STR_CALIBRATE[] = "KA\000\0006POBKA";
//#define STR_RESET_H "C6POC 4ERE3 8 C."
//#define STR_RESET_L "OTMEHA - \002M\001 OK!"
const char STR_SETTIME[] PROGMEM = ("HACTPO\001KA BPEMEH\001");
const char STR_UPTIME[] PROGMEM = "UPTIME x8 CEK";
const char STR_CALIBRATE_MIN[] PROGMEM = "M\001H\001MYM KOPMA MC";
const char STR_CALIBRATE_STEP[] PROGMEM = "\007AG ME\002DY 0\0011";

#define bmsstate (uniBoolFlag >> 6)
#define isActive ((uniBoolFlag >> 5) & 1)
#define currentChannel ((uniBoolFlag >> 4) & 1)
#define WDT_flag ((uniBoolFlag >> 3) & 1)
#define pastButton ((uniBoolFlag >> 2) & 1)
#define pastChSet ((uniBoolFlag >> 1) & 1)
#define isMinutes (uniBoolFlag & 1)

#define F_CPUdiv1000 8000UL
#define F_CPUdiv1000000 8
#define NONE 0
#define CW 1
#define HOLD_CW 2
#define CCW 3
#define HOLD_CCW 4

uint8_t pastEncoderState;
uint8_t displayBuffer[16];
uint8_t timeHMS[3];
uint16_t uptime;
uint8_t timeBuffer[2][4];
uint8_t lasttimers[2];
uint8_t calibrateMin[2];
uint8_t calibrateStep[2];
uint8_t cursor;
uint8_t uniBoolFlag;

void _lcd_print_P(const char* literal){
    uint8_t ch;
    while((ch = pgm_read_byte((uint8_t*)literal++))){
        lcdSendByte(ch, 1);
    }
}
uint8_t div100(uint8_t num){
    if(num < 100) return 0;
    if(num < 200) return 1;
    return 2;
}
void utoa(uint16_t num, char* bfr){
    //bfr[0] = num/10000+48;
    // bfr[1] = num%10000/1000+48;
    bfr[0] = (num*164)>>14+48;//div100(num)+48;
    bfr[1] = (num%100*205)>>11+48; //((num-bfr[0]*2600)>>8)+48;
    bfr[2] = (num-bfr[1]*10)+48;
}
void _delay_ms(uint16_t time){
    uint32_t i = (F_CPUdiv1000)*time;
    do{asm volatile("nop");}while(--i);
}
/*void _delay_ms_16bit(uint16_t time){
    uint16_t i = (F_CPUdiv1000)*time;
    do{asm volatile("nop");asm volatile("nop");}while(--i);
}*/
void _delay_us(uint8_t time){
    uint8_t i = (F_CPUdiv1000000)*time;
    do{asm volatile("nop");}while(--i);
}
void usiClock(){
    USICR |= (1<<USITC);
    _delay_ms(5);
    USICR |= (1<<USITC);
    _delay_ms(5);
}
uint8_t encmonitoring(){
    uint8_t encState = (PINB&0B00011000)>>3;
    if(encState==pastEncoderState) return NONE;
    asm volatile("wdr");
    uint8_t result = (((encState&1)^(pastEncoderState>>1)<<1)|1)+((PIND&(1<<ENCBUTTON))>>ENCBUTTON);
    pastEncoderState = encState;
    return result;
}
void usi_start() {
    PORTB |= (1<<SDA)|(1<<SCL);
    _delay_us(5);
    PORTB &= ~(1<<SDA);
    _delay_us(5);
}
void usi_stop() {
    PORTB &= ~((1<<SDA)|(1<<SCL));
    _delay_us(5);
    PORTB |= (1<<SCL);
    _delay_us(5);
    PORTB |= (1<<SDA);
    _delay_us(5);
}
void usi_send(uint8_t data) {
    USIDR = data;
    USISR = (1<<USIOIF)|(0x0F);
    while((USISR & (1<<USIOIF)) == 0) {
        usiClock();
    }
    usiClock();
    DDRB &= ~(1 << SDA);
    USISR = (1 << USIOIF) | (0x0E);
    usiClock();
    DDRB |= (1 << SDA);
}
uint8_t usi_read(uint8_t isAck) {
    uint8_t result;
    DDRB &= ~(1<<SDA);
    USISR = (1<<USIOIF)|(0x0F);
    while((USISR & (1<<USIOIF)) == 0) {
        usiClock();
    }
    result = USIDR;

    USIDR = 0xFF * isAck;
    USISR = (1 << USIOIF) | (0x0E);
    usiClock();
    USIDR = 0xff;
    return result;
}
[B]attribute[/B]((noinline))
void lcdSendNibble(uint8_t _byte, uint8_t isData) {
    usi_send(0x27<<1);

    usi_send((_byte)|(isData<<BIT_REGSET)|(1<<BIT_ENABLE));
    _delay_us(10);
    usi_send((_byte)|(isData<<BIT_REGSET));
    _delay_us(100);

    return;
}
void lcdSendByte(uint8_t _byte, uint8_t isData) {
    usi_send(0x27<<1);

    lcdSendNibble((_byte>>4), isData);
    lcdSendNibble(_byte&0b1111, isData);
}
void internalTimeActualize() {
    usi_start();
    usi_send(0xd0);
    usi_send(0);
    usi_start();
    usi_send(0xd1);
    timeHMS[0] = BCD_TO_DEC(usi_read(true));
    timeHMS[1] = BCD_TO_DEC(usi_read(true));
    timeHMS[2] = BCD_TO_DEC(usi_read(false));
    usi_stop();
}
void externalTimeActualize() {
    usi_start();
    usi_send(0xd0);
    usi_send(0);
    usi_send(DEC_TO_BCD(timeHMS[0]));
    usi_send(DEC_TO_BCD(timeHMS[1]));
    usi_send(DEC_TO_BCD(timeHMS[2]));
    usi_stop();
}
void createChar(uint8_t* array, uint8_t posit) {
    usi_start();
    usi_send(0x27<<1);
    lcdSendByte(posit|0x40, 0);
    for(uint8_t i = 0; i<8; i++) {
        lcdSendByte(array[i], 1);
    }
    usi_stop();
}
void lcd_createAllChars() {
    byte smile[8] =
    {
        B00000,
        B00110,
        B01010,
        B01010,
        B01010,
        B01010,
        B11010,
        B00000,
    };
    createChar(smile, 0);
    uint8_t smile1[] =
    {
        B00000,
        B10001,
        B10001,
        B10011,
        B10101,
        B11001,
        B10001,
        B00000,
    };
    createChar(smile1, 1);
    uint8_t smile2[] =
    {
        B00000,
        B10101,
        B10101,
        B01110,
        B01110,
        B10101,
        B10101,
        B00000,
    };
    createChar(smile, 2);
    uint8_t smile3[8];
    for(int8_t i=3; i>=0; i--){
        smile3[i<<1] = 63;
        smile3[i<<1+1] = 63;
        createChar(smile3, 3+i);
    }
    uint8_t smile4[8] = {0x00, 0x15, 0x15, 0x15, 0x15, 0x1F};
    createChar(smile4, 7);
}
void eepromLoad(uint8_t data, uint8_t address) {
    while(EECR & (1<<EEPE));
    EEAR = address;
    EEDR = data;
    EECR |= (1<<EEMPE);
    EECR |= (1<<EEPE);
}
uint8_t eepromRead(uint8_t address) {
    while(EECR & (1<<EEPE));
    EEAR = address;
    EECR |= (1<<EERE);
    return EEDR;
}
void feed(uint8_t channel) {
    uint8_t msdiv20 = calibrateMin[channel] + (calibrateStep[channel] * (timeBuffer[channel][lasttimers[channel]] & 7));
    do{
        PORTD |= (1 << (PD4 + channel));
        _delay_ms(1);
        PORTD ^= (1 << (PD4 + channel));
        _delay_ms(19);
    }while(--msdiv20);
    msdiv20 = 50;
    do{
        PORTD |= (1 << (PD4 + channel));
        _delay_ms(2);
        PORTD ^= (1 << (PD4 + channel));
        _delay_ms(18);
    }while(--msdiv20);
}
ISR(WDT_vect) {
    //sei();
    signal(500);
    if(isActive) {
        uint8_t i = 8;
        do{
            eepromLoad(timeBuffer[i>>2][i&3], i);
        }while(--i);
        eepromLoad(8, calibrateMin);
        eepromLoad(9, calibrateStep);
        displayOff();
        uniBoolFlag &= ~(1<<5);
    };
    uptime++;
    internalTimeActualize();
    if((timeBuffer[0][lasttimers[0]] == timeHMS[2]) && (timeHMS[1] == 0) && (timeHMS[0] < 8)) {
    PORTD |= (1<<MOSFET_A);
        feed(0);
        PORTD &= ~(1<<MOSFET_A);
    };
    if((timeBuffer[1][lasttimers[1]] == timeHMS[2]) && (timeHMS[1] == 0) && (timeHMS[0] < 8)) {
    PORTB |= (1<<MOSFET_B);
        feed(1);
        PORTB &= ~(1<<MOSFET_B);
    };
    if(ACSR & (1<<ACO)) {
    uniBoolFlag += (1<<6);;
    } else {
        uniBoolFlag &= ~(3<<6);
    };
    if(bmsstate >= 3) {
    PORTA |= (1<<SELFLOCK);
    };
}
void displayUpdate() {
    uint8_t i = 4;
    do{
        displayBuffer[i*4] = (timeBuffer[currentChannel][i] >> 3) / 10 + '0';
        displayBuffer[i*4+1] = (timeBuffer[currentChannel][i] >> 3) % 10 + '0';
        displayBuffer[i*4+2] = (timeBuffer[currentChannel][i] >> 3) >> 1 + 3; //не перевод в строчку,с места 3 и далее в памяти дисплея - кастомные символы для градаций
        displayBuffer[i*4+3] = ' ';
    }while(--i);
    setCursor(0, 0);
    for(uint8_t i=0; i<16; i++) {
        lcdSendByte(i, 1);
    }
}
void displayInit() {
    _delay_ms(50);
    for(uint8_t i = 0; i < 3; i++){
        lcdSendNibble(0x03, 0);
        _delay_ms(5);
    };
    lcdSendNibble(0x02, 0);
    _delay_us(50);
    lcdSendByte(0x28, 0);
    lcdSendByte(0x06, 0);
}
void menuDriver(uint8_t& incnum, uint8_t incvalue = 1){
    setCursor(11, 1);
        lcd_print(currentChannel ? STR_CH_B: STR_CH_A);
        lcdSendByte(0x02, 0);
        WDTFCHECK();
        switch(encmonitoring()) {
        case CW:
            incnum+= incvalue;
            break;
        case CCW:
            incnum-= incvalue;
            break;
        case HOLD_CW:
            calibrate();
        default:
            break;
        }
        displayUpdate();
        setCursor(cursor * 4, 0);
        if(PIND & (1<<CHANNEL_SET)) {
            uniBoolFlag ^= (1<<4);
        }
        if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
}
void calibrate() {
mainmenu:
    setCursor(0,0);
    lcd_print("ЧАС АПТ МИН \007АG"); //char-array
    setCursor(0,1);
    lcd_print(STR_CALIBRATE);
    while(1) {

        menuDriver(cursor);
        if(isFrontButton) {
            switch(cursor) {
            case 0:
                setCursor(0, 1);
                lcd_print(STR_SETTIME);
                setCursor(0, 0);
                uniBoolFlag &= ~1;
                while(1) {
                    menuDriver(timeHMS[1+isMinutes]);
                    if(isFrontButton) {
                        uniBoolFlag |= (1<<2);
                        if(isMinutes) {
                            externalTimeActualize();
                            goto mainmenu;
                        }
                        uniBoolFlag |= 1;
                    }
                }
                break;
            /*case 1:
            
                setCursor(0,0);
                char bfrstr[5];
                utoa(uptime, bfrstr, 10);
                lcd_print(bfrstr); //char-array
                setCursor(0,1);
                lcd_print(STR_UPTIME);
                if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
                while(1) {
                    if(isFrontButton) {
                        uniBoolFlag |= (1<<2);
                        goto mainmenu;
                    }
                }
            
                break;
            */
            case 2:
                calibrateUnit2And3(0);
                break;
            case 3:
                calibrateUnit2And3(1);
            }
        }
    }
}
void calibrateUnit2And3(uint8_t isStep) {
    setCursor(0,0);
    char bfrstr[3];
    utoa(calibrateMin[currentChannel], bfrstr);
    lcd_print(bfrstr); //char-array
    setCursor(0,1);
    lcd_print(STR_CALIBRATE_MIN);
    uint8_t* calibrateX = isStep?calibrateStep:calibrateMin;
    setCursor(0,0);
    while(1) {
        switch(encmonitoring()) {
        case CW:
            calibrateMin[currentChannel]++;
            utoa(calibrateX[currentChannel], bfrstr);
            lcd_print(bfrstr);
            break;
        case CCW:
            calibrateMin[currentChannel]--;
            utoa(calibrateX[currentChannel], bfrstr);
            lcd_print(bfrstr);
            break;
        case HOLD_CW:
            return;
        default:
            break;
        }
        if(!(PIND & (1<<ENCBUTTON))) {
            uniBoolFlag &= ~(1<<2);
        }
        if(isFrontButton) {
            uniBoolFlag |= (1<<2);
            feed(currentChannel);
        }
    }
}

ISR(INT0_vect) {
    uniBoolFlag |= (1<<5);
    displayOn();
mainmenu:
    while(1) {
        menuDriver(cursor);
        if(!(PIND & (1<<ENCBUTTON))) uniBoolFlag &= ~(1<<2);
        if(isFrontButton) {
            uniBoolFlag |= (1<<2);
            menuDriver(timeBuffer[currentChannel][cursor], 8);
            if(isFrontButton) {
                uniBoolFlag |= (1<<2);
                menuDriver(timeBuffer[currentChannel][cursor]);
                if(isFrontButton) {
                    uniBoolFlag |= (1<<2);
                    goto mainmenu;
                }
            }
        }
    }
}
int main() {
    DDRB |= ((1<<BUZZERPIN)|(1<<SDA)|(1<<SCL)|(1<<MOSFET_B));
    DDRD |= ((1<<MOSFET_A)|(1<<CHANNEL_A_PIN)|(1<<CHANNEL_B_PIN));
    DDRA |= ((1<<SELFLOCK)|(1<<LCDPOWER));
    signal(100);
    if(MCUSR){
        signal(200);
    }
    USICR |= 0B00100010;
    asm volatile("wdr");
    MCUSR = 0;
    WDTCSR |= (1<<WDCE)|(1<<WDE);
    WDTCSR |= (1<<WDIE)|(1<<WDP0)|(1<<WDP3);
    sei();
    MCUCR = 0b00110011;
    //GIMSK |= (1<<INT0);
    lable:
    asm volatile("nop");
    goto lable;
}
 

Bruzzer

★★★★✩✩✩
23 Май 2020
848
263
Зачастую, когда сталкиваются с проблемой, то пишут короткую программу для решения именно этой проблемы.
Тема называется "Прерывания сторожевого таймера не вызываются". Логично написать простейшую программу демонстрирующую эту проблему. И когда на простейшей все заработает, то переходить дальше.
(Так же может быть полезно запустить подходящий пример из библиотек, и посмотреть как он работает и что для этого делается).
В коде из предыдущего сообщения вообще нет команды sleep. И есть кучка косяков разного масштаба. Но так как у вас свой путь "программирование на регистрах и без библиотек", то .......
 
Изменено: