Digilent Pmod i STM32 (cz. 2) – PmodHYGRO i PmodOLEDrgb
W drugiej części cyklu poświęconego modułom peryferyjnym Pmod przedstawimy moduły PmodHYGRO (czujnik temperatury i wilgotności), a także PmodOLEDrgb (kolorowy wyświetlacz graficzny OLED). Przedstawione przykłady kodu wykorzystują bibliotekę STM32Cube_FW_L4 i mogą być uruchomione w środowisku Atollic TrueSTUDIO na zestawie deweloperskim z mikrokontrolerem STM32 KAmeleon (www.kameleonboard.org).
PmodHYGRO
Moduł PmodHYGRO jest czujnikiem temperatury i wilgotności względnej opartym o układ Texas Instruments HDC1080. Zakres mierzonych temperatur wynosi od -40ºC do +125ºC, natomiast rozdzielczość wyniku pomiaru można skonfigurować na 11 lub 14 bitów. Dokładność pomiaru zależy od mierzonej wartości, co przedstawiono na rysunku 1. W przypadku wilgotności, której zakres pomiarowy wynosi 0% – 100%, rozdzielczość pomiaru można skonfigurować jako 8, 11 lub 14 bitów. Podobnie jak w przypadku temperatury, dokładność pomiaru również zależy od mierzonej wartości. Zależność tą przedstawiono na rysunku 2. Czas pomiaru obu wielkości jest zależny od skonfigurowanej rozdzielczości i nie przekracza 6,5 ms dla 14 bitów.
Rysunek 1. Zależność dokładności pomiaru temperatury od mierzonej wartości (źródło: dokumentacja układu HDC1080)
Złącze Pmod w module PmodHYGRO
Moduł PmodHYGRO posiada 6-pinowe złącze Pmod dla interfejsu I2C. Na potrzeby przykładu moduł należy podłączyć do złącza I2C KAmod Expander tak, jak zostało to pokazane na fotografii 2. Lista pinów na złączu Pmod wraz z odpowiadającymi im pinami mikrokontrolera znajduje się w tabeli 1.
Fotografia 2. PmodHYGRO podłączony do zestawu KAmeleon
Rysunek 3. Zależność dokładności pomiaru wilgotności względnej od mierzonej wartości (źródło: dokumentacja układu HDC1080)
Tabela 1. Sygnały PmodHYGRO oraz odpowiadające im piny złącza KAmod Expander I2C i piny mikrokontrolera; N/C oznacza sygnały niepodłączone
Sygnał |
Numer pinu PmodHYGRO | Numer pinu Kameleon KAmod Expander I2C | Pin mikrokontrolera |
N/C | 1 | – | – |
N/C | 2 | – | – |
SCL | 3 | 2 | PF1 |
SDA | 4 | 3 | PF0 |
GND | 5 | 4 | – |
VCC | 6 | 1 | – |
Komunikacja z HDC1080 odbywa się za pośrednictwem 16-bitowych rejestrów zapisywanych i odczytywanych za pomocą interfejsu I2C. Rejestr konfiguracyjny znajduje się pod adresem 0x02 i zawiera bity ustawiające rozdzielczość i tryb pomiaru. Rozdzielczość ustawia się dla każdej z wielkości osobno, natomiast tryb pomiaru dotyczy pomiaru jednej z dwóch wielkości, lub też obu w sekwencji. Pełna struktura rejestru konfiguracyjnego znajduje się na rysunku 4. Warto dodać, że w rejestrze znajduje się także możliwość włączenia lub wyłączenia grzałki służącej do testowania pomiaru temperatury i usuwania wilgoci zgromadzonej wewnątrz urządzenia. Domyślna wartość rejestru po resecie wynosi 0x1000 i oznacza pomiar temperatury i wilgotności w sekwencji oraz maksymalną rozdzielczość – 14 bitów.
Rysunek 4. Rejestr konfiguracyjny (0x02) (źródło: dokumentacja układu HDC1080)
Kod do obsługi modułu – konfiguracja I2C
Obsługa modułu PmodHYGRO w przykładzie znajduje się w pliku PmodHYGRO.c. Funkcja PmodHYGRO_Config(), przedstawiona na listingu 1, odpowiada za konfigurację interfejsu I2C. Ustawia ona m.in. wartość rejestru I2C_TIMINGR, odpowiedzialnego za konfigurację przebiegów czasowych na liniach SDA i SCL. Definicja tego rejestru znajduje się na rysunku 5. Pole PRESC jest preskalerem głównego sygnału zegarowego taktującego moduł I2C mikrokontrolera, natomiast SCLL i SCLH ustalają długość stanu niskiego i wysokiego sygnału zegarowego. Pozostałe dwa pola dotyczą sygnału na linii danych SDA i oznaczają czas pomiędzy ustaleniem stanu na linii danych, a narastającym zboczem zegara (SCLDEL), a także czas pomiędzy opadającym zboczem zegara, a zmianą stanu na linii danych (SDADEL). Faktyczne wartości wszystkich wymienionych parametrów poza SDADEL mają wartość o 1 większą niż ustawiona w rejestrze. Konfiguracja kończy się wywołaniem funkcji opóźniającej – HAL_Delay realizującej wymagane przez układ HDC1080 opóźnienie 15 ms w celu inicjalizacji urządzenia (start-up time).
Listing 1. Konfiguracja I2C
void PmodHYGRO_Config() { pmodHygroI2c.Instance = I2C2; pmodHygroI2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; pmodHygroI2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; pmodHygroI2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; pmodHygroI2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; pmodHygroI2c.Init.OwnAddress1 = 0x01; // Set the I2C_TIMINGR register to fulfill the HDC1080 timing requirements (max 400kHz). pmodHygroI2c.Init.Timing = 0x10563046; HAL_I2C_Init(&pmodHygroI2c); // The HDC1080 requires at most 15 ms start-up delay. HAL_Delay(15); }
Rysunek 5. Definicja rejestru I2C_TIMINGR (źródło: dokumentacja mikrokontrolera STM32L496ZG)
Konfiguracja GPIO
Konfiguracja GPIO (piny PF0 i PF1) i włączenie zegara dla I2C znajduje się w funkcji HAL_I2C_MspInit, przedstawionej na listingu 2. Jest ona wywoływana wewnątrz biblioteki HAL, w funkcji HAL_I2C_Init. Wartość rejestru konfiguracyjnego nie jest modyfikowana podczas konfiguracji, więc obowiązuje wartość domyślna omówiona wyżej.
Listing 2. Konfiguracja GPIO
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c) { __HAL_RCC_I2C2_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); }
Odczyt wartości
Ostatnią z funkcji w pliku PmodHYGRO.c, przedstawiono na listingu 3. Jest odpowiedzialna za wyzwalanie pomiaru, a także odczyt wartości. Pierwszym krokiem jest zapisanie adresu rejestru zawierającego zmierzoną wartość temperatury (adres 0x00). Jest to jednoznaczne z wyzwoleniem sekwencji dwóch pomiarów: temperatury i wilgotności, ze względu na ustawiony tryb pracy w rejestrze konfiguracyjnym. Czas konwersji wynosi 6,5 ms dla pomiaru wilgotności i 6,35 ms dla pomiaru temperatury przy rozdzielczości 14 bitów. Z tego powodu, po wysłaniu adresu 0x00 wprowadzono opóźnienie 13 ms przed wykonaniem odczytu. Odczyt danych obejmuje 4 bajty, które można uzyskać w jednej transakcji I2C. Konwersja odczytanych danych na wartości temperatury i wilgotności jest zgodna z zależnościami przedstawionymi w dokumentacji układu HDC1080. Są one pokazane na rysunku 6.
Listing 3. Pomiar i odczyt wartości temperatury i wilgotności
void PmodHYGRO_GetMeasurements(int16_t* temperature, int16_t* humidity) { // Write the address 0x00 pointing to temperature register in order to execute the measurements. uint8_t data[4] = {0}; HAL_I2C_Master_Transmit(&pmodHygroI2c, PMODHYGRO_ADDRESS, data, 1, 100); // Wait for the measurements to complete. HAL_Delay(13); // Read the four bytes starting from address 0. First two bytes contain the 14-bit temperature // value, the last two bytes - humidity value. HAL_I2C_Master_Receive(&pmodHygroI2c, PMODHYGRO_ADDRESS, data, 4, 100); uint16_t temperatureRaw = (data[0] << 8) | data[1]; uint16_t humidityRaw = (data[2] << 8) | data[3]; // Calculate the real temperature and humidity values according to the formula described on the // website: https://reference.digilentinc.com/reference/pmod/pmodhygro/reference-manual float temp = (temperatureRaw * 1.0 / (1 << 16) * 165) - 40; *temperature = temp * 10; temp = (humidityRaw * 1.0 / (1 << 16)) * 100; *humidity = temp; }
Rysunek 6. Konwersja temperatury i wilgotności (źródło: dokumentacja układu HDC1080)
Funkcja PmodHYGRO_GetMeasurements jest wywoływana raz na sekundę w pętli głównej programu, natomiast wartości temperatury i wilgotności są wypisywane za pośrednictwem portu szeregowego LPUART1, którego obsługa znajduje się w pliku serial.c.