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

一、环境介绍

工程编译软件:  keil5

温湿度传感器: SHT30

MCU : STM32F103ZET6

程序采用模块化编程,iic时序为一个模块(iic.c 和 iic.h),SHT30为一个模块(sht30.c 和 sht30.h);IIC时序采用模拟时序方式实现,IO口都采用宏定义方式,方便快速移植到其他平台使用。

工程源码完整下载地址: https://download.csdn.net/download/xiaolong1126626497/18973724

二、SHT30介绍

特点:

1. 湿度和温度传感器
2. 完全校准、线性化和温度
3. 补偿数字输出,宽电源电压范围,从2.4 V到5.5 V
4. I2C接口,通信速度高达1MHz和两个用户可选地址
5. 典型精度 +- 2%相对湿度和+- 0.3°C
6. 启动和测量时间非常快
7. 微型8针DFN封装

  

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

 

三、设备运行效果

这是串口打印的数据:

 

 四、设备代码

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;
}


 

相关推荐
sht30的基于c51单片机驱动程序:#include <intrins.h> #include <reg51.h> #include "I2C.h" #include "SHT30.h" #define uint unsigned int #define uchar unsigned char void display(); unsigned char code tableduan[]= { 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71 }; uchar data DIS_ROME[6]= {0,0,0,0,0,0}; //显示缓存区(4) uchar DISP=0;//缓存区指针 uchar SCANF=0xDF;//扫描指针 sbit LED1=P1^0; sbit LED2=P1^1; sbit LED3=P1^2; sbit LED4=P1^3; sbit VOC_A=P3^5; sbit VOC_B=P3^6; sbit dula=P2^6; //IO口定义 sbit wela=P2^7; sbit key=P3^4; sbit beep_dr=P2^3; uint pm1 = 0; uint pm2 = 0; uint pm10 = 0; uchar vr=0; uint intrcnt=0; bit F_1HZ; uint voice_time_cnt; uchar Uart_Buf; uchar Rec_Addr=0; uchar mode=0; uchar Rec_Uart=0; uchar Recive_Buf[30]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; #define key P34 #define const_key_time1 50 unsigned char ucKeySec=0; //被触发的按键编号 unsigned int uiKeyTimeCnt1=0; //按键去抖动延时计数器 unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志 unsigned char displaycnt=0; void keyscan() { if(key==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位 { ucKeyLock1=0; //按键自锁标志清零 uiKeyTimeCnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。 } else if(ucKeyLock1==0)//有按键按下,且是第一次被按下 { uiKeyTimeCnt1++; //累加定时中断次数 if(uiKeyTimeCnt1>const_key_time1) { uiKeyTimeCnt1=0; ucKeyLock1=1; //自锁按键置位,避免一直触发 ucKeySec=1; //触发1号键 } } } void keyservice() { if(ucKeySec) { displaycnt=!displaycnt; } ucKeySec=0; } void UartInit(void) //9600bps@12.000MHz { TMOD=0x01; //设置定时器0为工作方式1 TH0=0xf8; //重装初始值(65535-500)=65035=0xfe0b TL0=0x2f; SCON=0x50; TMOD=0X21; IP =0x10; //把串口中断设置为最高优先级, EA=1; ES=1; ET0=1; TR0=1; } void T0_time(void) interrupt 1 //定时中断 { TF0=0; //清除中断标志 TR0=0; //关中断 keyscan(); keyservice(); display(); if(++intrcnt==1000) { intrcnt=0; } TH0=0xf8; TL0=0x2f; TR0=1; //开中断 } void display() //LED扫描 { if(displaycnt==1) { DIS_ROME[0]=0; DIS_ROME[1]=Hum_num[4]; DIS_ROME[2]=Hum_num[3]; DIS_ROME[3]=Hum_num[2]; DIS_ROME[4]=Hum_num[1]; DIS_ROME[5]=Hum_num[0]; } else { DIS_ROME[0]=0; DIS_ROME[1]=TEMP_num[4]; DIS_ROME[2]=TEMP_num[3]; DIS_ROME[3]=TEMP_num[2]; DIS_ROME[4]=TEMP_num[1]; DIS_ROME[5]=TEMP_num[0]; } wela=1; P0=SCANF; wela=0; dula=1; P0=tableduan[DIS_ROME[DISP]];//数据端口送数据 dula=0; DISP++;//缓存指针加1 SCANF=_cror_(SCANF,1);//扫描切换 if(DISP==7)//缓存指针到尾 { DISP=0;//计数归零 SCANF=0xDF;//扫完四个数码管,扫描复位 } // delay(5); } void main(void) //主函数 { UartInit(); I2C_inita(); while(1) { Getdat_SHT30(); SHT30_DATEChange(); } }
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:马嘣嘣 返回首页