STM8 模拟iic接口调试温湿度传感器SHT3x驱动

背景

项目实际使用SHT3x进行温湿度测量,主控芯片采用STM8S003F3P6,并且使用模拟IIC接口的硬件连接。

原理图

 如下图所示,使用STM8S003F3P6管脚PB4/PB5进行SHT3x数据接口

SHT3x-DIS是Sensirion新一代的温湿度传感器,精度为±2%RH和±0.3℃,输入电压范围从2.4V到5.5V,采用IIC总线接口,速率可达1MHz。测量温湿度范围分别为是-40℃ ~ 125℃和0 ~ 100%。

从下图可以看到SHT3x内部集成了湿度传感器和温度传感器,通过ADC采样输入到数据处理和线性化单元,同时带有校正储存器,处理环境对器件测量的影响。通过数字接口IIC读取数据。带警报引脚,可通过修改寄存器的值设定阈值,当测量的温湿度超过阈值时它会被置位。

软件设计

STM8S003F3P6基本配置如下

时钟配置,这里必须要提一下时钟配置,如果不提时钟配置,对SHT3x模拟IIC接口的时序延时

就不好判定


/************************************************
函数名称 : CLK_Configuration
功    能 : 时钟配置
参    数 : 无
返 回 值 : 无
作    者 : strongerHuang
*************************************************/
void CLK_Configuration(void)
{
/*
  ErrorStatus clk_return_status;
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); //HSI = 16M (8分频)=2MHZ
  
  //切换内部低速时钟128khz
  clk_return_status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_LSI, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
  if (clk_return_status == SUCCESS)  //SUCCESS or ERROR
  {
                              
    CLK_ClockSwitchCmd(ENABLE);
    CLK_LSICmd(ENABLE);
    CLK_ClockSwitchCmd(DISABLE);                              
  }*/
 // CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //HSI = 16M (1分频)
  //ErrorStatus clk_return_status;
  
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //HSI = 16M (8分频)=2MHZ
 /* 
  //切换内部低速时钟8M
  clk_return_status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
  if (clk_return_status == SUCCESS)  //SUCCESS or ERROR
  {
                              
    CLK_ClockSwitchCmd(ENABLE);
    CLK_HSECmd(ENABLE);
    CLK_ClockSwitchCmd(DISABLE);                              
  }*/
    
    CLK_DeInit();//设置为默认值
    CLK_HSICmd(ENABLE);//启用HSI
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//HSI分频
    CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);//CPU分频

}

使用IIC管脚PB4/PB5的管脚操作宏定义如下

#define         SHT30_SCL      (0x01<<4)
#define         SHT30_SDA      (0x01<<5)

#define SHT30_SCL0_O    GPIOB->DDR    |=  SHT30_SCL;  GPIOB->CR1 |= SHT30_SCL            //GPIOB4 推免输出
#define SHT30_SCL0_H    GPIOB->ODR    |=  SHT30_SCL
#define SHT30_SCL0_L    GPIOB->ODR    &=  ~SHT30_SCL

#define SHT30_SCL0_I    GPIOB->DDR    &=  ~SHT30_SCL;  GPIOB->CR1 &= ~SHT30_SCL          //GPIOB4 浮空输入
#define SHT30_SCL0_DAT  ( (GPIOB->IDR>>4) & 0x01)

#define SHT30_SDA0_O    GPIOB->DDR    |=  SHT30_SDA;  GPIOB->CR1 |= SHT30_SDA            //GPIOB5 推挽输出
#define SHT30_SDA0_H    GPIOB->ODR    |=  SHT30_SDA
#define SHT30_SDA0_L    GPIOB->ODR    &=  ~SHT30_SDA

#define SHT30_SDA0_I    GPIOB->DDR    &=  ~SHT30_SDA;  GPIOB->CR1 &= ~SHT30_SDA          //GPIOB5 浮空输入
#define SHT30_SDA0_DAT  ( (GPIOB->IDR>>5) & 0x01)

#define	SHT30_SlaveAddress	  		(0x44<<1)					//7位地址0x44 左移1位 0x45 -- 0x8A

#define noACK 0                                 //用于判断是否结束通讯 
#define ACK   1                                 //结束数据传输 

在main函数开始前,需要对使用的管脚进行初始化配置如下

配置PB4/PB5初始化为输出

uint8 SHT30_Init(vid)
{
	uint8 	vRval = 0x00;
  
  SHT30_SCL0_O;                          	//设置SCLK为输出
  SHT30_SDA0_O;                          	//设置SDA为输出
	
	SHT30_SCL0_H;
	SHT30_SCL0_L;
	
	SHT30_SDA0_H;
	SHT30_SDA0_L;
	
	vRval += SHT30_Soft_Reset();
	
	
	
	
	SHT30_DelayMs(1);
	
	vRval += SHT30_ClearStaus();
	
	SHT30_DelayMs(1);
	
	//SHT30_Periodic_Measure(SHT30_PERIODOC_H_MEASURE_1S);
  
	return vRval;
}

单次获取数据指令
单次获取数据指令(Measurement Commands for Single Shot Data Acquisition Mode)的详细数据格式如下图。首先从表格最上面开始,Repeatability指的是重复性(重复性越高精度越高,可参考手册的Sensor Performance部分),Clock Stretching指的是时钟延伸,它们的作用下面再讲述。数据流动过程如下。

