SHT30溫濕度采集(IIC通信)
SHT30數(shù)字溫濕度傳感器
SHT3x濕度傳感器系列包括低成本版本SHT30、標(biāo)準(zhǔn)版本SHT31,以及高端版本SHT35。
SHT3x濕度傳感器系列結(jié)合了多種功能和各種接口(I2C、模擬電壓輸出),應(yīng)用友好,工作電壓范圍寬(2.15至5.5 V),適合各類應(yīng)用。
SHT3x建立在全新和優(yōu)化的CMOSens? 芯片之上,進(jìn)一步提高了產(chǎn)品可靠性和精度規(guī)格。SHT3x提供了一系列新功能,如增強(qiáng)信號(hào)處理、兩個(gè)獨(dú)特和用戶可選I2C地址、一個(gè)可編程溫濕度極限的報(bào)警模式,以及高達(dá)1 MHz的通信速度。
DFN封裝的占位面積為2.5 × 2.5 mm2,高度為0.9 mm。這有助于SHT3x集成到多種應(yīng)用。此外,2.15至5.5 V的寬電源電壓范圍和多種可選接口可保證與不同集成要求的兼容性。總之,SHT3x濕度傳感器系列融入了Sensirion作為行業(yè)領(lǐng)導(dǎo)者15年的經(jīng)驗(yàn)和心血,是一款超高性價(jià)比的產(chǎn)品。
特點(diǎn)
完全校準(zhǔn),線性化,和溫度補(bǔ)償數(shù)字輸出
寬電源電壓范圍,從2.4到5.5 V
IIC接口通信速度1 MHz和兩個(gè)用戶可選擇的地址
典型精度2%RH(濕度)和0.3°C(溫度)
非常快速啟動(dòng)和測(cè)量時(shí)間
小8針DFN包(封裝)
32引腳既作輸入又作輸出
在51單片機(jī)中,引腳都叫通用輸入輸出引腳,是具有雙向功能的,32單片機(jī)的引腳也可以
開漏輸出框圖
CPU往位設(shè)置寄存器寫入1,則高電平1來到輸出控制電路這里,N-MOS管不會(huì)導(dǎo)通,此時(shí)IO端口的電平狀態(tài)由外部的上拉或者下拉決定,可能為高電平也可能為低電平;同時(shí)IO端口的狀態(tài)可以被讀取,通過虛線的電路被CPU讀取,此時(shí)讀取的并不一定是CPU輸出的高電平1,而是外部的狀態(tài)
CPU如果往位設(shè)置寄存器寫入0,則低電平0來到輸出控制寄存器,N-MOS管導(dǎo)通,IO端口與VSS導(dǎo)通,而VSS是電路公共地端電壓,一般接GND,所以IO端口就輸出低電平0;同時(shí)CPU讀取時(shí)端口狀態(tài)就是自己輸出的低電平0
所以IO引腳配置為開漏輸出就既可以作輸出又可以作輸入了,并不需要再配置改變IO口的工作模式
SHT30通信引腳配置
因?yàn)?strong>SHT30是IIC通信的,SCL與SDA均配置為開漏輸出,總線上均有上拉電阻。因此,SDA作為輸出的同時(shí),也可以作為輸入使用。與51內(nèi)核的準(zhǔn)雙向口一樣,作為輸入使用時(shí),需要先輸出高電平,關(guān)閉內(nèi)部的NMOS管。
CubeMX配置
因?yàn)镮IC通信的SCL引腳接到了PG11,SDA接到了PG12,所以需要配置這兩個(gè)引腳為開漏輸出
PG11和PG12都配置為開漏輸出,并輸出高電平,因?yàn)槭峭ㄐ?,輸出速度可以選高速
其他配置如定時(shí)器6,數(shù)碼管,串口,LED燈按照之前實(shí)驗(yàn)中配置方法就行,系統(tǒng)時(shí)鐘72MHz
程序
IIC.c
根據(jù)IIC通信時(shí)序圖編寫函數(shù),本次使用軟件模擬IIC通信的方式,對(duì)IIC通信加深理解
IIC通信介紹可以參考:http://t.csdn.cn/xvYI5
/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"
/* Private define-------------------------------------------------------------*/
#define SET_SCL HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_SET)
#define CLR_SCL HAL_GPIO_WritePin(SCL_GPIO_Port,SCL_Pin,GPIO_PIN_RESET)
#define SET_SDA HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_SET)
#define CLR_SDA HAL_GPIO_WritePin(SDA_GPIO_Port,SDA_Pin,GPIO_PIN_RESET)
#define READ_SDA HAL_GPIO_ReadPin(SDA_GPIO_Port,SDA_Pin)
/* Private function prototypes------------------------------------------------*/
static void IIC_Init(void);
static void IIC_Start(void);
static void IIC_Stop(void);
static void Write_Byte(uint8_t );
static uint8_t Recive_Byte(void);
static void SendACK(ACK_Value_t );
static ACK_Value_t ReciveACK(void);
static void IIC_Delay_us(uint8_t );
/* Private variables----------------------------------------------------------*/
/* Public variables-----------------------------------------------------------*/
IIC_Soft_t IIC_Soft =
{
IIC_Init,
IIC_Start,
IIC_Stop,
Write_Byte,
Recive_Byte,
SendACK,
ReciveACK
};
/*
* @name IIC_Init
* @brief IIC初始化
* @param None
* @retval None
*/
static void IIC_Init()
{
SET_SCL;
SET_SDA;
}
/*
* @name IIC_Start
* @brief 起始信號(hào)
* @param None
* @retval None
*/
static void IIC_Start()
{
//SCL為高電平時(shí),SDA的下降沿為IIC的起始信號(hào)
SET_SCL;
SET_SDA;
IIC_Delay_us(1);
CLR_SDA;
IIC_Delay_us(10);
CLR_SCL;
IIC_Delay_us(1);
}
/*
* @name IIC_Stop
* @brief 停止信號(hào)
* @param None
* @retval None
*/
static void IIC_Stop()
{
//SCL為高電平時(shí),SDA的上升沿為IIC的停止信號(hào)
CLR_SDA;
SET_SCL;
IIC_Delay_us(10);
SET_SDA;
}
/*
* @name Write_Byte
* @brief 主機(jī)發(fā)送一個(gè)字節(jié)
* @param WR_Byte:要發(fā)送的數(shù)據(jù)
* @retval None
*/
static void Write_Byte(uint8_t WR_Byte)
{
uint8_t i;
//傳輸一個(gè)字節(jié)
/*SCL為低電平時(shí),SDA準(zhǔn)備數(shù)據(jù),接著SCL為高電平,讀取SDA數(shù)據(jù)
數(shù)據(jù)按8位傳輸,高位在前,利用for循環(huán)逐個(gè)接收*/
for(i=0;i<8;i++)
{
CLR_SCL; //拉低SCL
IIC_Delay_us(1);
if((WR_Byte&BIT7) == BIT7) //如果一個(gè)字節(jié)最高位為1
{
SET_SDA; //往SDA上放1
}
else
{
CLR_SDA; //否則往SDA上放0
}
IIC_Delay_us(1);
SET_SCL; //拉高SCL,從機(jī)讀取數(shù)據(jù)
IIC_Delay_us(10);
WR_Byte <<= 1; //左移一位,發(fā)送下一位
}
}
/*
* @name Recive_Byte
* @brief 主機(jī)接收一個(gè)字節(jié)
* @param None
* @retval 接收到的數(shù)據(jù)
*/
static uint8_t Recive_Byte()
{
uint8_t i,Re_Byte = 0x00;
//釋放SDA,將控制權(quán)交給從機(jī),即SDA = 1
SET_SDA;
//接收一個(gè)字節(jié)
for(i=0;i<8;i++)
{
CLR_SCL; //拉低SCL,從機(jī)SDA準(zhǔn)備數(shù)據(jù)
IIC_Delay_us(10);
SET_SCL; //拉高SCL,讀取數(shù)據(jù)
IIC_Delay_us(10);
if(READ_SDA == GPIO_PIN_SET)
{
Re_Byte|=(BIT7>>i);
}
}
return Re_Byte;
}
/*
* @name SendACK
* @brief 主機(jī)發(fā)送應(yīng)答
* @param ACK_Value:ACK:應(yīng)答,NACK:非應(yīng)答
* @retval None
*/
static void SendACK(ACK_Value_t ACK_Value)
{
CLR_SCL; //拉低SCL,主機(jī)準(zhǔn)備發(fā)送應(yīng)答信息
IIC_Delay_us(1);
//發(fā)送應(yīng)答信息
if(ACK_Value == ACK)
{
CLR_SDA; //0表示應(yīng)答
}
else
{
SET_SDA; //1表示非應(yīng)答
}
IIC_Delay_us(1);
SET_SCL; //拉高SCL,主機(jī)發(fā)送應(yīng)答
IIC_Delay_us(1);
//釋放SDA數(shù)據(jù)線
//SCL先清零,再釋放SDA,防止連續(xù)傳輸數(shù)據(jù)時(shí),從機(jī)錯(cuò)將SDA釋放信號(hào)當(dāng)成NACk信號(hào)
CLR_SCL; //拉低SCL
SET_SDA; //因?yàn)橹鳈C(jī)發(fā)送應(yīng)答后,從機(jī)可能會(huì)繼續(xù)發(fā)送數(shù)據(jù),所以控制權(quán)要給到從機(jī)
IIC_Delay_us(1);
}
/*
* @name ReciveACK
* @brief 主機(jī)接收應(yīng)答,判斷從機(jī)是否應(yīng)答
* @param None
* @retval 從機(jī)的應(yīng)答
*/
static ACK_Value_t ReciveACK()
{
uint8_t RecAck;
CLR_SCL; //拉低SCL
SET_SDA; //主機(jī)釋放SDA,將控制權(quán)交給從機(jī),即SDA = 1
IIC_Delay_us(1);
SET_SCL; //拉高SCL,讀取SDA的值
IIC_Delay_us(10);
RecAck = READ_SDA; //讀取SDA的值,0表示應(yīng)答,1表示非應(yīng)答
CLR_SCL;
IIC_Delay_us(1);
return (ACK_Value_t)RecAck;
}
/*
* @name IIC_Delay_us
* @brief IIC延時(shí)函數(shù)——微秒級(jí),
* @param us:要延時(shí)的時(shí)間
* @retval None
*/
static void IIC_Delay_us(uint8_t us)
{
uint16_t i;
//通過示波器測(cè)量進(jìn)行校準(zhǔn)
while(us--)
{
for(i=0;i<7;i++);
}
}
/********************************************************
End Of File
********************************************************/
SHT30.c
根據(jù)SHT30的數(shù)據(jù)手冊(cè)來編寫通信函數(shù)
4.5定期數(shù)據(jù)采集模式的測(cè)量命令
在這種模式下,一個(gè)發(fā)出的測(cè)量命令會(huì)產(chǎn)生一個(gè)數(shù)據(jù)對(duì)流。每個(gè)數(shù)據(jù)對(duì)由一個(gè)16位溫度值和一個(gè)16位濕度值(按此順序)組成。在周期模式下,可以選擇不同的測(cè)量命令。對(duì)應(yīng)的16位命令如表9所示。它們?cè)诳芍貜?fù)性(低、中、高)和數(shù)據(jù)采集頻率(每秒0.5、1、2、4和10次測(cè)量值,mps)方面存在差異。在此模式下不能選擇時(shí)鐘拉伸。數(shù)據(jù)采集頻率和可重復(fù)性設(shè)置會(huì)影響傳感器的測(cè)量持續(xù)時(shí)間和電流消耗。
根據(jù)表格下方的通信時(shí)序,主機(jī)發(fā)送起始信號(hào),然后發(fā)送從機(jī)地址加寫指令命令,等待從機(jī)應(yīng)答,再發(fā)送命令的高位(MSB),等待從機(jī)應(yīng)答,再發(fā)送命令的低位(LSB)
調(diào)用IIC的函數(shù),根據(jù)通信時(shí)序,完成設(shè)置周期測(cè)量模式
//設(shè)置周期測(cè)量模式
IIC_Soft.IIC_Start();
IIC_Soft.Write_Byte(SHT30_ADDR&WRITE_CMD);
IIC_Soft.ReciveACK();
IIC_Soft.Write_Byte(0x27); //MSB,設(shè)置Repeatability為High,mps為10的測(cè)量模式
IIC_Soft.ReciveACK();
IIC_Soft.Write_Byte(0x37); //LSB
IIC_Soft.ReciveACK();
4.6周期模式下測(cè)量結(jié)果的讀數(shù)
讀數(shù)可以通過表10所示的命令啟動(dòng)。如果沒有測(cè)量數(shù)據(jù),I2C讀取頭用NACK而不是ACK(表10中的位9)響應(yīng),通信停止。
空白的數(shù)據(jù)塊是由32發(fā)送,黑色的數(shù)據(jù)塊是由SHT30發(fā)送
根據(jù)表10的通信時(shí)序,獲取SHT30的溫濕度數(shù)據(jù),讀數(shù)據(jù)的命令是0xE000,獲取的是16位的溫度值和16位的濕度值,溫度和濕度后都有CRC-8校驗(yàn)
從SHT30讀出的16位溫度和16位濕度還不是真正的溫濕度值,而是要根據(jù)上面這個(gè)公式來計(jì)算得到正確的溫濕度值,RH是濕度,T是溫度
通信時(shí)序代碼
在通過公式計(jì)算溫濕度值時(shí),因?yàn)?16 - 1是65535,175/65535 = 0.002670328…,結(jié)果除不盡,但浮點(diǎn)型float的精度為6~7位有效數(shù)字,直接計(jì)算的話相當(dāng)于把小數(shù)點(diǎn)后7位之后的數(shù)據(jù)省略掉了,會(huì)造成計(jì)算出來的溫濕度精度有些損失,所以有了這樣的方法:先讓公式的數(shù)值都*100,這樣的話計(jì)算出來的溫濕度值也會(huì) *100,但這樣計(jì)算的小數(shù)位就會(huì)多兩位,精度較為準(zhǔn)確,在賦給最后結(jié)果變量前再 *0.01,將結(jié)果變回正常值即可
//讀取數(shù)據(jù)
Timer6.SHT30_Measure_Timeout = 0;
do
{
//如果2秒內(nèi)沒有獲取到數(shù)據(jù),則break退出
if(Timer6.SHT30_Measure_Timeout >= TIMER_2s)
{
LED.LED_Fun(LED2,LED_OFF);
break;
}
IIC_Soft.IIC_Start();
IIC_Soft.Write_Byte(SHT30_ADDR&WRITE_CMD);
IIC_Soft.ReciveACK();
//0xE000是向SHT30取數(shù)據(jù)的指令,主機(jī)發(fā)送該指令后開始讀取SHT30的溫濕度數(shù)據(jù)
IIC_Soft.Write_Byte(0xE0);
IIC_Soft.ReciveACK();
IIC_Soft.Write_Byte(0x00);
IIC_Soft.ReciveACK();
//重新發(fā)送起始信號(hào),往SHT30發(fā)送地址加讀取數(shù)據(jù)指令
IIC_Soft.IIC_Start();
IIC_Soft.Write_Byte(SHT30_ADDR|READ_CMD);
/*判斷是否收到從機(jī)應(yīng)答,主機(jī)收到NACK時(shí),繼續(xù)循環(huán)發(fā)送取數(shù)據(jù)指令,主機(jī)收到ACK時(shí),不滿足
條件,退出,往下執(zhí)行*/
} while (IIC_Soft.ReciveACK() == NACK);
//接收溫濕度數(shù)據(jù)
//判斷是否是超時(shí)退出,如果不是,則有數(shù)據(jù),進(jìn)行接收;如果是則沒有數(shù)據(jù),不處理
if(Timer6.SHT30_Measure_Timeout < TIMER_2s)
{
temp_array[0] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);
temp_array[1] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);
temp_array[2] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);
temp_array[3] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);
temp_array[4] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(ACK);
temp_array[5] = IIC_Soft.Recive_Byte();IIC_Soft.SendACK(NACK);
IIC_Soft.IIC_Stop();
//計(jì)算溫度
if(CRC_8(temp_array,2) == temp_array[2]) //進(jìn)行CRC-8校驗(yàn)
{
temp_uint = temp_array[0]*256+temp_array[1]; //取出16位的溫度值
temp_float = ((float)temp_uint)*0.267032-4500; //根據(jù)手冊(cè)公式計(jì)算,為了精度,計(jì)算數(shù)值先*100
SHT30.fTemperature = temp_float*0.01; //再除以100,得到正常溫度值
}
//計(jì)算濕度
if(CRC_8(&temp_array[3],2) == temp_array[5]) //進(jìn)行CRC-8校驗(yàn)
{
temp_uint = temp_array[3]*256+temp_array[4]; //取出16位的濕度值
temp_float = ((float)temp_uint)*0.152590; //根據(jù)手冊(cè)公式計(jì)算
SHT30.ucHumidity = (uint8_t)(temp_float*0.01); //除以100,得到正常濕度值
}
LED.LED_Fun(LED1,LED_OFF); //轉(zhuǎn)換完成LED1熄滅
}
}
CRC-8檢驗(yàn)函數(shù)
/*
* @name CRC_8
* @brief CRC-8校驗(yàn)
* @param Crc_ptr -> 校驗(yàn)數(shù)據(jù)首地址
LEN -> 校驗(yàn)數(shù)據(jù)長度
* @retval CRC_Value -> 校驗(yàn)值
*/
static uint8_t CRC_8(uint8_t *Crc_ptr,uint8_t LEN)
{
uint8_t CRC_Value = 0xFF;
uint8_t i = 0,j = 0;
for(i=0;i<LEN;i++)
{
CRC_Value ^= *(Crc_ptr+i);
for(j=0;j<8;j++)
{
if(CRC_Value & 0x80)
CRC_Value = (CRC_Value << 1) ^ 0x31;
else
CRC_Value = (CRC_Value << 1);
}
}
return CRC_Value;
}
System.c
系統(tǒng)運(yùn)行函數(shù)中實(shí)現(xiàn)串口打印以及數(shù)碼管顯示溫濕度值
/*
* @name Run
* @brief 系統(tǒng)運(yùn)行
* @param None
* @retval None
*/
static void Run()
{
float Temp_float = 0;
uint16_t Temp_uint = 0;
//調(diào)用SHT30周期檢測(cè)函數(shù)
SHT30.Measure_Period_Mode();
//串口打印溫濕度
printf("溫度:%.1f度\r\n",SHT30.fTemperature);
printf("濕度:%d%%RH\r\n\r\n",SHT30.ucHumidity);
//判斷溫度正負(fù)
if(SHT30.fTemperature < 0)
{
Temp_float = 0 - SHT30.fTemperature;
Display.Disp_Other(Disp_NUM_4,0x40,Disp_DP_OFF);
}
else
{
Temp_float = SHT30.fTemperature;
Display.Disp_Other(Disp_NUM_4,0x00,Disp_DP_OFF);
}
//顯示溫度
Temp_uint = (uint16_t)(Temp_float*10); //將溫度值乘以10,顯示小數(shù)點(diǎn)后一位
Display.Disp_Hex(Disp_NUM_3,Temp_uint/100,Disp_DP_OFF); //顯示十位
Display.Disp_Hex(Disp_NUM_2,Temp_uint%100/10,Disp_DP_ON); //顯示個(gè)位,開啟小數(shù)點(diǎn)
Display.Disp_Hex(Disp_NUM_1,Temp_uint%10,Disp_DP_OFF); //顯示小數(shù)點(diǎn)后一位
//顯示濕度
Display.Disp_Hex(Disp_NUM_6,SHT30.ucHumidity/10,Disp_DP_OFF);
Display.Disp_Hex(Disp_NUM_5,SHT30.ucHumidity%10,Disp_DP_OFF);
//延時(shí)
HAL_Delay(500);
}
實(shí)驗(yàn)效果
串口打印
數(shù)碼管顯示文章來源:http://www.zghlxwxcb.cn/news/detail-420258.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-420258.html
到了這里,關(guān)于STM32物聯(lián)網(wǎng)項(xiàng)目-SHT30溫濕度采集(IIC通信)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!