嵌入式系统开发14——基于I2C协议使用AHT20传感器采集温湿度

本文主要介绍I2C总线通信协议,并在此基础上,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。

一、任务要求

学习 I2C 总线通信协议,使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。具体任务:
1)解释什么是“软件I2C”和“硬件I2C”? (阅读野火配套教材的第23章“I2C–读写EEPROM”原理章节)
2)阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win11)。

二、I2C总线通信协议

1、I2C简介

IIC(Inter-Integrated Circuit) 总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在 小数据量场合 使用, 传输距离短 ,任意时刻只能有一个主机等特性。

I2C 是很常见的一种总线协议, I2C 是 NXP 公司设计的, I2C 使 用两条线在主控制器和从机之间进行数据通信 。一条是 SCL(串行时钟线),另外一条是 SDA(串行数据线),由于不接上拉电阻,这两个引脚为悬空状态,由于 悬空状态引脚的电平是无法确定 的,所以这 两条数据线需要接上拉电阻 ,一般是4.7K,总线 空闲 的时候 SCL 和 SDA 都处于高电平
在这里插入图片描述

I2C总线CPU 与被控器件之间、被控器件与被控器件之间进行 双向传送I2C 总线 标准模式 下速度可以达到 100Kb/S,快速模式下可以达到 400Kb/SI2C 总线工作是按照一定的协议来运行的,I2C支持多从机 的,也就是一个 I2C 控制器下可以挂多个 I2C 从设备,这些不同的 I2C 从设备有不同的器件地址,这样 I2C 主控制器就可以通过 I2C 设备的器件地址访问指定的 I2C设备了,一个 I2C 总线可以连接多个 I2C 设备。
在这里插入图片描述
注意 I2C 是为了与 低速设备通信 而发明的,所以 I2C 的传输速率比不上 SPI

2、I2C总线的特点

I²C特性:

  • 只需要一根 数据线SDA 和一根 时钟线SCL,**SDA(串行数据线)**和 SCL(串行时钟线) 都是 双向 I/O线
    SCL(Serial Clock): 串行 时钟线,传输CLK信号,一般是主设备向从设备提供
    SDA(Serial Data) : 串行 数据线, 传输通信数据

  • 多主机总线,任何器件既可以作为主机又可以作为从机,但是 同一时刻只能有一个主机,连接到总线的每个设备均可通过 唯一地址 进行软件寻址;可以通过 外部连线检测 ,便于系统故障诊断和调试

  • 连接到相同总线上的IC数量只 受总线最大电容的限制,串行的8位双向数据传输位速率在标准模式下可达100Kbit/s,快速模式下可达400Kbit/s,高速模式下可达3.4Mbit/s

  • 在总线上 消耗的电流很小,因此,总线上扩展的器件数量主要由电容负载来决定,抗高噪声干扰,增加总线驱动器可以使总线电容扩大10倍,传输距离达到15m;兼容不同电压等级的器件, 工作温度范围宽

  • 接口电路为 开漏输出,需 通过上拉电阻接电源VCC ,当总线 空闲 时,两根线都是 高电平,连接总线的外同器件都是CMOS器件输出级也是开漏电路。为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是 漏极开路(OD)输出集电极开路(OC)输出

  • 没有严格的波特率要求 ,例如使用RS232,主设备生成总线时钟,产生起始信号和停止信号

  • IIC是 半双工,而不是全双工 ,同一时间 只可以 单向通信

传输速度:

  • 标准模式: Standard Mode = 100 Kbps
  • 快速模式: Fast Mode = 400 Kbps
  • 高速模式: High speed mode = 3.4 Mbps
  • 超快速模式: Ultra fast mode = 5 Mbps

最大主设备数: 无限制

最大从机数: 理论上是127

3、I2C物理层

I2C 总线 在物理连接上非常简单,分别由 SDA(串行数据线)SCL(串行时钟线)上拉电阻 组成。通信原理是通过对 SCL和SDA线高低电平时序的控制 ,来产生I2C总线协议所需要的信号进行数据的传递。在总线 空闲 状态时,SCL和SDA 被上拉电阻Rp拉高 ,使SDA和SCL线都 保持高电平

I2C通信方式为半双工 ,只有一根 SDA 线,同一时间只可以单向通信 ,485也为半双工,SPIuart 通信为 全双工
在这里插入图片描述

