- Zestaw rozwojowy nRF52:
- Segger Embedded Studio
- DHT11 z nRF52DK
- Jak pracować z Bluetooth Low Energy (BLE)?
- Diagram usług / charakterystyk BLE
- Objaśnienie programu BLE nRF52
- Testowanie naszego programu przy użyciu nRF Connect
Wraz ze wzrostem popularności opasek fitness, smartwatche i innych urządzeń do noszenia, korzystanie z technologii Bluetooth 5 / Bluetooth Low Energypowszechnie przyjmuje się standardy komunikacyjne. BLE pomaga nam wymieniać dane na krótkie odległości przy bardzo małej mocy, co jest bardzo ważne w przypadku urządzeń zasilanych bateryjnie, takich jak urządzenia do noszenia. Pomaga nam również w konfigurowaniu bezprzewodowych sieci kratowych BLE, ta funkcja jest przydatna w przypadku urządzeń automatyki domowej, w których wiele urządzeń musi komunikować się ze sobą w zamkniętym środowisku. Użyliśmy już BLE z Raspberry Pi i BLE z ESP32, aby wykonać kilka podstawowych funkcji BLE. Inżynierowie eksperymentują z BLE, aby zaprojektować przenośne urządzenia bezprzewodowe, które mogą działać przez długi czas na małych bateriach. Dostępnych jest wiele zestawów programistycznych do pracy z BLE. W naszej ostatniej recenzji na temat Arduino Nano 33 zauważyliśmy również, że płyta ma nRF52840 z funkcjami BLE.
W tym samouczku zbadamy inną ekscytującą i popularną płytkę programistyczną o nazwie nRF52 DK do pomiaru temperatury i wilgotności za pomocą BLE. Domyślnie profile wykrywania środowiska BLE obsługują szeroki zakres parametrów środowiskowych, ale ten samouczek jest ograniczony tylko do wartości temperatury i wilgotności. To rozwiązanie łączy się ze smartfonem przez Bluetooth niskoenergetyczny i zapewnia częstą aktualizację parametrów środowiskowych, tj. Temperatury, wilgotności. Będziemy używać czujnika DHT1 i pomiar temperatury będzie wykonywany z rozdzielczością 0,01 stopnia Celsjusza, a pomiar wilgotności z rozdzielczością 0,01 procent.
Zestaw rozwojowy nRF52:
nRF52DK to kompletna platforma prototypowa dla aplikacji Bluetooth Low Energy i Wireless Internet of Things 2,4 GHz. Zestaw deweloperski obsługuje różne standardowe Nordic Toolchains, takie jak open-source, GCC i komercyjne zintegrowane środowiska programistyczne, takie jak Keil, IAR i Segger Embedded Studio, itp. Nordic zapewnia również pełnoprawny zestaw programistyczny dla nRF52, który obejmuje pełne wsparcie dla nRF52DK.
nRF52DK jest zasilany przez mikrokontroler nRF52832 ARM Cortex-M4F, który jest zintegrowany z 512 kilobajtami pamięci Flash i 64 kilobajtami pamięci SRAM. nRF52DK ma zintegrowany debugger Segger J-Link On Board, który zapewnia łatwiejsze i szybsze debugowanie bez zewnętrznych / dodatkowych urządzeń debugujących jtag. Zawiera również złącze kompatybilne z Arduino Uno Rev3, który obsługuje łączenie wejść analogowych i cyfrowych z mikroprocesorem, a także zawiera standardowe protokoły komunikacyjne, takie jak I2C (układ scalony), SPI (szeregowy interfejs peryferyjny) i UART (uniwersalny asynchroniczny odbiornik i nadajnik). Ten zestaw rozwojowy został zaprojektowany z wbudowaną anteną PCB, która zapewnia bezprzewodową komunikację krótkiego zasięgu przy użyciu technologii Bluetooth Low Energy do łączenia ze smartfonem, laptopami i tabletami.
Segger Embedded Studio
Aby zaprogramować płytkę programistyczną, użyjemy Segger Embedded Studio z nRF52. Segger Embedded Studio to potężne zintegrowane środowisko programistyczne (IDE) C / C ++ przeznaczone specjalnie do tworzenia systemów wbudowanych. Zapewnia to kompletne rozwiązanie typu „wszystko w jednym”, zawierające wszystko, co jest potrzebne do programowania, programowania i debugowania wbudowanego języka C. Obejmuje to pełny przepływ pracy dla programowania i rozwoju systemów wbudowanych, obejmujący zarządzanie projektami, edytor, debugger obsługujący urządzenia ARM Cortex. To potężne i łatwe w użyciu środowisko IDE jest całkowicie bezpłatne dla klientów skandynawskich z pełną licencją bez ograniczeń rozmiaru kodu. IDE można pobrać z linku podanego poniżej,
Pobierz Segger Embedded Studio
DHT11 z nRF52DK
DHT11 to w pełni funkcjonalny czujnik temperatury i wilgotności z rezystancyjnym elementem do pomiaru wilgotności i elementem do pomiaru temperatury typu NTC. Oferuje doskonałą jakość, szybszą reakcję i opłacalność. Domyślnie wszystkie czujniki DHT11 są kalibrowane w laboratorium, co zapewnia wyjątkową dokładność i niezawodność. Komunikuje się za pomocą systemu jednoprzewodowego interfejsu szeregowego, a inne specyfikacje podano poniżej
Specyfikacje DHT11:
- Zakres wilgotności: 20 - 90% RH
- Zakres temperatur: 0 - 50 stopni Celsjusza
- Dokładność wilgotności: ± 5 % RH
- Dokładność temperatury: ± 2 ℃
Schemat czasowy DHT11:
Odczyt danych z czujnika DHT11 jest stosunkowo prosty przy użyciu schematu czasowego pokazanego powyżej. Procedura jest podobna do każdego kontrolera i używaliśmy już tego czujnika z innymi platformami programistycznymi, takimi jak
- Czujnik DHT11 z Raspberry Pi
- Czujnik DHT11 z PIC16F877A
- Czujnik DHT11 z STM32F103C8
- Czujnik DHT11 z NodeMCU
Aby połączyć czujnik temperatury i wilgotności DHT11 z zestawem rozwojowym nRF52, postępuj zgodnie ze schematem połączeń podanym poniżej.
Używam modułu złącza do podłączenia czujnika do mojej płyty, więc moja ostateczna konfiguracja wygląda tak
Schemat blokowy komunikacji z DHT11:
Poniższy schemat blokowy wyjaśnia logiczny przepływ programu, którego będziemy używać do komunikacji między nRF52DK i DHT11
Format danych:
Jak pracować z Bluetooth Low Energy (BLE)?
Aby zrozumieć, jak korzystać z funkcji BLE, musimy zrozumieć kilka podstawowych terminologii, które są wyjaśnione poniżej, możesz również przeczytać artykuł ESP32 BLE, aby dowiedzieć się więcej o BLE
Ogólny profil dostępu (GAP)
Ogólny profil dostępu ponosi pełną odpowiedzialność za ustanowienie połączenia w celu komunikacji między urządzeniami peryferyjnymi BLE a urządzeniami centralnymi. GAP zapewnia również różne procedury, w tym skanowanie / wykrywanie urządzeń, nawiązywanie połączenia w warstwie łącza, kończenie łącza, uzgadnianie funkcji zabezpieczeń i pełną konfigurację urządzeń. GAP działa w następujących stanach urządzeń
Stany GAP |
Opis |
Czekaj |
Początkowy stan urządzenia po zresetowaniu |
Człowiek ogłaszający |
Reklama urządzenia z danymi, które pomagają w skanowaniu inicjatora |
Skaner |
Odbiera i wysyła żądanie skanowania do reklamodawcy |
Inicjator |
Wysyła żądanie połączenia w celu ustanowienia łącza |
Mistrz niewolników |
Podczas połączenia urządzenie jako slave, jeśli reklamodawca, master, jeśli inicjator |
Warstwa profilu atrybutów ogólnych (GATT)
GATT jest skrótem od Generic Attribute Profile Layer, odpowiada za komunikację danych między dwoma urządzeniami BLE (Peripheral & Central). Komunikacja danych charakteryzuje się charakterystykami, które przekazują i przechowują dane. Urządzenie BLE pełni dwie różne role w komunikacji z urządzeniami podanymi poniżej,
- Serwer GATT zawiera informacje o charakterystyce, które będą używane do odczytu i zapisu. W naszym samouczku czujnik DHT11 i dev. zestaw to nasz serwer GATT.
- Klient GATT odczytuje i zapisuje dane z / do serwera GATT. Smartfon to klient GATT, który odczytuje i zapisuje dane na naszej płytce czujników.
Bluetooth SIG
Bluetooth Special Interest Group (SIG) to organizacja normalizacyjna, która monitoruje rozwój standardów Bluetooth i licencjonowanie technologii Bluetooth. Grupa SIG nie produkuje ani nie sprzedaje żadnych produktów Bluetooth. Określa specyfikację i standaryzację Bluetooth. Definiują one unikalny identyfikator profilu niskiego zużycia energii Bluetooth i odpowiednie właściwości. Specyfikacje profilu GATT można znaleźć pod linkiem poniżej
Specyfikacja profilu GATT
Na podstawie Specyfikacji GATT podanej w powyższym linku zebraliśmy unikalne identyfikatory wymagane dla naszego projektu, które przedstawiono w tabeli poniżej.
Profil / Charakterystyka |
UUID |
GAP (dostęp ogólny) |
0x1800 |
GATT (atrybut ogólny) |
0x1801 |
ESS (wyczuwanie środowiska) |
0x181A |
Temperatura |
0x2A6E |
Wilgotność |
0x2A6F |
Diagram usług / charakterystyk BLE
BLE UUID
UUID |
Wartość 16-bitowa |
128-bitowy UUID |
Usługa ESS |
0x181A |
0000181A-0000-0000-0000-00000000000 |
Temp Char |
0x2A6E |
00002A6E-0000-0000-0000-00000000000 |
Wilgotność Char |
0x2A6F |
00002A6F-0000-0000-0000-00000000000 |
Charakterystyka temperaturowa
własność |
Opis |
Jednostka |
Stopień Celsjusza z rozdzielczością 0,01 stopnia |
Format |
sint16 |
UUID |
0x2A6E |
Wykładnik dziesiętny |
2 |
Czytać |
Obowiązkowy |
Charakterystyka wilgotności
własność |
Opis |
Jednostka |
Procent z rozdzielczością 0,01 procent |
Format |
uint16 |
UUID |
0x2A6F |
Wykładnik dziesiętny |
2 |
Czytać |
Obowiązkowy |
Objaśnienie programu BLE nRF52
Będziemy używać zestawu SDK nRF5 do programowania naszego zestawu rozwojowego nRF52. nRF5 SDK to kompletny zestaw programistyczny zintegrowany z wieloma profilami Bluetooth Low Energy, serializatorem GATT i obsługą sterowników dla wszystkich urządzeń peryferyjnych w SoC z serii nRF5. Ten pakiet SDK pomaga programistom tworzyć w pełni funkcjonalne, niezawodne i bezpieczne aplikacje Bluetooth o niskim zużyciu energii z mikrokontrolerami z serii nRF52 i nRF51. Cały program można pobrać stąd, wyjaśnienie kodu jest następujące.
Skonfiguruj pin DHT11 DATA jako wejście w nrf52 z włączoną funkcją pull up. Stan pinu powinien być wysoki, aby potwierdzić, że nRF52 zapewnia prawidłowe PULLUP dla pinu danych DHT11
/ * ustaw na wejście i sprawdź, czy sygnał jest podciągany * / Data_SetInput (); DelayUSec (50); if (Data_GetVal () == 0) {return DHT11_NO_PULLUP; }
Wygeneruj sygnał START z mikrokontrolera nRF52 i sprawdź sygnał potwierdzenia.
/ * wyślij sygnał startu * / Data_SetOutput (); Data_ClrVal (); DelayMSec (20); / * utrzymuj niski poziom sygnału przez co najmniej 18 ms * / Data_SetInput (); DelayUSec (50); / * sprawdź sygnał potwierdzenia * / if (Data_GetVal ()! = 0) {/ * sygnał musi być obniżony przez czujnik * / return DHT11_NO_ACK_0; } / * czekaj maksymalnie 100 us na sygnał potwierdzenia z czujnika * / cntr = 18; while (Data_GetVal () == 0) {/ * czekaj, aż sygnał wzrośnie * / DelayUSec (5); if (--cntr == 0) {return DHT11_NO_ACK_1; / * sygnał powinien być włączony dla potwierdzenia tutaj * /}} / * poczekaj, aż ponownie spadnie, koniec sekwencji potwierdzającej * / cntr = 18; while (Data_GetVal ()! = 0) {/ * czekaj, aż sygnał opadnie * / DelayUSec (5); if (--cntr == 0) {return DHT11_NO_ACK_0; / * sygnał powinien znowu spaść do zera * /}}
Teraz odczytaj 40 bitów danych, które zawierają 2 bajty temperatury, 2 bajty wilgotności i 1 bajt sumy kontrolnej.
/ * odczytaj teraz 40-bitowe dane * / i = 0; data = 0; loopBits = 40; do {cntr = 11; / * czekaj max 55 us * / while (Data_GetVal () == 0) {DelayUSec (5); if (--cntr == 0) {return DHT11_NO_DATA_0; }} cntr = 15; / * czekaj max 75 us * / while (Data_GetVal ()! = 0) {DelayUSec (5); if (--cntr == 0) {return DHT11_NO_DATA_1; }} dane << = 1; / * następny bit danych * / if (cntr <10) {/ * sygnał danych wysoki> 30 us ==> bit danych 1 * / data - = 1; } if ((loopBits & 0x7) == 1) {/ * następny bajt * / buffer = data; i ++; data = 0; }} while (- loopBits! = 0);
Sprawdź poprawność danych za pomocą sumy kontrolnej.
/ * test CRC * / if ((uint8_t) (bufor + bufor + bufor + bufor)! = bufor) {return DHT11_BAD_CRC; }
Manipuluj i przechowuj temperaturę i wilgotność
/ * przechowuj wartości danych dla dzwoniącego * / wilgotność = ((int) bufor) * 100 + bufor; temperatura = ((int) bufor) * 100 + bufor;
Zainicjuj usługę rejestratora zestawu SDK nRF5. SDK nRF52 jest wyposażony w interfejs sterowania rejestrowaniem o nazwie nrf_log i używa domyślnego zaplecza do rejestrowania informacji. Domyślnym zapleczem będzie port szeregowy. Tutaj inicjalizujemy zarówno interfejs sterujący nrf_log, jak i domyślne backendy nrf_log .
ret_code_t err_code = NRF_LOG_INIT (NULL); APP_ERROR_CHECK (kod_błędu); NRF_LOG_DEFAULT_BACKENDS_INIT ();
SDK nRF52 posiada funkcję timera aplikacji. Moduł timera aplikacji umożliwia tworzenie wielu instancji timera w oparciu o urządzenie peryferyjne RTC1. Tutaj inicjalizujemy moduł timera aplikacji nRF5. W tym rozwiązaniu używane są dwa liczniki czasu aplikacji i interwał aktualizacji danych.
ret_code_t err_code = app_timer_init (); APP_ERROR_CHECK (kod_błędu);
nRF52 SDK ma pełen moduł zarządzania energią, ponieważ urządzenia BLE muszą pracować przez wiele miesięcy na baterii pastylkowej. Zarządzanie energią odgrywa kluczową rolę w aplikacjach BLE. Moduł zarządzania energią nRF52 całkowicie radzi sobie z tym samym. Tutaj inicjalizujemy moduł zarządzania energią zestawu SDK nRF5
ret_code_t err_code; err_code = nrf_pwr_mgmt_init (); APP_ERROR_CHECK (kod_błędu);
nRF52 SDK ma wbudowany plik szesnastkowy oprogramowania Nordic Soft Device, który zawiera centralny i peryferyjny stos o niskim zużyciu energii Bluetooth. Ten wysoko kwalifikowany stos protokołów obejmuje GATT, GAP, ATT, SM, L2CAP i Link Layer. Tutaj śledzimy sekwencję inicjalizacji, która zainicjowała stos radiowy nRF5 BLE (Nordic Soft Device)
ret_code_t err_code; err_code = nrf_sdh_enable_request (); APP_ERROR_CHECK (kod_błędu); // Skonfiguruj stos BLE przy użyciu ustawień domyślnych. // Pobierz adres początkowy pamięci RAM aplikacji. uint32_t ram_start = 0; err_code = nrf_sdh_ble_default_cfg_set (APP_BLE_CONN_CFG_TAG, & ram_start); APP_ERROR_CHECK (kod_błędu); // Włącz stos BLE. err_code = nrf_sdh_ble_enable (& ram_start); APP_ERROR_CHECK (kod_błędu); // Zarejestruj procedurę obsługi dla zdarzeń BLE. NRF_SDH_BLE_OBSERVER (m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
GAP jest odpowiedzialny za skanowanie / wykrywanie urządzeń, ustanowienie łącza, zakończenie łącza, inicjowanie funkcji bezpieczeństwa i konfigurację. GAP został wyposażony w kluczowe parametry połączenia, takie jak interwał połączenia, opóźnienie urządzenia podrzędnego, limit czasu nadzoru itp. Z tym inicjalizacją parametrów połączenia ogólnego profilu dostępu
ret_code_terr_code; ble_gap_conn_params_tgap_conn_params; ble_gap_conn_sec_mode_t sec_mode; BLE_GAP_CONN_SEC_MODE_SET_OPEN (& sec_mode); err_code = sd_ble_gap_device_name_set (& sec_mode, (const uint8_t *) DEVICE_NAME, strlen (DEVICE_NAME)); APP_ERROR_CHECK (kod_błędu); memset (& gap_conn_params, 0, sizeof (gap_conn_params)); gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL; gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL; gap_conn_params.slave_latency = SLAVE_LATENCY; gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT; err_code = sd_ble_gap_ppcp_set (& gap_conn_params); APP_ERROR_CHECK (kod_błędu);
GATT jest odpowiedzialny za komunikację danych między urządzeniami peryferyjnymi BLE a urządzeniami centralnymi. Moduł nRF52 GATT jest pomocny w negocjowaniu i śledzeniu maksymalnego rozmiaru ATT_MTU. Tutaj inicjalizujemy Generic Attribute Module nRF52 SDK, ret_code_t err_code = nrf_ble_gatt_init (& m_gatt, NULL); APP_ERROR_CHECK (kod_błędu);
GATT zajmuje się przesyłaniem danych w postaci usług i cech. Tutaj inicjalizujemy usługi wykrywania środowiska GATT, które obejmują inicjalizację charakterystyk, takich jak temperatura i wilgotność.
ret_code_terr_code; nrf_ble_qwr_init_t qwr_init = {0}; // Zainicjuj moduł zapisu w kolejce. qwr_init.error_handler = nrf_qwr_error_handler; err_code = nrf_ble_qwr_init (& m_qwr, & qwr_init); APP_ERROR_CHECK (kod_błędu); m_ess.notif_write_handler = ble_ess_notif_write_handler; err_code = ble_ess_init (& m_ess); APP_ERROR_CHECK (kod_błędu);
Reklama odgrywa istotną rolę w środowisku aplikacji BLE. pakiety zawierają informacje o typie adresu, rodzaju reklamy, danych reklamowych, danych specyficznych dla producenta urządzenia i danych odpowiedzi na skanowanie. nRF52 SDK wyposażony w moduł reklamowy. Tutaj wykonujemy inicjalizację modułu reklamowego z parametrami.
ret_code_terr_code; ble_advdata_t advdata; ble_advdata_t srdata; ble_uuid_t adv_uuids = {{ESS_UUID_SERVICE, BLE_UUID_TYPE_BLE}}; // Tworzenie i konfigurowanie danych reklamowych. memset (& advdata, 0, sizeof (advdata)); advdata.name_type = BLE_ADVDATA_FULL_NAME; advdata.include_appearance = true; advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; memset (& srdata, 0, sizeof (srdata)); srdata.uuids_complete.uuid_cnt = sizeof (adv_uuids) / sizeof (adv_uuids); srdata.uuids_complete.p_uuids = adv_uuids; err_code = ble_advdata_encode (& advdata, m_adv_data.adv_data.p_data, & m_adv_data.adv_data.len); APP_ERROR_CHECK (kod_błędu); err_code = ble_advdata_encode (& srdata, m_adv_data.scan_rsp_data.p_data, & m_adv_data.scan_rsp_data.len); APP_ERROR_CHECK (kod_błędu); ble_gap_adv_params_t adv_params; // Ustaw parametry reklamowe. memset (& adv_params, 0, sizeof (adv_params)); adv_params.primary_phy = BLE_GAP_PHY_1MBPS; adv_params.duration = APP_ADV_DURATION; adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED; adv_params.p_peer_addr = NULL; adv_params.filter_policy = BLE_GAP_ADV_FP_ANY; adv_params.interval = APP_ADV_INTERVAL; err_code = sd_ble_gap_adv_set_configure (& m_adv_handle, & m_adv_data, & adv_params); APP_ERROR_CHECK (kod_błędu);
Połączenie BLE będzie obsługiwane i monitorowane za pomocą różnych parametrów połączenia, takich jak opóźnienie aktualizacji parametrów pierwszego połączenia, następne kolejne opóźnienia, licznik aktualizacji, funkcja wywołania zwrotnego obsługi zdarzeń połączenia i procedura obsługi zdarzenia wywołania zwrotnego błędu połączenia. Tutaj wykonujemy inicjalizację parametrów ustanowienia połączenia BLE i procedurę obsługi zdarzeń wywołania zwrotnego dla zdarzeń połączenia i zdarzeń błędów.
ret_code_terr_code; ble_conn_params_init_t cp_init; memset (& cp_init, 0, sizeof (cp_init)); cp_init.p_conn_params = NULL; cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY; cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY; cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT; t_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID; cp_init.disconnect_on_fail = false; cp_init.evt_handler = on_conn_params_evt; cp_init.error_handler = conn_params_error_handler; err_code = ble_conn_params_init (& cp_init); APP_ERROR_CHECK (kod_błędu);
Po zakończeniu inicjalizacji systemu zaczynamy od rozgłaszania nazwy urządzenia BLE i informacji o możliwościach. Stąd to urządzenie peryferyjne można zobaczyć na liście skanowania Ble smartfona.
ret_code_terr_code; err_code = sd_ble_gap_adv_start (m_adv_handle, APP_BLE_CONN_CFG_TAG); APP_ERROR_CHECK (kod_błędu);
Główna pętla działa przez 2 sekundy, odczytuje temperaturę i wilgotność oraz aktualizuje podłączone urządzenie inteligentne za pomocą odczytu lub powiadomienia
dla (;;) { uint16_t temperatura, wilgotność; DHTxx_ErrorCode dhtErrCode; idle_state_handle (); if (updtmrexp) { dhtErrCode = DHTxx_Read (& temperatura i & wilgotność); if (dhtErrCode == DHT11_OK) { NRF_LOG_INFO ("Temperatura:% d Wilgotność:% d \ n", temperatura, wilgotność); if (temp_notif_enabled) { ble_ess_notify_temp (m_conn_handle, & m_ess, temperatura); } else { ble_ess_update_temp (& m_ess, temperatura); } if (humid_notif_enabled) { ble_ess_notify_humid (m_conn_handle, & m_ess, wilgotność); } else { ble_ess_update_humid (& m_ess, wilgotność); } } updtmrexp = false; } }
Testowanie naszego programu przy użyciu nRF Connect
nRF Connect to potężne narzędzie Bluetooth o niskim zużyciu energii, które umożliwia skanowanie i eksplorację urządzeń peryferyjnych obsługujących BLE. nRF Connect for mobile obsługuje szeroką gamę standardowych profili przyjętych przez Bluetooth SIG. Możemy zweryfikować nasz program za pomocą tego, po zainstalowaniu aplikacji możemy sparować płytkę nRF52 z naszym telefonem, skanując w aplikacji urządzenia BLE. Wewnątrz atrybutu Wykrywanie w środowisku możemy zauważyć aktualizację wartości temperatury i wilgotności, jak pokazano na poniższych ilustracjach.
Hariharan Veerappan jest niezależnym konsultantem z ponad 15-letnim doświadczeniem w rozwoju produktów wbudowanych. Świadczy usługi konsultingowe w zakresie rozwoju oprogramowania wbudowanego / Linuksa, prowadzi również szkolenia korporacyjne i internetowe. Hariharan posiada tytuł licencjata inżyniera w dziedzinie elektroniki i inżynierii komunikacji, a poprzez swoje artykuły i samouczki dzieli się swoim doświadczeniem i przemyśleniami z czytelnikami Circuit Digest.