前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。


github:my github


注:博客所涉及的关于 stm32 的代码,均在仓库【stm32f013_study】下,包括底层驱动和应用测试代码。
本文设计的文件包含:
(1)drvsfi2c.c:软件模拟 i2c 驱动实现
(2)app_htu21d.c:HTU21D测试实现
(3)头文件:
drvsfi2c.h : 软件模拟I2C;
app_htu21d.h:HTU21D应用测试;


1. 简介

法国 Humirel 公司新一代 HTU21D 温度和湿度传感器在尺寸与智能方面建立了新的标准:它嵌入了适于回流焊的双列扁平无引脚 DFN 封装, 底面 3 x 3mm ,高度 1.1mm。传感器输出经过标定的数字信号,标准 I2C 格式

HTU21D 温度和湿度传感器为 OEM 应用提供一个准确可靠的温湿度测量数据。通过一个微控制器的接口和模块连接达到温度和湿度数字输出。HTU21D 的分辨率可以通过输入命令进行改变(8/12bit 乃至12/14bit 的 RH/T),传感器可以检测到电池低电量状态,并且输出校验和,有助于提高通信的可靠性。


2. 规格参数

25 摄氏度,3.3V 供电时的电气特性如下:

数据手册下载地址如下:

温湿度敏感芯片传感器HTU21D

印刷板设计注意:

如果 SCL 和 SDA 信号线相互平行并且非常接近,有可能导致信号串扰和通讯失败。解决方法是在两个信号线之间放置 VDD 或 GND,将信号线隔开,或使用屏蔽电缆。此外,降低 SCL 频率也可能提高信号传输的完整性。须在电源引脚(VDD, GND)之间加一个100nF 的去藕电容,用于滤波。此电容应尽量靠近传感器。

引脚定义:

本实验采用的为成品 HTU21D 模块,直接与 STM32 开发板连接即可。

引脚 说明
电源引脚 (VDD, GND) HTU21 的供电范围为 1.8VDC - 3.6VDC,推荐电压为 3.0V。电源(VDD)和接地(VSS)之间须连接一个0.1uF的去耦电容,且电容的位置应尽可能靠近传感器。
串行时钟输入(SCK) SCK 用于微处理器与 HTU21 之间的通讯同步。由于接口包含了完全静态逻辑,因而不存在最小 SCK 频率。
串行数据 (DATA) DATA 引脚为三态结构,用于读取传感器数据。当向传感器发送命令时, DATA 在 SCK 上升沿有效且在 SCK 高电平时必须保持稳定。 DATA 在 SCK 下降沿之后改变。当从传感器读取数据时, DATA 在 SCK 变低以后有效,且维持到下一个 SCK 的下降沿。为避免信号冲突,微处理器应驱动 DATA 在低电平。需要一个外部的上拉电阻(例如: 10kΩ)将信号提拉至高电平。上拉电阻通常已包含在微处理器的 I/O 电路中。

3. 通讯过程

Htu21d 遵循标准的 IIC 进行通信,关于 IIC 的介绍请看—>IIC专题(一)——基础知识准备。本文设计也多参考此篇文章–>STM32F10x_模拟I2C读写EEPROM。

3.1 IIC 启动信号

启动传输,发送一位数据时,包括 DATA 线在 SCK 线高电平期间一个向低电平的跳变。

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_Start
//  功能说明: I2C起始信号
//  形    参: 无
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void I2c_Start(void)
{I2C_SDA_1();                       //拉高SDA线I2C_SCL_1();                        //拉高SCL线I2c_Delay(StI2cInfo.uiI2cSpeed);                    //延时,速度控制I2C_SDA_0();                        //当SCL线为高时,SDA线一个下降沿代表开始信号I2c_Delay(StI2cInfo.uiI2cSpeed);                   //延时,速度控制I2C_SCL_0();
}

3.2 IIC停止信号

终止传输,停止发送数据时,包括 DATA 线在 SCK 线高电平期间一个向高电平的跳变。

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_Stop
//  功能说明: I2C停止信号
//  形    参: 无
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void I2c_Stop(void)
{I2C_SDA_0();I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_1();I2C_SDA_1();I2c_Delay(StI2cInfo.uiI2cSpeed);
}