主机和从机的概念:

主机就是负责整个系统的任务协调与分配,从机一般是通过接收主机的指令从而完成某些特定的任务,主机和从机之间通过总线连接,进行数据通讯。
发布主要命令的称为主机,接受命令的称为从机

4、I2C协议层

I2C 总线在传送数据过程中共有三种类型信号, 它们分别是: 开始信号、结束信号应答信号

开始信号 SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
结束信号 SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
应答信号 接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

这些信号中,起始信号是必需的 ,结束信号和应答信号,都可以不要。

5、I2C总线时序图

在这里插入图片描述

起始位:
I2C开始通信的标志,主机通过这个标志告诉从机要开始进行通信了,当 SCL为高电平,SDA出现下将沿时表示起始位
在这里插入图片描述

停止位:
I2C通信结束的标志,当 SCL为高电平,SDA出现上升沿时表示停止位
在这里插入图片描述

数据传输:
I2C数据总线传输要保证在 SCL为高电平时,SDA数据稳定 ,所以SDA上数据变化只能在SCL为低电平时
在这里插入图片描述

地址帧/读写位/ACK位:
在这里插入图片描述

地址帧: 这是一个 8 位的数据,其中高 7 位是设备地址,最后 1 位是读写位,为1 的话表示这是一个读操作,为 0 的话表示这是一个写操作

读/写位: 0:低电平,主设备向从设备写数据,1:高电平从机读数据

ACK: 消息的每一个帧都有一个确认位,如果设备接收到了地址帧或者数据帧,都会给发送设备返回一个ACK

空闲状态:
当IIC总线的数据线SDA和时钟线SCL 两条信号线同时处于高电平 时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在 截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高

应答信号:
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

应答信号为 低电平 时,规定为 有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;应答信号为 高电平 时,规定为 非应答位(NACK),一般表示接收器接收该字节没有成功

在这里插入图片描述

接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平,发送一个ACK信号, 如果接收器是主机端,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放数据线SDA,以便主机端发送一个停止信号P

补充:
非应答信号可能是主机发出的也可能是从机产生的
有几种可能:
1、I2C总线上没有主机所指定地址的从机设备
2、从机正在执行一些操作,处于忙状态,还没有准备好与主机通讯
3、主机发送的一些控制命令,从机不支持
4、主机接收从机数据时,主机产生非应答信号,通知从机数据传输结束,不要再发数据了

6、数据传输

数据发送:
主机向从机写时序,红色部分表示主机发送,蓝色部分表示从机发送。A表示应答,NA表示非应答(高电平)。S表示起始信号,P表示终止信号
在这里插入图片描述
在这里插入图片描述

  • 1.开始信号:在SCL从高电平切换为低电平之前,主设备通过将SDA从高电平切换到低电平,启动信号与停止信号始终是由主设备控制产生的
  • 2.主设备向每个从设备发送要与之通信的从设备的7位或10位地址,通过发送具体的设备地址来决定要访问哪个I2C设备,这是一个8位的数据,其中高8位是设备地址,最后1位是读写位,1表示读操作,0表示写操作
  • 3.每一个从设备会根据主设备发过来的地址与自身的地址做比较,如果地址匹配,那么从设备会将SDA拉低来返回ACK应答信号,地址不匹配时,从设备会将SDA拉高,在从设备没有将SDA拉低会将Master视为超时,将放弃数据传送,发送“Stop”
  • 4.重新发送开始信号
  • 5.主机发送要写入的丛机的寄存器地址
  • 6.从机发送ACK信号
  • 7.发送要写入寄存器的数据帧,传输完每个数据帧后,即8位数据,主机将SDA拉高,等待从机将SDA拉低,即返回ACK,以确认已成功接收到该帧
  • 8.结束信号:主设备将SCL切换为高电平,再将SDA切换为高电平,从而向从设备发送停止信号

