[嵌入式开发模块]SHT30/20 温湿度传感器 驱动模块

以你之姓@ 2023-02-16 01:54 292阅读 0赞

文章目录

  • 前言
  • SHT30简介
    • 概述
    • 通信协议
  • 驱动文件
    • SHT30Driver.h
    • SHT30Recver.c
    • SHT30Cmder.c
    • 依赖
  • 使用示例
  • 更新历史

前言

干活中用到了SHT30,其实是对应的转串口板子,写了相应的驱动程序,放出来。

好像SHT20和30几乎是一样的,所以不用纠结这个。

这个模块本身的协议比较简单,所以模块的驱动也很小巧。

驱动被设计为拥有指令器和接收机两个部分,完全被动方式运行,与具体的平台解耦。

SHT30简介

概述

SHT20是由瑞士推出的数字温湿度传感器,基于领先世界的CMOSens数字传感技术,具有极高的可靠性和卓越的长期稳定性。全量程标定,两线数字接口,可与单片机直接相连,大大缩短研发时间、简化外围电路并降低费用。此外,体积微小、响应迅速、低能耗、可浸没、抗干扰能力强、温湿一体,兼有露点测量,性价比高,使该产品能够适于多种场合的应用。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70

通信协议

(1) 串口通信参数

电平:TTL
波特率:115200
停止位:1
校验位:0

(2)输出格式

输出字符串格式: Temp = XX.XXX Hum = XX.XXX\r\n

(3)控制指令:下面指令需要发送两次,第一次使模块由工作模式进入到配置模式,第二次发送才是设置模块。
设置回传速度:
20200607223017817.png
设置报警值(这个驱动没有实现):

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9zdHJvbmc_size_16_color_FFFFFF_t_70 1

驱动文件

SHT30Driver.h

  1. /*
  2. *******************************************************************************************
  3. *
  4. * SHT30 DRIVER MODULE
  5. * SHT30驱动模块
  6. *
  7. * File : SHT30Driver.h
  8. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  9. * Date : 2020/06/17
  10. * version: V1.1
  11. * History: 2020/04/29 V1.0 the prototype
  12. * 2020/06/17 V1.1 find that SHT30's data is "XXXX Hum = XXXX"
  13. * but not "XXXX Humi = XXXX" in SHT20, so fix it.
  14. * Note : The SHT30 driver is divided into two part, i.e. cmder and recver. The cmder is for
  15. * sending the SHT30 command. The recver is for resolving data from the SHT30.
  16. ********************************************************************************************
  17. */
  18. #ifndef SHT30DRIVER_H
  19. #define SHT30DRIVER_H
  20. /*
  21. ******************************************************************************************
  22. * INCLUDE
  23. ******************************************************************************************
  24. */
  25. #include <stdint.h>
  26. /*
  27. ******************************************************************************************
  28. * DEBUG CONFIGURATION
  29. ******************************************************************************************
  30. */
  31. // to enable debug messages in this module
  32. // #define SHT30_DEBUG
  33. /*
  34. ******************************************************************************************
  35. * TYPE DEFINE
  36. ******************************************************************************************
  37. */
  38. typedef struct SHT30STRUCT_DATA{
  39. float temp; // °C
  40. float humi; // percent
  41. } SHT30Data;
  42. typedef void (* SHT30FUNC_DATA)(SHT30Data data);
  43. typedef enum {
  44. SHT30SR_10Hz ,
  45. SHT30SR_5Hz ,
  46. SHT30SR_2Hz ,
  47. SHT30SR_1Hz ,
  48. SHT30SR_0d5Hz, // 0.5Hz
  49. SHT30SR_0d2Hz, // 0.2Hz
  50. SHT30SR_0d1Hz, // 0.1Hz
  51. }SHT30SampleRate;
  52. /*
  53. ************************************************************************************
  54. * INTERFACES
  55. ************************************************************************************
  56. */
  57. void SHT30Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len));
  58. void SHT30Cmder_Destroy(void);
  59. void SHT30Cmder_setSampleRate(SHT30SampleRate value);
  60. void SHT30Recver_Init(SHT30FUNC_DATA onRecvData);
  61. // Call it to modify the call-back function.
  62. void SHT30Recver_RegisterCallback(SHT30FUNC_DATA onRecvData);
  63. void SHT30Recver_CleanupBuffer(void);
  64. // Feed the receiver every byte received so that receiver can notify user
  65. // the resolved data for each frame.
  66. void SHT30Recver_Feed(uint8_t nextByte);
  67. void SHT30Recver_Destroy(void);
  68. #endif // of SHT30DRIVER_H

