2
Метценгерштейнимхо, было бы неплохо нарисовать граф состояний устройства с условиями переходов, а то, похоже, Вы уже действительно запутались.
Большинство моих программ для контроллеров вписываются в примерно такую структуру:
Код
void main(void) {
// startup - разбор причины сброса, соответствующая инициализация
...
for(;;) {
// синхронные события
if(Flags.b._10ms) {
Flags.b._10ms = 0;
GetSlowInputs(); // опрос и фильтрация медленных входов и датчиков
if(DoorLockTmr) {
if(!--DoorLockTmr) {
ODoorLock = 0;
ODoorUnlock = 0;
}
}
...
}
if(Flags.b._500ms) {
Flags.b._500ms = 0;
if(MKeyBtn0HoldTmr) {
if!--MKeyBtn0HoldTmr) {
Mode.b.Prog = 1;
ProgModeTmr = 30 sec;
}
};
if(SirenOnTmr) {
if(!--SirenOnTmr) OSiren = 0;
};
if(LightOnTmr) {
LightOnTmr--
if(!LightOnTmr) {
OLight = 0;
LightPtrn = 0;
}
else {
if(LightPtrn & 1) OLight = 1;
else OLight = 0;
сsr(LightPtrn) // циклический сдвиг вправо
}
}
else if(LightPtrn) {
if(LightPtrn & 1) OLight = 1;
else OLight = 0;
lsr(LightPtrn) // логический сдвиг вправо
}
...
}
// обработка изменений по медленным входам из GetSlowInputs()
// - вынесена из if(Flags.b._10ms){} для удобства восприятия
if(PortAChg.b.ShockSens) {
if(PortA.b.ShockSens) { // сработал датчик удара
if(Mode.b.Armed && SensSts.b.SensEn) {
SirenOnTmr = 15 sec;
LightOnTmr = 25 sec;
LightPtrn = 0xaa;
...
}
}
}
// асинхронные события:
// быстрые входы обрабатываются или своими прерываниями или в быстрых
// таймерных прерываниях с выставлением флагов событий;
if(RcvSts.b.ValidPktRcvd) {
if(RcvSts.b.BtnPressed) {
if(RcvSts.b.MasterKey) {
if(BtnPrsd.b._0) {
MKeyBtn0HoldTmr = 5 sec;
...
}
if(BtnPrsd.b._1) ...
...
}
else {
if(BtnPrsd.b._0) {
if(Mode.b.Prog) {
// сформировать очередь для записи в EEPROM кода брелока
}
else {
if(Mode.b.Armed) {
Mode.i = 1<<MDisarmed;
DoorLockTmr = DoorUnlockTime;
ODoorUnlock = 1;
LightPtrn = 0x05;
}
else if(Mode.b.Disarmed) {
Mode.i = 1<<MArmed;
DoorLockTmr = DoorLockTime;
ODoorLock = 1;
LightPtrn = 0x01;
}
...
}
}
if(BtnPrsd.b._1) ...
...
}
...
}
if(RcvSts.b.BtnReleased) {
if(RcvSts.b.MasterKey) {
if(BtnRlsd.b._0) MKeyBtn0HoldTmr = 0;
...
}
else {
if(BtnRlsd.b._0) ...
...
}
}
RcvSts.b.ValidPktRcvd = 0;
}
// обработка очереди записи в EEPROM
if(!EEQueue->EESts.b.Busy) {
...
}
...
} // end for(;;)
} // end main()
// в синтаксисе PICC и для PIC'ов - мне пока так проще:)
interrupt void isr(void) {
do {
if(TMR0IF) {
TMR0 += по потребностям;
TMR0IF = 0;
// Flags.b._100us = 1;
здесь обрабатываем быстрые входы, н-р, приемник
желательно, на ассемблере:)
if(!RcvSts.b.ValidPktRcvd) {
...
}
};
if(TMR1IF) {
TMR1ON = 0;
TMR1 += по потребностям;
TMR1ON = 1;
TMR0IF = 0;
Flags.b._10ms = 1; // 10 ms только для примера
};
if(...IF) {
...
Flags.b.xxx = 1;
};
...
} while(any (IF & IE)); // do{}while, естесно, по вкусу/необходимости
}
Компилировать это, естесно, не стоит.
hints:
Используйте count-down программные таймеры - проще обрабатывать, код короче, можно использовать как признак состояния.
Не злоупотребляйте switch'ами - код для них что от PICC (для PIC'ов, естесно), что от WinAVR и IAR трудно назвать оптимальным. Но если места и времени (контроллера

не жалко, то вперед.