数据接收:
在这里插入图片描述
在这里插入图片描述
接收数据就是读时序的过程,读时序主要分为四个大步骤:1.发送设备地址;2.发送要读取的寄存器值;3.重新发送设备地址;4.I2C 从设备输出要读取的寄存器值

  • 1.主机发送起始信号
  • 2.主机发送要读写的从设备地址
  • 3.读写控制位,因为是向 I2C 从设备发送数据,因此是写信号
  • 4.从机发送 ACK 应答信号
  • 5.重新发送start信号
  • 6.主机发送要读取的寄存器地址
  • 7.从机发送的 ACK 应答信号
  • 8.重新发送 START 信号
  • 9.重新发送要读取的 I2C 从设备地址
  • 10.读写控制位,这里是读信号,表示接下来是从 I2C 从设备里面读取数据
  • 11.从机发送的 ACK 应答信号
  • 12.从 I2C 器件里面读取数据
  • 13.在读到最后8位数据时,主机要将SDA置1,主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了
  • 14.主机发出 STOP 信号,停止 I2C 通信

注意:
SCL一直由主机端控制 ,SDA依照数据传送的方向,读数据时由从机控制SDA,写数据时由主机控制SDA。当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反

7、软件I2C和硬件I2C

I2C分为 软件I2C硬件I2C

软件IIC 软件I2C通信指的是用单片机的两个I/O端口 模拟 出来的I2C,用软件控制管脚状态以模拟I2C通信波形,软件模拟寄存器的工作方式。

直接使用 CPU 内核按照 I2C 协议的要求控制 GPIO 输出高低电平,从而模拟I2C。
使用: 需要在控制产生 I2C 的起始信号时,控制作为SCL 线的 GPIO 引脚输出高电平,然后控制作为 SDA 线的 GPIO 引脚在此期间完成由高电平至低电平的切换,最后再控制SCL线切换为低电平,这样就输出了一个标准的 I2C 起始信号。

硬件I2C 一块硬件电路,硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,硬件(固件)I2C是直接调用内部寄存器进行配置。

直接利用 STM32 芯片中的硬件 I2C 外设。
使用: 只要配置好对应的寄存器,外设就会产生标准串口协议的时序。在初始化好 I2C 外设后,只需要把某寄存器位置 1,此时外设就会控制对应的 SCL 及 SDA 线自动产生 I2C 起始信号,不需要内核直接控制引脚的电平。

硬件I2C的效率要远高于软件的,而软件I2C由于不受管脚限制,接口比较灵活。

三、实现过程

1、任务要求

阅读AHT20数据手册,编程实现:每隔2秒钟采集一次温湿度数据,并通过串口发送到上位机(win11)。

2、准备工作

建议根据正点原子或者野火提供的示例代码进行修改与代码添加。

相关的AHT20资料大家可以去官网进行查看与下载: http://www.aosong.com/class-36.html

3、核心代码

AHT20芯片的使用过程 read_AHT20_once 函数:

void  read_AHT20_once(void)
{
    
    
	delay_ms(1);

	reset_AHT20();//重置AHT20芯片
	delay_ms(1);

	init_AHT20();//初始化AHT20芯片
	delay_ms(1);

	startMeasure_AHT20();//开始测试AHT20芯片
	delay_ms(1);

	read_AHT20();//读取AHT20采集的到的数据
	delay_ms(1);
}

AHT20芯片读取数据 read_AHT20 函数:

void read_AHT20(void)
{
    
    
	uint8_t   i;
	for(i=0; i<6; i++)
	{
    
    
		readByte[i]=0;
	}
	I2C_Start();//I2C启动

	I2C_WriteByte(0x71);//I2C写数据
	ack_status = Receive_ACK();//收到的应答信息
	readByte[0]= I2C_ReadByte();//I2C读取数据
	Send_ACK();//发送应答信息

	readByte[1]= I2C_ReadByte();
	Send_ACK();

	readByte[2]= I2C_ReadByte();
	Send_ACK();

	readByte[3]= I2C_ReadByte();
	Send_ACK();

	readByte[4]= I2C_ReadByte();
	Send_ACK();

	readByte[5]= I2C_ReadByte();
	SendNot_Ack();
	//Send_ACK();

	I2C_Stop();//I2C停止函数
	//判断读取到的第一个字节是不是0x08,0x08是该芯片读取流程中规定的,如果读取过程没有问题,就对读到的数据进行相应的处理
	if( (readByte[0] & 0x68) == 0x08 )
	{
    
    
		H1 = readByte[1];
		H1 = (H1<<8) | readByte[2];
		H1 = (H1<<8) | readByte[3];
		H1 = H1>>4;

		H1 = (H1*1000)/1024/1024;

		T1 = readByte[3];
		T1 = T1 & 0x0000000F;
		T1 = (T1<<8) | readByte[4];
		T1 = (T1<<8) | readByte[5];

		T1 = (T1*2000)/1024/1024 - 500;

		AHT20_OutData[0] = (H1>>8) & 0x000000FF;
		AHT20_OutData[1] = H1 & 0x000000FF;

		AHT20_OutData[2] = (T1>>8) & 0x000000FF;
		AHT20_OutData[3] = T1 & 0x000000FF;
	}
	else
	{
    
    
		AHT20_OutData[0] = 0xFF;
		AHT20_OutData[1] = 0xFF;

		AHT20_OutData[2] = 0xFF;
		AHT20_OutData[3] = 0xFF;
		printf("测量失败!!!");
	}
	printf("\r\n");
	//根据AHT20芯片中,温度和湿度的计算公式,得到最终的结果,通过串口显示
	printf("当前温度为:%d%d.%d\n",T1/100,(T1/10)%10,T1%10);
	printf("当前湿度为:%d%d.%d",H1/100,(H1/10)%10,H1%10);
	printf("\r\n");
}

