ISIX-RTOS. Obsługa przerwań

ISIX-RTOS. Obsługa przerwań
Pobierz PDF Download icon
Wątki w ISIX-RTOS mogą komunikować się ze sobą za pomocą semaforów lub kolejek komunikatów. Korzystanie z nich może powodować usypianie procesu (sleep state) w wyniku oczekiwania na pozyskanie zasobu. W przypadku przerwań uśpienie procedury obsługi przerwania nie jest możliwe z uwagi na to, że przerwania nie są wykonywane w kontekście procesu.
100 ELEKTRONIKA PRAKTYCZNA 9/2010 NOTATNIK KONSTRUKTORA Ustawienie zwór adresowych J1? J3 na rysunku 1 ma wpływ tylko na adres pamięci EEPROM zintegrowanej w układzie M41T56C64, adres zegara RTC jest niezmienny. W  związku z  tym dla procedur obsługi przerwań należy wywołać tylko metody nie- blokujące. W  systemie ISIX, w  kontekście obsługi przerwań mogą być wywoływane je- dynie metody z sufiksem _isr. Sposób obsłu- gi komunikacji pomiędzy zadaniami a proce- durami obsługi przerwań pokażemy na przy- kładzie obsługi magistrali I2 C z podłączonym scalonym zegarem RTC M41T56C64 (na przykład z  modułu KAmodRTC). Działanie aplikacji sprowadzać się będzie do odczyta- nia godziny z zegara RTC, przetworzenia go na komunikat oraz przesłania do serwera wy- świetlania, zaprezentowanego w  poprzed- nim przykładzie. Kolejny niezależny wątek podobnie jak w  poprzednim przykładzie będzie migał diodą LED D1 zamontowaną w zestawie STM32Butterfly. W  przykładzie zastosowano także wy- świetlacz od Nokii3310 (KAmodLCD1). Spo- sób dołączenia wyświetlacza i  układu RTC do mikrokontrolera pokazano na rysunku 1. Układ M41T56C64 firmy ST jest bardzo interesującym opracowaniem, integrującym w  jednej obudowie zegar czasu rzeczywi- stego RTC z  wbudowanym rezonatorem kwarcowym 32768 Hz oraz pamięć EEPROM AT24C64. Układ charakteryzuje się poborem prądu rzędu 400 nA, co umożliwia mu pracę z  małej baterii litowej nawet 10 lat. Dzięki zintegrowaniu w układzie rezonatora kwar- cowego nie musimy dołączać z  zewnątrz praktycznie żadnych elementów, dodatkowo rezonator ten jest kalibrowany w  procesie produkcji przez firmę ST, która gwarantuje dokładność rzędu ?5 ppm. Przykładowy program pokazuje na wy- świetlaczu LCD aktualną godzinę oraz miga diodą LED D1 znajdującą się na płytce STM- 32Butterfly. Sposób działania aplikacji z po- działem na wątki przedstawiono na rysun- ku 2. Wątek obsługi LED pracuje zupełnie nie- zależnie od pozostałych wątków, co pozwala pokazać ich wzajemną niezależność. Wątek obsługi LCD, który z punktu widzenia pozo- stałych wątków jest serwerem wyświetlania, odpowiada za odbiór rozkazów oraz odpo- Dodatkowe materiały na CD i FTPISIX-RTOS Obsługa przerwań Wątki w  ISIX-RTOS mogą komunikować się ze sobą za pomocą semaforów lub kolejek komunikatów. Korzystanie z  nich może powodować usypianie procesu (sleep state) w  wyniku oczekiwania na pozyskanie zasobu. W  przypadku przerwań uśpienie procedury obsługi przerwania nie jest możliwe z  uwagi na to, że przerwania nie są wykonywane w  kontekście procesu. wiednie sterowanie wyświetlaczem. Wątek RTC jest odpowiedzialny za od- czytanie aktualnej godziny z zegara RTC poprzez interfejs I2 C, sformatowanie tekstu, następnie wygenerowanie i prze- słanie komunikatu dla serwera wyświet- lania. Aplikacja została napisana w spo- sób obiektowy w języku C++, hierarchię klas przedstawiono na rysunku 3. Hierarchia klas jest bardzo podobna do przykładu 2, ponieważ wykorzysta- no opisaną w  nim architekturę serwera wyświetlania. Klasa the_applica- tion jest klasą aplikacji, w której zawarto wszystkie pozosta- łe obiekty. Klasa led_blink jest odpowiedzialna za cykliczne miganie diodą LED i jest dziedziczona z  klasy isix::task_base implementu- jącej obsługę wątków. Klasa display_server jest odpowiedzialna za odbiór komunikatów z kolejki FIFO oraz fizyczne sterowanie kon- trolerem wyświetlacza za pomocą klasy no- kia_display. Klasa i2c_host jest uniwersalną klasą sterownika, implementującą obsługę magistrali I2 C z wykorzystaniem sprzętowego kontrolera I2C1 w trybie 7-bitowym. Została ona napisana w taki sposób, aby można było ją rozwinąć o obsługę dodatkowych sprzęto- wych kontrolerów I2 C, występujących w mi- krokontrolerach rodziny STM32F. Deklaracja klasy znajduje się w  pliku i2c_host.hpp (li- stingu 1). Klasa została zaprzyjaźniona z  funkcją i2c1_ev_isr_vector stanowiącą wektor obsłu- gi przerwania od kontrolera I2C1. Wszystkie procedury obsługi przerwań muszą mieć linkowanie typu C (extern ?C?). Funkcje wywoływane są w  momencie wystąpienia przerwania bez żadnych dodatkowych pa- rametrów, co wymusza istnienie dostępu do instancji klasy kontrolera I2 C poprzez wskaź- nik lub referencję globalną. Wskaźnik do obiektu i2c umożliwiający dostęp do obiektu kontrolera I2 C przez funkcję obsługi przerwa- nia umieszczono w nienazwanej przestrzeni nazw w pliku implementacji klasy (i2c_host. cpp), przez co dostęp do niej jest możliwy tylko w obrębie tego modułu. Zadeklarowanie przyjaźni funkcji umoż- liwia wywoływanie dowolnych metod chro- nionych klasy z funkcji zaprzyjaźnionej, co zostało wykorzystane do wywołania metody isr() stanowiącą wektor obsługi przerwa- nia. Do synchronizacji wątku z  procedurą obsługi przerwania wykorzystano semafor sem_irq, natomiast semafor sem_lock jest wykorzystywany do blokowania sterownika w przypadku, gdy jest on zajęty obsługą ma- gistrali I2 C. Konstruktor klasy obiektu i2c_host przyj- muje dwa argumenty: adres wybranego kon- trolera I2 C (np. I2C1, I2C2) oraz szybkość tak- towania magistrali I2 C wyrażoną w hercach, 101ELEKTRONIKA PRAKTYCZNA 9/2010 Obsługa przerwań której domyślna wartość wynosi 100000. Zadaniem konstruktora jest inicjalizacja kon- trolera sprzętowego I2 C, uruchomienie prze- rwań oraz przypisanie wskaźnika this utwo- rzonego obiektu do wskaźnika wykorzysty- wanego przez procedurę obsługi przerwania. Na początku sprawdzany jest numer kontrolera I2 C (obecnie zaimplementowana jest tylko obsługa kontrolera I2C1), następ- nie konfigurowane są porty GPIO, tak aby pełniły funkcję wyjścia układu peryferyjne- go. Następnie konfigurowany jest sprzętowy kontroler I2 C, tak aby pełnił rolę sterowni- ka master z  7-bitowym adresowaniem. Do wskaźnika na obiekt wykorzystanego przez procedurę obsługi przerwania przypisywa- ny jest wskaźnik this aktualnie tworzonego obiektu. Przyjęto założenie, że istnieje tylko jedna instancja klasy i2c_host, ponieważ do danego kontrolera magistrali może być przypisany tylko jeden sterownik. Na zakoń- czenie włączane są przerwania w  kontrole- rze I2 C oraz konfigurowane są przerwania w kontrolerze NVIC. Jedyną metodą interfejsu użytkownika klasy sterownika I2 C jest metoda i2c_transfe- r_7bit (listing  3) umożliwiająca przeprowa- dzenie na magistrali transakcji I2 C. Jako parametry przyjmuje ona kolejno adres sprzętowy układu I2 C, z którym chce- my przeprowadzić transakcję, wskaźnik do bufora z  danymi oraz długość bufora, z  którego dane chcemy przesłać magistralą I2 C. Następnie przekazujemy wskaźnik do bufora, gdzie będą przesłane dane odebra- ne z magistrali I2 C oraz liczba danych, jaką chcemy odczytać. Jeśli chcemy wykonać tylko pojedynczy zapis danych lub odczyt, do nieużywanego wskaźnika na bufor nale- ży przypisać wartość NULL. Metoda blokuje wykonanie bieżącego wątku do chwili za- kończenia transakcji I2 C oraz w  przypadku powodzenia zwraca wartość ERR_OK. Na początku funkcji wywoływana jest metoda wait() na głównym semaforze blokującym, w wyniku czego proces może zostać zabloko- wany, jeżeli sterownik jest zajęty przez inny proces. Do zmiennych klasy przypisywane są wskaźniki do buforów oraz wielkości tych buforów i jest generowany sekwencja start. Następnie oczekujemy na semaforze sygna- lizującym zakończenie pracy przez proce- durę obsługi przerwania. Cała obsługa cyklu magistrali wykonywana jest w  przerwaniu. Oczekiwanie na semafor kończy się w  mo- mencie sygnalizacji przez procedurę obsłu- gi przerwania lub w  wyniku przekroczenia czasu oczekiwania, co informuje nas o wy- stąpieniu błędu. W  przypadku powodzenia zwracany jest status ERR_OK oraz podnoszo- ny jest semafor blokujący sem_lock za po- mocą wywołania metody sem_lock.signal(). Generacja bitu startu powoduje rozpoczęcie działania kontrolera I2 C. W  wyniku wystą- pienia poszczególnych zdarzeń zgłaszane Rysunek 1. Sposób dołączenia zegara RTC i wyświetlacza LCD do zestawu STM32Butterfly Rysunek 3. Hierarchia klas projektu Rysunek 2. Podział aplikacji na wątki 102 ELEKTRONIKA PRAKTYCZNA 9/2010 NOTATNIK KONSTRUKTORA jest przerwanie, którego obsługa realizowa- na jest przez procedurę i2c1_ev_isr_vector (listing 4). Funkcja ta jest zaprzyjaźniona z  klasą i2c_host. Na rzecz obiektu klasy i2c_host jest wywoływana funkcja isr(), która jest właści- wą procedurą obsługi przerwania (listing 5). Kontroler I2 C działa na zasadzie zdarzeń, zatem procedura obsługi przerwania sprowa- dza się do odczytania zdarzenia, a następnie wykonania określonej akcji przypisanej dla tego zdarzenia. W przypadku transmisji da- nych do układu podłączonego do magistrali I2 C, po wysłaniu sekwencji start otrzymujemy zdarzenie informującej o przejęciu arbitrażu nad magistralą I2 C przez kontroler. W wyni- ku wystąpienia zdarzenia I2C_EVENT_MA- STER_MODE_SELECTED? wywołujemy funkcję? send_7bit_addr(),? co? powoduje przesłanie adresu sprzętowego dla urządze- nia. W wyniku wysłania adresu sprzętowe- go dostajemy zdarzenie I2C_EVENT_MA- STER_TRANSMITTER_MODE_SELECTED, po którym możemy rozpocząć przesyłać dane. Wraz z  każdym przesłanym bajtem otrzymujemy zdarzenie I2C_EVENT_MA- STER_BYTE_TRANSMITTED. Oba zdarze- nie obsługiwane są przez ten sam fragment programu, którego zadaniem jest wysłanie danych z  bufora. W  przypadku przesłania ostatniego bajtu, jeżeli nie ma konieczności odbierania danych, jest wy- woływana metoda powodują- ca wygenerowanie sekwencji stop, następnie jest podnoszony semafor sem_irq informujący wątek o  zakończeniu obsługi przerwania. Realizacja podno- szenia semafora odbywa się za pomocą metody sem_signal_ isr(), która jest przeznaczona do wywołania z  procedur obsługi przerwań. Jeżeli po zakończe- niu nadawania konieczne jest odbieranie danych z  urządze- nia, generowany jest ponownie bit startu oraz przesyłany jest adres sprzętowy, z  najmłod- szym bitem ustawionym do odczytu. W  wyniku przesłania adresu sprzętowego otrzymuje- my zdarzenie I2C_EVENT_MA- STER_RECEIVER_MODE_SE- LECTED, w którym sprawdzamy, czy mamy do odebrania jeden bajt. Jeżeli tak jest, to wy- łączamy generowanie bitu ACK, a następnie przechodzimy do odbioru kolejnych danych. W przypadku odebrania bajtu otrzymujemy zdarzenie I2C_EVENT_MASTER_BYTE_RE- CEIVED, gdzie realizujemy przepisywanie bajtów do bufora odbiorczego. Gdy skończy- my odbieranie przedostatniego bajtu zgodnie ze specyfikacją I2 C wyłączamy, generowanie bitu potwierdzenia ACK, a  po odebraniu ostatniego bajtu wysyłamy polecenie wyge- Listing 1. //I2c host class class i2c_host { //Friend interrupt class friend void i2c1_ev_isr_vector(void); public: enum errno { ERR_OK = 0, //All is ok ERR_BUS = -5000, //Bus error ERR_ARBITRATION_LOST = -5001, ERR_ACK_FAILURE = -5002, ERR_OVERRUN = - 5003, ERR_PEC = - 5004, //Parity check error ERR_BUS_TIMEOUT = -5005, //Bus timeout ERR_TIMEOUT = - 5006, //timeout error ERR_UNKNOWN = - 5007 }; //Default constructor i2c_host(I2C_TypeDef * const _i2c, unsigned clk_speed=100000); //I2c transfer main function int i2c_transfer_7bit(uint8_t addr, const void* wbuffer, short wsize, void* rbuffer, short rsize); private: //Interrupt service routine void isr(); //Configuration data static const unsigned TRANSFER_TIMEOUT = 1000; static const unsigned IRQ_PRIO = 1; static const unsigned IRQ_SUB = 7; //Rest of the data static const unsigned CR1_ACK_BIT = 0x0400; static const unsigned CR1_START_BIT = 0x0100; static const unsigned CR1_STOP_BIT = 0x0200; static const uint16_t I2C_IT_BUF = 0x0400; static const uint16_t I2C_IT_EVT = 0x0200; static const uint16_t I2C_IT_ERR = 0x0100; static const uint16_t CR1_PE_SET = 0x0001; //Get last i2c event uint32_t get_last_event() { static const uint32_t sflag_mask = 0x00FFFFFF; return ( static_cast(i2c->SR1) | static_cast(i2c->SR2)<<16 ) & sflag_mask; } //Send 7 bit address on the i2c bus void send_7bit_addr(uint8_t addr) { i2c->DR = addr; } //Send data on the bus void send_data(uint8_t data) { i2c->DR = data; } //Read data from the bus uint8_t receive_data() { return i2c->DR; } //CR1 reg enable disable void cr1_reg(unsigned bit, bool en) { if(en) i2c->CR1 |= bit; else i2c->CR1 &= ~bit; } //ACK ON control void ack_on(bool on) { cr1_reg( CR1_ACK_BIT, on ); } //Generate start void generate_start(bool en=true) { cr1_reg( CR1_START_BIT, en ); } //Generate stop void generate_stop(bool en=true) { cr1_reg( CR1_STOP_BIT, en ); } //Clear data flags (dummy read) void clear_flags() { static_cast(static_cast(i2c->SR1)); static_cast(static_cast(i2c->DR)); } //Control enabling disabling int in the device void devirq_on(bool en=true) { if(en) /* Enable I2C interrupt */ i2c->CR2 |= I2C_IT_EVT| I2C_IT_ERR; else /* diasable I2C interrupt */ i2c->CR2 &= ~(I2C_IT_EVT | I2C_IT_ERR); }p //Set bus speed void set_speed(unsigned speed); //Translate error to the error code Listing 1. c.d. int get_hwerror(); private: //Data //I2c device number I2C_TypeDef *i2c; //Tx buffer pointer const uint8_t *tx_buf; //Rx buffer pointer uint8_t *rx_buf; //Busy semaphore isix::semaphore sem_lock; //Read semaphore isix::semaphore sem_irq; //Bus address volatile uint8_t bus_addr; //Bus error flags volatile uint8_t err_flag; //Tx counter volatile short tx_bytes; //Rx counter volatile short rx_bytes; //Position in the buffer volatile short buf_pos; private: //Noncopyable i2c_host(i2c_host &); i2c_host& operator=(const i2c_host&); }; 103ELEKTRONIKA PRAKTYCZNA 9/2010 Obsługa przerwań Listing 3. int i2c_host::i2c_transfer_7bit(uint8_t addr, const void* wbuffer, short wsize, void* rbuffer, short rsize) { int ret; if( (ret=sem_lock.wait(isix::ISIX_TIME_INFINITE))<0 ) { return ret; } //Disable I2C irq devirq_on(false); if(wbuffer) { bus_addr = addr & ~I2C_BUS_RW_BIT; } else if(rbuffer) { bus_addr = addr | I2C_BUS_RW_BIT; } tx_buf = static_cast(wbuffer); rx_buf = static_cast(rbuffer); tx_bytes = wsize; rx_bytes = rsize; buf_pos = 0; //ACK config ack_on(true); //Enable I2C irq devirq_on(); //Send the start generate_start(); //Sem read lock if( (ret=sem_irq.wait(TRANSFER_TIMEOUT)) <0 ) { if(ret==isix::ISIX_ETIMEOUT) { sem_irq.signal(); sem_lock.signal(); return ERR_TIMEOUT; } else { sem_irq.signal(); sem_lock.signal(); return ret; } } Listing 2. // TODO Add configuration for i2c2 device support if(_i2c==I2C1) { //GPIO configuration RCC->APB2ENR |= I2C1_GPIO_ENR; io_config(I2C1_PORT,I2C1_SDA_PIN,GPIO_MODE_50MHZ,GPIO_CNF_ALT_OD); io_config(I2C1_PORT,I2C1_SCL_PIN,GPIO_MODE_50MHZ,GPIO_CNF_ALT_OD); io_set(I2C1_PORT,I2C1_SCL_PIN); io_set(I2C1_PORT,I2C1_SDA_PIN); //I2C module configuration RCC->APB1ENR |= I2C1_ENR; } /* Enable I2C module*/ i2c->CR1 |= CR1_PE_SET; /* Reset the i2c device */ i2c->CR1 |= CR1_SWRST; nop(); i2c->CR1 &= ~CR1_SWRST; uint16_t tmpreg = i2c->CR2; /* Clear frequency FREQ[5:0] bits */ tmpreg &= CR2_FREQ_RESET; tmpreg |= static_cast(config::PCLK1_HZ/1000000); i2c->CR2 = tmpreg; //Set speed set_speed(clk_speed); /* CR1 configuration */ /* Get the I2Cx CR1 value */ tmpreg = i2c->CR1; /* Clear ACK, SMBTYPE and SMBUS bits */ tmpreg &= CR1_CLEAR_MASK; /* Configure I2Cx: mode and acknowledgement */ /* Set SMBTYPE and SMBUS bits according to I2C_Mode value */ /* Set ACK bit according to I2C_Ack value */ tmpreg |= I2C_MODE_I2C | I2C_ACK_ENABLE; /* Write to I2Cx CR1 */ i2c->CR1 = tmpreg; /* Set I2Cx Own Address1 and acknowledged address */ i2c->OAR1 = I2C_AcknowledgedAddress_7bit; i2c->SR1 = 0; i2c->SR2 = 0; /* Enable I2C interrupt */ devirq_on(); //Assign as the global object if(_i2c==I2C1) { i2c1_obj = this; } /* Enable interrupt controller */ nvic_set_priority( I2C1_EV_IRQn, IRQ_PRIO, IRQ_SUB); nvic_irq_enable(I2C1_EV_IRQn,true); } Listing 3. c.d. if( (ret=get_hwerror()) ) { err_flag = 0; sem_lock.signal(); return ret; } sem_lock.signal(); return ERR_OK; } 104 ELEKTRONIKA PRAKTYCZNA 9/2010 NOTATNIK KONSTRUKTORA Listing 5. //I2c interrupt handler void i2c_host::isr() { uint32_t event = get_last_event(); switch( event ) { //Send address case I2C_EVENT_MASTER_MODE_SELECT: //EV5 send_7bit_addr(bus_addr); break; //Send bytes in tx mode case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: //EV6 case I2C_EVENT_MASTER_BYTE_TRANSMITTED: //EV8 if(tx_bytes>0) { send_data(tx_buf[buf_pos++]); tx_bytes--; } if(tx_bytes==0) { if(rx_buf) { //Change address to read only bus_addr |= I2C_BUS_RW_BIT; ack_on(true); generate_start(); buf_pos = 0; } else { generate_stop(); sem_irq.signal_isr(); } } break; //Master mode selected case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: //EV7 if(rx_bytes==1) { ack_on(false); } break; //Master byte rcv case I2C_EVENT_MASTER_BYTE_RECEIVED: if(rx_bytes>0) { rx_buf[buf_pos++] = receive_data(); rx_bytes--; } if(rx_bytes==1) { ack_on(false); generate_stop(); } else if(rx_bytes==0) { generate_stop(); sem_irq.signal_isr(); } break; //Stop generated event default: if(event & EVENT_ERROR_MASK) { err_flag = event >> 8; i2c->SR1 &= ~EVENT_ERROR_MASK; sem_irq.signal_isr(); } else { clear_flags(); } break; } } Listing 4. //Call to the global c function extern ?C? { void i2c1_ev_isr_vector(void) __attribute__ ((interrupt)); void i2c1_ev_isr_vector(void) { if(i2c1_obj) i2c1_obj->isr(); } nerowania sekwencji stop oraz podnosimy semafor sem_isr informujący o  zakończeniu procedury odbioru. Po wygenerowaniu se- kwencji stop magistrala I2 C zostaje zwolniona. Klasa sterownika i2c wykorzystywana jest przez klasę rtc_reader, której zadaniem jest odczytanie bieżącej godziny z  zegara RTC oraz przygotowanie i przesłanie komu- nikatów do obiektu serwera wyświetlacza. Działanie wątku odpowiedzialnego za to za- danie realizowane jest przez metodę wirtual- ną pokazaną na listingu 6. 105ELEKTRONIKA PRAKTYCZNA 9/2010 Obsługa przerwań Listing 6. //Main rtc reader core task void rtc_reader::main() { static const uint8_t pgm_regs[] = { 0x01, //Sec 0x02, //Min 0x03, //Hour 0x04, //Day num 0x05, //day 0x06, //Month 0x07, //Year 0x00 //Config }; //Software address static const uint8_t sw_addr = 0; static uint8_t buf[3]; static time_msg tmsg( 3,2 ); int status; //Send configuration registgers i2c_bus.i2c_transfer_7bit(I2C_RTC_ADDR,pgm_regs,sizeof(pgm_ regs),NULL,0); //Main task loop for(;;) { //Send configuration registgers status = i2c_bus.i2c_transfer_7bit(I2C_RTC_ADDR,&sw_ addr,sizeof(sw_addr),buf, sizeof(buf) ); if(status>=0) { //If no error display time tmsg.set_time( buf[2]&0x3f, buf[1]&0x7f, buf[0]&0x7f ); } else { //If error display it tmsg.set_text(?I2C ERR?); } //Send message to the i2c device disp_srv.send_message(tmsg); //Refresh screen delay isix::isix_wait(200); } } Listing 7. class time_msg : public text_msg { public: time_msg(short xpos=0,short ypos=0) :text_msg(??,xpos,ypos) { } //Set text void set_time(short h, short m, short s) { conv_hex(sbuf,h,2); sbuf[2] = ?:?; conv_hex(&sbuf[3],m,2); sbuf[5] = ?:?; conv_hex(&sbuf[6],s,2); set_text(sbuf); } private: void strrev(char *str, int len); const char* conv_hex(char *txt, unsigned value,int zeros); private: char sbuf[9]; }; Pierwszą czynnością jest ustawienie wartości początkowej daty i czasu. Wartości początkowe zdefiniowane są w tablicy pgm_ regs. W  rzeczywistej aplikacji należałoby zadbać o możliwość odczytania danych z in- terfejsu użytkownika. Przesłanie wartości początkowych jest realizowane za pomocą funkcji i2c_transfer_7bit. Następnie wcho- dzimy do pętli głównej programu, gdzie realizowany jest odczyt bieżącej godziny z zegara RTC. Procedura odbywa się poprzez wywołanie pojedynczej metody i2c_transfer- 7bit(). Po odczytaniu danych z magistrali I2 C sprawdzany jest status błędu i w przypadku jego wystąpienia jest wysyłany komunikat tekstowy. Jeżeli odczyt danych z  magistra- li I2 C wykonano pomyślnie, jest tworzony komunikat klasy time_msg, zawierający in- formację o czasie w formie tekstowej, który następnie przesyłany jest do serwera wy- świetlania. Klasa time_msg dziedziczy z kla- sy text_msg, zatem może być wysłana bezpo- średnio do serwera wyświetlania (listing 7). Utworzenie komunikatu tekstowego za- wierającego aktualny czas odbywa się przez wywołanie metody set_time(), która jako ar- gumenty przyjmuje aktualną godzinę, minu- tę i sekundę w formacie BCD. Lucjan Bryndza, EP lucck@boff.pl
Artykuł ukazał się w
Wrzesień 2010
DO POBRANIA
Pobierz PDF Download icon

Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik listopad 2021

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio listopad - grudzień 2021

Świat Radio

Magazyn krótkofalowców i amatorów CB

Automatyka Podzespoły Aplikacje listopad 2021

Automatyka Podzespoły Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna listopad 2021

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Elektronika dla Wszystkich grudzień 2021

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów