STM32F103ZE+SHT30检测环境温度与湿度(IIC模拟时序)

278 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情

一、环境介绍

工程编译软件: keil5

温湿度传感器: SHT30

MCU : STM32F103ZET6

SHT30是I2C接口的高精度温湿度传感器,应用范围较广,小米的温湿度检测智能设备也是采用SHT30,相比DHT11而言,灵敏度都好一些。 当前程序采用模块化编程,iic时序为一个模块(iic.c 和 iic.h),SHT30为一个模块(sht30.c 和 sht30.h);IIC时序采用模拟时序方式实现,IO口都采用宏定义方式,方便快速移植到其他平台使用。

二、SHT30介绍

img

img

特点:

\1. 湿度和温度传感器

\2. 完全校准、线性化和温度

\3. 补偿数字输出,宽电源电压范围,从2.4 V到5.5 V

\4. I2C接口,通信速度高达1MHz和两个用户可选地址

\5. 典型精度 +- 2%相对湿度和+- 0.3°C

\6. 启动和测量时间非常快

\7. 微型8针DFN封装

img

img

这是SHT30的* 7位*IIC设备地址:

img

三、设备运行效果

这是串口打印的数据:

img

img

img

四、设备代码

4.1 main.c

 #include "stm32f10x.h"
 #include "led.h"
 #include "delay.h"
 #include "key.h"
 #include "usart.h"
 #include "iic.h"
 #include "sht3x.h"
 ​
 int main()
 {
    float Humidity;
    float Temperature;
    USART1_Init(115200);
    USART1_Printf("设备运行正常....\r\n");
    IIC_Init(); 
    Init_SHT30();
    while(1)
    {
        //读取温湿度
        SHT3x_ReadData(&Humidity,&Temperature);
        USART1_Printf("温度:%0.2f,湿度:%0.2f\r\n",Temperature,Humidity);
        delay_ms(1000);
    }
 }

