[STM32] Wyjątki C++ na przykładzie systemu ISIX-RTOS
Tab. 1. Błędy logiczne sygnalizowane wyjątkami
Klasa wyjątku | Opis |
logic_error | Klasa bazowa dla pozostałych błędów logicznych wywodząca się z exception. |
domain_error | Liczba poza dziedziną. |
invalid_argument | Błędny argument przekazany do funkcji. |
length_error | Błąd rozmiaru. Np przy próbie zmiany rozmiaru wektora. |
out_of range | Wartość poza zakresem. |
Tab. 2. Błędy wykonania sygnalizowane wyjątkami
Klasa wyjątku | Opis |
runtime_error | Klasa bazowa dla pozostałych błędów wykonania wywodząca się z exception. |
range_error | Błąd zakresu. |
overflow_error | Błąd przepełnienia. |
underflow_error | Błąd niedomiaru. |
Oczywiście każdy z tych wyjątków może być zgłaszany nie tylko przez bibliotekę standardową, ale także przez kod użytkownika. Bazując na powyższych klasach, hierarchia wyjątków może być rozbudowywana w razie potrzeb przez użytkownika.
Przykład praktyczny: obsługa wyjątków w ISIX-RTOS
Po zapoznaniu się z podstawowymi wiadomościami teoretycznymi na temat wyjątków w C++ , pokażemy, że mogą być stosowane z powodzeniem również w przypadku nieco większych mikrokontrolerów. Pozwalając na znaczące podniesienie niezawodności działania programu, oraz przy stosowaniu z umiarem zapewniają również podniesienie ogólnej wydajności aplikacji.
Posłużmy się teraz prostym przykładem (platforma STM32Butterfly), w którym jeden wątek będzie odpowiedzialny za mruganie diodą D1, i sygnalizował będzie jedynie prawidłowe działanie systemu operacyjnego. Natomiast drugi wątek, będzie zmieniał stan diody D2 na przeciwny w przypadku wciśnięcia klawisza joysticka OK. W przypadku wciśnięcia klawisza DOWN, lub UP, zgłaszany będzie wyjątek, który będzie symulował wystąpienie, błędu. Dodatkowo na linii PE0 wystawiany będzie stan 1 przez czas od momentu zgłoszenia wyjątku, do jego przechwycenia co pozwoli na zbadanie ogólnej wydajności obsługi wyjątków w GCC na architekturze CORTEX-M3. Kod programu przedstawiono na poniższym listingu:
namespace app { class ledblink: public isix::task_base { public: //Constructor ledblink() : task_base(STACK_SIZE,TASK_PRIO), LED_PORT(GPIOE) { using namespace stm32; //Enable PE in APB2 RCC->APB2ENR |= RCC_APB2Periph_GPIOE; io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); } protected: //Main function virtual void main() { while(true) { //Enable LED stm32::io_clr( LED_PORT, LED_PIN ); //Wait time isix::isix_wait( isix::isix_ms2tick(BLINK_TIME) ); //Disable LED stm32::io_set( LED_PORT, LED_PIN ); //Wait time isix::isix_wait( isix::isix_ms2tick(BLINK_TIME) ); } } private: static const unsigned STACK_SIZE = 256; static const unsigned TASK_PRIO = 3; GPIO_TypeDef * const LED_PORT; static const unsigned LED_PIN = 14; static const unsigned BLINK_TIME = 500; }; /* ------------------------------------------------------------------ */ class ledkey: public isix::task_base { public: //Constructor ledkey() : task_base(STACK_SIZE,TASK_PRIO), is_enabled(false), KEY_PORT(GPIOE), LED_PORT(GPIOE) { using namespace stm32; //Enable PE in APB2 RCC->APB2ENR |= RCC_APB2Periph_GPIOE; io_config(LED_PORT,LED_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); io_config(LED_PORT,NOTIFY_PIN,GPIO_MODE_10MHZ,GPIO_CNF_GPIO_PP); } protected: //Main function virtual void main() { //Last key state bool state = true; //Task/thread main loop try { while(true) { execute_keycheck(state); } } catch( int &val) { stm32::io_clr( LED_PORT,NOTIFY_PIN ); dbprintf("INT exception [%d]", val); } catch( const std::exception &e ) { stm32::io_clr( LED_PORT,NOTIFY_PIN ); dbprintf("std::exception [%s]", e.what()); } } private: //Execute keycheck function void execute_keycheck(bool &p_state) { //Change state on rising edge if(stm32::io_get(KEY_PORT, KEY_PIN) && !p_state) { is_enabled = !is_enabled; } //Get previous state p_state = stm32::io_get(KEY_PORT, KEY_PIN); //If enabled change state if(is_enabled) stm32::io_clr( LED_PORT, LED_PIN ); else stm32::io_set( LED_PORT, LED_PIN ); //Wait short time isix::isix_wait( isix::isix_ms2tick(DELAY_TIME) ); if( !stm32::io_get(KEY_PORT, KEY_RAISE_LOGIC )) { /** From raise to catch 151us **/ stm32::io_set( LED_PORT,NOTIFY_PIN ); throw(std::logic_error("critical error raised")); } if( !stm32::io_get(KEY_PORT, KEY_RAISE_INT )) { /** From raise to catch 108us **/ stm32::io_set( LED_PORT,NOTIFY_PIN ); throw(-1); } } private: static const unsigned STACK_SIZE = 2048; static const unsigned TASK_PRIO = 3; bool is_enabled; GPIO_TypeDef * const KEY_PORT; GPIO_TypeDef * const LED_PORT; static const unsigned LED_PIN = 15; static const unsigned KEY_PIN = 8; static const unsigned NOTIFY_PIN = 0; static const unsigned KEY_RAISE_LOGIC = 9; static const unsigned KEY_RAISE_INT = 10; static const unsigned DELAY_TIME = 25; }; } /* ------------------------------------------------------------------ */ //App main entry point int main() { dblog_init( stm32::usartsimple_putc, NULL, stm32::usartsimple_init, USART2,115200,true, config::PCLK1_HZ, config::PCLK2_HZ ); dbprintf(" Exceptions presentation app using ISIXRTOS "); //The blinker class static app::ledblink led_blinker; //The ledkey class static app::ledkey led_key; //Start the isix scheduler isix::isix_start_scheduler(); }