AHT20温湿度采集(I2C协议)


前言

本例使用I2C协议读取AHT20温湿度传感器的值,并将读取到的数据通过串口打印出来。

一、I2C简介

(一)I2C协议简介

I2C 通讯协议(Inter-Integrated Circuit)是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。

I2C总线主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
 
I2C总线的另一个优点是,它支持多主控(multimastering), 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主控。

1.I2C物理层

在这里插入图片描述

  • 它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在一个I2C通讯总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机。

  • 一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

  • 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

  • 总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。

  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

  • 具有三种传输模式:标准模式传输速率为100kbit/s ,快速模式为400kbit/s ,高速模式下可达3.4Mbit/s,但目前大多I2C设备尚不支持高速模式。

引用来源(野火参考资料)

2.I2C协议层

I2C的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

  • I2C基本读写过程
  • 通讯的起始和停止信号
  • 数据有效性
  • 地址及数据方向
  • 响应

其中,按照是否使用I2C基本外设可分为

软件模拟协议:使用CPU直接控制通讯引脚的电平,产生出符合通讯协议标准的逻辑。

硬件实现协议:由STM32的I2C片上外设专门负责实现I2C通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理I2C协议的方式减轻了CPU的工作,且使软件设计更加简单。

本例我们主要软件I2C为例,详细分析I2C的通讯格式。

3.AHT20简介

产品外型
在这里插入图片描述
引脚定义
在这里插入图片描述
传感器读取流程

  1. 上电后要等待不少于100ms, 读取温湿度值之前, 通过发送0x71获取一个字节的状态字,如果状态字和0x18相与后不等于0x18,初始化0x1B、 0x1C、 0x1E寄存器, 详细初始化流程请参照官网例程; 如果相等,执行下一步
  2. 等待10ms发送0xAC命令(触发测量), 此命令参数有两个字节, 第一个字节为0x33,第二个字节为0x00
  3. 等待80ms待测量完成,如果读取状态字Bit[7]为0, 表示测量完成, 然后可以连续读取六个字节; 否则继续等待
  4. 当接收完六个字节后, 紧接着下一个字节是CRC校验数据, 用户可以根据需要读出, 如果接收端需要CRC校验,则在接收完第六个字节后发ACK应答, 否则发NACK结束,CRC初始值为0XFF,CRC8校验多项式为:

CRC[7:0]=1+x4+x5+x8AHT20

  1. 计算温湿度值。 注: 在第一步的校准状态检验只需要上电时检查, 在正常采集过程无需操作。

在这里插入图片描述

  1. 原始数据处理

在这里插入图片描述

二、模拟I2C

本例是以AHT20温湿度传感器读取数据为例,主要分析在I2C通讯协议的起始与停止信号、应答/非应答信号,数据有效性、数据读写操作等。
AHT20例程
在这里插入图片描述

关于AHT20例程文件的移植的详细讲解,可参考

STM32基于IIC的温湿度采集(AHT20)

(一)起始/停止信号

在这里插入图片描述

起始信号

void IIC_Start(void)
{
	SDA_OUT();     //配置SDA线输出为通用推挽输出,输出速度为50Mhz
	IIC_SDA=1;	   //SDA线输出高电平
	IIC_SCL=1;     //SCL线输出高电平
	delay_us(4);
 	IIC_SDA=0;   	//SCL线为高电平时,SDA线由高变低(下降沿),表示通信的开始
	delay_us(4);
	IIC_SCL=0;		//钳住I2C总线,准备发送或接收数据 
}	  

可以看到,当SCL线是高电平时,SDA线从高电平向低电平切换,表示通讯的开始。

停止信号

void IIC_Stop(void)
{
	SDA_OUT();  	//配置SDA线输出为通用推挽输出,输出速度为50Mhz
	IIC_SCL=0;  	//SCL线输出低电平
	IIC_SDA=0;   	//SDA线输出高电平
 	delay_us(4);
	IIC_SCL=1;   	//SCL线输出高电平
	IIC_SDA=1;   	//SCL线为高电平时,SDA线由低变高(上升沿),表示通信的结束
	delay_us(4);							   	
}

当SCL线是高电平时,SDA线从低电平向高电平切换,表示通讯的停止。

(二)数据有效性

在这里插入图片描述
I2C使用SDA信号线来传输数据,使用SCL线进行数据同步。