SHT30Recver.c

  1. /*
  2. *******************************************************************************************
  3. *
  4. * SHT30 RECEIVER MODULE
  5. * SHT30驱动模块 - 接收机
  6. *
  7. * File : SHT30Recver.c
  8. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  9. * Date : 2020/06/17
  10. * version: V1.1
  11. * History: 2020/06/17
  12. * Note :
  13. ********************************************************************************************
  14. */
  15. /*
  16. *********************************************************************************************
  17. * INCLUDES
  18. *********************************************************************************************
  19. */
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include "SHT30Driver.h"
  23. #include "RxMac.h"
  24. #ifndef SHT30_DEBUG
  25. #undef _DEBUG
  26. #endif
  27. #include "DebugMsg.h"
  28. /*
  29. *********************************************************************************************
  30. * LOCAL FUNCTION
  31. *********************************************************************************************
  32. */
  33. #define ARRAYSIZE(arr) (sizeof(arr)/ sizeof(arr[0]))
  34. static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
  35. RxFlag HorU,RxFlag Ender);
  36. /*
  37. *********************************************************************************************
  38. * LOCAL VARIABLE
  39. *********************************************************************************************
  40. */
  41. static const char * _str_SHT30Recver = "SHT30Recver";
  42. static SHT30FUNC_DATA _onRecvData;
  43. static const uint8_t _flag_header[] = {
  44. (uint8_t)'T', (uint8_t)'e', (uint8_t)'m', (uint8_t)'p',
  45. (uint8_t)' ', (uint8_t)'=', (uint8_t)' '};
  46. static const uint8_t _flag_ender[] = {
  47. (uint8_t)'\r', (uint8_t)'\n'};
  48. static const RXFLAG_STRUCT _flags[] = {
  49. {
  50. _flag_header, sizeof(_flag_header), RXFLAG_OPTION_STRONG_HEADER},
  51. {
  52. _flag_ender , sizeof(_flag_ender) , RXFLAG_OPTION_STRONG_ENDER }
  53. };
  54. static RxMac _mac;
  55. static uint8_t _macBuf[36];
  56. /*
  57. *********************************************************************************************
  58. * INTERFACE IMPLEMENTATION
  59. *********************************************************************************************
  60. */
  61. void SHT30Recver_Init(SHT30FUNC_DATA onRecvData){
  62. _onRecvData = onRecvData;
  63. _mac = RxMac_Create(_flags, ARRAYSIZE(_flags), _macBuf, sizeof(_macBuf) - 1,
  64. NULL, NULL, _onFlushed);
  65. if(_mac == NULL)
  66. for(;;)
  67. ;
  68. }
  69. void SHT30Recver_Destroy(){
  70. _onRecvData = NULL;
  71. RxMac_Destroy(_mac);
  72. }
  73. void SHT30Recver_RegisterCallback(SHT30FUNC_DATA onRecvData){
  74. _onRecvData = onRecvData;
  75. }
  76. void SHT30Recver_CleanupBuffer(void){
  77. RxMac_ResetState(_mac);
  78. }
  79. void SHT30Recver_Feed(uint8_t nextByte){
  80. RxMac_FeedData(_mac, nextByte);
  81. }
  82. /*
  83. *********************************************************************************************
  84. * LOCAL FUNCTION IMPLEMENTATION
  85. *********************************************************************************************
  86. */
  87. static int _FloatFormatRight(const char *beg, const char *end){
  88. const char *p;
  89. if(end - beg <= 0)
  90. return 0;
  91. for(p = beg; end - p > 0; p++)
  92. if(!isdigit(*p) && *p != '-' && *p != '.')
  93. return 0;
  94. return 1;
  95. }
  96. static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
  97. RxFlag HorU,RxFlag Ender){
  98. const char *p;
  99. SHT30Data data;
  100. if(_onRecvData == NULL || !state.headerFound || !state.enderFound)
  101. return;
  102. buf[len] = '\0';
  103. p = strstr((const char *)buf, " Hum = ");
  104. if(p == NULL || !_FloatFormatRight((const char *)&buf[7], p) ||
  105. !_FloatFormatRight((const char *)&p[9], (const char *)buf + len - 2)){
  106. _dbg_printf2("%s: got corrupt frame-%s", _str_SHT30Recver, (const char *)buf);
  107. return;
  108. }
  109. data.temp = (float)atof((const char *)&buf[7]);
  110. data.humi = (float)atof((const char *)&p[9]);
  111. _dbg_printf3("%s: got data-temp(%.3f),humi(%.3f)\r\n", _str_SHT30Recver, data.temp, data.humi);
  112. _onRecvData(data);
  113. }