4.2 sht30.c

 #include "sht3x.h"
 ​
 const int16_t POLYNOMIAL = 0x131;
 ​
 /***************************************************************
 * 函数名称: SHT30_reset
 * 说    明: SHT30复位
 * 参    数: 无
 * 返 回 值: 无
 ***************************************************************/
 void SHT30_reset(void)
 {
     u8 r_s;
     
     IIC_Start(); //发送起始信号
     
     IIC_WriteOneByteData(SHT30_AddrW); //写设备地址
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:1\r\n");
 ​
     IIC_WriteOneByteData(0x30); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:2\r\n");
     
     IIC_WriteOneByteData(0xA2); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:3\r\n");
     
     IIC_Stop(); //停止信号 
 ​
     delay_ms(50);    
 }
 ​
 ​
 /***************************************************************
 * 函数名称: Init_SHT30
 * 说    明: 初始化SHT30,设置测量周期
 * 参    数: 无
 * 返 回 值: 无
 ***************************************************************/
 void Init_SHT30(void)
 {
      u8 r_s;
     
     IIC_Start(); //发送起始信号
     
     IIC_WriteOneByteData(SHT30_AddrW); //写设备地址
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:1\r\n");
 ​
     IIC_WriteOneByteData(0x22); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:2\r\n");
     
     IIC_WriteOneByteData(0x36); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("Init_SHT30_error:3\r\n");
     
     IIC_Stop(); //停止信号  
     
     delay_ms(200);
 }
 ​
 ​
 /***************************************************************
 * 函数名称: SHT3x_CheckCrc
 * 说    明: 检查数据正确性
 * 参    数: data:读取到的数据
                         nbrOfBytes:需要校验的数量
                         checksum:读取到的校对比验值
 * 返 回 值: 校验结果,0-成功      1-失败
 ***************************************************************/
 u8 SHT3x_CheckCrc(char data[], char nbrOfBytes, char checksum)
 {
     
     char crc = 0xFF;
     char bit = 0;
     char byteCtr ;
     
     //calculates 8-Bit checksum with given polynomial
     for(byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
     {
         crc ^= (data[byteCtr]);
         for ( bit = 8; bit > 0; --bit)
         {
             if (crc & 0x80) crc = (crc << 1) ^ POLYNOMIAL;
             else crc = (crc << 1);
         }
     }
     
     if(crc != checksum)
         return 1;
     else
         return 0;
     
 }
 ​
 /***************************************************************
 * 函数名称: SHT3x_CalcTemperatureC
 * 说    明: 温度计算
 * 参    数: u16sT:读取到的温度原始数据
 * 返 回 值: 计算后的温度数据
 ***************************************************************/
 float SHT3x_CalcTemperatureC(unsigned short u16sT)
 {
     
     float temperatureC = 0;            // variable for result
 ​
     u16sT &= ~0x0003;           // clear bits [1..0] (status bits)
     //-- calculate temperature [℃] --
     temperatureC = (175 * (float)u16sT / 65535 - 45); //T = -45 + 175 * rawValue / (2^16-1)
     
     return temperatureC;
     
 }
 ​
 /***************************************************************
 * 函数名称: SHT3x_CalcRH
 * 说    明: 湿度计算
 * 参    数: u16sRH:读取到的湿度原始数据
 * 返 回 值: 计算后的湿度数据
 ***************************************************************/
 float SHT3x_CalcRH(unsigned short u16sRH)
 {
     
     float humidityRH = 0;              // variable for result
     
     u16sRH &= ~0x0003;          // clear bits [1..0] (status bits)
     //-- calculate relative humidity [%RH] --
     humidityRH = (100 * (float)u16sRH / 65535);  // RH = rawValue / (2^16-1) * 10
     
     return humidityRH;
     
 }
 ​
 ​
 //读取温湿度数据
 void SHT3x_ReadData(float *Humidity,float *Temperature)
 {
     char  data[3];    //data array for checksum verification
     u8 SHT3X_Data_Buffer[6];                                                                        //byte 0,1 is temperature byte 4,5 is humidity
     u8 r_s=0;
     u8 i;
     unsigned short tmp = 0;
     uint16_t dat;
     
     IIC_Start(); //发送起始信号
     
     IIC_WriteOneByteData(SHT30_AddrW); //写设备地址
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("SHT3X_error:1\r\n");
 ​
     IIC_WriteOneByteData(0xE0); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("SHT3X_error:2\r\n");
     
     IIC_WriteOneByteData(0x00); //写数据
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("SHT3X_error:3\r\n");
     
     //IIC_Stop(); //停止信号 
     
    // DelayMs(30); //等待
     
     //读取sht30传感器数据
     IIC_Start(); //发送起始信号
     IIC_WriteOneByteData(SHT30_AddrR);
     r_s=IIC_GetACK();//获取应答
     if(r_s)printf("SHT3X_error:7\r\n");
     
     for(i=0;i<6;i++)
     {
         SHT3X_Data_Buffer[i]=IIC_ReadOneByteData(); //接收数据
         if(i==5)
         {
              IIC_SendACK(1); //发送非应答信号
             break;
         }
         IIC_SendACK(0); //发送应答信号
     }
     IIC_Stop(); //停止信号
     
     //    /* check tem */
     data[0] = SHT3X_Data_Buffer[0];
     data[1] = SHT3X_Data_Buffer[1];
     data[2] = SHT3X_Data_Buffer[2];
 ​
     tmp=SHT3x_CheckCrc(data, 2, data[2]);
     if( !tmp ) /* value is ture */
     {
         dat = ((uint16_t)data[0] << 8) | data[1];
         *Temperature = SHT3x_CalcTemperatureC( dat );    
     }
 ​
     //    /* check humidity */
     data[0] = SHT3X_Data_Buffer[3];
     data[1] = SHT3X_Data_Buffer[4];
     data[2] = SHT3X_Data_Buffer[5];
 ​
     tmp=SHT3x_CheckCrc(data, 2, data[2]);
     if( !tmp ) /* value is ture */
     {
         dat = ((uint16_t)data[0] << 8) | data[1];
         *Humidity = SHT3x_CalcRH( dat );    
     }
 }

4.3 iic.c

 #include "iic.h"
 ​
 /*
 函数功能:IIC接口初始化
 硬件连接:
 SDA:PB7
 SCL:PB6
 */
 void IIC_Init(void)
 {
     RCC->APB2ENR|=1<<3;//PB
     GPIOB->CRL&=0x00FFFFFF;
     GPIOB->CRL|=0x33000000;
     GPIOB->ODR|=0x3<<6;
 }
 ​
 /*
 函数功能:IIC总线起始信号
 */
 void IIC_Start(void)
 {
     IIC_SDA_OUTMODE(); //初始化SDA为输出模式
     IIC_SDA_OUT=1;       //数据线拉高
     IIC_SCL=1;           //时钟线拉高
     DelayUs(4);        //电平保持时间
     IIC_SDA_OUT=0;       //数据线拉低
     DelayUs(4);        //电平保持时间
     IIC_SCL=0;           //时钟线拉低
 }
 ​
 ​
 /*
 函数功能:IIC总线停止信号
 */
 void IIC_Stop(void)
 {
         IIC_SDA_OUTMODE(); //初始化SDA为输出模式
         IIC_SDA_OUT=0;       //数据线拉低
         IIC_SCL=0;           //时钟线拉低
         DelayUs(4);        //电平保持时间
         IIC_SCL=1;           //时钟线拉高
         DelayUs(4);        //电平保持时间
         IIC_SDA_OUT=1;       //数据线拉高
 }
 ​
 /*
 函数功能:获取应答信号
 返 回 值:1表示失败,0表示成功
 */
 u8 IIC_GetACK(void)
 {
         u8 cnt=0;
         IIC_SDA_INPUTMODE();//初始化SDA为输入模式
         IIC_SDA_OUT=1;        //数据线上拉
       DelayUs(2);         //电平保持时间
         IIC_SCL=0;            //时钟线拉低,告诉从机,主机需要数据
         DelayUs(2);         //电平保持时间,等待从机发送数据
       IIC_SCL=1;              //时钟线拉高,告诉从机,主机现在开始读取数据
         while(IIC_SDA_IN)   //等待从机应答信号
         {
                 cnt++;
                 if(cnt>250)return 1;
         }
         IIC_SCL=0;            //时钟线拉低,告诉从机,主机需要数据
         return 0;
 }
 ​
 /*
 函数功能:主机向从机发送应答信号
 函数形参:0表示应答,1表示非应答
 */
 void IIC_SendACK(u8 stat)
 {
         IIC_SDA_OUTMODE(); //初始化SDA为输出模式
         IIC_SCL=0;           //时钟线拉低,告诉从机,主机需要发送数据
         if(stat)IIC_SDA_OUT=1; //数据线拉高,发送非应答信号
         else IIC_SDA_OUT=0;      //数据线拉低,发送应答信号
         DelayUs(2);            //电平保持时间,等待时钟线稳定
         IIC_SCL=1;               //时钟线拉高,告诉从机,主机数据发送完毕
         DelayUs(2);            //电平保持时间,等待从机接收数据
         IIC_SCL=0;               //时钟线拉低,告诉从机,主机需要数据
 }
 ​
 ​
 /*
 函数功能:IIC发送1个字节数据
 函数形参:将要发送的数据
 */
 void IIC_WriteOneByteData(u8 data)
 {
         u8 i;
         IIC_SDA_OUTMODE(); //初始化SDA为输出模式
         IIC_SCL=0;           //时钟线拉低,告诉从机,主机需要发送数据
         for(i=0;i<8;i++)
         {
                 if(data&0x80)IIC_SDA_OUT=1; //数据线拉高,发送1
                 else IIC_SDA_OUT=0;      //数据线拉低,发送0
                 IIC_SCL=1;               //时钟线拉高,告诉从机,主机数据发送完毕
                 DelayUs(2);            //电平保持时间,等待从机接收数据
                 IIC_SCL=0;                   //时钟线拉低,告诉从机,主机需要发送数据
                 DelayUs(2);            //电平保持时间,等待时钟线稳定
                 data<<=1;              //先发高位
         }
 }
 ​
 ​
 /*
 函数功能:IIC接收1个字节数据
 返 回 值:收到的数据
 */
 u8 IIC_ReadOneByteData(void)
 {
         u8 i,data;
         IIC_SDA_INPUTMODE();//初始化SDA为输入模式
       for(i=0;i<8;i++)
       {
                 IIC_SCL=0;            //时钟线拉低,告诉从机,主机需要数据
                 DelayUs(2);         //电平保持时间,等待从机发送数据
                 IIC_SCL=1;            //时钟线拉高,告诉从机,主机现在正在读取数据
                 data<<=1;           
                 if(IIC_SDA_IN)data|=0x01;
                 DelayUs(2);         //电平保持时间,等待时钟线稳定
       }
         IIC_SCL=0;                  //时钟线拉低,告诉从机,主机需要数据 (必须拉低,否则将会识别为停止信号)
         return data;
 }