SDA数据线在SCL的每个时钟周期传输一位数据。

  • SCL为高电平的时候,表示SDA的数据有效,即此时的SDA为高电平时表示数据“1”,低电平时表示数据“0”。
  • 当SCL为低电平时,表示SDA的数据无效,一般在这个时候进行电平转换,为下一次传输数据做好准备。
void AHT20_WR_Byte(uint8_t Byte) //往AHT20写一个字节
{
	uint8_t Data,N,i;	
	Data=Byte;
	SDA_OUT();  	//配置SDA线输出为通用推挽输出,输出速度为50Mhz
	i = 0x80;    //1000 0000
	for(N=0;N<8;N++)
	{
		
		/*此时SCL线为低电平,表示SDA数据的交换		*/	
		IIC_SCL=0;  
		delay_us(4);	
		if(i&Data)
		{
			IIC_SDA=1; 
		}
		else
		{
			IIC_SDA=0; 
		}	
	  /*此时SCL线为低电平,表示SDA数据的交换		*/	
		
    	IIC_SCL=1;     //SCL线为高电平、表示数据有效
		delay_us(4);	
		Data <<= 1;   //移位发送,从高位向低位发送数据
		 
	}
	IIC_SCL=0;    //SCL线再次置低
	delay_us(8);	
}	

我们用示波器观察发送以数据0x12为例的波形

在这里插入图片描述

(三)应答/非应答

在这里插入图片描述

发送应答信号

//I2C应答信号
void IIC_Ack(void)
{
	IIC_SCL=0;   //SCL线输出低电平
	SDA_OUT();   //配置SDA线输出为通用推挽输出,输出速度为50Mhz
	
	IIC_SDA=0;   //SDA线输出低电平
	delay_us(2);
	IIC_SCL=1;   //SCL线输出高电平,当SCL线为高电平时,此时SDA为低电平,表示应答
	
	delay_us(2);
	IIC_SCL=0;   //SCL线输出低电平
}

当SCL线为高电平时、SDA线为低电平表示响应。

发送非应答信号

//I2C非应答信号
void IIC_NAck(void)
{
	IIC_SCL=0;  //SCL线输出低电平
	SDA_OUT();  //配置SDA线输出为通用推挽输出,输出速度为50Mhz
	
	IIC_SDA=1;  //SDA线输出高电平
	delay_us(2);
	IIC_SCL=1;  //SCL线输出高电平,此时SCL线为高电平,SDA线也为高电平,表示不响应
	
	delay_us(2);
	IIC_SCL=0;  //SCL线输出低电平
}					 			

可以看到,当SCL线为高电平时、SDA线为高电平表示不响应。

因为I2C协议的规定,主机每接收(发送)一个字节的数据,主机(传感器)都要返回一个应答/非应答信号。

因为I2C协议的规定,主机每接收(发送)一个字节的数据,主机(传感器)都要返回一个应答/非应答信号。
以下是主机写多个字节数据的帧格式(我们以stm32向AHT20传感器写数据为例)
在这里插入图片描述

  • 主机stm32产生起始信号
  • 主机向总线发送7位设备(AHT20)地址和一个读/写位,构成一个字节数据
  • AHT20判断主机发送的地址与自身设备地址相同,产生应答响应
  • 主机发送一个数据,AHT20成功接收,并产生应答响应(表示AHT20还需要接收数据)
  • 主机再次发送一个数据,AHT20成功接收,并产生非应答响应(表示AHT20不需要接收数据了)
  • 主机收到非应答响应,产生停止信号,通信结束

IIC写字节代码

//IIC_WriteByte流程
void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{
	IIC_Start();  //产生起始信号
	
	if(device_addr==0xA0) 
		IIC_Send_Byte(0xA0 + ((addr/256)<<1));  //写入设备“读”地址
	else
		IIC_Send_Byte(device_addr);	    		//写入设备“写”地址
		
	IIC_Wait_Ack();  //等待应答信号
	
	IIC_Send_Byte(addr&0xFF);   //写入要读/写操作的寄存器地址
	IIC_Wait_Ack(); 			//等待应答信号
	
	IIC_Send_Byte(data);     //写入数据				   
	IIC_Wait_Ack();  		 //等待应答信号
	  	   
    IIC_Stop();				//数据停止信号
  
	if(device_addr==0xA0) 
		delay_ms(10);
	else
		delay_us(2);
}

