使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集

本文介绍了I2C总线的基本原理及其在温度采集中的应用。I2C是一种高性能的串行总线,由PHILIPS公司推出,可用于连接多个主设备和从设备。文章详细阐述了I2C总线的开始与停止条件,并提供了温度采集的具体实施案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、IIC

1.1介绍

即I2C,一种总线结构。
例如:内存中的SPD信息,通过IIC,与BX芯片组联系,IIC 存在于英特尔PIIX4结构体系中。
随着大规模集成电路技术的发展,把CPU和一个单独工作系统所必需的ROM、RAM、I/O端口、A/D、D/A等外围电路集成在一个单片内而制成的单片机或微控制器愈来愈方便。目前,世界上许多公司生产单片机,品种很多。其中包括各种字长的CPU,各种容量的ROM、RAM以及功能各异的I/O接口电路等等,但是,单片机的品种规格仍然有限,所以只能选用某种单片机来进行扩展。扩展的方法有两种:一种是并行总线,另一种是串行总线。由于串行总线的连线少,结构简单,往往不用专门的母板和插座而直接用导线连接各个设备。因此,采用串行线可大大简化系统的硬件设计。PHILIPS公司早在十几年前就推出了I2C串行总线,利用该总线可实现多主机系统所需的裁决和高低速设备同步等功能。因此,这是一种高性能的串行总线。
飞利浦电子公司日前推出新型二选一I2C主选择器,可以使两个I2C主设备中的任何一个与共享资源连接,广泛适用于从MP3播放器到服务器等计算、通信和网络应用领域,从而使制造商和终端用户从中获益。PCA9541可以使两个I2C主设备在互不连接的情况下与同一个从设备相连接,从而简化了设计的复杂性。此外,新产品以单器件替代了I2C多个主设备应用中的多个芯片,有效节省了系统成本。

1.2原理

在I2C总线传输过程中,将两种特定的情况定义为开始和停止条件(见图3):当SCL保持“高”时,SDA由“高”变为“低”为开始条件;当SCL保持“高”且SDA由“低”变为“高”时为停止条件。开始和停止条件均由主控制器产生。使用硬件接口可以很容易地检测到开始和停止条件,没有这种接口的微机必须以每时钟周期至少两次对SDA取样,以检测这种变化。
SDA线上的数据在时钟“高”期间必须是稳定的,只有当SCL线上的时钟信号为低时,数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位,每次传输的字节不受限制,但每个字节必须要有一个应答ACK。如果一接收器件在完成其他功能(如一内部中断)前不能接收另一数据的完整字节时,它可以保持时钟线SCL为低,以促使发送器进入等待状态;当接收器准备好接受数据的其它字节并释放时钟SCL后,数据传输继续进行。I2C数据总线传送时序。数据传送具有应答是必须的。与应答对应的时钟脉冲由主控制器产生,发送器在应答期间必须下拉SDA线。当寻址的被控器件不能应答时,数据保持为高并使主控器产生停止条件而终止传输。在传输的过程中,在用到主控接收器的情况下,主控接收器必须发出一数据结束信号给被控发送器,从而使被控发送器释放数据线,以允许主控器产生停止条件。合法的数据传输格式如下:
I2C总线在开始条件后的首字节决定哪个被控器将被主控器选择,例外的是“通用访问”地址,它可以在所有期间寻址。当主控器输出一地址时,系统中的每一器件都将开始条件后的前7位地址和自己的地址进行比较。如果相同,该器件即认为自己被主控器寻址,而作为被控接收器或被控发送器则取决于R/W位。

二、实现温度采集

给出文件自行下载
链接:https://pan.baidu.com/s/1hzUldR3IL98osBcwRf9-9w
提取码:1234
程序烧录之后使用野火调试助手即可看到结果
在这里插入图片描述

三丶总结

采集和输出温湿度比较简单,只需要注意传感器的接法即可,传感器的接法在打包的文件夹中可以看到

四丶参考

IIC

