STM32 采集SHT10传感器数据(非float)

本来想在网上直接load一个sht10驱动就直接能用用了,没想到太天真了。

非但没有stm32L0cube这个库的程序而且大部分还是使用浮点运算的,你妹的,stm32好多都是不支持浮点运算的呀。所以只好自己搞了。

以下为sth10常规的时序,抠出来的没啥好说

  1、接口定义:
  SHT10的接口定义如下图所示:
                                                             
           如上图所示,1脚为GND,4脚为VDD。它的供电电压范围为2.4~5.5V,建议的电压为3.3V,在电源引脚(VDD、GND)之间必须加上一个0.1uf的电容,应于去耦滤波用。它的2脚DATA为数据引脚,3脚SCK为时钟控制引脚,没有发现这两个引脚很像IIC所使用的引脚功能?没错,这个传感器确实可以认为是IIC接口,但是又有却别。该传感器不能按照IIC的协议编址,但是,如果IIC总线上没有挂接别的元件,传感器可以直接连到IIC总线上,但是单片机必须按照传感器的协议工作。传感器与单片机的接线如下图所示:
                                    

    2、传感器的通讯
      
     2.1、“启动传输”时序
用一组“启动传输”时序来完成数据传输的初始化。它包括:当SCK时钟高电平时DATA翻转为低电平,紧接着SCK变成低电平,随后是在SCK时钟高电平,随后是在SCK时钟高电平DATA翻转位高电平。时序如下:

                       

     2.2、复位时序
如果与SHT1x 通讯中断,可通过下列信号时序复位:当DATA 保持高电平时,触发SCK 时钟9 次或更多。时序图如下:
                    
    2.3、命令集
传感器的命令包含三个地址位(目前只支持000,这就是他只能挂接在空闲的IIC总线上的原因)和五个命令位。。SHT1x 会以下述方式表示已正确地接收到指令:在第8 个SCK 时钟的下降沿之后,将DATA 下拉为低电平(ACK 位)。在第9 个SCK 时钟的下降沿之后,释放DATA(恢复高电平)。命令集如下:
                            

     2.4、温湿度测量
发布一组测量命令(‘00000101’表示相对湿度RH,‘00000011’表示温度T)后,控制器要等待测量结束。这个过程需要大约20/80/320ms,分别对应8/12/14bit 测量。确切的时间随内部晶振速度,最多可能有-30%的变化。。SHT1x 通过下拉DATA 至低电平并进入空闲模式,表示测量的结束。控制器在再次触发SCK 时钟前,必须等待这个“数据备妥”信号来读出数据。检测数据可以先被存储,这样控制器可以继续执行其它任务在需要时再读出数据。
在收到CRC 的确认位之后,表明通讯结束。如果不使用CRC-8 校验,控制器可以在测量值LSB 后,通过保持ACK高电平终止通讯。在测量和通讯完成后,SHT1x 自动转入休眠模式。

    2.5、状态寄存器
SHT1x 的某些高级功能可以通过给状态寄存器发送指令来实现,如选择测量分辨率,电量不足提醒,使用 OTP 加载或启动加热功能等。状态寄存器度、写如下:


状态寄存器写


状态寄存器读

状态寄存器的具体描述如下表所示:



测量分辨率:默认分辨率 14bit (温度) 和 12bit (湿度) 可以被降低为 12 和 8bit. 尤其适用于要求测量速度极高或者功耗极低的应用。
电量不足检测功能:在电压不足 2.47V 发出警告。精度为±0.05 V。
加热:可通过向状态寄存器内写入命令启动传感器内部加热器.。加热器可以使传感器的温度高于周围环境 5 – 10°C12 。功耗大约为 8mA @ 5V 。
OPT加载:开启此功能,标定数据将在每次测量前被上传到寄存器。如果不开启此功能,可减少大约 10ms的测量时间。
上面的寄存器如果没有什么特殊要求或应用于特定的场合,则无需配置,选择默认就可以了。

     2.6、通讯过程