3.2 IIC 数据传输

SCL 时钟电平为低, 可以改换 SDA 数据线的电平,在 SCL 上升沿的过程将 SDA数据发送出去。SCL 为高电平时,SDA 上的数据保持稳定。

I2C 是以字节(8位)的方式进行传输,总线上每传输完 1 字节之后会有一个应答信号,应答信号总是由接收方来产生。通信过程的时钟由主器件(主机)提供。

IIC 写一字节:

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_SendOneByte
//  功能说明: I2C发送一个字节数据
//  形    参:
//              _ucData:发送的一字节数据
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void I2c_SendOneByte(uint8_t _ucData)
{uint8_t ucCnt = 0;I2C_SDASetOutput(); //SDA设置为输出(若IO为开漏,无需进行方向切换)for(ucCnt = 0; ucCnt < 8; ucCnt++){I2C_SCL_0();        //SCL低电平,允许数据改变I2c_Delay(StI2cInfo.uiI2cSpeed);if(_ucData & 0x80)       //从高位开始传输{I2C_SDA_1();      }else{I2C_SDA_0();      }_ucData <<= 1;I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_1();      //数据稳定,发送给从机I2c_Delay(StI2cInfo.uiI2cSpeed);}I2C_SCL_0();       //第9个时钟,SCL低电平,等待应答信号来到I2c_Delay(StI2cInfo.uiI2cSpeed);
}

数据发送结束,进行应答操作。

0:表示从机应答,可以继续下一步操作;
1:表示从机非应答,不能进行下一步操作。

IIC 读一字节:

IIC 读取操作类似于发送,只是传输数据方向相反。

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_RecvOneByte
//  功能说明: I2C接收一个字节数据
//  形    参:
//              _ucAck:应答判断(0:给出应答;1:给出非应答)
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
uint8_t I2c_RecvOneByte(uint8_t _ucAck)
{uint8_t ucCnt = 0, ucData = 0;I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SDA_1();I2C_SDASetInput();     //切换SDA传输方向for(ucCnt = 0; ucCnt < 8; ucCnt++){I2C_SCL_1();        //SCL高电平时SDA上的数据达到稳定I2c_Delay(StI2cInfo.uiI2cSpeed);        //延时等待信号稳定ucData <<= 1;if(I2C_SDA_READ){ucData |= 0x01;}else{ucData &= 0xfe;       }I2C_SCL_0();       //允许数据改变I2c_Delay(StI2cInfo.uiI2cSpeed);}I2C_SDASetOutput();if(_ucAck){I2c_GetNack();}else{I2c_GetAck();}return ucData;
}

注: 当主机读取数据最后一字节时,发送的 NACK 告诉从机数据读取完成,其余发送的是 ACK 。

3.3 IIC 应答信号处理

等待应答:

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_Wait_Ack
//  功能说明: I2C等待应答
//  形    参:
//              _usErrTime:超时时间设置(此函数无作用,仅是为了和#if里面公用声明)
//  返 回 值: 无
//  日    期: 2019-12-29
//  备    注:
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
uint8_t I2c_WaitAck(uint16_t _usErrTime)
{uint8_t ucAck = 0xFF;I2C_SDA_1();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_1();     //此时判断是否有应答I2c_Delay(StI2cInfo.uiI2cSpeed);if(I2C_SDA_READ){ucAck = I2C_NACK;  }else{ucAck = I2C_ACK; }I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);return ucAck;
}

产生应答:

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_GetAck
//  功能说明: I2C得到应答
//  形    参: 无
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void I2c_GetAck(void)
{I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SDASetOutput();I2C_SDA_0();    //第九个时钟,SDA为低应答I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_1();     //SCL高电平,高电平时读取SDA的数据I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SDA_1();       //释放SDA
}

产生非应答:

//--------------------------------------------------------------------------------------------------------
//  函 数 名: I2c_GetNack
//  功能说明: I2C得到非应答()
//  形    参: 无
//  返 回 值: 无
//  日    期: 2019-12-29
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void I2c_GetNack(void)
{I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SDASetOutput();I2C_SDA_1();    //第九个时钟,SDA为高非应答I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_1();        //SCCL高电平,高电平时读取SDA的数据I2c_Delay(StI2cInfo.uiI2cSpeed);I2C_SCL_0();I2c_Delay(StI2cInfo.uiI2cSpeed);
}

4. HTU21D 数据测量

测量命令如下表:

本文采用非保持主机:
//非主机模式

#define HTU_TEMP    0xf3
#define HTU_HUMI    0Xf5

在非主机模式下, MCU 需要对传感器状态进行查询。此过程通过发送一个启动传输时序,之后紧接着是如图所示的 I2C 首字节(1000’0001)来完成。如果内部处理工作完成,单片机查询到传感器发出的确认信号后,相关数据就可以通过 MCU 进行读取。如果测量处理工作没有完成,传感器无确认位(ACK)输出,此时必须重新发送启动传输时序。

传感器初始化:

//---------------------------------------------------------------------------------------------------------------------------------------------
//  函 数 名: Htu_Init
//  功能说明: 传感器初始化
//  形    参: 无
//  返 回 值: 无
//  备    注:
//  日    期: 2020-03-11
//  作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void Htu_Init(void)
{I2c_Init();I2c_Start();I2c_SendOneByte(HTU_ADDR_WR);   //写I2C器件地址I2c_WaitAck(200);I2c_SendOneByte(HTU_SOFTWARE_RESET);     //软复位I2c_WaitAck(200);I2c_Stop();delay_ms(15);      //软复位时间最多需要15ms
}

传感器数据读取与转换:

传感器内部设置的默认分辨率为相对湿度12位和温度14 位。 SDA 的输出数据被转换成两个字节的数据包,高字节MSB 在前(左对齐)。每个字节后面都跟随一个应答位。两个状态位,即LSB 的后两位在进行物理计算前须置‘0’。

转换计算如下图:

源代码实现:

显示方式:

本实验通过串口打印显示,串口打印有助于程序的调试。