SHT30Cmder.c

  1. /*
  2. *******************************************************************************************
  3. *
  4. * SHT30 COMMANDER MODULE
  5. * SHT30驱动模块 - 指令器
  6. *
  7. * File : SHT30Cmder.c
  8. * By : Lin Shijun(https://blog.csdn.net/lin_strong)
  9. * Date : 2020/06/17
  10. * version: V1.1
  11. * History: 2020/06/17
  12. * Note : Only implement the set sample rate command for now.
  13. ********************************************************************************************
  14. */
  15. /*
  16. *********************************************************************************************
  17. * INCLUDES
  18. *********************************************************************************************
  19. */
  20. #include <stdio.h>
  21. #include "SHT30Driver.h"
  22. /*
  23. *********************************************************************************************
  24. * LOCAL VARIABLE
  25. *********************************************************************************************
  26. */
  27. static void (* _out)(uint8_t *buf, uint16_t len) = NULL;
  28. /*
  29. *********************************************************************************************
  30. * INTERFACE IMPLEMENTATION
  31. *********************************************************************************************
  32. */
  33. void SHT30Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len)){
  34. _out = outChannel;
  35. }
  36. void SHT30Cmder_Destroy(){
  37. _out = NULL;
  38. }
  39. void SHT30Cmder_setSampleRate(SHT30SampleRate value){
  40. uint8_t buf[] = {
  41. 0xFF, 0xAA, 0x09, 0x00, 0x00};
  42. buf[3] = (uint8_t)value;
  43. if(_out != NULL)
  44. _out(buf, sizeof(buf));
  45. }

依赖

接收器的实现依赖于我写的通用接收机:
通用接收状态机模块

至于DebugMsg.h则是我自己使用的调试信息的模块:

  1. #ifndef _DEBUG_MSG_H
  2. #define _DEBUG_MSG_H
  3. #include <stdio.h>
  4. #ifdef _DEBUG
  5. #define _dbg_printf0(format) ((void)printf(format))
  6. #define _dbg_printf1(format,p1) ((void)printf(format,p1))
  7. #define _dbg_printf2(format,p1,p2) ((void)printf(format,p1,p2))
  8. #define _dbg_printf3(format,p1,p2,p3) ((void)printf(format,p1,p2,p3))
  9. #define _dbg_printf4(format,p1,p2,p3,p4) ((void)printf(format,p1,p2,p3,p4))
  10. #define _dbg_printf5(format,p1,p2,p3,p4,p5) ((void)printf(format,p1,p2,p3,p4,p5))
  11. #define _dbg_printf6(format,p1,p2,p3,p4,p5,p6) ((void)printf(format,p1,p2,p3,p4,p5,p6))
  12. #define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7) \
  13. ((void)printf(format,p1,p2,p3,p4,p5,p6,p7))
  14. #define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8) \
  15. ((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8))
  16. #define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9) \
  17. ((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8,p9))
  18. #else
  19. #define _dbg_printf0(format)
  20. #define _dbg_printf1(format,p1)
  21. #define _dbg_printf2(format,p1,p2)
  22. #define _dbg_printf3(format,p1,p2,p3)
  23. #define _dbg_printf4(format,p1,p2,p3,p4)
  24. #define _dbg_printf5(format,p1,p2,p3,p4,p5)
  25. #define _dbg_printf6(format,p1,p2,p3,p4,p5,p6)
  26. #define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7)
  27. #define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8)
  28. #define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9)
  29. #endif
  30. int dummyprintf(const char *format, ...);
  31. #endif

