[STM32U5] 【NUCLEO-U5A5ZJ-Q测评】温湿度信息检测仪表盘

[复制链接]
 楼主| HonestQiao 发表于 2023-12-12 14:07 | 显示全部楼层 |阅读模式
<
#申请原创#
在之前的文章中,分享了 【NUCLEO-U5A5ZJ-Q测评】驱动DFRobot高清彩屏使用lvgl显示动态仪表盘,这篇文章在此基础上,获取SHT3x温湿度传感器的信息,然后使用仪表盘显示温湿度信息。
一、硬件连接

1. 1.47 英寸 172×320 IPS LCD 高清显示屏,参考上述 【NUCLEO-U5A5ZJ-Q测评】驱动DFRobot高清彩屏使用lvgl显示动态仪表盘 连接即可:




2. SHT3x温湿度传感器
我使用的SHT3x是维特智能SHT30传感器模块:
iShot_2023-12-12_13.34.32.png
这个温湿度传感器,支持串口通讯,也支持IIC接口通讯。
在之前分享的 【NUCLEO-U5A5ZJ-Q测评】无需移植使用lvgl驱动SSD1306 OLED显示中英文和绘图中,使用过IIC接口,那么这里,也急需使用IIC接口,来存SHT30读取数据。

参考之前的连接方式:



将SHT30的IIC接口和NUCLEO-U5A5ZJ-Q开发板上Arduino兼容接口的IIC接口连接即可。
供电部分,注意使用的SHT30需要的供电电压。我使用的这个是3.3v、5V通用的。

二、驱动处理
1. 显示驱动
显示部分,在 【NUCLEO-U5A5ZJ-Q测评】驱动DFRobot高清彩屏使用lvgl显示动态仪表盘 已经详细说明过。

2. SHT30驱动
因为使用的是Arduino兼容接口,Zephyr本身已经有SHT30的驱动,我们只需要做一个NUCLEO-U5A5ZJ-Q开发板对应的 overlay 定义即可。
具体文件:samples/sensor/sht3xd/boards/nucleo_u5a5zj_q.overlay
  1. #include <zephyr/dt-bindings/led/led.h>

  2. &arduino_i2c {
  3.         sht3xd: sht3xd@44 {
  4.                 compatible = "sensirion,sht3xd";
  5.                 reg = <0x44>;
  6.                 alert-gpios = <&gpioa 9 GPIO_ACTIVE_HIGH>;
  7.         };
  8. };

  9. / {
  10.         aliases {
  11.                 sht3xd = &sht3xd;
  12.         };
  13. };
这个定义的含义,是指 定义了一个 sht3xd 设备,使用预定义的 arduino_i2c 接口,设备IIC地址为 0x44

三、基础测试
上述overlay处理好以后,就可以直接使用 samples/sensor/sht3xd 实例了。
代码中,读取温湿度信息的核心代码如下:
  1.   rc = sensor_sample_fetch(sht3x_dev);
  2.                 if (rc == 0) {
  3.                         rc = sensor_channel_get(sht3x_dev, SENSOR_CHAN_AMBIENT_TEMP,
  4.                                                 &temp);
  5.                 }
  6.                 if (rc == 0) {
  7.                         rc = sensor_channel_get(sht3x_dev, SENSOR_CHAN_HUMIDITY,
  8.                                                 &hum);
  9.                 }
  10.                 if (rc != 0) {
  11.                         printf("SHT3XD: failed: %d\n", rc);
  12.                         continue;
  13.                 }

  14.                 printf("SHT3XD: %.2f Cel ; %0.2f %%RH\n",
  15.                        sensor_value_to_double(&temp),
  16.                        sensor_value_to_double(&hum));
其逻辑较为简单,具体如下:
  • 使用 sensor_sample_fetch 通知sht30进行数据采样
  • 使用 sensor_channel_get 获取温度信息
  • 使用 sensor_channel_get 获取湿度信息
  • 打印出来



现在,编译上述实例进行测试,编译命令如下:
  1. west build -b nucleo_u5a5zj_q samples/sensor/sht3xd
编译通过后,下载到 NUCLEO-U5A5ZJ-Q开发板 开发板,然后使用串口工具连接到开发板挂接的串口,就能看到温湿度信息的输出了:

iShot_2023-12-12_11.40.35.png

四、在屏幕上显示两个仪表盘
因为需要同时显示温度和湿度信息,我们需要在屏幕上,显示两个仪表盘,在  【NUCLEO-U5A5ZJ-Q测评】驱动DFRobot高清彩屏使用lvgl显示动态仪表盘 的基础上,我们只需要做如下的处理即可:
1. 生成中文字体文件:
  1. lv_font_conv --no-compress --format lvgl --font $ttf_path -o opposans_m_16_sht3x.c --bpp 4 --size 16 -r 0x20-0x7F --symbols "温度湿度"


2. 预定义:
  1. LV_FONT_DECLARE(opposans_m_16_sht3x);

  2. static lv_obj_t * meter;
  3. static lv_obj_t * meter2;
  4. static lv_meter_indicator_t * indic;
  5. static lv_meter_indicator_t * indic2;
  6. static lv_style_t label_style_cn;

上述代码定义了使用的字体文件,以及两个仪表盘,以及仪表盘对应的指示器。

3. 温度仪表盘
  1. void lv_example_sht3x_temp(void)
  2. {
  3.     meter = lv_meter_create(lv_scr_act());
  4.         lv_obj_align(meter, LV_ALIGN_CENTER, 0, -80);
  5.     lv_obj_set_size(meter, 150, 150);

  6.     /*Add a scale first*/
  7.     lv_meter_scale_t * scale = lv_meter_add_scale(meter);
  8.     lv_meter_set_scale_ticks(meter, scale, 41, 2, 10, lv_palette_main(LV_PALETTE_GREY));
  9.     lv_meter_set_scale_major_ticks(meter, scale, 8, 4, 15, lv_color_black(), 10);

  10.     // lv_meter_indicator_t * indic;
  11.         lv_meter_set_scale_range(meter, scale, -40, 60, 270, 90);

  12.     /*零下*/
  13.     indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_BLUE), 0);
  14.     lv_meter_set_indicator_start_value(meter, indic, -40);
  15.     lv_meter_set_indicator_end_value(meter, indic, -10);

  16.     /*Make the tick lines blue at the start of the scale*/
  17.     indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_BLUE),
  18.                                      false, 0);
  19.     lv_meter_set_indicator_start_value(meter, indic, -40);
  20.     lv_meter_set_indicator_end_value(meter, indic, -10);

  21.     // /*零上*/
  22.     // indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_YELLOW), 0);
  23.     // lv_meter_set_indicator_start_value(meter, indic, 0);
  24.     // lv_meter_set_indicator_end_value(meter, indic, 18);

  25.     // /*Make the tick lines blue at the start of the scale*/
  26.     // indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_YELLOW), lv_palette_main(LV_PALETTE_YELLOW),
  27.     //                                  false, 0);
  28.     // lv_meter_set_indicator_start_value(meter, indic, 0);
  29.     // lv_meter_set_indicator_end_value(meter, indic, 18);

  30.     /*舒适*/
  31.     indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_GREEN), 0);
  32.     lv_meter_set_indicator_start_value(meter, indic, 17);
  33.     lv_meter_set_indicator_end_value(meter, indic, 27);

  34.     /*Make the tick lines blue at the start of the scale*/
  35.     indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_GREEN), lv_palette_main(LV_PALETTE_GREEN),
  36.                                      false, 0);
  37.     lv_meter_set_indicator_start_value(meter, indic, 17);
  38.     lv_meter_set_indicator_end_value(meter, indic, 27);

  39.     /*高温*/
  40.     indic = lv_meter_add_arc(meter, scale, 3, lv_palette_main(LV_PALETTE_RED), 0);
  41.     lv_meter_set_indicator_start_value(meter, indic, 35);
  42.     lv_meter_set_indicator_end_value(meter, indic, 60);

  43.     /*Make the tick lines red at the end of the scale*/
  44.     indic = lv_meter_add_scale_lines(meter, scale, lv_palette_main(LV_PALETTE_RED), lv_palette_main(LV_PALETTE_RED), false,
  45.                                      0);
  46.     lv_meter_set_indicator_start_value(meter, indic, 35);
  47.     lv_meter_set_indicator_end_value(meter, indic, 60);

  48.     /*Add a needle line indicator*/
  49.     indic = lv_meter_add_needle_line(meter, scale, 4, lv_palette_main(LV_PALETTE_GREY), -10);

  50.         lv_obj_t *temp_label;
  51.         temp_label = lv_label_create(lv_scr_act());
  52.         lv_label_set_text(temp_label, "温度");
  53.         lv_obj_align(temp_label, LV_ALIGN_CENTER, 40, -50);
  54.         lv_obj_add_style(temp_label, &label_style_cn, LV_PART_MAIN);                // 应用效果风格
  55. }