//--------------------------------------------------------------------------------------------------------------------------
//  函 数 名: htu_write_some_bytes
//  功能说明: htu21d 通过IC写入多字节数据
//  形    参:     pbdata:写入的数据
//              write_length:写入数据的长度
//  返 回 值: 无
//  日    期: 2020-03-19
//  备    注: 测试I2C发送多字节数据时序
//  作    者: by 霁风AI
//-------------------------------------------------------------------------------------------------------------------------
bool htu_write_some_bytes(uint8_t *pbdata, uint16_t write_length)
{I2c_Start();I2c_SendOneByte(HTU_ADDR_WR);if (I2C_NACK == I2c_WaitAck(200)){return false;}//for循环发送多个字节数据for (uint16_t i = 0; i < write_length; i++){I2c_SendOneByte(pbdata[i]);if (I2C_NACK == I2c_WaitAck(200)){return false;}}//while循环发送多个字节数据
//  while (write_length--)
//  {//      I2c_SendOneByte(*pbdata++);
//      if (I2C_NACK == I2c_WaitAck(200))
//      {//          return false;
//      }
//  }// I2c_Stop();return true;}//--------------------------------------------------------------------------------------------------------------------------
//  函 数 名: htu_read_some_bytes
//  功能说明: htu21d 通过IC读取多字节数据
//  形    参:     pbdata:写入的数据
//              read_length:写入数据的长度
//  返 回 值: 无
//  日    期: 2020-03-19
//  备    注: 测试I2C接收多字节数据时序
//  作    者: by 霁风AI
//-------------------------------------------------------------------------------------------------------------------------
bool htu_read_some_bytes(uint8_t *pbdata, uint16_t read_length)
{I2c_Start();I2c_SendOneByte(HTU_ADDR_RD);if (I2C_NACK == I2c_WaitAck(200)){return false;}for (uint16_t i = 0; i < read_length - 1; i++){*pbdata++ = I2c_RecvOneByte(I2C_ACK);}*pbdata++ = I2c_RecvOneByte(I2C_NACK); //接收最后一个字节发送NACK,告诉从机读操作已经完成I2c_Stop();return true;
}//--------------------------------------------------------------------------------------------------------------------------
//  函 数 名: Htu_Measure
//  功能说明: Htu21d 温湿度读取
//  形    参:     _ucOrder:温度 or 湿度读取命令
//  返 回 值: 无
//  日    期: 2020-03-16
//  备    注:
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------------------------
float Htu_Measure(uint8_t _ucOrder)
{uint8_t ucaRecvBuf[2] = {0};uint8_t ucTmpVal = _ucOrder;volatile float fTemp = 0.0;volatile float fHumi = 0.0;volatile float fRetVal = 0.0;htu_write_some_bytes(&ucTmpVal, 1);        //写如操作命令delay_ms(50);   //14位测量时间范围(44-58ms)htu_read_some_bytes(ucaRecvBuf, 2); //接收两字节数据ucaRecvBuf[1] &= 0xFC;        //设置分辨率,最低两位为0,温度:14位;湿度:12位    fRetVal = (ucaRecvBuf[0] << 8) | ucaRecvBuf[1];  // MSB=(MSB<<=8)+LSB;即将MSB移位到高8位if(_ucOrder == HTU_TEMP){fTemp = (175.72) * fRetVal / 65536 - 46.85;//温度:T= -46.85 + 175.72 * ST/2^16return fTemp;}else if(_ucOrder == HTU_HUMI){fHumi = (fRetVal * 125) / 65536 - 6.00;//湿度: RH%= -6 + 125 * SRH/2^16return fHumi;}else{return false;}
} //--------------------------------------------------------------------------------------------------------
//  函 数 名: Htu_Display
//  功能说明: 测量数据显示
//  形    参: 无
//  返 回 值: 无
//  日    期: 2020-03-16
//  备    注:
//  作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------void Htu_Display(void)
{u16 usTemp = 0;volatile float f_RetVal = 0.0;u8 ucTest[10] = {0};f_RetVal = Htu_Measure(HTU_TEMP);//得到温度值printf("The htu measure temp is :%4.2fC \r\n", f_RetVal);sprintf((char*)ucTest,"%4.2f", f_RetVal);        //LCD显示方式1:sprintf函数将结果打印到test数组里,转换成字符串printf("test is %sC \r\n", ucTest);printf("\r\n");usTemp = f_RetVal;            //LCD显示方式2:将得到的数值拆分成整数和小数直接显示在液晶f_RetVal -= usTemp;f_RetVal *= 100;       //保留两位小数f_RetVal= Htu_Measure(HTU_HUMI);       //得到湿度值printf("The htu measure humi is :%4.2fRH \r\n", f_RetVal);usTemp = f_RetVal;f_RetVal -= usTemp;f_RetVal *= 100;printf("\r\n");
}

测试结果:


参考:

  1. STM32F10x_模拟I2C读写EEPROM

  2. 正点原子库函数

STM32 驱动温湿度传感器 HTU21D相关推荐

  1. STM32驱动温湿度传感器HTU21D

    https://blog.csdn.net/wwt18811707971/article/details/80034047 1.简介 法国Humirel公司新一代HTU21D温度和湿度传感器在尺寸与智 ...

  2. 【linux驱动开发】i2c驱动框架之温湿度传感器htu21d

    文章目录 一.linux内核i2c驱动框架 1.1 i2c适配器 1.2 i2c设备驱动 1.3 i2c设备驱动匹配过程 二.温湿度传感器htu21d 三.htu21d设备驱动编写 3.1 修改设备树 ...

  3. K_A13_001 基于STM32驱动霍尔开关传感器 串口与OLED0.96双显示

    K_A13_001 基于STM32驱动霍尔开关传感器 串口与OLED0.96双显示 一.资源说明 二.基本参数 参数 引脚说明 三.驱动说明 对应程序: 四.部分代码说明 1.接线引脚定义 STM32 ...

  4. 【GD32片上i2c外设应用】温湿度传感器htu21d

    文章目录 一.温湿度传感器htu21d介绍 1.1 参数 1.1.1 湿度参数 1.1.2 温度参数 1.2 芯片i2c协议 1.2.1 器件地址 1.2.2 读取温湿度 1.2.3 芯片复位 二.g ...

  5. sht20中写用户寄存器_数字输出温湿度传感器HTU21D和SHT21对比评测(图文)

    超小体积的温湿度一体数字输出模块由于体积小,精度高的特点,广泛应用于手机.通讯.HVAC.医疗.环境监测.家用电器.控制板等,近日从深圳市工采网(ISweek)拿到市面上最常用的HTU21D和SHT2 ...

  6. 基于I2C协议利用STM32进行温湿度传感器的数据采集

    目录 一.I2C总线通信协议的介绍 1.I2C简介 2.I2C总线时序图 3.五种速率 4.四种信号 5.I2C的优缺点 6.软件IIC和硬件IIC 二.创建工程 1.实验目的 2.工具的选择 3.相 ...

  7. HT66F2390/STM32——AM2320温湿度传感器

    1.说明 AM2320 数字温湿度传感器采用单总线.标准 I²C 两种通信方式.本文主要基于HT66F2390单片机,采用单总线通讯,实现AM2320传感器数据获取.关于AM2320传感器的使用,可参 ...

  8. STM32使用温湿度传感器

    前言 MDK5(Keil5)软件:uVision5 IDE 集成开发环境,是目前针对 ARM 处理器,尤其是 Cortex M 内核处理器的最佳开发工具. 本项目采用ARM结构中最为代表的Cortex ...

  9. 嵌入式 STM32 SHT31温湿度传感器

    目录 简介 1.原理图 2.时序说明 数据传输 起始信号 结束信号 3.SHT31读写数据 SHT31指令集 读数据 温湿度转换 4.温湿度转换应用 sht3x初始化 读取温湿度 简介 什么是SHT3 ...

最新文章

  1. java exception用法_JavaException的使用
  2. TinaFace:人脸检测新纪录
  3. xml之结构(company-employ buyer)
  4. python写服务器端qt客户端_python写一些简单的tcp服务器和客户端
  5. 41. First Missing Positive
  6. 将一个数组中的值按逆序重新排放。_六十五、下一个更大的数系列,单调栈解决方法...
  7. JAVA验证数字的正则表达式,来一发
  8. qt 线程接收线程 moveToThread 特性
  9. 碰撞检测之OBB-OBB检测
  10. protel dxp 2004电路仿真
  11. 面试官;经典面试题-JVM篇
  12. 缺陷检测论文回顾(一)
  13. 游戏热更新:游戏客户端热更新那点事
  14. pikachu通关教程
  15. 【C语言】C语言中赋值语句规则
  16. 联想在钛媒体峰会上提前泄漏了MOTO新杀器
  17. js 一个等号= 二个等号== 三个等号=== 的区别
  18. PHP实现微信映美打印机,映美在2015--做一台有爱的打印机
  19. 个人项目:中小学数学卷子自动生成程序
  20. 像大师一样画图-PCB常用设置与操作-PCB系列教程3-2

热门文章

  1. setuptools清华源_安装setuptools和pip(转载)
  2. java二进制转为汉字_Java 实现中文与二进制代码互转
  3. 大数据架构师成长之路
  4. SOLIDWORKS Simulation有限元分析工具使用方法
  5. python怎么生成伪代码_Python零基础入门—算法的实现与伪代码
  6. 解决EMI传导干扰8大方法
  7. 题目 1514: [蓝桥杯][算法提高VIP]夺宝奇兵
  8. linux 无线网卡驱动 centrino 6200 agn,联想Thinkpad无线网卡驱动(Intel Centrino Advanced-N 6200)...
  9. 股票历史行情数据api_历史API
  10. 字节一面:Redis主节点宕机,如何处理?