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 lipiec 2020

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio lipiec 2020

Świat Radio

Magazyn użytkowników eteru

APA - Automatyka Podzespoły Aplikacje czerwiec 2020

APA - Automatyka Podzespoły Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna lipiec 2020

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Praktyczny Kurs Elektroniki 2018

Praktyczny Kurs Elektroniki

24 pasjonujące projekty elektroniczne

Elektronika dla Wszystkich czerwiec 2020

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów