ESP32 C3 SHT40温湿度传感器_驱动源码 基于Arduino_软件I2C方式实现

1 篇文章 0 订阅
1 篇文章 0 订阅

简介:

SHT40是一款高性能的温湿度芯片,由业内知名的Sensirion公司推出,属于其第四代数字温湿度传感器系列1。这款芯片在测量范围内能够提供始终如一的高精确度,具有多种显著的优点和特性。

首先,SHT40在精度和稳定性方面表现出色。其温度精度可达±0.2°C(典型值),湿度精度可达±1.8%RH(典型值),相较于其前代产品SHT20有了进一步的提升2。同时,它还具有更好的长期稳定性,这主要得益于其内部增加的自校准功能,能够有效地补偿传感器老化和温度漂移1。

其次,SHT40在灵敏度和响应速度上也进行了优化,尤其在湿度测量方面,其响应时间更快,能够更迅速地捕捉到环境变化2。这种特性使其在需要快速响应的应用场景中非常适用。

此外,SHT40在集成度和功耗控制方面也进行了改进。它在继承了SHT20低功耗和紧凑封装的基础上,进一步优化了功耗控制,更适合于低功耗应用,如物联网(IoT)设备和能源敏感的系统2。其电源电压范围从1.08 V扩展到3.6 V,非常适合移动和电池驱动应用34。

SHT40还增强了抗干扰能力,能够更好地抵抗电磁干扰(EMI)和其他环境因素的影响,确保在复杂环境中也能提供可靠的测量结果1。

在应用方面,SHT40因其高精度、低功耗和快速响应等特性,被广泛应用于智能楼宇、天气站、仓库存储、养殖、孵化等场景1。同时,其坚固的DFN外壳和异常小的尺寸使得它易于集成到各种具有挑战性的设计中,同时满足最高的可靠性要求4。

SHT40是一款高性能、高精度、低功耗的温湿度芯片,适用于各种需要高精度测量的应用场景。

接下来看看如何实现驱动,以下提供了完整的全部代码以及原理图

温湿度传感器数据手册:

sht40数据手册.pdf

原理图:

I2C读写时序(此图是SHT30的仅供参考):

相关命令:

原理图以及伪代码驱动:

程序:

配置为开漏输出

IO6--SDA   

IO7--SCL

 器件地址     0x44

ADDR引脚连接到 VDD   地址为0x45

ADDR引脚连接到VSS   地址为0x44

驱动代码:

#define  slave_addr 0x44       //从机地址 
#define IIC_SDA 6
#define IIC_SCL 7


const int buttonPin = 1;  // the number of the pushbutton pin
const int I2C_SDA = 6;
const int I2C_SCL = 7;

//****************************************************************************** 
//功能:   延时函数,当ms=1时, 
//         延时为1毫秒(@12MHz) 
//入口:   ms 
//出口:无 
//****************************************************************************** 
void DelayMs(uint ms) 
{ 
     delay(ms);
} 

//******************************************************************************
//功能:    延时函数 延时微妙
//入口:   j 
//出口:无 
//****************************************************************************** 
void DelayUs(unsigned int j)     
{ 
    delayMicroseconds(j);
} 

/*-------------------------------------------------
* 函数名:IIC_Start
* 功能:  产生IIC起始信号
* 输入:  无
* 输出:  无
 --------------------------------------------------*/
void IIC_Start(void)
{
	pinMode(I2C_SDA,OUTPUT);              //SDA线输出
	digitalWrite(IIC_SDA,HIGH);	  	  
	digitalWrite(IIC_SCL,HIGH);
	DelayUs(10);
 	digitalWrite(IIC_SDA,LOW);            //起始信号:当SCL为高电平时,SDA由高电平跳变为低电平
	DelayUs(10);
	digitalWrite(IIC_SCL,LOW);            //钳住I2C总线,准备发送或接收数据 
  DelayUs(10);
}	  
/*-------------------------------------------------
* 函数名:IIC_Stop
* 功能:  产生IIC停止信号
* 输入:  无
* 输出:  无
 --------------------------------------------------*/
 void IIC_Stop(void)
{
	pinMode(I2C_SDA,OUTPUT);  ;              //SDA线输出
	digitalWrite(IIC_SCL,LOW);
	digitalWrite(IIC_SDA,LOW);            //终止信号:当SCL为高电平时,SDA有低电平跳变到高电平
 	DelayUs(10);
	digitalWrite(IIC_SCL,HIGH);
  DelayUs(10); 
	digitalWrite(IIC_SDA,HIGH);            //发送I2C总线结束信号
	DelayUs(10);							   	
}
/*-------------------------------------------------
* 函数名:IIC_Wait_Ack
* 功能:  等待应答信号到来
* 输入:  无
* 输出:  返回值:1,接收应答失败
*                 0,接收应答成功
 --------------------------------------------------*/
