|
Реализация конечного автомата на 8битном контроллере., Около 20 состояний. Хорошие исходники бы посмотреть. |
|
|
|
Jul 9 2017, 10:42
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Всем привет! Сейчас сделано как-то так. Прекрасно работает, расширяется. Всем доволен, но хотелось бы сравнить с тру 8ми битным подходом. Собственно какую-нибудь хорошую реализацию конечного автомата и хотелось бы где-то посмотреть. Код enum DeviceEvents { DEVEV_HEARTBEAT, //this event occures every ~100ms DEVEV_STARTBTN_PRESSED, //etc... DEVEV_NO_EVENT = 0xff, }
enum DeviceState_enum { DEVSTATE_OFF, DEVSTATE_LOCKED, //etc.... DEVSTATE_INVALID = 0xff, }
//state interface class struct DeviceStateImplementation { virtual void EnterThisStateFrom( const DeviceState_enum &prevState ) = 0; //Handles event and returns new device state in response of event virtual DeviceState_enum HandleEvent( const DeviceEvents &event ) = 0; };
//Implementation of DEVSTATE_OFF state class StateImpl_OFF: public DeviceStateImplementation { timestamp_t MillisecondsCounter; uint8_t MinutesCounter; bool ReactOnStartBTNRelease;
void ResetMillisecondsCounter(); public: virtual void EnterThisStateFrom( const DeviceState_enum &prevState ); virtual DeviceState_enum HandleEvent( const DeviceEvents &event ); };
//Implementation of DEVSTATE_OFF state void StateImpl_OFF::EnterThisStateFrom( const DeviceState_enum &prevState ) { TurnOffAllOutputs(); DisableRPMMeasure(); G_SettingsStateSelector.ResetPressCounter(); ReactOnStartBTNRelease = false; ResetMillisecondsCounter(); }
void StateImpl_OFF::ResetMillisecondsCounter() { MillisecondsCounter = GetTickCount(); MinutesCounter = 0; }
DeviceState_enum StateImpl_OFF::HandleEvent( const DeviceEvents &event ) { DeviceState_enum retval = DEVSTATE_OFF;
switch(event) { case DEVEV_HEARTBEAT: ACC_LEDBlinker.DoTheJob();
if( G_SettingsStateSelector.GetSelectedState() != DEVSTATE_INVALID ) { ACC_LEDBlinker.StartEndlessBlinkSequence(100, 100);//fast blinking indicating some settings mode was selected } break;
case DEVEV_STARTBTN_PRESSED: ReactOnStartBTNRelease = true; break;
case DEVEV_STARTBTN_RELEASED: //react on release only if press also was made in this state if( ReactOnStartBTNRelease ) { ResetMillisecondsCounter(); if( GlobalVarsRef.BrakePedal.GetButtonState() == GPIOBTNSTATE_PUSHED ) { DeviceState_enum SelectedSettingsModeState = G_SettingsStateSelector.GetSelectedState(); if( SelectedSettingsModeState != DEVSTATE_INVALID ) retval = SelectedSettingsModeState; else retval = DEVSTATE_CRANKING; } else { retval = DEVSTATE_IGNON; } } break;
case DEVEV_STARTBTN_LONGPRESS: if( GlobalVarsRef.BrakePedal.GetButtonState() == GPIOBTNSTATE_PUSHED ) retval = DEVSTATE_FORCEDCRANKING; else retval = DEVSTATE_ACCON; break;
case DEVEV_BREAKPEDAL_PRESSED: ResetMillisecondsCounter(); G_SettingsStateSelector.SelectorWasPressed();
ACC_LED::Clear(); ACC_LEDBlinker.StartBlinkSequence(2, 50, 100); break;
case DEVEV_BREAKPEDAL_RELEASED: ACC_LED::Clear(); ACC_LEDBlinker.AbortBlinkSequence(); break;
case DEVEV_ENGINE_STARTED: retval = DEVSTATE_RUNNING; break;
case DEVEV_ENGINE_STALLED: break; }
return retval; }
/////main state machine implementation class MainStateMachine { public: void EnterStateForced( const DeviceState_enum &state ); void ProcessEvent( const DeviceEvents &evnt );
private: DeviceStateImplementation *CurrentDevStateImplementation; //<----pointer to state interface class DeviceState_enum CurrentDevState;
void SetNewDeviceState( const DeviceState_enum &newDevState ); };
void MainStateMachine::ProcessEvent( const DeviceEvents &evnt ) { DeviceState_enum newDevState = CurrentDevStateImplementation->HandleEvent( evnt ); if( newDevState != CurrentDevState ) SetNewDeviceState( newDevState ); }
void MainStateMachine::SetNewDeviceState( const DeviceState_enum &newDevState ) { switch( newDevState ) {
case DEVSTATE_OFF: CurrentDevStateImplementation = &OFFState; break; case DEVSTATE_LOCKED: CurrentDevStateImplementation = &LockedState; break; } CurrentDevStateImplementation->EnterThisStateFrom( CurrentDevState ); CurrentDevState = newDevState; }
//main loop simplifiyed int main() { while(1) { event = DEVEV_HEARTBEAT; while( event != DEVEV_NO_EVENT ) { MainStateMachine.ProcessEvent( event ); event = DetectOneMoreEvents(); } } }
--------------------
The truth is out there...
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
Jul 10 2017, 07:37
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(sigmaN @ Jul 9 2017, 13:42)  Всем доволен, но хотелось бы сравнить с тру 8ми битным подходом. Собственно какую-нибудь хорошую реализацию конечного автомата и хотелось бы где-то посмотреть. Биты то при чем? Реализация автомата - дело интимное. При реализации UI как автомата параметры такие: - состояний - около сотни - событий - два десятка (кнопки и таймеры) - новое состояние определяется внутри обработки конкретного состояния (т.к. не все, что происходит и изменяет состояния - это события) - изменение состояния - тоже событие (удобно для единообразия) - Х-макросы для перечисления имен функций, названий состояний, текста в первой строке, особенностей поддержки каждого состояния (например, чистить или нет экран) - механизм возврата в предыдущее состояние Очень важная для меня цель была - прозрачность понимания, т.к. приходится корректировать проекты после большого перерыва.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Jul 11 2017, 06:33
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(sigmaN @ Jul 11 2017, 02:02)  . . . В связи с чем и становится интересно, а будет ли реальная экономия хоть чего-нибудь если все эти состояния положить в огромный switch, который потом IAR доблестно превратит в таблицу с адресами функций... Что в итоге будет снова ооочень напоминать vtable ) Смотря как компилятором реализуется работа vtable и какая "вложенность". Если использовать правильный switch (опятьже зависит от комилятора) который генерирует "вычисляемые" переходы. "правильный" - это в IAR конструкция Код switch ( __even_in_range(TBIV, 14) ) { ...
|
|
|
|
|
Jul 11 2017, 06:38
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Dog Pawlowa, можно тоже исходники глянуть? m65535625@gmail.com А то как не крути вечно такой колхоз получается (Передача пакета данных по usart) CODE void Sendpackage(void){ static uint8_t mode; static uint16_t counter; uint8_t* Data; switch(mode){ case 0:{ //--------------------------------------------- //--------Ожидание команды на отправку--------- //--------------------------------------------- if(TransmitDataStart==Transmit_START){ TransmitDataStart=Transmit_STOP; Data=&Protocol; mode=1; } break; } //------------------------------------------------- case 1:{ if(counter<sizeof(ProtocolExchange_t)){ if(USART3->SR & USART_SR_TC){ USART3->DR =(uint8_t)Data[counter]; counter++; } }else{ mode=0; } break; } //------------------------------------------------- } }
|
|
|
|
|
Jul 11 2017, 10:02
|

I WANT TO BELIEVE
     
Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751

|
Цитата Смотря как компилятором реализуется работа vtable и какая "вложенность". Ну "вложенность" получается 1. Указатель на абстрактный класс указывает на реализацию класса. Про __even_in_range() не знал, протестируем Add: Последний IAR STM8 Error[Pe020]: identifier "__even_in_range" is undefined main.cpp 140
--------------------
The truth is out there...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|