在温度仪表盘中:
  • 定义了从零下40度到零上60度的范围
  • 零下40度到零下10度,为蓝色超冷区域
  • 零上17度到27度,为绿色合适温度区域
  • 零上35度到60度,为红色超热温度区域
  • 合适的区域显示“温度”标签


4. 湿度仪表盘
  1. void lv_example_sht3x_humi(void)
  2. {
  3.     meter2 = lv_meter_create(lv_scr_act());
  4.         lv_obj_align(meter2, LV_ALIGN_CENTER, 0, 80);
  5.     lv_obj_set_size(meter2, 150, 150);

  6.     /*Add a scale first*/
  7.     lv_meter_scale_t * scale = lv_meter_add_scale(meter2);
  8.     lv_meter_set_scale_ticks(meter2, scale, 41, 2, 10, lv_palette_main(LV_PALETTE_GREY));
  9.     lv_meter_set_scale_major_ticks(meter2, scale, 8, 4, 15, lv_color_black(), 10);

  10.     // lv_meter_indicator_t * indic2;
  11.         lv_meter_set_scale_range(meter2, scale, 0, 100, 270, 90);

  12.     /*较低*/
  13.     indic2 = lv_meter_add_arc(meter2, scale, 3, lv_palette_main(LV_PALETTE_BLUE), 0);
  14.     lv_meter_set_indicator_start_value(meter2, indic2, 0);
  15.     lv_meter_set_indicator_end_value(meter2, indic2, 20);

  16.     /*Make the tick lines blue at the start of the scale*/
  17.     indic2 = lv_meter_add_scale_lines(meter2, scale, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_BLUE),
  18.                                      false, 0);
  19.     lv_meter_set_indicator_start_value(meter2, indic2, 0);
  20.     lv_meter_set_indicator_end_value(meter2, indic2, 20);

  21.     /*合适*/
  22.     indic2 = lv_meter_add_arc(meter2, scale, 3, lv_palette_main(LV_PALETTE_GREEN), 0);
  23.     lv_meter_set_indicator_start_value(meter2, indic2, 40);
  24.     lv_meter_set_indicator_end_value(meter2, indic2, 60);

  25.     /*Make the tick lines blue at the start of the scale*/
  26.     indic2 = lv_meter_add_scale_lines(meter2, scale, lv_palette_main(LV_PALETTE_GREEN), lv_palette_main(LV_PALETTE_GREEN),
  27.                                      false, 0);
  28.     lv_meter_set_indicator_start_value(meter2, indic2, 40);
  29.     lv_meter_set_indicator_end_value(meter2, indic2, 60);

  30.     /*高温较高*/
  31.     indic2 = lv_meter_add_arc(meter2, scale, 3, lv_palette_main(LV_PALETTE_RED), 0);
  32.     lv_meter_set_indicator_start_value(meter2, indic2, 80);
  33.     lv_meter_set_indicator_end_value(meter2, indic2, 100);

  34.     /*Make the tick lines red at the end of the scale*/
  35.     indic2 = lv_meter_add_scale_lines(meter2, scale, lv_palette_main(LV_PALETTE_RED), lv_palette_main(LV_PALETTE_RED), false,
  36.                                      0);
  37.     lv_meter_set_indicator_start_value(meter2, indic2, 80);
  38.     lv_meter_set_indicator_end_value(meter2, indic2, 100);

  39.     /*Add a needle line indicator*/
  40.     indic2 = lv_meter_add_needle_line(meter2, scale, 4, lv_palette_main(LV_PALETTE_GREY), -10);

  41.         lv_obj_t *humi_label;
  42.         humi_label = lv_label_create(lv_scr_act());
  43.         lv_label_set_text(humi_label, "湿度");
  44.         lv_obj_align(humi_label, LV_ALIGN_CENTER, 40, 110);
  45.         lv_obj_add_style(humi_label, &label_style_cn, LV_PART_MAIN);                // 应用效果风格
  46. }



