程序功能:
1、軟件模擬I2C協(xié)議與SHT30數(shù)字溫濕度傳感器通訊;
2、數(shù)碼管顯示環(huán)境溫濕度;
3、串口打印環(huán)境溫濕度。
目錄
一、硬件電路
二、技術(shù)講解?
2.1IIC簡介
2.2 IIC總線協(xié)議
2.2設(shè)備接入
?三、SHT30數(shù)字溫濕度傳感器
?3.1性能介紹
3.1.1濕度最優(yōu)測量環(huán)境
3.1.2溫度最優(yōu)測量環(huán)境
3.1.3測量配置
3.2通訊介紹
3.2.1單周期數(shù)據(jù)采集模式
?3.2.2周期采集
?四、軟件編程
4.1參數(shù)配置
4.2軟件框架?
4.3運(yùn)行函數(shù)?
?4.4 I2C函數(shù)
4.4.1 iic結(jié)構(gòu)體?
?4.4.2iic函數(shù)
4.5SHT30函數(shù)
4.5.1結(jié)構(gòu)體函數(shù)
4.5.2SHT30函數(shù)
5結(jié)果演示
一、硬件電路
二、技術(shù)講解?
2.1IIC簡介
IIC (I2C,Inter-Integrated Circuit)即集成電路總線,是一種兩線式串行總線,由PHILIPS公司開發(fā)用于連接微控制器及其外圍設(shè)備。多用于主機(jī)和從機(jī)在數(shù)據(jù)量不大且傳輸距離短的場合下的主從通信。
I2C總線由數(shù)據(jù)線SDA和時(shí)鐘線SCL構(gòu)成通信線路,既可用于發(fā)送數(shù)據(jù),也可接收數(shù)據(jù)。只有一根數(shù)據(jù)線,屬于半雙工通信方式。
標(biāo)準(zhǔn)模式:100Kbit/s 快速模式:400kbit/s 高速模式:3.4Mbit/s
2.2 IIC總線協(xié)議
?
?文章來源地址http://www.zghlxwxcb.cn/news/detail-422397.html
?
I2C協(xié)議特點(diǎn):
1、串行協(xié)議,多主機(jī)模式;
2、起始信號(hào),SCL為高電平時(shí),SDA下降沿,主機(jī)發(fā)出;
3、停止信號(hào),SCL為高電平時(shí),SDA上升沿,主機(jī)發(fā)出;
4、數(shù)據(jù)與地址按8位/字節(jié)傳輸(附帶讀寫位),高位在前;
5、傳輸過程中,SCL為低電平時(shí),SDA更改狀態(tài),SCL為高電平時(shí),SDA狀態(tài)需穩(wěn)定;
6、每傳輸一個(gè)字節(jié),接收器必須回應(yīng)1個(gè)應(yīng)答位(ACK)給發(fā)送器。
?
2.2設(shè)備接入
通過上面IIC協(xié)議的介紹,我們知道,通信是相互的,從機(jī)接收到讀的命令,也會(huì)像主機(jī)發(fā)送數(shù)據(jù),所以?I2C 器件一般采用開漏結(jié)構(gòu)與總線相連,SCL 和 SDA 均需接上拉電阻。也正因此,當(dāng)總線空閑時(shí),這兩條線路都處于高電平狀態(tài),當(dāng)連到總線上的任一器件輸出低電平,都將使總線拉低,即各器件的 SDA 及 SCL 都是“線與”關(guān)系。I2C 總線支持多主和主從兩種工作方式。在主從工作方式中,主機(jī)啟動(dòng)數(shù)據(jù)的發(fā)送(發(fā)出啟動(dòng)信號(hào))并產(chǎn)生時(shí)鐘信號(hào),數(shù)據(jù)發(fā)送完成后,發(fā)出停止信號(hào)。
?
?三、SHT30數(shù)字溫濕度傳感器
?3.1性能介紹
?
SHT30工作電壓范圍:2.4v--5.5v,通信速率:最高1MHz,接口:提供兩個(gè)用戶可選擇地址的IIC接口,精度:2%RH,0.3° C的典型精度。
3.1.1濕度最優(yōu)測量環(huán)境
3.1.2溫度最優(yōu)測量環(huán)境
?
? ?該傳感器在推薦的正常溫度和濕度范圍內(nèi)分別為5-60° C和20-80%RH時(shí)顯示出最佳的性能。 長期暴露在正常范圍以外的條件下, 特別是在高濕度下, 可能會(huì)暫時(shí)抵消RH信號(hào)(例如在80%RH條件下60h后+3%RH)。 在恢復(fù)到正常的溫度和濕度范圍后, 傳感器將自行緩慢地恢復(fù)到校準(zhǔn)狀態(tài)。 長期暴露在極端條件下可能會(huì)加速衰老。 為了確保濕度傳感器的穩(wěn)定運(yùn)行, 必須滿足文件“SMD包裝的SHTxx組裝” 中關(guān)于接觸揮發(fā)性有機(jī)化合物的“儲(chǔ)存和處理說明” 一節(jié)中所描述的條件。 請(qǐng)注意, 這不僅適用于運(yùn)輸和制造, 而且也適用于SHT3x-DIS的操作。
3.1.3測量配置
?
??
3.2通訊介紹
?測量通信序列由START條件、 I2C寫報(bào)頭(7位I2C設(shè)備)組成地址加0(R)作為寫位)和16位測量命令(高八位,低八位)。 每個(gè)字節(jié)的正確接收由傳感器指示。 它將SDA引腳拉低(ACK位)后, 第8個(gè)SCL時(shí)鐘的下降邊緣?以指示接收。 描述了一個(gè)完整的測量周期。通過確認(rèn)測量命令, SHT3x-DIS開始測量濕度和溫度。
3.2.1單周期數(shù)據(jù)采集模式
?
在這種模式下, 一個(gè)發(fā)出的測量命令觸發(fā)一個(gè)數(shù)據(jù)對(duì)的獲取。 每個(gè)數(shù)據(jù)對(duì)由一個(gè)16位溫度
和一個(gè)16位濕度值(按此順序)組成) 。 在傳輸期間, 數(shù)據(jù)對(duì)總是后面跟著CRC校驗(yàn)位, 請(qǐng)
在單周期模式下, 可以選擇不同的測量命令。 16位命令顯示在它們?cè)谥貜?fù)性( 低、中、 高)和時(shí)鐘拉伸(啟用或禁用)方面不同) 。重復(fù)性設(shè)置影響傳感器的測量持續(xù)時(shí)間和電流消耗。 ?傳感器通常不響應(yīng)任何I2C活動(dòng), 即不承認(rèn)I2C讀寫標(biāo)題(NACK)。 然而, 當(dāng)發(fā)出帶有時(shí)鐘拉伸的命令時(shí), 傳感器用ACK響應(yīng)讀報(bào)頭, 然后拉下SCL線。 將SCL線拉下, 直至測量完成。 測量完成后, 傳感器釋放SCL線并發(fā)送測量結(jié)果。圖解如下:
?
?3.2.2周期采集
?在這種模式下, 一個(gè)發(fā)出的測量命令產(chǎn)生一個(gè)數(shù)據(jù)對(duì)流。 每個(gè)數(shù)據(jù)對(duì)由一個(gè)16位溫度和一
個(gè)16位濕度值(按此順序)組成) 。在周期模式下, 可以選擇不同的測量命令。相應(yīng)的16位命令顯示在重復(fù)性(低、 中、 高)和數(shù)據(jù)采集頻率(每秒0.5、 1、 2、 4和10次測量, MPS)方面)。 ?無法在此模式下選擇時(shí)鐘拉伸。數(shù)據(jù)采集頻率和重復(fù)性設(shè)置影響傳感器的測量持續(xù)時(shí)間和電流消耗
。
?四、軟件編程
4.1參數(shù)配置
?只需要配置gpio口味開漏輸出就可以了,如下圖所示:
4.2軟件框架?
在原有的基礎(chǔ)上,新增I2C和SHT30源文件。如下圖所示:
?
?
4.3運(yùn)行函數(shù)?
static void Run()
{
float Temp_float = 0;
uint16_t Temp_uint = 0;
//周期性測量獲取SHT30的溫濕度
SHT30.Measure_Period_Mode();
//串口打印
printf("Wendu = %.1f??\r\n",SHT30.fTemperature);
printf("shidu = %d%%RH\r\n\r\n",(uint16_t)SHT30.ucHumidity);
數(shù)碼管顯示
//溫度
if(SHT30.fTemperature < 0) //負(fù)溫
{
Temp_float = 0 - SHT30.fTemperature;
Display.Disp_Other(Disp_NUM_4,0x40,Disp_DP_OFF); //4號(hào)數(shù)碼管
}
else
{
Temp_float = SHT30.fTemperature;
Display.Disp_Other(Disp_NUM_4,0x00,Disp_DP_OFF); //4號(hào)數(shù)碼管
}
Temp_uint = (uint16_t)(Temp_float*10);
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);
Display.Disp_HEX(Disp_NUM_1,Temp_uint%10,Disp_DP_OFF);
//濕度
Display.Disp_HEX(Disp_NUM_6,SHT30.ucHumidity/10,Disp_DP_OFF);
Display.Disp_HEX(Disp_NUM_5,SHT30.ucHumidity%10,Disp_DP_OFF);
HAL_Delay(500);
}
?4.4 I2C函數(shù)
4.4.1 iic結(jié)構(gòu)體?
枚舉,ACK,和NACK,結(jié)構(gòu)體封裝,iic的起始,停止 讀 寫函數(shù)。?
typedef enum
{
ACK = GPIO_PIN_RESET,//響應(yīng)
NACK = GPIO_PIN_SET,//不響應(yīng)
}ACK_Value_t;
//定義結(jié)構(gòu)體類型
typedef struct
{
void (*Init)(void); //初始化
void (*Start)(void); //起始信號(hào)
void (*Stop)(void); //停止信號(hào)
ACK_Value_t (*Write_Byte)(uint8_t); //I2c寫字節(jié)
uint8_t (*Read_Byte) (ACK_Value_t); //I2讀字節(jié)
}I2C_Soft_t
?4.4.2iic函數(shù)
1.將設(shè)置sda,scl引腳的端口,宏定義,方便代碼編寫,以及后期移植,?
//置位與清零SCL管腳
#define SET_SCL HAL_GPIO_WritePin(SHT30_SCL_GPIO_Port,SHT30_SCL_Pin,GPIO_PIN_SET)
#define CLR_SCL HAL_GPIO_WritePin(SHT30_SCL_GPIO_Port,SHT30_SCL_Pin,GPIO_PIN_RESET)
//置位與清零SDL管腳
#define SET_SDA HAL_GPIO_WritePin(SHT30_SDA_GPIO_Port,SHT30_SDA_Pin,GPIO_PIN_SET)
#define CLR_SDA HAL_GPIO_WritePin(SHT30_SDA_GPIO_Port,SHT30_SDA_Pin,GPIO_PIN_RESET)
//讀SDA管腳狀態(tài)
#define READ_SDA HAL_GPIO_ReadPin(SHT30_SDA_GPIO_Port,SHT30_SDA_Pin)
?2.初始化
將sda和scl均拉高
static void Init(void)
{
SET_SCL;
SET_SDA;
}
?3起始
拉低sda,延時(shí)一會(huì)拉低scl等待發(fā)送
static void Start(void)
{
//SCL為該電平,SDA為下降沿IIC起始信號(hào)
SET_SDA;
SET_SCL;
I2C_Delay_us(1);
CLR_SDA;
I2C_Delay_us(10);
CLR_SCL;
I2C_Delay_us(1);
}
?4停止
拉低SDA,拉高SCL再次拉高SDA 停止
static void Stop(void)
{
//SCL為高電平,SDA上升沿為IIC停止信號(hào)
CLR_SDA;
SET_SCL;
I2C_Delay_us(1);
I2C_Delay_us(10);
SET_SDA;
}
5寫數(shù)據(jù)
BIT7為1,將數(shù)據(jù)位和他與 判斷為高定電平,選擇對(duì)應(yīng)的SDA位。
static ACK_Value_t Write_Byte(uint8_t WR_Byte)
{
uint8_t i;
ACK_Value_t ACK_Rspond;
//SCL為低電平,SDA準(zhǔn)備數(shù)據(jù),接著SCL為高電平,讀取SDA數(shù)據(jù)
//數(shù)據(jù)按八位傳輸,高位在前,利用for循環(huán)逐個(gè)接收
for(i=0;i<8;i++)
{
//SCL清零,主機(jī)SDA 準(zhǔn)備數(shù)據(jù)
CLR_SCL;
I2C_Delay_us(1);
if((WR_Byte&BIT7) == BIT7)
{
SET_SDA;
}
else
{
CLR_SDA;
}
I2C_Delay_us(1);
//SCL置高,傳輸數(shù)據(jù)
SET_SCL;
I2C_Delay_us(10);
//準(zhǔn)備發(fā)送下一個(gè)bit
WR_Byte <<= 1;
}
CLR_SCL;
//釋放SDA,等待從機(jī)yingda
SET_SDA;
I2C_Delay_us(1);
SET_SCL;
I2C_Delay_us(10);
ACK_Rspond = (ACK_Value_t)READ_SDA;
CLR_SCL;
I2C_Delay_us(1);
//返回從機(jī)應(yīng)答信號(hào)
return ACK_Rspond;
}
?6讀數(shù)據(jù)
static uint8_t Read_Byte(ACK_Value_t ACK_Value)
{
uint8_t RD_Byte = 0,i;
接收數(shù)據(jù)
//SCL位低電平,SDA準(zhǔn)備數(shù)據(jù),接著SCL為高電平,讀取SDA數(shù)據(jù)
//數(shù)據(jù)傳輸八位,高位在前,利用for循環(huán)諸葛接收
for(i=0;i<8;i++)
{
//準(zhǔn)備接收下一個(gè)bit
RD_Byte <<= 1;
//SCL清零,從機(jī)SDA準(zhǔn)備數(shù)據(jù)
CLR_SCL;
I2C_Delay_us(10);
//SCL志高,獲取數(shù)據(jù)
SET_SCL;
I2C_Delay_us(10);
RD_Byte |= READ_SDA;
}
//SCL清零,主機(jī)準(zhǔn)備應(yīng)答信號(hào)
CLR_SCL;
I2C_Delay_us(1);
//主機(jī)發(fā)送應(yīng)答信號(hào)
if(ACK_Value == ACK)
{
CLR_SDA;
}
else
{
SET_SDA;
}
I2C_Delay_us(1);
SET_SCL;
I2C_Delay_us(10);
//Note:
//釋放SDA數(shù)據(jù)線
//SCL先清零,在釋放SDA,防止連續(xù)傳輸數(shù)據(jù)時(shí)。從機(jī)錯(cuò)將SDA釋放。
CLR_SCL;
SET_SDA;
I2C_Delay_us(1);
//返回?cái)?shù)據(jù)
return RD_Byte;
}
4.5SHT30函數(shù)
4.5.1結(jié)構(gòu)體函數(shù)
?選擇周期測量模式,因?yàn)镾HT30地址位是七位,所以需要左移 然后與讀寫位與或 加上讀寫位構(gòu)成八位數(shù)據(jù)傳輸。
#define SHT30_ADDR (uint8_t)(0x44 << 1) //′傳感器地址
//#define SHT30_ADDR (unsigned char)(0x45 << 1) //′另一種模式傳感器地址
#define Write_CMD 0xFE
#define Read_CMD 0x01
//定義結(jié)構(gòu)體類型
typedef struct
{
float fTemperature; //溫度 -40 至 125 精度 百一
uint8_t ucHumidity; //濕度 0 - 100 精度 百一
void (*Measure_Period_Mode)(void); //周期測量模式
}SHT30_t;
4.5.2SHT30函數(shù)
1.信號(hào)輸出的轉(zhuǎn)換
測量數(shù)據(jù)總是以16位值( 無符號(hào)整數(shù))的形式傳輸) 。 這些值已經(jīng)線性化, 并補(bǔ)償了溫度
和電源電壓的影響。 將這些原始值轉(zhuǎn)換為物理標(biāo)度可以使用以下公式實(shí)現(xiàn)。相對(duì)濕度換算公式(結(jié)果為%RH):
?
??
static void Measure_Period_Mode(void)
{
uint8_t temp_array[6] = {0};
uint16_t temp_uint = 0;
float temp_float = 0;
//啟動(dòng)周期性測量
I2C_Soft.Start();
I2C_Soft.Write_Byte(SHT30_ADDR & Write_CMD);
I2C_Soft.Write_Byte(0x27); //High repeat , mps = 10
I2C_Soft.Write_Byte(0x37);
Timer6.SHT30_Measure_Timeout = 0;
//發(fā)送接收數(shù)據(jù)命令
do
{
if(Timer6.SHT30_Measure_Timeout >= TIMER6_2S) //2s內(nèi)沒獲取跳出
break;
I2C_Soft.Start();
I2C_Soft.Write_Byte(SHT30_ADDR & Write_CMD);
I2C_Soft.Write_Byte(0xE0);
I2C_Soft.Write_Byte(0x00);
I2C_Soft.Start();
}
while(I2C_Soft.Write_Byte(SHT30_ADDR | Read_CMD) ==NACK);
//開始接收測量數(shù)據(jù),并計(jì)算
if(Timer6.SHT30_Measure_Timeout < TIMER6_2S)
{
temp_array[0] = I2C_Soft.Read_Byte(ACK);
temp_array[1] = I2C_Soft.Read_Byte(ACK);
temp_array[2] = I2C_Soft.Read_Byte(ACK);
temp_array[3] = I2C_Soft.Read_Byte(ACK);
temp_array[4] = I2C_Soft.Read_Byte(ACK);
temp_array[5] = I2C_Soft.Read_Byte(NACK);
I2C_Soft.Stop();
計(jì)算溫度 精度0.1
if(CRC_8(temp_array,2) == temp_array[2]) //CRC-8 D£?é
{
temp_uint = temp_array[0]*256+temp_array[1];
temp_float = ((float)temp_uint)*0.267032-4500;
SHT30.fTemperature = temp_float*0.01;
}
計(jì)算濕度 1%RH
if(CRC_8(&temp_array[3],2) == temp_array[5]) //CRC-8 D£?é
{
temp_uint = temp_array[3]*256+temp_array[4];
temp_float = ((float)temp_uint)*0.152590;
temp_float = temp_float*0.01;
SHT30.ucHumidity = (unsigned char)temp_float;
}
}
}
校驗(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;
}
5結(jié)果演示
?
?
?
?文章來源:http://www.zghlxwxcb.cn/news/detail-422397.html
?
到了這里,關(guān)于STM32實(shí)戰(zhàn)項(xiàng)目-溫濕度傳感器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!