unsigned char IIC_Wait_Ack(void)
{
	unsigned char ucErrTime=0;      
  
	pinMode(I2C_SDA,INPUT);               //SDA设置为输入  
	digitalWrite(IIC_SDA,HIGH);
	DelayUs(5);	   
	digitalWrite(IIC_SCL,HIGH);
	DelayUs(5);	 
	while(digitalRead(I2C_SDA)==HIGH)
	{
		ucErrTime++;
		if(ucErrTime>250) //等待超时
		{
			IIC_Stop();
			return 1;
		}
	}
	digitalWrite(IIC_SCL,LOW);            //时钟输出0 	   
	return 0;  
} 
/*-------------------------------------------------
* 函数名:IIC_Ack
* 功能:  产生ACK应答
* 输入:  无
* 输出:  无
 --------------------------------------------------*/
void IIC_Ack(void)
{
	digitalWrite(IIC_SCL,LOW);
	pinMode(I2C_SDA,OUTPUT);  ;              //SDA线输出
	digitalWrite(IIC_SDA,LOW);
	DelayUs(5);	
	digitalWrite(IIC_SCL,HIGH);
	DelayUs(5);	
	digitalWrite(IIC_SCL,LOW);
  //digitalWrite(IIC_SDA,HIGH);              //释放总线,修复湿度和精度问题
}
/*-------------------------------------------------
* 函数名:IIC_NAck
* 功能:  不产生ACK应答
* 输入:  无
* 输出:  无
 --------------------------------------------------*/	    
void IIC_NAck(void)
{
	digitalWrite(IIC_SCL,LOW);
	pinMode(I2C_SDA,OUTPUT);  ;              //SDA线输出
	digitalWrite(IIC_SDA,HIGH);
	DelayUs(5);	
	digitalWrite(IIC_SCL,HIGH);
	DelayUs(5);	
	digitalWrite(IIC_SCL,LOW);
}					 				     
/*-------------------------------------------------
* 函数名:IIC_Send_Byte
* 功能:  IIC发送一个字节
* 输入:  写入要发送的一个人字节数据txd
* 输出:  无
 --------------------------------------------------*/		  
void IIC_Send_Byte(unsigned char txd)
{                        
    unsigned char t;   
	pinMode(I2C_SDA,OUTPUT);	          //SDA线输出   
    digitalWrite(IIC_SCL,LOW);            //拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
		if((txd&0x80)>>7)
			digitalWrite(IIC_SDA,HIGH);
		else
			digitalWrite(IIC_SDA,LOW);
		txd<<=1; 	  
		DelayUs(5);				  
		digitalWrite(IIC_SCL,HIGH);
		DelayUs(5);	
		digitalWrite(IIC_SCL,LOW);	
		DelayUs(5);
    }	 
} 	    
/*-------------------------------------------------
* 函数名:IIC_Read_Byte
* 功能:  IIC读一个字节
* 输入:  无
* 输出:  读出存储器里面的数据并返回receive
 --------------------------------------------------*/
 unsigned char IIC_Read_Byte(void)
{
	unsigned char i,receive=0;
	pinMode(I2C_SDA,INPUT);               //SDA设置为输入
    for(i=0;i<8;i++ )
	{
        digitalWrite(IIC_SCL,LOW); 
        DelayUs(5);	
     	digitalWrite(IIC_SCL,HIGH);
        receive<<=1;
        if(digitalRead(I2C_SDA)==HIGH)receive++;   
		DelayUs(5);	
    }					 
    //IIC_NAck();           //发送nACK  去除,修复后续读写应答问题
  
    return receive;
}




void SHT40_Read_Temperature_Humidity(unsigned char addr)
{
	unsigned int tem,hum;
	unsigned char  buff[6];
	float Temperature=0;
	float Humidity=0;
  float humiture[2] = {0};

  IIC_Start();
	IIC_Send_Byte(addr<<1 | 0x00);   //w 0     r 1
	IIC_Wait_Ack();
  IIC_Send_Byte(0x94); //复位
	IIC_Wait_Ack();
	IIC_Stop(); 
	delay(10);


  IIC_Start();
	IIC_Send_Byte(addr<<1 | 0x00);   //w 0     r 1
	IIC_Wait_Ack();
  IIC_Send_Byte(0xFD); 
	IIC_Wait_Ack();
	// IIC_Send_Byte(0x06);
	// IIC_Wait_Ack();
	IIC_Stop(); 
	delay(10);
	
  IIC_Start();
	IIC_Send_Byte(addr<<1 | 0x01);   //w 0     r 1
	if(IIC_Wait_Ack()==0)
	{
		buff[0]=IIC_Read_Byte();
		IIC_Ack();
		buff[1]=IIC_Read_Byte();
		IIC_Ack();
		buff[2]=IIC_Read_Byte();
		IIC_Ack();
		buff[3]=IIC_Read_Byte();
		IIC_Ack();
		buff[4]=IIC_Read_Byte();
		IIC_Ack();
		buff[5]=IIC_Read_Byte();
		IIC_NAck();
		IIC_Stop();
	}

	//计算最终结果
	tem = buff[0] * 256 + buff[1];
	//checksum_t = buff[2];
	hum = buff[3] * 256 + buff[4];
	//checksum_rh = buff[5];
	Temperature = -45 + 175 * tem/65535.0;
	Humidity = -6 + 125 * hum/65535.0;
	if (Humidity > 100)
	  Humidity = 100;
	if (Humidity < 0)
	  Humidity = 0;


	if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))
	{
		humiture[0]=Temperature;
		humiture[2]=Humidity;
		Serial.print(Temperature);
    Serial.print("  C,  ");
    Serial.print(Humidity);
    Serial.println(" HT   ");

    //打印原始数据查看
    // for(int i=0;i<6;i++)
	  //   Serial.print(buff[i]);
    // Serial.print("      ");

	}
	IIC_Read_Byte();
  IIC_Stop(); 
	DelayMs(10);
	hum=0;
	tem=0;
 
} 





