Урок 55
Часть 1
Датчик влажности HTS221
Сегодня мы познакомимся с датчиком, который измеряет относительную влажность.
Относительная влажность – отношение парциального давления паров воды в газе (в первую очередь, в воздухе) к равновесному давлению насыщенных паров при данной температуре. Поэтому, соответственно, в данном датчике присутствует и датчик температуры.
Данный датчик установлен на плате расширения X-NUCLEO-IKS01A1, предназначенной для работы с отладочной платой Nucleo. Мы будем подключать данную оценочную плату к плате Nucleo STM32F401RE. Выполнен данный датчик также с использованием технологии MEMS.
Этот датчик влажности также наряду с интерфейсом I2C может подключаться и с использованием интерфейса SPI. Но мы будем использовать подключение именно по привычному I2C.
Датчик имеет следующие технические характеристики:
Диапазон показаний относительной влажности 0 – 100 %;
Диапазон показаний температуры -40 – +120 °С
Разрешение – 16 бит;
Чувствительность по давлению 0.004 %rH/LSB или 256 LSB/%rH.
Чувствительность по температуре 0.016 °C/LSB или 64 LSB/°C.
Точность показаний давления ±3.5% rH при 20 – 80% rH и ±5% rH при 0 – 100% rH.
Точность показаний температуры ±0.5 °C при 15 – 40 °C и ±1 °C при 0 – 60 °C
Среднеквадратичное значение уровня шума (RMS noise) – 0,03 по давлению и 0,07 по температуре;
Частота измерений 1 – 12,5 Гц.
С некоторыми остальными показателями, регистрами, значениями и другими тонкостями гироскопа мы познакомимся в ходе его программирования.
Проект мы создадим из проекта прошлого занятия, в котором мы работали с датчиком давления, установленном на этой же плате расширения – из проекта Press_ LPS25HB, только назовём мы данный проект теперь соответственно Humidity_HTS221.
Файлы lps25hb.c и lps25hb.h соответственно переименуем в hts221.c и hts221.h.
Запустим проект Cube MX. Убедимся, что скорость USART установлена в 115200 bps
Больше ничего не трогаем. Сгенерируем проект, откроем его. Настроим программатор на авторезет и отключим оптимизацию. Добавим файл hts221.c. Скомпилируем проект.
По причине переименования файлов у нас будут ошибки. Для устранения данных ошибок мы исправим подключение заголовочных файлов в main.c и в hts221.с
#include «stm32f4xx_hal.h»
#include «hts221.h»
#include «hts221.h»
//———————————————
В обработчике прерываний от таймера закомментируем вызов функции считывания данных и отправки их в USART.
В бесконечном цикле он у нас уже закомментирован
//Press_Read();
HAL_UART_Receive_IT(&huart2,(uint8_t*)str,8);
В файле hts221.h удалим весь код и скопируем туда для экономии драгоценного времени заранее подготовленный код со всеми макросами и переменными из файла macro.txt
#ifndef HTS221_H_
#define HTS221_H_
#include «stm32f4xx_hal.h»
#include <string.h>
//————————————————
#define ABS(x) (x < 0) ? (-x) : x
//————————————————
#define LD2_Pin GPIO_PIN_5
#define LD2_GPIO_Port GPIOA
#define LD2_ON HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET) //GREEN
#define LD2_OFF HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
//————————————————
#define HTS221_ADDRESS 0xBE
//————————————————
#define HTS221_WHO_AM_I_REG 0x0F
#define HTS221_CTRL_REG1 0x20
//————————————————
#define HTS221_WHO_AM_I_VAL 0xBC
//————————————————
#define HTS221_PD_ACTIVE_MODE 0x80
#define HTS221_PD_POWERDOWN_MODE 0x00
#define HTS221_PD_MASK 0x80
//————————————————
#define HTS221_ODR_ONE_SHOT 0x00
#define HTS221_ODR_1HZ 0x01
#define HTS221_ODR_7HZ 0x02
#define HTS221_ODR_12_5HZ 0x03
#define HTS221_ODR_MASK 0x03
//————————————————
#define LPS25HB_DIFF_EN_ENABLE 0x08
#define LPS25HB_DIFF_EN_DISABLE 0x00
#define LPS25HB_DIFF_EN_MASK 0x08
//————————————————
#define HTS221_BDU_DISABLE 0x00
#define HTS221_BDU_ENABLE 0x04
#define HTS221_BDU_MASK 0x04
//————————————————
//————————————————
#define HTS221_HR_OUT_L_REG 0x28
#define HTS221_HR_OUT_H_REG 0x29
#define HTS221_H0_RH_X2 0x30
#define HTS221_H1_RH_X2 0x31
#define HTS221_T0_DEGC_X8 0x32
#define HTS221_T1_DEGC_X8 0x33
#define HTS221_T0_T1_DEGC_H2 0x35
#define HTS221_H0_T0_OUT_L 0x36
#define HTS221_H0_T0_OUT_H 0x37
#define HTS221_H1_T0_OUT_L 0x3A
#define HTS221_H1_T0_OUT_H 0x3B
#define HTS221_T0_OUT_L 0x3C
#define HTS221_T0_OUT_H 0x3D
#define HTS221_T1_OUT_L 0x3E
#define HTS221_T1_OUT_H 0x3F
#define HTS221_TEMP_OUT_L_REG 0x2A
#define HTS221_TEMP_OUT_H_REG 0x2B
//————————————————
void Humidity_Ini(void);
void Humidity_Read(void);
//————————————————
#endif /* HTS221_H_ */
Функцию Press_Ini переименуем в Humidity_Ini в файлах main.c и в hts221.с
//———————————————
void Humidity_Ini(void)
{
Humidity_Ini();
/* USER CODE END 2 */
Также исправим функцию Press_Read в Humidity_Read()в файлах main.c и в hts221.с, в файле main.c она должна быть закомментирована
void Humidity_Read(void)
{
/* USER CODE BEGIN 3 */
//Humidity_Read();
Следующая задача у нас – написать код инициализации датчика. И, как всегда, по сложившейся традиции, раз уж у нас подключение именно по шине I2C, начинаем мы её, конечно же, со считывания идентификатора микросхемы.
Исходя из подключения микросхемы, адрес мы выбираем 0xBE
Регистр для чтения идентификатора используем WHO_AM_I (0Fh)
В данной таблице мы также видим, переведя двоичный код в шестнадцатеричный, что идентификатор должен быть равен именно 0xBC.
Функцию Press_ReadID переименуем в Humidity_ReadID и в реализации, и в вызове
//———————————————
uint8_t Humidity_ReadID(void)
{
HAL_Delay(1000);
if(Humidity_ReadID()==LPS25HB_WHO_AM_I) LD2_ON;
Аналогичным образом поступим и с функциями Press_IO_Read и Press_IO_Write
//———————————————
uint8_t Humidity_IO_Read(uint16_t DeviceAddr, uint8_t RegisterAddr)
{
//———————————————
void Humidity_IO_Write(uint16_t DeviceAddr, uint8_t RegisterAddr, uint8_t Value)
{
Также подправим код в функции чтения идентификатора
//———————————————
uint8_t Press_ReadID(void)
{
uint8_t ctrl = 0x00;
ctrl = Humidity_IO_Read(HTS221_ADDRESS,HTS221_WHO_AM_I_REG);
return ctrl;
}
Исправим код в главной функции инициализации
HAL_Delay(1000);
if(Humidity_ReadID()==HTS221_WHO_AM_I_VAL) LD2_ON;
В функциях, которые мы пока не используем, закомментируем весь код, облачив его вот в такие теги /* */.
Также закомментируем в инициализации вот это
else Error();
//LD2_OFF;
//PressInit(ctrl);
//LD2_ON;
Скомпилируем код, прошьём контроллер и проверим результат нашей работы. Зелёный светодиод должен загореться.
Если всё нормально, то продолжаем инициализацию.
Переименуем функцию PressInit в HumidityInit.
//———————————————
void HumidityInit(uint16_t InitStruct)
{
Также исправим и раскомментируем вызов данной функции в главной функции инициализации датчика
LD2_OFF;
HumidityInit(ctrl);
LD2_ON;
Продолжаем писать инициализацию, постепенно раскомментировывая и подправляя код в функции
uint8_t value = 0;
//пока выключим датчик (PD = 0)
value = Humidity_IO_Read(HTS221_ADDRESS,HTS221_CTRL_REG1);
value&=~HTS221_PD_MASK;
value|=HTS221_PD_POWERDOWN_MODE;
Humidity_IO_Write(HTS221_ADDRESS,HTS221_CTRL_REG1,value);
/*
Здесь мы используем регистр CTRL_REG1 (20h) и сбросим там бит PD с целью пока выключить датчик
Пишем код дальше
//Enable BDU
value = Humidity_IO_Read(HTS221_ADDRESS,HTS221_CTRL_REG1);
value&=~HTS221_BDU_MASK;
value|=HTS221_BDU_ENABLE;
Humidity_IO_Write(HTS221_ADDRESS,HTS221_CTRL_REG1,value);
У нас тот же регистр CTRL_REG1 (20h). Устанавливаем мы в нем теперь бит, отвечающий за включение BDU (Block data update). С данным режимом мы с вами уже хорошо знакомы
Идём дальше
//Включим Data Rate 12.5 Гц
value = Humidity_IO_Read(HTS221_ADDRESS,HTS221_CTRL_REG1);
value&=~HTS221_ODR_MASK;
value|=HTS221_ODR_12_5HZ;
Humidity_IO_Write(HTS221_ADDRESS,HTS221_CTRL_REG1,value);
Здесь мы используем тот же регистр CTRL_REG1 (20h) и устанавливаем там биты, отвечающие за частоту считывания показаний, которую выставим максимальную
И последнее:
//теперь включим датчик (PD = 1)
value = Humidity_IO_Read(HTS221_ADDRESS,HTS221_CTRL_REG1);
value&=~HTS221_PD_MASK;
value|=HTS221_PD_ACTIVE_MODE;
Humidity_IO_Write(HTS221_ADDRESS,HTS221_CTRL_REG1,value);
Здесь мы битом 1 регистра переведём датчик в активный режим, то есть включим его
На этом инициализация закончена.
Соберём код, прошьём контроллер и проверим, не погаснет ли у нас светодиод.
Если всё нормально, то начнём писать код считывания показаний с датчика
Сначала напишем функцию считывания показаний температуры
Функцию Press_Get_Temp переименуем в Humidity_Get_Temp, также добавим некоторые переменные и передвинем комментарий ниже
void Humidity_Get_Temp(float* pData)
{
uint8_t btnstat;
int16_t T0_degC, T1_degC;
int16_t T0_out, T1_out, T_out, T0_degC_x8_u16, T1_degC_x8_u16;
uint8_t buffer[4], tmp;
/*
Также подправим имя функции и в её вызове в функции Humidity_Read
Humidity_Get_Temp(&temper);
Хотя по сравнению с прошлым датчиком инициализация была проще, то же самое отнюдь нельзя сказать о считывании, там будет потяжелее, здесь куча калибровочных ячеек. В формат занятия не входит калибровка, поэтому пользоваться мы будем ими только на чтение.
Считаем в буфер сначала регистры T0_degC_x8 и T1_degC_x8
uint8_t buffer[4], tmp;
buffer[0]=Humidity_IO_Read(HTS221_ADDRESS,HTS221_T0_DEGC_X8);
buffer[1]=Humidity_IO_Read(HTS221_ADDRESS,HTS221_T1_DEGC_X8);
Вот эти регистры
Произведём некоторые расчёты
buffer[1]=Humidity_IO_Read(HTS221_ADDRESS,HTS221_T1_DEGC_X8);
tmp = Humidity_IO_Read(HTS221_ADDRESS,HTS221_T0_T1_DEGC_H2);
В следующей части нашего урока мы проверим работу нашего кода и датчика сначала в терминальной программе в текстовом виде, а затем в программе визуализации.
Предыдущий урок Программирование МК STM32 Следующая часть
Техническая документация на датчик:
HTS221 Interpreting humidity and temperature readings
Программа NS Port Monitor для значений с плавающей точкой
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Оценочную плату можно приобрести здесь STM32 X-NUCLEO-IKS01A1
Смотреть ВИДЕОУРОК
подскажите , как подключить два HTS221 по i2c, что бы последовательно считывать данные?
Использовать специальную ножку для изменения адреса.
Подскажите как считывать данные с двух HTS221 по i2c ?
Там есть специальная ножка изменения адреса, вот её и используйте.
Это не гироскоп, а гигроскоп