注意:只有最后希望通信停止的时候才发送NACK信号,而表示对数据正确接收到并希望继续接收数据,需要发送ACK信号。

三、硬件I2C

(一)I2C的功能框图

在这里插入图片描述

I2C 的所有硬件架构都是根据图中左侧 SCL 线和 SDA 线展开的 。 STM32 芯片有多个 I2C 外设,它们的 I2C 通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚,见表 STM32F10x 的 I2C 引脚 。

关于I2C的GPIO引脚的复用功能,参考如下

在这里插入图片描述

(二)I2C硬件控制逻辑

1.时钟控制逻辑

SCL 线的时钟信号,由 I2C 接口根据时钟控制寄存器 (CCR) 控制,控制的参数主要为时钟频率。

配置 I2C 的 CCR 寄存器可修改通讯速率相关的参数:
在这里插入图片描述
选择不同的模式,可以配置I2C不同的通讯速率。

2.数据控制逻辑

在这里插入图片描述

I2C 的 SDA 信号主要连接到数据移位寄存器上,数据移位寄存器的数据来源及目标是数据寄存器 (DR)、地址寄存器 (OAR)、 PEC 寄存器以及 SDA 数据线。当向外发送数据的时候,数据移位寄存器以“数据寄存器”为数据源,把数据一位一位地通过 SDA 信号线发送出去;当从外部接收数据的时候,数据移位寄存器把 SDA 信号线采样到的数据一位一位地存储到“数据寄存器”中。

若使能了数据校验,接收到的数据会经过 PCE 计算器运算,运算结果存储在“PEC 寄存器”中。 当 STM32 的 I2C 工作在从机模式的时候,接收到设备地址信号时,数据移位寄存器会把接收到 的地址与 STM32 的自身的“I2C 地址寄存器”的值作比较,以便响应主机的寻址。 STM32 的自 身 I2C 地址可通过修改“自身地址寄存器”修改,支持同时使用两个 I2C 设备地址,两个地址分 别存储在 OAR1 和 OAR2 中。

3.整体控制逻辑

在这里插入图片描述

整体控制逻辑负责协调整个 I2C 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器 (SR1 和 SR2)”,我们只要读取这些寄存器相关的寄存器位,就可以了解 I2C 的工作状态。

除此之外,控制逻辑还根据要求,负责控制产生 I2C 中断信号、 DMA 请求及各种 I2C 的通讯信号(起始、停止、响应信号等)。


四、演示实例

  • main文件
int main(void)
 {	 	
    u32 CT_data[2]={0};
    volatile float  hum=0,tem=0;     
     
    delay_init();	    	 //延时函数初始化	  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);	 //串口初始化为115200
    
    temphum_init();     //ATH20初始化    
	
	while(1)
	{
        AHT20_Read_CTdata(CT_data);       //不经过CRC校验,直接读取AHT20的温度和湿度数据 

        hum = CT_data[0]*100*10/1024/1024;  //计算得到湿度值(放大了10倍)
        tem = CT_data[1]*200*10/1024/1024-500;//计算得到温度值(放大了10倍)

        printf("湿度:%.1f%%\r\n",(hum/10));
        printf("温度:%.1f度\r\n",(tem/10));
        printf("\r\n");
        
        delay_ms(1000);
	 }

}
 
  • 接线方式
AHT20STM32F103C8T6
SCLPB6
SDAPB7
VCC3V3
GNDGND
  • 演示效果如下
    在这里插入图片描述

总结

硬件I2C和软件I2C各有其特点,对软件I2C代码分析让我对I2C的数据通讯格式有了更深刻的理解,但是也只是简单的了解一些通讯格式。原本是想尝试参考软件I2C的流程使用硬件I2C替代一下,,但是参考例程配置硬件I2C外设以以及数据的格式处理等,中途遇到了一些问题,现在尚未解决。

以上若有不当之处,敬请指教!

参考

《STM32库开发指南-基于野火指南者开发板PDF》

《AHT20产品规格书》

基于I2C硬件协议的AHT20温湿度数据采集

STM32基于IIC的温湿度采集(AHT20)

IIC原理超详细讲解—值得一看

STM32下基于IIC协议的AHT20温湿度采集

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值