嵌入式系统开发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转TTLSTM32F103C8T6
GNDG
3V33V3
RXDPA9
TXDPA10

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

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

AHT20传感器模块连接方法:

STM32F103C8T6AHT20传感器
3.3V1号脚(VDD)
PB72号脚(SDA)
GND3号脚(GND)
PB64号脚(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 通信协议

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

6¿6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值