这样在项目中同时宏定义 _DEBUGSHT30_DEBUG 时才会打印调试信息。不需要的话删除相关语句就好。

想要了解相关技巧的话详见:
C语言宏配置的各种奇淫技巧

使用示例

使用此模块基本分几步:

  1. 初始化模块
  2. 如需要发送指令则实现并注册信道给指令器;注册回调函数给接收器,这样接收器在发现完整的数据帧时就会通过回调函数进行通知。
  3. 不断接收数据,并喂(Feed)给接收器;如需要发指令,随时调用指令器的接口。

以下代码示例了在上电后不断读取数据并进行解析(假设使用标准输入输出上的串口和SHT30通信):

  1. #include "SHT30Driver.h"
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. ……
  5. // 收到数据的回调函数
  6. static void onDataResolved(SHT30Data data);
  7. // 发送信道
  8. static void sendChannel(uint8_t *buf, uint16_t len);
  9. void main(){
  10. uint8_t b;
  11. ……
  12. SHT30Recver_Init(onDataResolved);
  13. SHT30Cmder_Init(sendChannel);
  14. // 如果需要调整采样率的话发送对应指令,注意要先发一次指令使进入配置模式的问题
  15. // SHT30Cmder_setSampleRate(SHT30SR_1Hz);
  16. for(;;){
  17. // 不断得到下一个字节并喂给接收机
  18. // 接收机会通过回调函数实时传递解析出来的值
  19. b = (uint8_t)getchar();
  20. SHT30Recver_Feed(b);
  21. }
  22. }
  23. static void onDataResolved(SHT30Data data){
  24. // data中就是实时解析到的数据,具体怎么使用是你的事
  25. }
  26. static void sendChannel(uint8_t *buf, uint16_t len){
  27. // 往标准输出输出这个字节
  28. while(len-- > 0)
  29. putchar((char)*buf++);
  30. }

更新历史

2020/06/07 放出V1.0
2020/06/17 发现了SHT30和SHT20在数据输出格式上一个是Humi,一个是Hum,所以修正为了SHT30的Hum。如果是SHT20。则将Recver中的onFlush函数按如下修改即可。

  1. static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
  2. RxFlag HorU,RxFlag Ender){
  3. const char *p;
  4. SHT30Data data;
  5. if(_onRecvData == NULL || !state.headerFound || !state.enderFound)
  6. return;
  7. buf[len] = '\0';
  8. p = strstr((const char *)buf, " Humi = ");
  9. if(p == NULL || !_FloatFormatRight((const char *)&buf[7], p) ||
  10. !_FloatFormatRight((const char *)&p[10], (const char *)buf + len - 2)){
  11. _dbg_printf2("%s: got corrupt frame-%s", _str_SHT30Recver, (const char *)buf);
  12. return;
  13. }
  14. data.temp = (float)atof((const char *)&buf[7]);
  15. data.humi = (float)atof((const char *)&p[10]);
  16. _dbg_printf3("%s: got data-temp(%.3f),humi(%.3f)\r\n", _str_SHT30Recver, data.temp, data.humi);
  17. _onRecvData(data);
  18. }

发表评论

表情:
评论列表 (有 0 条评论,292人围观)

还没有评论,来说两句吧...

相关阅读