发送起始信号以及由高7位的器件地址和最低位的写信号(WR=0) 组成的一字节地址,等待应答信号。(注意地址位于高7位,所以传址的时候需要将地址左移一位并加上读1/写0信号,ADDR<<1 | WR);
发送指令的高字节(Most Significant Byte,MSB)并等待应答信号;
发送指令的低字节(Least Significant Byte,LSB)并等待应答信号,之后发送停止信号;
等待一段时间(测量正在进行);
发送起始信号以及由高7位的器件地址和最低位的读信号(RD=1) 组成的一字节地址,然后根据选择的Clock Stretching从两个方向选择。假如失能了时钟延长功能,则等待非应答信号,发送停止信号,延迟一段时间(这步很重要!!延迟时间大约为50ms左右)等待转换结束,然后发送八位的应答信号并等待应答信号,之后便是逐字节分别读取温度和湿度的高字节、低字节以及CRC校验字节,每字节接收完都要发送应答信号,最后发送停止信号即可。而如果使能了是时钟延长功能,则总线的SCL由SHT3x控制,我们只需要通过while(SCL==0)阻塞程序,等待其释放总线然后MCU读取数据即可;

针对SHT3x的一些时序函数如下

/*---------------------------------------------------------------------
 功能描述: SHT30 测量结果计算
 参数说明:  vTemSymbol [out] - 返回温度符号
						vTem [out] - 温度
						vHum [out] - 湿度

 函数返回: 无
 ---------------------------------------------------------------------*/
uint8 SHT30_Get_TH(uint8 *vTemSymbol, uint16 *vTem, uint16 *vHum)
{
	uint8 vDat[8];
	uint8 vRval = 0;
	
	vRval = SHT30_Single_Measure(vDat);
	if (!vRval) SHT30_calc(vDat, vTemSymbol, vTem, vHum);
	
	return vRval;
}

/*---------------------------------------------------------------------
 功能描述: SHT30单次测量
 参数说明: vBuf [out] - 测量读取结果
 函数返回: 0 - 成功  大于1出错
 ---------------------------------------------------------------------*/
uint8 SHT30_Single_Measure(uint8 *vBuf)
{
	uint8 vRval = 0;
	uint8 i = 0;
	
	SHT30_Start();
	
	vRval |= SHT30_SendByte(SHT30_SlaveAddress+0);					//地址写
	if (!vRval) vRval |= SHT30_SendByte( (SHT30_SINGLE_H_MEASURE_EN>>8)&0xFF );				//使能高精度采集
	if (!vRval) vRval |= SHT30_SendByte( (SHT30_SINGLE_H_MEASURE_EN)&0xFF );
	SHT30_Stop();
	
	if (vRval)	return vRval;
	
	SHT30_SCL0_H;
	SHT30_DelayMs(15);														//15Ms
	
	
	SHT30_Start();
	if (!vRval) vRval |= SHT30_SendByte(SHT30_SlaveAddress+1);					//地址读
	
	if (vRval)	return vRval;
	
	for(i=0; i<6; i++)
	{
		vBuf[i] = SHT30_RecvByte();                	//存储数据
    if (i == 0x06)
    {
      
      SHT30_SendACK(1);                         //最后一个数据需要回NOACK
    }
    else
    {		
      SHT30_SendACK(0);                         //回应ACK
    }
	}
	
	SHT30_Stop();
	
	return vRval;
}

/*---------------------------------------------------------------------
 功能描述: SHT30 测量结果计算
 参数说明:  vBuf [in] - 测量读取结果
						vTemSymbol [out] - 返回温度符号
						vTem [out] - 温度
						vHum [out] - 湿度

 函数返回: 无
 ---------------------------------------------------------------------*/
void SHT30_calc(uint8 *vBuf, uint8 *vTemSymbol, uint16 *vTem, uint16 *vHum)
{
	uint16 	vVal = 0x00;
	uint8 	vCrc = 0x00;
	float		vTemp = 0.00;
	
	//温度
	vCrc = SHT30_CheckCrc8(vBuf, 2);
	if (vCrc == vBuf[2])
	{
		vVal = vBuf[0];
		vVal<<=8;
		vVal |= vBuf[1];
		
		vTemp = 175.0*vVal/(65536.0-1.0);
		
		if (vTemp >= 45)
		{
			*vTemSymbol = 1;
			*vTem = (uint16)((vTemp - 45.0)*10.0);
		}
		else
		{
			*vTemSymbol = 0;
			*vTem = (uint16)((45.0 - vTemp)*10.0);
		}
		
	}
	
	vBuf += 3;
	vVal = 0x00;
	vCrc = SHT30_CheckCrc8(vBuf, 2);
	if (vCrc == vBuf[2])
	{
		vVal = vBuf[0];
		vVal<<=8;
		vVal |= vBuf[1];
		
		vTemp = 100.0*vVal/(65536.0-1.0);
		*vHum = (uint16)(vTemp*10);
	}
}

猜你喜欢

转载自blog.csdn.net/li171049/article/details/130854531