文章目錄
- 前言
- SHT30簡介
-
- 概述
- 通信協定
- 驅動檔案
-
- SHT30Driver.h
- SHT30Recver.c
- SHT30Cmder.c
- 依賴
- 使用示例
- 更新曆史
前言
幹活中用到了SHT30,其實是對應的轉序列槽闆子,寫了相應的驅動程式,放出來。
好像SHT20和30幾乎是一樣的,是以不用糾結這個。
這個子產品本身的協定比較簡單,是以子產品的驅動也很小巧。
驅動被設計為擁有指令器和接收機兩個部分,完全被動方式運作,與具體的平台解耦。
SHT30簡介
概述
SHT20是由瑞士推出的數字溫濕度傳感器,基于領先世界的CMOSens數字傳感技術,具有極高的可靠性和卓越的長期穩定性。全量程标定,兩線數字接口,可與單片機直接相連,大大縮短研發時間、簡化外圍電路并降低費用。此外,體積微小、響應迅速、低能耗、可浸沒、抗幹擾能力強、溫濕一體,兼有露點測量,成本效益高,使該産品能夠适于多種場合的應用。

通信協定
(1) 序列槽通信參數
電平:TTL
波特率:115200
停止位:1
校驗位:0
(2)輸出格式
輸出字元串格式: Temp = XX.XXX Hum = XX.XXX\r\n
(3)控制指令:下面指令需要發送兩次,第一次使子產品由工作模式進入到配置模式,第二次發送才是設定子產品。
設定回傳速度:
設定報警值(這個驅動沒有實作):
驅動檔案
SHT30Driver.h
/*
*******************************************************************************************
*
* SHT30 DRIVER MODULE
* SHT30驅動子產品
*
* File : SHT30Driver.h
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/06/17
* version: V1.1
* History: 2020/04/29 V1.0 the prototype
* 2020/06/17 V1.1 find that SHT30's data is "XXXX Hum = XXXX"
* but not "XXXX Humi = XXXX" in SHT20, so fix it.
* Note : The SHT30 driver is divided into two part, i.e. cmder and recver. The cmder is for
* sending the SHT30 command. The recver is for resolving data from the SHT30.
********************************************************************************************
*/
#ifndef SHT30DRIVER_H
#define SHT30DRIVER_H
/*
******************************************************************************************
* INCLUDE
******************************************************************************************
*/
#include <stdint.h>
/*
******************************************************************************************
* DEBUG CONFIGURATION
******************************************************************************************
*/
// to enable debug messages in this module
// #define SHT30_DEBUG
/*
******************************************************************************************
* TYPE DEFINE
******************************************************************************************
*/
typedef struct SHT30STRUCT_DATA{
float temp; // °C
float humi; // percent
} SHT30Data;
typedef void (* SHT30FUNC_DATA)(SHT30Data data);
typedef enum {
SHT30SR_10Hz ,
SHT30SR_5Hz ,
SHT30SR_2Hz ,
SHT30SR_1Hz ,
SHT30SR_0d5Hz, // 0.5Hz
SHT30SR_0d2Hz, // 0.2Hz
SHT30SR_0d1Hz, // 0.1Hz
}SHT30SampleRate;
/*
************************************************************************************
* INTERFACES
************************************************************************************
*/
void SHT30Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len));
void SHT30Cmder_Destroy(void);
void SHT30Cmder_setSampleRate(SHT30SampleRate value);
void SHT30Recver_Init(SHT30FUNC_DATA onRecvData);
// Call it to modify the call-back function.
void SHT30Recver_RegisterCallback(SHT30FUNC_DATA onRecvData);
void SHT30Recver_CleanupBuffer(void);
// Feed the receiver every byte received so that receiver can notify user
// the resolved data for each frame.
void SHT30Recver_Feed(uint8_t nextByte);
void SHT30Recver_Destroy(void);
#endif // of SHT30DRIVER_H
SHT30Recver.c
/*
*******************************************************************************************
*
* SHT30 RECEIVER MODULE
* SHT30驅動子產品 - 接收機
*
* File : SHT30Recver.c
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/06/17
* version: V1.1
* History: 2020/06/17
* Note :
********************************************************************************************
*/
/*
*********************************************************************************************
* INCLUDES
*********************************************************************************************
*/
#include <string.h>
#include <ctype.h>
#include "SHT30Driver.h"
#include "RxMac.h"
#ifndef SHT30_DEBUG
#undef _DEBUG
#endif
#include "DebugMsg.h"
/*
*********************************************************************************************
* LOCAL FUNCTION
*********************************************************************************************
*/
#define ARRAYSIZE(arr) (sizeof(arr)/ sizeof(arr[0]))
static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender);
/*
*********************************************************************************************
* LOCAL VARIABLE
*********************************************************************************************
*/
static const char * _str_SHT30Recver = "SHT30Recver";
static SHT30FUNC_DATA _onRecvData;
static const uint8_t _flag_header[] = {(uint8_t)'T', (uint8_t)'e', (uint8_t)'m', (uint8_t)'p',
(uint8_t)' ', (uint8_t)'=', (uint8_t)' '};
static const uint8_t _flag_ender[] = {(uint8_t)'\r', (uint8_t)'\n'};
static const RXFLAG_STRUCT _flags[] = {
{_flag_header, sizeof(_flag_header), RXFLAG_OPTION_STRONG_HEADER},
{_flag_ender , sizeof(_flag_ender) , RXFLAG_OPTION_STRONG_ENDER }
};
static RxMac _mac;
static uint8_t _macBuf[36];
/*
*********************************************************************************************
* INTERFACE IMPLEMENTATION
*********************************************************************************************
*/
void SHT30Recver_Init(SHT30FUNC_DATA onRecvData){
_onRecvData = onRecvData;
_mac = RxMac_Create(_flags, ARRAYSIZE(_flags), _macBuf, sizeof(_macBuf) - 1,
NULL, NULL, _onFlushed);
if(_mac == NULL)
for(;;)
;
}
void SHT30Recver_Destroy(){
_onRecvData = NULL;
RxMac_Destroy(_mac);
}
void SHT30Recver_RegisterCallback(SHT30FUNC_DATA onRecvData){
_onRecvData = onRecvData;
}
void SHT30Recver_CleanupBuffer(void){
RxMac_ResetState(_mac);
}
void SHT30Recver_Feed(uint8_t nextByte){
RxMac_FeedData(_mac, nextByte);
}
/*
*********************************************************************************************
* LOCAL FUNCTION IMPLEMENTATION
*********************************************************************************************
*/
static int _FloatFormatRight(const char *beg, const char *end){
const char *p;
if(end - beg <= 0)
return 0;
for(p = beg; end - p > 0; p++)
if(!isdigit(*p) && *p != '-' && *p != '.')
return 0;
return 1;
}
static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender){
const char *p;
SHT30Data data;
if(_onRecvData == NULL || !state.headerFound || !state.enderFound)
return;
buf[len] = '\0';
p = strstr((const char *)buf, " Hum = ");
if(p == NULL || !_FloatFormatRight((const char *)&buf[7], p) ||
!_FloatFormatRight((const char *)&p[9], (const char *)buf + len - 2)){
_dbg_printf2("%s: got corrupt frame-%s", _str_SHT30Recver, (const char *)buf);
return;
}
data.temp = (float)atof((const char *)&buf[7]);
data.humi = (float)atof((const char *)&p[9]);
_dbg_printf3("%s: got data-temp(%.3f),humi(%.3f)\r\n", _str_SHT30Recver, data.temp, data.humi);
_onRecvData(data);
}
SHT30Cmder.c
/*
*******************************************************************************************
*
* SHT30 COMMANDER MODULE
* SHT30驅動子產品 - 指令器
*
* File : SHT30Cmder.c
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/06/17
* version: V1.1
* History: 2020/06/17
* Note : Only implement the set sample rate command for now.
********************************************************************************************
*/
/*
*********************************************************************************************
* INCLUDES
*********************************************************************************************
*/
#include <stdio.h>
#include "SHT30Driver.h"
/*
*********************************************************************************************
* LOCAL VARIABLE
*********************************************************************************************
*/
static void (* _out)(uint8_t *buf, uint16_t len) = NULL;
/*
*********************************************************************************************
* INTERFACE IMPLEMENTATION
*********************************************************************************************
*/
void SHT30Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len)){
_out = outChannel;
}
void SHT30Cmder_Destroy(){
_out = NULL;
}
void SHT30Cmder_setSampleRate(SHT30SampleRate value){
uint8_t buf[] = {0xFF, 0xAA, 0x09, 0x00, 0x00};
buf[3] = (uint8_t)value;
if(_out != NULL)
_out(buf, sizeof(buf));
}
依賴
接收器的實作依賴于我寫的通用接收機:
通用接收狀态機子產品
至于DebugMsg.h則是我自己使用的調試資訊的子產品:
#ifndef _DEBUG_MSG_H
#define _DEBUG_MSG_H
#include <stdio.h>
#ifdef _DEBUG
#define _dbg_printf0(format) ((void)printf(format))
#define _dbg_printf1(format,p1) ((void)printf(format,p1))
#define _dbg_printf2(format,p1,p2) ((void)printf(format,p1,p2))
#define _dbg_printf3(format,p1,p2,p3) ((void)printf(format,p1,p2,p3))
#define _dbg_printf4(format,p1,p2,p3,p4) ((void)printf(format,p1,p2,p3,p4))
#define _dbg_printf5(format,p1,p2,p3,p4,p5) ((void)printf(format,p1,p2,p3,p4,p5))
#define _dbg_printf6(format,p1,p2,p3,p4,p5,p6) ((void)printf(format,p1,p2,p3,p4,p5,p6))
#define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7))
#define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8))
#define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8,p9))
#else
#define _dbg_printf0(format)
#define _dbg_printf1(format,p1)
#define _dbg_printf2(format,p1,p2)
#define _dbg_printf3(format,p1,p2,p3)
#define _dbg_printf4(format,p1,p2,p3,p4)
#define _dbg_printf5(format,p1,p2,p3,p4,p5)
#define _dbg_printf6(format,p1,p2,p3,p4,p5,p6)
#define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7)
#define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8)
#define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9)
#endif
int dummyprintf(const char *format, ...);
#endif
這樣在項目中同時宏定義 _DEBUG 和 SHT30_DEBUG 時才會列印調試資訊。不需要的話删除相關語句就好。
想要了解相關技巧的話詳見:
C語言宏配置的各種奇淫技巧
使用示例
使用此子產品基本分幾步:
- 初始化子產品
- 如需要發送指令則實作并注冊信道給指令器;注冊回調函數給接收器,這樣接收器在發現完整的資料幀時就會通過回調函數進行通知。
- 不斷接收資料,并喂(Feed)給接收器;如需要發指令,随時調用指令器的接口。
以下代碼示例了在上電後不斷讀取資料并進行解析(假設使用标準輸入輸出上的序列槽和SHT30通信):
#include "SHT30Driver.h"
#include <stdio.h>
#include <stdint.h>
……
// 收到資料的回調函數
static void onDataResolved(SHT30Data data);
// 發送信道
static void sendChannel(uint8_t *buf, uint16_t len);
void main(){
uint8_t b;
……
SHT30Recver_Init(onDataResolved);
SHT30Cmder_Init(sendChannel);
// 如果需要調整采樣率的話發送對應指令,注意要先發一次指令使進入配置模式的問題
// SHT30Cmder_setSampleRate(SHT30SR_1Hz);
for(;;){
// 不斷得到下一個位元組并喂給接收機
// 接收機會通過回調函數實時傳遞解析出來的值
b = (uint8_t)getchar();
SHT30Recver_Feed(b);
}
}
static void onDataResolved(SHT30Data data){
// data中就是實時解析到的資料,具體怎麼使用是你的事
}
static void sendChannel(uint8_t *buf, uint16_t len){
// 往标準輸出輸出這個位元組
while(len-- > 0)
putchar((char)*buf++);
}
更新曆史
2020/06/07 放出V1.0
2020/06/17 發現了SHT30和SHT20在資料輸出格式上一個是Humi,一個是Hum,是以修正為了SHT30的Hum。如果是SHT20。則将Recver中的onFlush函數按如下修改即可。
static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender){
const char *p;
SHT30Data data;
if(_onRecvData == NULL || !state.headerFound || !state.enderFound)
return;
buf[len] = '\0';
p = strstr((const char *)buf, " Humi = ");
if(p == NULL || !_FloatFormatRight((const char *)&buf[7], p) ||
!_FloatFormatRight((const char *)&p[10], (const char *)buf + len - 2)){
_dbg_printf2("%s: got corrupt frame-%s", _str_SHT30Recver, (const char *)buf);
return;
}
data.temp = (float)atof((const char *)&buf[7]);
data.humi = (float)atof((const char *)&p[10]);
_dbg_printf3("%s: got data-temp(%.3f),humi(%.3f)\r\n", _str_SHT30Recver, data.temp, data.humi);
_onRecvData(data);
}