|
Реализация конечного автомата на 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...
|
|
|
|
|
 |
Ответов
|
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, 20:24
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(pokk @ Jul 11 2017, 09:38)  А то как не крути вечно такой колхоз получается Что касается такого колхоза, то этого хватает у каждого. И вообще это не колхоз, это классика - см ниже!  Если речь идет о автоматах, кроющих практически всю функциональность устройства, то тут все становится сложнее, потому что не есть проблема реализовать это все, а проблемой является выбор собственного стиля и подхода, чтобы было все понятно и прозрачно в первую очередь для самого себя. CODE #define TRANSPORT_TIMEOUT_SERIAL_SEC 10 #define TRANSPORT_TIMEOUT_TCPIP_SEC 5 #define LONG_RUN_TIMEOUT_SEC 60 #define AUTO_PICKUP_TIME_MS 500 #define NUM_RETRIES 3
// added by me timeouts: #define RECEIVE_TIMEOUT_MS 1000 #define ANSWER_TIMEOUT_MS 100
enum { errNO=0, errMESSAGE_SIZE, errOP_CODE, errRECORDS_QTY, errINDEX1, errINDEX2, errINDEX3, errNOT_SUPPORTED, errREAD_ONLY, errWRONG_SIZE, errWRITE_ONLY, errWRONG_OPCODE, errSIZE, };
#define RECEIVED_MESSAGE_LENGTH ((int)com1.rx_buf[1]+((int)com1.rx_buf[2])<<8) #define RECEIVED_TYPE (com1.rx_buf[3]) #define RECEIVED_SEQUENCE (com1.rx_buf[4]) #define ctrlRECEIVED (com1.rx_buf[5]) #define ctrlACK ('A') #define ctrlNAK ('N') #define ctrlEND ('E') #define ctrlWAIT ('W') #define ctrlPICKUP ('P') #define ctrlDROP ('D') #define XML_PTR_FIRST (char*)(com1.rx_buf+5) #define XML_PTR_LAST (com1.rx_buf+RECEIVED_MESSAGE_LENGTH-4) #define ETX_INDEX (RECEIVED_MESSAGE_LENGTH-3)
/* Control message 1 byte STX StartMessage 2 byte Unsigned Binary Length Length of the entire message; including StartMessage and EndMessage but excluding CRC bytes 1 byte ASCII Type 'C' 1 byte Unsigned Binary Sequence 0x00 is invalid value 1 byte ASCII ControlFunction 'A' ACK 'N' NAK 'E' End Sequence 'W' Wait 'P' Pickup 'D' Drop Link 1 byte ETX EndMessage 2 byte Binary CRC See CRC Calculation
Payload message 1 byte STX StartMessage 2 byte UnsignedBinary Length Length of the entire message; including StartMessage and EndMessage but excluding CRC bytes 1 byte ASCII Type 'P' 1 byte Unsigned Binary Sequence 0x00 is invalid value Variable Unsigned Binary Payload The transported application protocol message 1 byte ETX EndMessage 2 byte Unsigned Binary CRC See CRC Calculation
*/
#define XML_START_OFFSET 5 #define XML_END_OFFSET 2
char payload_sent_wait_control; char payload_sent_time; char payload_sent_qty;
void PrepareTransportPayloadHeader(void) { com1.tx_head=com1.tx_buf; *com1.tx_head++=STX; com1.tx_head+=2; // pass length *com1.tx_head++='P'; // payload type *com1.tx_head++=RECEIVED_SEQUENCE; }
void PrepareTransportControlMessage(char com) { int my_checksum;
com1.tx_head=com1.tx_buf; *com1.tx_head++=STX; *com1.tx_head++=7; // length = 7 *com1.tx_head++=0; *com1.tx_head++='C'; // control type *com1.tx_head++=RECEIVED_SEQUENCE; *com1.tx_head++=com; *com1.tx_head++=ETX; my_checksum=crc16_ccitt(com1.tx_buf, 7); *com1.tx_head++=(char)(my_checksum&0x00ff); *com1.tx_head++=(char)(my_checksum>>8); }
void PrepareTransportTrailer(void) { int my_size; int my_checksum;
*com1.tx_head++=ETX; my_size=com1.tx_head- com1.tx_buf; com1.tx_buf[1]=(char)(my_size&0x00ff); com1.tx_buf[2]=(char)(my_size>>8); my_checksum=crc16_ccitt(com1.tx_buf, my_size); *com1.tx_head++=(char)(my_checksum&0x00ff); *com1.tx_head++=(char)(my_checksum>>8);
}
enum { UNCONFIGURED, RESTART_RX, WAITING_STX, WAITING_ETX, WAITING_BCC1, WAITING_BCC2, ANALYSE_MESSAGE, PREPARE_MESSAGE, START_SEND_MESSAGE, WAITING_START_TRANSMIT, WAITING_END_TRANSMIT, FINAL, PREPARE_NAK, PREPARE_DROP, PREPARE_END };
char transport_error;
#define USE_TIMEOUT 1
u16 TimeoutRunning(void) { #ifdef USE_TIMEOUT return com1.timeout; #else return 1; #endif }
void fRnt(void) {
static u16 my_checksum; static u16 message_checksum;
switch (pstate) { case UNCONFIGURED: Com1Init(); pstate++; break;
case RESTART_RX: Com1SetReceive(COM1_WAIT_STX); prot_error=errNO; pstate++; OFF_LED5(); OFF_LED4(); break;
case WAITING_STX: if ( payload_sent_wait_control ) { if (payload_sent_qty<2) { if (event==evSec) { if (payload_sent_time<10) payload_sent_time++; else { pstate=START_SEND_MESSAGE; payload_sent_qty++; payload_sent_time=0; } } } else // all attempts done payload_sent_wait_control=0; } else { payload_sent_qty=0; payload_sent_time=0; }
switch (com1.rx_status) { case COM1_RECEIVED: pstate=RESTART_RX; // buffer is over break;
case COM1_RECEIVING_: pstate=WAITING_ETX; com1.timeout=RECEIVE_TIMEOUT_MS; break; } break;
case WAITING_ETX: ON_LED4(); // recieving starts if (TimeoutRunning()) { if (com1.rx_head>com1.rx_tail) { switch (*com1.rx_tail) { case ETX: // case EOT: com1.rx_tail++; if (com1.rx_tail>com1.rx_buf+5) pstate++; break;
default: com1.rx_tail++; break; } } } else pstate=RESTART_RX; break;
case WAITING_BCC1: if (TimeoutRunning()) { if (com1.rx_head>com1.rx_tail) { com1.rx_tail++; pstate++; } } else pstate=RESTART_RX; break;
case WAITING_BCC2:
if (TimeoutRunning()) { if (com1.rx_head>com1.rx_tail) { com1.rx_tail++; pstate++; Com1SetReceive(COM1_PASSIVE); } } else pstate=RESTART_RX; break;
case ANALYSE_MESSAGE: OFF_LED4(); if (com1.rx_head<com1.rx_buf+8) // too short message { pstate=RESTART_RX; break; } my_checksum=crc16_ccitt(com1.rx_buf, com1.rx_tail-com1.rx_buf-2); message_checksum= ( ((unsigned int)*(com1.rx_head-2)) ) | ( ((unsigned int)*(com1.rx_head-1))<<8 );
#if (defined IGNORE_CHECKSUM)
#elif (defined USE_CHECKSUM) if ( (my_checksum!=message_checksum) || // wrong checksum (*(com1.rx_head-3) !=ETX) //not ETX ) { pstate=RESTART_RX; break; } #else #error "What to do with checksum?" #endif
switch (RECEIVED_TYPE) { case 'C': // control message switch (ctrlRECEIVED) { case ctrlEND: pstate=PREPARE_END; break; case ctrlDROP: pstate=PREPARE_DROP; break;
default: pstate=RESTART_RX; break; } break;
case 'P': // if (!AnalyseXmlOk(XML_PTR_FIRST,(char*)com1.rx_head-4)) pstate=PREPARE_NAK; else pstate=PREPARE_MESSAGE; break; } break;
case PREPARE_MESSAGE: ON_LED5(); // answering started com1.tx_head=com1.tx_buf; PrepareTransportPayloadHeader(); PrepareXml(); PrepareTransportTrailer(); pstate++; payload_sent_wait_control=1; payload_sent_time=0; break;
case START_SEND_MESSAGE: SET_TRANSMIT(); // for driver pstate++; com1.timeout=ANSWER_TIMEOUT_MS; break;
case WAITING_START_TRANSMIT: if (!com1.timeout) { Com1SetTransmit(COM1_TRANSMITTING); pstate++; } break;
case WAITING_END_TRANSMIT: if (com1.tx_status==COM1_TRANSMITTED) if (TRANSMIT_OVER()) { com1.timeout=0; pstate++; } break;
case FINAL: OFF_LED5(); pstate=RESTART_RX; break;
case PREPARE_NAK: pstate = UNCONFIGURED; break;
case PREPARE_DROP: //0207004300440389AC ON_LED5(); PrepareTransportControlMessage('D'); com1.timeout=ANSWER_TIMEOUT_MS; SET_TRANSMIT(); pstate=WAITING_START_TRANSMIT; break;
case PREPARE_END: ON_LED5(); PrepareTransportControlMessage('E'); com1.timeout=ANSWER_TIMEOUT_MS; SET_TRANSMIT(); pstate=WAITING_START_TRANSMIT; payload_sent_wait_control=0; break;
default: pstate = UNCONFIGURED; break; } }
--------------------
Уходя, оставьте свет...
|
|
|
|
Сообщений в этой теме
sigmaN Реализация конечного автомата на 8битном контроллере. Jul 9 2017, 10:42 iosifk Цитата(sigmaN @ Jul 9 2017, 13:42) Всем д... Jul 9 2017, 12:50 sigmaN iosifk, спасибо, кажется нашел пдфку с которой сто... Jul 9 2017, 16:33 iosifk Цитата(sigmaN @ Jul 9 2017, 19:33) iosifk... Jul 9 2017, 18:59 XVR Цитата(sigmaN @ Jul 9 2017, 19:33) iosifk... Jul 10 2017, 10:30  Dog Pawlowa Цитата(XVR @ Jul 10 2017, 13:30) либо в в... Jul 10 2017, 12:37 Dog Pawlowa Цитата(sigmaN @ Jul 9 2017, 13:42) Всем д... Jul 10 2017, 07:37 sigmaN Биты при том, что при моей нынешней реализации(кот... Jul 10 2017, 07:53 Dog Pawlowa Цитата(sigmaN @ Jul 10 2017, 10:53) Биты ... Jul 10 2017, 09:09 sigmaN Спасибо, будет интересно посмотреть!
altersoft... Jul 10 2017, 09:21 sigmaN ЦитатаЧто касается автоматов на МК с минимумум рес... Jul 10 2017, 10:56 sigmaN Вот дойдут как-нибудь руки до сравнений и будет ин... Jul 10 2017, 23:02 k155la3 Цитата(sigmaN @ Jul 11 2017, 02:02) . . .... Jul 11 2017, 06:33 sigmaN ЦитатаСмотря как компилятором реализуется работа v... Jul 11 2017, 10:02 jcxz Цитата(sigmaN @ Jul 11 2017, 13:02) Error... Jul 11 2017, 10:46 k155la3 Цитата(sigmaN @ Jul 11 2017, 13:02) Error... Jul 11 2017, 10:52  jcxz Цитата(k155la3 @ Jul 11 2017, 13:52) Есть... Jul 11 2017, 11:08 sigmaN С этим разобрались, осталось провести эксперименты... Jul 11 2017, 11:47 Lerk Цитата(sigmaN @ Jul 11 2017, 14:47) Честн... Jul 11 2017, 12:40 sigmaN Видел. Там даже мой лайк имеется под этим видео ))... Jul 11 2017, 13:15 501-q https://www.state-machine.com/
https://state-machi... Jul 25 2017, 05:57
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|