4、项目总览

在这里插入图片描述

5、项目地址

我已经将项目打包上传到gitee仓库里面了,地址如下:

基于I2C总线协议使用AHT20传感器实现温度采集

四、编译烧录

1、硬件连接

通信模块和供电模块连接方法:

USB转TTL STM32F103C8T6
GND G
3V3 3V3
RXD PA9
TXD PA10

注意将核心板上的BOOT0设置为1,BOOT1设置为0

在这里插入图片描述
在这里插入图片描述

AHT20传感器模块连接方法:

STM32F103C8T6 AHT20传感器
3.3V 1号脚(VDD)
PB7 2号脚(SDA)
GND 3号脚(GND)
PB6 4号脚(SCL)

在这里插入图片描述
在这里插入图片描述

2、编译

(1)点击 Options for Target…,在 Output 下勾选 Create HEX File
在这里插入图片描述

(2)在 Debug 下勾选 Use Simulator,将 Dialog DLL下的输入框改为 DARMSTM.DLLParameter 输入框改为 -pSTM32F103C8
在这里插入图片描述

(3)在 Target 选择使用 V5编译器
在这里插入图片描述

(4)点击 Rebuild进行编译
在这里插入图片描述

3、烧录

打开 FlyMcu 烧录助手,选择刚刚生成的 HEX文件,点击 开始编程 进行烧录
在这里插入图片描述

4、运行效果

使用SSCOM串口调试助手观察串口输出,发现可以正常显示采集到的温度。我把AHT20传感器放在电脑散热口,发现测量到的温度和湿度都发生了改变。

基于I2C协议使用AH20温湿度传感器采集温湿度

在这里插入图片描述

五、总结

通过本次实验,我基本了解了I2C总线通信协议。并在此基础上,我实现了使用 STM32F103C8T6 基于 I2C 协议的 AHT20 温湿度传感器的数据采集,并将采集的温度-湿度值通过串口输出。

本次实验不仅加深了我对I2C总线协议的理解,还加深了我对串口通信相关知识的理解,还学习到了AHT20温湿度传感器的使用。

本次实验完成过程中也遇到了不少问题。刚开始的时候,我本来打算用自己最开始创建的模板来实现,但是进行到一半的时候,发现缺少一些必须的文件,比如 bsp_i2c.c 文件;另外就是当代码开始运行时,串口读到的温度和湿度一直都是 0.0 。最后发现是因为:由于传感器引脚很细,不能很好地固定住,于是为了让温度传感器更加牢固地接到杜邦线上,给传感器的四个引脚点了一些锡,这样的确把温度传感器固定住了,但是却导致了接触不良,后面换了一个传感器就成功解决了这个问题。

最后就是,只有在动手实践的过程中才能发现自己掌握到的知识的局限性,才能发现实现过程中容易遇到的问题以及解决办法,从而提升自己解决问题的能力。


参考列表:
1.I2C总线通信协议及实操stm32通过I2C实现温湿度(AHT20)采集
2.I2C总线协议详解(特点、通信过程、典型I2C时序)
3.i2c总线协议简介
4.一文看懂 I2C 通信协议

猜你喜欢

转载自blog.csdn.net/qq_52068373/article/details/127629640