/*************************************************************************************************
*	函 数 名: SHT40_Heater_200mW_1s
*	入口参数: 无
*	返回值:无
*	函数功能: 开始内部加热器,以200mW加热1秒(一秒)
*	说    明:加热时间不能超过运行时间的10%,否则会过热。详情说明请参考数据手册12页
*************************************************************************************************/
void SHT40_Heater_200mW_1s()
{
  IIC_Start();
	IIC_Send_Byte(0x44<<1 | 0x00);   //w 0     r 1
	IIC_Wait_Ack();
  IIC_Send_Byte(0x39); //复位
	IIC_Wait_Ack();
	IIC_Stop(); 
	delay(10);

}



/*************************************************************************************************
*	函 数 名: SHT40_Read_Serial_Number
*	入口参数: 无
*	返回值:32bit的序列号
*	函数功能: 读取SHT40的出场唯一序列号
*	说    明:无
*************************************************************************************************/
uint32_t SHT40_Read_Serial_Number()
{
	uint32_t Serial_Number;
	uint8_t I2C_Receive_Data[6];


  IIC_Start();
	IIC_Send_Byte(0x44<<1 | 0x00);   //w 0     r 1
	IIC_Wait_Ack();
  IIC_Send_Byte(0x89); //SHT40_READ_SERIAL_NUMBER = 0x89  
	IIC_Wait_Ack();
	IIC_Stop(); 
	

  IIC_Start();
	IIC_Send_Byte(0x44<<1 | 0x01);   //w 0     r 1
	if(IIC_Wait_Ack()==0)
	{
		I2C_Receive_Data[0]=IIC_Read_Byte();
		IIC_Ack();
		I2C_Receive_Data[1]=IIC_Read_Byte();
		IIC_Ack();
		I2C_Receive_Data[2]=IIC_Read_Byte();
		IIC_Ack();
		I2C_Receive_Data[3]=IIC_Read_Byte();
		IIC_Ack();
		I2C_Receive_Data[4]=IIC_Read_Byte();
		IIC_Ack();
		I2C_Receive_Data[5]=IIC_Read_Byte();
		IIC_NAck();
		IIC_Stop();
	}


	Serial_Number=(I2C_Receive_Data[0] << 24)|
			(I2C_Receive_Data[1] << 16)|
			(I2C_Receive_Data[3] << 8)|
			(I2C_Receive_Data[4] << 0);

  Serial.print("Serial_Number:");
  Serial.println(Serial_Number);

	return Serial_Number;
 
 
}




void setup() {
  Serial.begin(115200);
  // initialize the pin as an output:
  pinMode(I2C_SDA, OUTPUT);
  pinMode(I2C_SCL, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);

}



void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  //读取温湿度并打印
  SHT40_Read_Temperature_Humidity(0x44);


  // check if the pushbutton is pressed. If it is, the buttonState is LOW:
  if (buttonState == LOW) {
    delay(10);
    if (digitalRead(buttonPin) == LOW) {
        Serial.println("key press");

        //加热1s,读序列号
        SHT40_Heater_200mW_1s();
        SHT40_Read_Serial_Number();

          

    //等待按钮松开,跳出循环
    while(digitalRead(buttonPin) == LOW)
    {
    }


    }

  }




  // 检查是否有可用的串口数据
  if (Serial.available() > 0) {
    // 读取整个命令字符串
    String command = Serial.readStringUntil(';');
    // 在串口监视器中输出接收到的命令
    Serial.println(command);

    // 尝试解析命令

  }





}



输出结果:

可能会遇到的问题:

读出6个字节数据时,只有第一字节有数据,其他的都是0xff

解决方法:

1.确认ack的处理是否正确

2.确保在ack后SDA引脚有设置为高电平,即要释放SDA的控制

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值