【STM32笔记】STM32的IIC通信基础(二)---IIC读取AHT20温湿度数据(轮询模式)


I2C的常用术语:

  • 主机:初始化发送、产生时钟和终止发送的器件,通常是微控制器。
  • 从机:被主机寻址的器件。
  • 发送器:本次传输中发送数据到I2C总线的器件,既可以作为主机又可以作为从机,由通信过程具体而定。
  • 接收器:本次传输中从I2C总线上接收数据的器件,既可以作为主机又可以作为从机,由通信过程具体而定。

连接在I2C总线上的器件即是主机(或从机),又是发送器(或接收器),这取决于器件所要完成的具体功能。

一. IIC的物理层

1. IIC接口

  I2C是半双工同步通信,相比于USART和SPI,它需要的信号最少,只需要SDASCL两根线。
  (1). SCL(Serial Clock,串行时钟线):I2C通信中用于传输时钟的信号线,通常由主机发出。SCL采用集电极开路或漏极开路的输出方式。这样,I2C器件只能使SCL下拉到逻辑0,而不能强行将SCL上拉到逻辑1。
  (2). SDA(Serial Data,串行数据线):I2C通信中用于传输数据的信号线,SDA采用集电极开路或漏极开路输出方式。这样,I2C器件只能使SDA下拉到逻辑0,而不能强行将SDA上拉到逻辑1。

2. IIC互连

  (1). 必须在I2C总线上外接上拉电阻。由于I2C采用集电极开路或漏极开路的输出方式,连接到I2C总线上的任何器件都只能使SCL和SDA置0。所以必须在SCL和SDA上外加上拉电阻,使两根信号线进行置1,才能正确进行数据通信。

  (2). 通过地址区分挂载在I2C总线上的不同的器件。多个I2C器件可以并联I2C总线上,I2C使用地址来识别总线上的器件,更易于器件的扩展。在I2C互连的系统中,每个I2C器件都有一个唯一而独立的身份标识(ID)——(器件地址 address)。

  (3). 支持多主机互连。I2C带有竞争检测和仲裁电路,实现了真正的多主机互连。当多主机使用总线发送数据时,根据仲裁方式决定由哪一个设备占用总线,以防止数据冲突数据丢失。尽管I2C支持多主机互连,但同一时刻只能有一个主机。