传感器的通讯过程为:发送”启动传输“时序,初始化传感器——>发送命令——>等待传感器应答,及测量结束——>接收传感器的16位数据值——>接收8为的CRC校验数据——>休眠,等待下一次传输开始。
传输的过程的测量时序可以由下图示意:

  上图中 TS = 传输开始, MSB = 高有效字节,LSB =低有效字节, LSb = 低有效位。
下面举个实际测量时的相对湿度测量时序例子。时序如下:

这张图可以知道:我们接收到的数据数值为”0000 0100 0011 0001“ = 1073 = 35.50% RH (位含温度补偿),至于怎么计算的,请接着往下看。

      2.7、信号转化   
       2.7.1 温度的转化
设T 2 1 SOt为从传感器上读出来的测量数值,我们需要用下面的公式将测量数值转换成整整的温度值。
T = d1 + d2 * SOt  (其中d1,d2的值根据实际情况选择,选项如下)



      2.7.2 湿度的转换 
湿度的转换公式如下: 。其中湿度的转化参数如下选择:根据采样的精度不同而不同。

99%以上的湿度已经接近饱和必须经过处理显示100%RH13.请注意 湿度传感器对电压无依赖性。测量值与相对湿度的转化如下图所示:

  相对湿度根据上面的参数与公式算出来之后,还需要考虑当前环境温度而进行适当的补偿。补偿的公式及其参数选择如下:

头文件部分
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SHT10_H
#define __SHT10_H

/* Includes ------------------------------------------------------------------*/
#include "stm32l0xx_hal.h"
#include "stm32l0xx_nucleo.h"



#define SHT10_DATA_PIN		GPIO_PIN_6
#define SHT10_SCK_PIN		GPIO_PIN_7
#define SHT10_GPIO_PORT		GPIOA
#define DATA_PIN_HIGH()		HAL_GPIO_WritePin(SHT10_GPIO_PORT,SHT10_DATA_PIN,1)
#define DATA_PIN_LOW()		HAL_GPIO_WritePin(SHT10_GPIO_PORT,SHT10_DATA_PIN,0)
#define SCK_PIN_HIGH()		HAL_GPIO_WritePin(SHT10_GPIO_PORT,SHT10_SCK_PIN,1)
#define SCK_PIN_LOW()		HAL_GPIO_WritePin(SHT10_GPIO_PORT,SHT10_SCK_PIN,0)
#define DATA_VALUE()		HAL_GPIO_ReadPin(SHT10_GPIO_PORT,SHT10_DATA_PIN)

extern void SHT10_init(void);
extern void GetEnvInfo(uint16_t *humi_val_real,uint16_t *temp_val_real);

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */

#endif /* __MAIN_H */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/



c文件

#include "main.h"
#include "sht10.h"
typedef union 
{ 
	unsigned int i; 
	float f; 
} value; 
//----------------------------------------------------------------------------------
// modul-var 
//----------------------------------------------------------------------------------
enum {TEMP,HUMI}; 
#define noACK 0 
#define ACK 1 
//adr command r/w 
#define STATUS_REG_W 0x06 //000 0011 0 
#define STATUS_REG_R 0x07 //000 0011 1 
#define MEASURE_TEMP 0x03 //000 0001 1 
#define MEASURE_HUMI 0x05 //000 0010 1 
#define RESET 0x1e //000 1111 0 
static GPIO_InitTypeDef  GPIO_InitSckStruct;
static GPIO_InitTypeDef  GPIO_InitDataStruct;

void SHT10_Dly(void)  
{  
    uint16_t i;  
    for(i = 500; i > 0; i--);  
}  