<think>好的,我需要帮助用户解决STM32F103C8T6通过模拟I2CAHT20通信的问题。用户想要示例代码,所以我得先确保代码正确,并符合他们的需求。 首先,用户提到使用模拟I2C协议,所以不能依赖硬件I2C,需要软件实现GPIO控制。我需要定义SDA和SCL的引脚,并初始化它们为输出模式。通常,这两个引脚需要上拉电阻,但用户可能已经接好,所以在代码中可能需要配置为开漏模式,但STM32的GPIO模式设置可能需要特别注意。不过,模拟I2C通常会将引脚设置为推挽输出,并在适当的时候切换为输入读取数据。因此,初始化部分应该设置GPIO为输出,并初始化为高电平。 接下来是I2C的起始和停止信号。起始信号是SCL高时,SDA从高到低;停止信号是SCL高时,SDA从低到高。这部分需要正确实现时序,可能需要微秒级的延时,这里用HAL_Delay不太合适,应该用更精确的延时函数,比如HAL_Delay(1)可能太长,但作为示例代码可能简化处理,用户实际使用时可能需要调整。 发送字节的函数需要逐位发送,从高位开始。每个时钟周期,设置SDA的电平,然后拉高SCL,保持一段时间,再拉低SCL。接收字节时,需要释放SDA(设置为输入模式),读取每一位,并在SCL高时采样。 AHT20的初始化步骤需要发送初始化命令,比如0xE1后跟两个参数0x08和0x00。然后需要等待传感器校准完成,通过读取状态字,判断最高位是否为0。如果校准未完成,可能需要延时等待。 读取数据时,发送触发测量命令0xAC,然后等待数据就绪,同样通过状态字判断。之后读取6个字节的数据,组合成温湿度值。注意数据需要转换,比如湿度值SRH是20位的,温度是20位的,需要按位操作提取,并进行公式计算。 示例代码中需要包含这些步骤,并添加必要的注释,让用户理解每个部分的作用。同时,需要提醒用户检查引脚配置、延时函数是否合适,以及可能的硬件连接问题。 可能的问题包括:I2C地址是否正确(AHT20地址是0x38),GPIO是否正确配置,延时是否足够,是否处理了传感器的响应信号(ACK/NACK)。此外,用户可能需要根据实际情况调整计算公式中的参数,确保温湿度值的准确性。 最后,生成相关问题,帮助用户深入理解,比如如何提高采集精度,处理通信失败的情况,或者优化代码结构。这些问题应该与用户的应用场景相关,帮助他们进一步开发和调试。</think>### 解答步骤 #### 步骤1:配置GPIO模拟I2C协议 STM32F103C8T6需通过GPIO模拟I2C时序,定义`SDA`和`SCL`引脚: ```c // 定义I2C引脚(示例使用GPIOB_Pin6和GPIOB_Pin7) #define I2C_SCL_PIN GPIO_PIN_6 #define I2C_SDA_PIN GPIO_PIN_7 #define I2C_PORT GPIOB // 初始化GPIO void I2C_Init() { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出模式 GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = I2C_SCL_PIN | I2C_SDA_PIN; HAL_GPIO_Init(I2C_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(I2C_PORT, I2C_SDA_PIN, GPIO_PIN_SET); } ``` #### 步骤2:实现I2C基础函数 包括起始信号、停止信号、发送字节、接收应答等: ```c // I2C起始信号 void I2C_Start() { HAL_GPIO_WritePin(I2C_PORT, I2C_SDA_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_SET); Delay_us(5); HAL_GPIO_WritePin(I2C_PORT, I2C_SDA_PIN, GPIO_PIN_RESET); Delay_us(5); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_RESET); } // 发送一个字节 void I2C_WriteByte(uint8_t data) { for (int i = 0; i < 8; i++) { HAL_GPIO_WritePin(I2C_PORT, I2C_SDA_PIN, (data & 0x80) ? GPIO_PIN_SET : GPIO_PIN_RESET); data <<= 1; HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_SET); Delay_us(5); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_RESET); Delay_us(5); } // 等待ACK HAL_GPIO_WritePin(I2C_PORT, I2C_SDA_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_SET); Delay_us(5); HAL_GPIO_WritePin(I2C_PORT, I2C_SCL_PIN, GPIO_PIN_RESET); } ``` #### 步骤3:AHT20初始化与数据读取 AHT20需发送校准命令并等待就绪: ```c #define AHT20_ADDRESS 0x38 // I2C地址 void AHT20_Init() { I2C_Start(); I2C_WriteByte(AHT20_ADDRESS << 1); // 写模式 I2C_WriteByte(0xE1); // 初始化命令 I2C_WriteByte(0x08); // 参数1 I2C_WriteByte(0x00); // 参数2 I2C_Stop(); HAL_Delay(40); // 等待校准完成 } // 读取温湿度数据 void AHT20_ReadData(float *temp, float *humi) { uint8_t data[6] = {0}; I2C_Start(); I2C_WriteByte(AHT20_ADDRESS << 1); I2C_WriteByte(0xAC); // 触发测量命令 I2C_WriteByte(0x33); I2C_WriteByte(0x00); I2C_Stop(); HAL_Delay(80); // 等待测量完成 // 读取6字节数据 I2C_Start(); I2C_WriteByte((AHT20_ADDRESS << 1) | 0x01); // 读模式 for (int i = 0; i < 5; i++) { data[i] = I2C_ReadByte(); I2C_SendAck(0); // 发送ACK } I2C_SendAck(1); // 发送NACK I2C_Stop(); // 数据解析(公式见AHT20手册) uint32_t raw_humi = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4; uint32_t raw_temp = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; *humi = (raw_humi * 100.0) / (1 << 20); *temp = (raw_temp * 200.0) / (1 << 20) - 50; } ``` #### 步骤4:主函数调用 ```c int main() { HAL_Init(); SystemClock_Config(); I2C_Init(); AHT20_Init(); float temp, humi; while (1) { AHT20_ReadData(&temp, &humi); HAL_Delay(2000); // 每2秒采集一次 } } ``` #### 注意事项 1. **延时函数**需根据实际时钟频率调整(示例中`Delay_us`需自行实现) 2. **GPIO模式**需根据硬件设计选择(开漏输出需外接上拉电阻) 3. **数据校验**需检查状态字(参考AHT20手册)[^1][^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值