二. IIC的协议层

  I2C是同步串行半双工通信,因此它按照时钟线SCL上的时钟节拍在数据线SDA上一位一位地进行数据传输。SCL每产生一个时钟脉冲,SDA上传输一位数据。
  I2C的协议层包括位传输字节传输数据流传输传输模式传输速率

  (1). 位传输(起始条件数据有效性停止条件

  • 起始条件(起始信号):当SCL为高电平时,SDA上由高电平到低电平地跳变。
    在这里插入图片描述

  • 数据有效性:SDA数据线必须在SCL为高电平时保持稳定,只能在SCL为低电平时才可以改变。否则将会误判断为起始信号或停止信号。
    在这里插入图片描述

  • 停止条件(停止信号):当SCL为高电平时,SDA线由低电平到高电平地跳变。
    在这里插入图片描述

  (2). 字节传输
  I2C上所有数据都是以1B(8b)为最小单位,按照高位(MSB)在前,低位(LSB)在后的顺序在SDA上传输。
  每当发送器发送完一个字节,接收器必须发送一个应答位(ACK,Acknowledgemen)以确认接收器是否成功收到了数据。

  (3). 数据流传输
  在I2C中,一次标准的I2C通信由起始信号从机地址传输数据传输停止信号组成的。

  • 起始信号S或重复起始信号SR,I2C通信由主机发送一个起始信号S或重复起始信号SR启动。
  • 从机地址传输ADDRESS。起始信号后,第一个字节由7/10位地址位和一位传输方向组成。特别的,当地址位全为0,且传输方向也为0时,为广播呼叫地址。
  • 数据传输DATA。I2C每次单位传输可以发送的数量不受限制。而且,每个字节传输完毕后必须等待接收器的应答。
  • 停止信号P或重复起始信号SR。

  (4). 传输模式
  在I2C中有两种传输模式:主机向从机写数据,主机向从机读数据。

  (5). 传输速率
  I2C中的标准传输速率为100kbps,快速传输可达到400kbps。目前,还增加了高速模式,最高传输速率可达3.4Mbps。

三. 使用STM32CubeMX实现 IIC 通信

打开STM32CubeMX,选择STM32103C8芯片,设置基本配置,设置时钟配置,打开USART1串口通信(使用轮询模式)。
在这里插入图片描述
在这里插入图片描述
Master Features (主机模式特性)

  • I2C Speed Mode(I2C速度模式):Standard Mode(标准模式)/ Fast Mode(快速模式) 修改此项改变下面的I2C时钟速率。
  • I2C Clock Speed(I2C时钟速率):在Standard Mode下,速率为100KHz,在Fast Mode下,速率为400KHz。
    Slave Features(从机模式特性)
  • Clock No Stretch Mode(时钟无拉伸模式): Disabled(禁止)/ Enabled(启用)
  • Primary Address Length selection(地址设备长度选择):7-bit(7位) / 10-bit(10位)
  • Dual Address Acknowledged(双地址确认): Disabled(禁止)/ Enabled(启用)
  • Primary slave address(主从地址)

设置好之后,设置存储路径,选择所用IDE,然后点击GENERATE CODE创建工程,在弹出的open project打开工程进行全局编译。
这里使用AHT20温湿度检测模块来进行IIC通信实验。

四. HAL库中IIC通信的重要函数

1. 主设备发送数据到从设备函数:HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

/**
  * @简介  在主模式下以阻塞模式向从机发送一定量的数据
  * @参数  hi2c 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
  * @参数  DevAddress Target device address(目标设备地址): 在调用接口之前,必须将数据表中的设备7位地址值向左移动
  * @参数  pData 指向数据缓冲区的pData指针
  * @参数  Size 要发送的数据量
  * @参数  Timeout 超时时间
  * @返回值  HAL status
  */

2. 主设备接收从设备发送来的数据函数:HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

/**
  * @简介  在主模式下以阻塞模式接收一定量的从机发来的数据
  * @参数  hi2c 指向I2C_HandleTypeDef结构体的指针,该结构体包含指定I2C的配置信息。
  * @参数  DevAddress Target device address(目标设备地址): 在调用接口之前,必须将数据表中的设备7位地址值向左移动
  * @参数  pData 指向数据缓冲区的pData指针
  * @参数  Size 要发送的数据量
  * @参数  Timeout 超时时间
  * @返回值  HAL status 
  */

以上函数在stm32f1xx_hal_i2c.c文件中:
在这里插入图片描述

五. 关于AHT20温湿度检测模块工作原理

  AHT20,新一代温湿度传感器在尺寸与智能方面建立了新的标准,传感器输出经过标定的数字信号,标准的I2C格式。
发送命令
  在启动传输后,随后传输的I2C首字节包括7位的I2C设备地址0x38和一个SDA的读写方向位(读:1,写:0)。在第8个SCL时钟下降沿之后,通过拉低SDA引脚(ACK位),指示传感器数据接收正常。在发送测量命令0xAC之后,MCU必须等到测量完成。
在这里插入图片描述
传感器读取数据流程
  1. 上电后要等待40ms,读取温湿度之前,首先要看状态字的校准使能位Bit[3]是否为1(发送0x71来获取一个字节的状态字),如果不为1,要发送0xBE,此命令有两个字节,第一个字节为0x08,第二个字节为0x00,然后等待10ms。

  2. 直接发送0xAC命令(开启测量),此命令参数有两个字节,第一个字节为0x33,第二个字节为0x00。
在这里插入图片描述

  3. 等待80ms待测量完成后,如果读取返回的第一个字节状态字Bit[7]为0,则表示测量完成,然后可以连续的读取6个字节,否则继续等待。
在这里插入图片描述
  4. 当接收完6个字节后,紧接着下一个字节是CRC校验数据,用户可以根据需要读出,如果接收端需要CRC校验,则在接收完第6个字节后发送ACK应答信号,否则发送NAC结束,CRC初始值为0xFF,CRC校验多项式为:
CRC [7:0] = 1 + x4 + x5 + x8

  5. 根据返回来的温湿度测量数据(首先返回两个半字节的湿度数据,其次在返回两个半字节的温度数据,最后返回CRC校验数据)。温湿度数据可根据以下公式来进行转换。
相对湿度转换 RH 公式,RH[%] = Srh / 2^20 * 100% |||| 温度转换 T 公式,T[℃] = St / 2^20 * 200 -50 ℃

在这里插入图片描述

六. 实现IIC通信

打开生成的工程文件找到Core文件,按照要求新建如下文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

打开生成的工程,按照要求添加文件
在这里插入图片描述
在这里插入图片描述

将如下代码添加到AHT20.c文件中(先写入#include "AHT20.h"代码再编译程序后,再将以下代码写入到AHT20.c文件中)

#include "AHT20.h"

#define AHT20 0x70

unsigned char readbuffer[6];

/* AHT20初始化
 * 进行AHT20温湿度模块的初始化,上电后等待40ms,发送0x71可以获取一个字节的状态字
 * 如果返回的数据(装载在readbuffer中)的校准使能位Bit[3]是否为1,即(xxxx 1xxx)
 * 若不为1,则需要发送0xBE命令(初始化)包含有两个字节0x08、0x00然后在等待10ms
*/ 
void AHT20_Init(){
	unsigned char readbuffer; // 装取数据
	HAL_Delay(40);
	// HAL_MAX_DELAY 永久等待 主机读取从机数据 读:函数会自动在设备地址基础上加1
	HAL_I2C_Master_Receive(&hi2c1,AHT20,&readbuffer,1,HAL_MAX_DELAY);
	if((readbuffer & 0x08) == 0x00){
		unsigned char sendbuffer[3] = {0xBE, 0x08, 0x00}; 
		// 主机向从机写入数据函数 写:函数会自动在设备地址基础上加0
		HAL_I2C_Master_Transmit(&hi2c1,AHT20,sendbuffer,1,HAL_MAX_DELAY); 
	}
}

/* AHT20读取温湿度数据 轮询模式下
 * 直接发送 0xAC命令(触发测量),此命令参数有两个字节0x33、为0x00
 * 等待80ms待测量完成,首先发送过来的是一组状态字
 * 其Bit[7]为0时,则表示测量完成,然后可以连续读取六个字节,否则就继续等待 (1为设备忙:测量,0为设备闲:休眠)
 * 返回6个字节后,紧接着下一个字节是CRC校验 校验公式为 CRC[7:0] = 1 + X^4 + X^5 + X^8
*/ 
void AHT20_Read(float *tm,float *hm){
	unsigned char sendbuffer[3] = {0xAC, 0x33, 0x00}; // 开启AHT20温湿度测量命令
	unsigned char readbuffer[6]; // 读取传来的6字节温湿度数据 先接收湿度数据,后接收温度数据
	unsigned int data = 0;
	
	HAL_I2C_Master_Transmit(&hi2c1,AHT20,sendbuffer,3,HAL_MAX_DELAY); // 向从机写入数据函数(开启AHT20温湿度测量)
	HAL_Delay(80);
	HAL_I2C_Master_Receive(&hi2c1,AHT20,readbuffer,6,HAL_MAX_DELAY); // 向从机读取数据函数(等待75ms后,读取AHT20测量的温湿度数据)
	if((readbuffer[0] & 0x80) == 0x00){ 
		data = ((uint32_t)readbuffer[1]<<12)+((uint32_t)readbuffer[2]<<4)+((uint32_t)readbuffer[3]>>4);
		// 相对湿度转换 RH 公式,RH[%] = Srh / 2^20 * 100% %
		*hm = data * 100.0f / (1<<20);
		
		data = (((uint32_t)readbuffer[3]&0x0f)<<16)+((uint32_t)readbuffer[4]<<8)+((uint32_t)readbuffer[5]);
		// 温度转换 T 公式,T[℃] = St / 2^20 * 200 -50 ℃
		*tm = (data * 200.0f) / (1<<20) - 50;
	}
}


将如下代码添加到AHT20.h文件中

#ifndef __AHT20_H
#define __AHT20_H

#include "i2c.h"

// 轮询状态下
void AHT20_Init(void); // 顶层头文件声明函数()必须要加void
void AHT20_Read(float *tm,float *hm);

#endif 


在main.c文件中的Private variables中的USER CODE BEGIN PV注释对中添加如下代码

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
float temperature,humidity;
char message[50];
/* USER CODE END PV */

在main.c文件中的Private includes中的USER CODE BEGIN Includes注释对中添加如下代码

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <AHT20.h>
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */

在main.c文件中的USER CODE BEGIN 2注释对中添加如下代码

/* USER CODE BEGIN 2 */
  AHT20_Init();
/* USER CODE END 2 */

在main.c文件中的main函数下USER CODE BEGIN WHILE注释对中添加如下代码

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {	
	  // 轮询模式
	  AHT20_Read(&temperature,&humidity);
	  sprintf((char *)message,"温度:%.1f ℃,湿度:%.1f %% \r\n",temperature,humidity);
	  HAL_UART_Transmit(&huart1,(uint8_t *)message,strlen(message),1000);
	  
	  HAL_Delay(500);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

完成以上代码的编写后,将开发板连接好所需要的对应的设备(AHT20,USB转TTL模块)。将工程下载到开发板上,打开串口调试助手,这里我使用的波特率是115200Bit/s。
在这里插入图片描述
至此,基于IIC通信(轮询模式)实现AHT20测量温湿度数据基本上就已经实现了。

下一节我们来聊聊基于STM32CubeMX的实现IIC通信(中断模式)的设计步骤

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值