void SHT10_DATAOut(void)  
{  
	GPIO_InitDataStruct.Mode  = GPIO_MODE_OUTPUT_PP;
	GPIO_InitDataStruct.Pull  = GPIO_PULLUP;
	GPIO_InitDataStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

	GPIO_InitDataStruct.Pin = SHT10_DATA_PIN;
	HAL_GPIO_Init(SHT10_GPIO_PORT, &GPIO_InitDataStruct);
}  
  
  
/************************************************************* 
  Function   :SHT10_DATAIn   
  Description:设置DATA引脚为输入 
  Input      : none         
  return     : none     
*************************************************************/  
void SHT10_DATAIn(void)  
{  
    //PD0 DATA 浮动输入   
	
	GPIO_InitDataStruct.Mode  = GPIO_MODE_INPUT;
	GPIO_InitDataStruct.Pull  = GPIO_NOPULL;
	GPIO_InitDataStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

	GPIO_InitDataStruct.Pin = SHT10_DATA_PIN;
	HAL_GPIO_Init(SHT10_GPIO_PORT, &GPIO_InitDataStruct);
}  
  

/************************************************************* 
  Function   :SHT10_TransStart   
  Description:开始传输信号,时序如下: 
                     _____         ________ 
               DATA:      |_______| 
                         ___     ___ 
               SCK : ___|   |___|   |______  
  Input      : none         
  return     : none     
*************************************************************/  
void SHT10_TransStart(void)  
{  
    SHT10_DATAOut();              //设置DATA数据线为输出  
  
    //SHT10_DATA_H();  
	DATA_PIN_HIGH();
    //SHT10_SCK_L();  
	SCK_PIN_LOW();
    SHT10_Dly();  
    //SHT10_SCK_H();   
	SCK_PIN_HIGH();
    SHT10_Dly();  
    //SHT10_DATA_L(); 
	DATA_PIN_LOW();  
    SHT10_Dly();  
    //SHT10_SCK_L();  
	SCK_PIN_LOW();	
    SHT10_Dly();  
    //SHT10_SCK_H();     
	SCK_PIN_HIGH();
    SHT10_Dly();  
    //SHT10_DATA_H();  
	DATA_PIN_HIGH(); 
    SHT10_Dly();  
    //SHT10_SCK_L();   
	SCK_PIN_LOW();	 
  
}  

void SHT10_ConReset(void)  
{  
    uint8_t i;  
  
    SHT10_DATAOut();  
	
  
    //SHT10_DATA_H();  
	DATA_PIN_HIGH();
    //SHT10_SCK_L();  
	SCK_PIN_LOW();
  
    for(i = 0; i < 9; i++)         //触发SCK时钟9c次  
    {  
        //SHT10_SCK_H();  
        SCK_PIN_HIGH();
        SHT10_Dly();  
        //SHT10_SCK_L();  
		SCK_PIN_LOW();
        SHT10_Dly();  
    }  
    SHT10_TransStart();           //启动传输  
}  

void SHT10_init(void)
{
	
	GPIO_InitSckStruct.Mode  = GPIO_MODE_OUTPUT_PP;
	GPIO_InitSckStruct.Pull  = GPIO_PULLUP;
	GPIO_InitSckStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

	GPIO_InitSckStruct.Pin = SHT10_SCK_PIN;
	HAL_GPIO_Init(SHT10_GPIO_PORT, &GPIO_InitSckStruct);


	GPIO_InitDataStruct.Mode  = GPIO_MODE_OUTPUT_PP;
	GPIO_InitDataStruct.Pull  = GPIO_PULLUP;
	GPIO_InitDataStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

	GPIO_InitDataStruct.Pin = SHT10_DATA_PIN;
	HAL_GPIO_Init(SHT10_GPIO_PORT, &GPIO_InitDataStruct);
	SHT10_ConReset();
}
uint8_t SHT10_WriteByte(uint8_t value)  
{  
    uint8_t i;
	uint8_t err = 0;  
      
    SHT10_DATAOut();              //设置DATA数据线为输出  
  
    for(i = 0x80; i > 0; i /= 2)  //写1个字节  
    {  
        if(i & value)  
            DATA_PIN_HIGH();  
        else  
            DATA_PIN_LOW();  
        SHT10_Dly();  
        SCK_PIN_HIGH();  
        SHT10_Dly();  
        SCK_PIN_LOW();  
        SHT10_Dly();  
    }  
    SHT10_DATAIn();               //设置DATA数据线为输入,释放DATA线  
    SCK_PIN_HIGH();  
    err = DATA_VALUE();         //读取SHT10的应答位  
    SCK_PIN_LOW();  
  
    return err;  
}  