在湿度仪表盘中:
  • 定义了从0到100的范围
  • 0到20,为蓝色干燥区域
  • 40到60,为绿色合适湿度区域
  • 80~100,为红色超湿温度区域
  • 合适的区域显示“湿度”标签



然后,在主代码中,使用下面的代码,来绘制上述两个仪表盘:
  1. lv_obj_clean(lv_scr_act());
  2.         lv_example_sht3x_temp();
  3.         lv_example_sht3x_humi();

  4.         while(1) {
  5.                 lv_task_handler();

  6.                 k_sleep(K_MSEC(5000));
  7.         }


最终的实际效果如下:
44901702359121_.pic.jpg


五、结合温湿度传感器的数据,更新到仪表盘
上面已经显示了两个仪表盘,下一步,把温湿度信息给整合进来即可。
1. prj.conf处理
首先,需要在prj.conf中添加sht3x的配置:
  1. # sht3x
  2. CONFIG_I2C=y
  3. CONFIG_SENSOR=y
  4. CONFIG_CBPRINTF_FP_SUPPORT=y


2. main.c代码处理
头文件调用部分添加:
  1. #include <zephyr/drivers/sensor.h>


main()部分设备初始化检查:
  1. const struct device *const sht3x_dev = DEVICE_DT_GET_ONE(sensirion_sht3xd);
  2.         int rc;

  3.         if (!device_is_ready(sht3x_dev)) {
  4.                 printf("Device %s is not ready\n", sht3x_dev->name);
  5.                 return 0;
  6.         }


while循环部分读取温湿度信息,并更新到仪表盘:
  1. struct sensor_value temp, hum;
  2.         while(1) {
  3.                 rc = sensor_sample_fetch(sht3x_dev);
  4.                 if (rc == 0) {
  5.                         rc = sensor_channel_get(sht3x_dev, SENSOR_CHAN_AMBIENT_TEMP,
  6.                                                 &temp);
  7.                 }
  8.                 if (rc == 0) {
  9.                         rc = sensor_channel_get(sht3x_dev, SENSOR_CHAN_HUMIDITY,
  10.                                                 &hum);
  11.                 }
  12.                 if (rc != 0) {
  13.                         printf("SHT3XD: failed: %d\n", rc);
  14.                         continue;
  15.                 }

  16.                 printf("SHT3XD: %.2f Cel ; %0.2f %%RH\n",
  17.                        sensor_value_to_double(&temp),
  18.                        sensor_value_to_double(&hum));

  19.                 lv_meter_set_indicator_value(meter, indic, sensor_value_to_double(&temp));
  20.                 lv_meter_set_indicator_value(meter2, indic2, sensor_value_to_double(&hum));
  21.                 lv_task_handler();

  22.                 k_sleep(K_MSEC(5000));
  23.         }


在上述代码中,参考sht3xd实例读取出来温湿度数据,然后使用 lv_meter_set_indicator_value 更新仪表盘的value即可。

在室内环境的情况下,具体呈现结果:
44911702359123_.pic.jpg

对着SHT30哈气后,湿度上升:
44921702359126_.pic.jpg

六、总结
感觉在NUCLEO-U5A5ZJ-Q开发板上进行相关的开发,真是的太方便了。
得益于良好的结构设计,以及Zephyr的支持,上诉温湿度信息仪表盘显示的效果非常的好。
后面会继续尝试,连接更多的传感器,制作更丰富的呈现界面。
AloneKaven 发表于 2024-1-12 16:38 | 显示全部楼层
这个模块也带湿度检测吗
 楼主| HonestQiao 发表于 2024-2-1 15:19 | 显示全部楼层
AloneKaven 发表于 2024-1-12 16:38
这个模块也带湿度检测吗

不带啊,自备的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

110

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部

42

主题

110

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部