今天來說說溫溼度讀取的部分吧,首先來看看這顆的Datasheet:
https://www.silabs.com/documents/public/data-sheets/Si7020-A20.pdf
這是第一頁,他的接腳不複雜四條線就可以使用了:SCL、SDA、VDD、GND,DNC腳空接就好
在手冊的第1頁有說明了,他不需要校準出工廠前都有效準過了,我覺得溫度這真的很難有個絕對,沒必要討論溫溼度到底準不準,每的地點溫度又不同也會受風的影響,要真的說溫度測的準不準我覺得要用1個恆溫箱來觀看吧,那又有個問題恆溫箱是真的準確的?之前有被問到這問題,個人覺得討論這個沒甚麼意義。
#ifndef __BSP_I2C_si7020_H
#define __BSP_I2C_si7020_H
#include "stm32f0xx.h"
#include "bsp_I2C_gpio.h"
#define SI7020_ADDRESS 0x40 //SI7020器件地址
#define SI7020_WEITE 0X80 //7位地址+1bit寫地址
#define SI7020_READ 0X81 //7位地址+1bit讀地址
//---- Measure---
#define SI7020_Humidity_Hold_Master_Mode 0xE5
#define SI7020_Humidity_No_Hold_Master_Mode 0xF5
#define SI7020_Temperature_Hold_Master_Mode 0xE3
#define SI7020_Temperature_No_Hold_Master_Mode 0xF3
//****************
#define SI7020_SOFT_RESET 0xFE
void SI7020_Init(void); //初始化IIC
uint16_t SI7020_ReadOneByte(uint8_t ReadAddr); //讀取暫存器的數值
int16_t SI7020_Read_Humidity(void); //取出濕度值
int16_t SI7020_Read_Temperture(void); //取出溫度值
uint8_t SI7020_WaitStandby(void); //等待I2C總線空閒
#endif /*__BSP_I2C_si7020_H*/
以上是一些定義下面是函示的宣告SI7020_ReadOneByte這個示讀暫存器裡的數值,下面那兩個個別的取出濕度和溫度的函示裡面來使用 SI7020_ReadOneByte
接下來我會分段講
#include "bsp_I2C_si7020.h"
#include "bsp_SysTick.h"
void SI7020_Init(void) //初始化si7020******
{
//初始化GPIO_IIC ******
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(i2c_GPIO_CLK, ENABLE); /* 打開GPIO時鐘 */
GPIO_InitStructure.GPIO_Pin = i2c_SCL_PIN | i2c_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /* 開漏輸出 */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(i2c_GPIO_PORT, &GPIO_InitStructure);
/* 給一個停止信號, 重定I2C匯流排上的所有設備到待機模式 */
i2c_Stop();
}
因為我是GPIO口的方式來完成讀寫,所以會初始化這些兩個IO口 i2c_SCL_PIN | i2c_SDA_PIN
//在SI7020指定地址讀出一个数据
//ReadAddr:讀取温度或濕度_暫存器位置
//return value:讀到的數據
uint16_t SI7020_ReadOneByte(uint8_t ReadAddr)
{
uint8_t temp[2];
uint16_t value=0;
i2c_Start();
i2c_SendByte(SI7020_WEITE);
i2c_WaitAck();
i2c_SendByte(ReadAddr);
i2c_WaitAck();
delay_ms(20);
i2c_Start();
i2c_SendByte(SI7020_READ);
i2c_WaitAck();
delay_ms(20);
// i2c_Start(); //********************************************
// i2c_SendByte(SI7020_READ); //使用No Hold Master Mode多使用此3行程序
// i2c_WaitAck(); //********************************************
temp[1]=i2c_ReadByte();
i2c_Ack();
temp[0]=i2c_ReadByte();
i2c_NAck();
i2c_Stop();
value=temp[0]|(temp[1]<<8);
return value;
}
這是讀取數值的部分,再來看手冊說明的部分
不管讀溫度還是濕度的有兩種模式,保持跟部保持數據,程式碼沒甚麼大差別,我程式碼有註解上去
白色為主機端,灰色為從機端
//Humidity 讀取濕度
//return 返回濕度
int16_t SI7020_Read_Humidity(void)
{
uint16_t value=0;
double temp;
value=SI7020_ReadOneByte(SI7020_Humidity_Hold_Master_Mode);
temp=(double)value;
temp=(temp/65536.0f)*125.0f-6.0f;
printf("%.1lf %%RH\r\n",(temp-5)); //
return (int16_t)(temp*10); //返回Humidity,此處放大了10倍
}
//Temperture_讀取溫度
//return _返回溫度
int16_t SI7020_Read_Temperture(void)
{
uint16_t value=0;
double temp;
value=SI7020_ReadOneByte(SI7020_Temperature_Hold_Master_Mode);
temp=(double)value;
temp=(temp/65536.0f) * 175.72f - 46.85f;
printf("%.1lf C\r\n",(temp-2)); //-2 校正誤差
return (int16_t)(temp*10); //返回温度值,此处放大了10倍
}
uint8_t SI7020_WaitStandby(void)
{
uint32_t wait_count = 0;
while(i2c_CheckDevice(SI7020_WEITE))
{
//若檢測超過次數,退出循環
if(wait_count++>0x0FFFF)
{
return 1;//等待超時
}
}
return 0;//等待完成
}
我讀取溫度和濕度分開寫了,可以看到中間有個計算,是根據手冊上的說明去計算
再來是main.c的部份
#include "bsp_I2C_si7020.h"
#include "bsp_SysTick.h"
int main(void)
{
SysTick_Init(48); //初始化M0內核計時器
SI7020_Init(); //SI7020_GPIO初始化
DEBUG_USART_Config(); //UARTt初始化
while(1)
{
SI7020_WaitSdby(); //確定I2C BUS可否使用
delay_ms(10);
SI7020_Read_Humidity(); //抓取濕度後,列印濕度
SI7020_Read_Temperture(); //抓取溫度後,列印溫度
delay_ms(500);
}
}
這些都是要花時間看的,我當初學這些也花了不少時間,了解這I2C時序運作方式後讓我會看任何手冊的數位訊號的時序會更快進入狀況,遇到其他協定也大概都知道如何看。