uint8_t SHT10_ReadByte(uint8_t Ack)  
{  
    uint8_t i;
	uint8_t val = 0;  
  
    SHT10_DATAIn();               //设置DATA数据线为输入  
    for(i = 0x80; i > 0; i /= 2)  //读取1字节的数据  
    {  
        SHT10_Dly();  
        SCK_PIN_HIGH();  
        SHT10_Dly();  
        if(DATA_VALUE())  
            val = (val | i);  
        SCK_PIN_LOW();  
    }  
    SHT10_DATAOut();              //设置DATA数据线为输出  
    if(Ack)  
        DATA_PIN_LOW();           //应答,则会接下去读接下去的数据(校验数据)  
    else  
        DATA_PIN_HIGH();           //不应答,数据至此结束  
    SHT10_Dly();  
    SCK_PIN_HIGH();  
    SHT10_Dly();  
    SCK_PIN_LOW();  
    SHT10_Dly();  
  
    return val;                   //返回读到的值  
}  

uint8_t SHT10_Measure(uint16_t *p_value, uint8_t *p_checksum, uint8_t mode) 
{
	uint8_t err = 0;  
    uint32_t i;  
    uint8_t value_H = 0;  
    uint8_t value_L = 0;  
  
    SHT10_TransStart();                      //开始传输  
    switch(mode)                               
    {  
    case TEMP:                               //测量温度  
        err += SHT10_WriteByte(MEASURE_TEMP);//写MEASURE_TEMP测量温度命令  
        break;  
    case HUMI:  
        err += SHT10_WriteByte(MEASURE_HUMI);//写MEASURE_HUMI测量湿度命令  
        break;  
    default:  
        break;  
    }  
    SHT10_DATAIn();  
    for(i = 0; i < 72000000; i++)                 //等待DATA信号被拉低  
    {  
        if(DATA_VALUE() == 0) break;       //检测到DATA被拉低了,跳出循环  
    }  
    if(DATA_VALUE() == 1)                  //如果等待超时了  
        err += 1;  
	//HAL_Delay(20);
    value_H = SHT10_ReadByte(ACK);  
    value_L = SHT10_ReadByte(ACK);  
    *p_checksum = SHT10_ReadByte(noACK);     //读取校验数据  
    *p_value = (value_H << 8) | value_L;  
    return err;  
}
int getTemprature(void)
{
	uint16_t temp_val = 0;	
	uint8_t  checksum = 0;  
	SHT10_Measure(&temp_val, &checksum, TEMP);
	return (int)(temp_val/100-40);
}
int getHumidity(void)
{
	int realHumi=0;
	uint16_t humi_val = 0;	
	uint8_t  checksum = 0;  
	SHT10_Measure(&humi_val, &checksum, HUMI);
	realHumi = ((humi_val*405/10000)+(((humi_val*humi_val)*28)/1000000)-4);
	if(realHumi > 100)
	{	
		realHumi = 100;
	}
	else if(realHumi < 0)
	{
		realHumi = 0;
	}
	return realHumi;
}

#if 1
void GetEnvInfo(uint16_t *humi_val_real,uint16_t *temp_val_real)
{
	*humi_val_real = getHumidity();
	*temp_val_real = getTemprature();
	 
} 
#endif

使用的话,先调用SHT10_init,然后调用GetEnvInfo即可。我是用的是pa6,pa7作为模拟io口实际使用可任君选择。(另外说下,我是用的是STM32L0系列的库,使用的芯片是stm32L071RB)。

你可能感兴趣的:(嵌入式)