当前位置: 首页 > news >正文

STM32-Cube-IIC通讯

一、温湿度传感器AHT20–IIC通讯轮询模式

1、创建新项目,芯片选用STM32F103C8T6,项目名为iic。

2、根据AHT20所连接的引脚,开启IIC1外设。

在这里插入图片描述

3、项目管理,为每个外设生成一个.c、.h文件,这样就可以include头文件,拿到huart1或者hi2c这类外设的操作句柄了,之后保存生成代码。

在这里插入图片描述

4、创建自己的.c、.h文件

  1. Core→Inc右键→New→Hreader File,命名aht20.h
  2. Core→src右键→New→Source File,命名aht20.c

5、代码部分

在这里插入图片描述

  1. 根据数据手册的传感器读取流程1,可以写出AHT20的初始化函数。
#define AHT20_ADDRESS	0X70
/* HAL库会根据用户发送或者接受数据将地址最后一位置1或者置0 */void AHT20_Init(void) {uint8_t	readBuffer;HAL_Delay(40);HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, &readBuffer, 1, HAL_MAX_DELAY);if ((readBuffer & 0x08) == 0x00) {uint8_t	sendBuffer[3] = {0xBE, 0x08, 0x00};HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);}
}
  1. 根据数据手册的传感器读取流程2跟3,还有数据表可以写出AHT20的读取测量数据的函数。
    在这里插入图片描述
void AHT20_Read(float *Temperature, float *Humidity) {uint8_t	sendBuffer[3] = {0xAC, 0x33, 0x00};uint8_t	readBuffer[6];HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);HAL_Delay(75);HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS, readBuffer, 6, HAL_MAX_DELAY);if ((readBuffer[0] & 0x80) == 0x00) {uint32_t data = 0;data = ((uint32_t)readBuffer[3] >> 4) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);*Humidity = data * 100.0f / (1 << 20);data = ((uint32_t)readBuffer[5]) + ((uint32_t)readBuffer[4] << 8) + (((uint32_t)readBuffer[3] & 0x0F) << 16);*Temperature = (data * 200.0f / (1 << 20)) - 50;}}
  1. 由于我们使用到浮点数,Cube默认没有启用编译器对浮点数输出的支持,在菜单栏project→properties进入设置页面勾选图纸选项开启此功能。
    在这里插入图片描述
  2. 主函数部分。
  • 先将AHT20初始化,创建两个变量和一个用来临时存放数据的数组。
  AHT20_Init();float temperature, humidity;char dataArray[50];
  • 在循环语句种,读取测量数据并通过串口发送出来。
  while (1){AHT20_Read(&temperature, &humidity);sprintf(dataArray, "温度:%.f ℃, 湿度:%.f %%\r\n", temperature, humidity);/* sprintf() 函数只是将特定格式存于数组dataArray中,再通过串口将数组发送出去 */HAL_UART_Transmit(&huart1, (uint8_t*)dataArray, strlen(dataArray), HAL_MAX_DELAY);HAL_Delay(1000);}
  1. 编译代码并烧录,再通过连接串口获取单片机发送的数据。
    在这里插入图片描述

二、IIC中断模式与状态机

1、IIC中断模式

  1. 打开IIC的中断向量并保存生成代码。
    在这里插入图片描述

2、利用状态机编程代码。

  • 前面我们使用的轮询的方式,读取模块的数据时,有等待时间,等待读取成功之后才发送到串口显示出来。如果我们只是简单的将轮询模式中IIC的发送和接受改成中断模式,会导致数据的读取还未完成时就将数据给发送出去,造成数据的错误,所以我们需要对代码进行改造,利用状态机来编码,不同的状态做不同的事。

1.因为状态机的原理就是不同的状态做不同的事情,所以我们将上面读取数据的函数AHT20_Read()拆分为三个单独的函数,如下:

  1. 发送测量指令:
/* 测量函数 */
void AHT20_Measure(void) {//因为函数用的是sendBuffer指针的地址,函数运行结束之后就会被释放,被其他变量所使用,所以这里需要使用static来创建数组,保证数组的地址一直存在。static uint8_t	sendBuffer[3] = {0xAC, 0x33, 0x00};HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
}
  1. 获取模块的数据:
/* 获取数据 */
void AHT20_GetData(void) {//将获取的数据存于readBuffer数组之中,readBuffer为全局变量,方便其他函数使用HAL_I2C_Master_Receive_IT(&hi2c1, AHT20_ADDRESS, readBuffer, 6);
}
  1. 解析获取的数据:
uint8_t	readBuffer[6] = {0};/* 解析获取到的数据 */
void AHT20_AnalysisData(float *Temperature, float *Humidity) {if ((readBuffer[0] & 0x80) == 0x00) {uint32_t data = 0;data = ((uint32_t)readBuffer[3] >> 4) + ((uint32_t)readBuffer[2] << 4) + ((uint32_t)readBuffer[1] << 12);*Humidity = data * 100.0f / (1 << 20);data = ((uint32_t)readBuffer[5]) + ((uint32_t)readBuffer[4] << 8) + (((uint32_t)readBuffer[3] & 0x0F) << 16);*Temperature = (data * 200.0f / (1 << 20)) - 50;}
}
  1. 函数注意要在头文件中申明,方便其他文件使用。

2.创建状态机模型

/* USER CODE BEGIN PV */
uint8_t aht20State = 0;
/* USER CODE END PV */

在这里插入图片描述

  • 0:初始状态,发送测量指令,然后将状态变为1
  • 1:正在发送测量指令中
  • 2:发送完成,按照手册中需要等75ms后才可以进行读取
  • 3:读取中
  • 4:读取完成,对数据进行解析并展示数据并且需要将状态恢复到初始状态,进行下一个循环。

3.代码部分

  • 主函数的循环语句中,我们发现没有状态1切换到状态2、状态3切换到状态4的语句,我们需要所以我们需要借助IIC中断的回调函数来实现切换状态的功能。也因为状态aht20State需要在其他函数中使用,所以我们需要将次变量在头文件中加上extern来声明,其他文件中才可以使用。
  • main.h文件中
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
extern uint8_t aht20State;
/* USER CODE END EC */
  • main.c文件中
  while (1){if (aht20State == 0) {			//初始状态,发送测量指令AHT20_Measure();aht20State = 1;}  else if (aht20State == 2) {		//发送完成,等75ms后才可以进行读取HAL_Delay(75);AHT20_GetData();aht20State = 3;} else if (aht20State == 4) {		//读取完成,对数据进行解析并展示数据AHT20_AnalysisData(Temperature, Humidity);sprintf(dataArray, "温度:%.f ℃, 湿度:%.f %%\r\n", temperature, humidity);HAL_UART_Transmit(&huart1, (uint8_t*)dataArray, strlen(dataArray), HAL_MAX_DELAY);HAL_Delay(5000);aht20State = 0;}
  • 在i2c.c文件中,发送完成和接受完成的回调函数。
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) {if (hi2c == &hi2c1) {aht20State = 2;}
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) {if (hi2c == &hi2c1) {aht20State = 4;}
}
  • 在上个实例中我们用得是阻塞式IIC通讯,关于AHT20_Init()的函数中也要修改成中断模式:
void AHT20_Init(void) {uint8_t	readBuffer;HAL_Delay(40);HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, &readBuffer, 1);if ((readBuffer & 0x08) == 0x00) {uint8_t	sendBuffer[3] = {0xBE, 0x08, 0x00};HAL_I2C_Master_Receive_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);}
}
  • 烧录后通过串口发送数据,一切正常。
    在这里插入图片描述

三、IIC通讯DMA模式

1、开启DMA模式

  • 开启IIC的DMA模式,添加两个通道,一个RX一个TX,其他设置无需修改,保持默认。保存生成代码
    在这里插入图片描述

2、将中断模式的代码修改为DMA模式的代码。

  • 初始化函数,将后缀_IT改为_DMA即可。
void AHT20_Init(void) {uint8_t	readBuffer;HAL_Delay(40);HAL_I2C_Master_Transmit_DMA(&hi2c1, AHT20_ADDRESS, &readBuffer, 1);if ((readBuffer & 0x08) == 0x00) {uint8_t	sendBuffer[3] = {0xBE, 0x08, 0x00};HAL_I2C_Master_Receive_DMA(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);}
}
  • 测量函数,将后缀_IT改为_DMA即可。
/* 测量函数 */
void AHT20_Measure(void) {//因为函数用的是sendBuffer指针的地址,函数运行结束之后就会被释放,被其他变量所使用,所以这里需要使用static来创建数组,保证数组的地址一直存在。static uint8_t	sendBuffer[3] = {0xAC, 0x33, 0x00};HAL_I2C_Master_Transmit_DMA(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
}
  • 获取数据函数,将后缀_IT改为_DMA即可。
/* 获取数据 */
void AHT20_GetData(void) {//将获取的数据存于readBuffer数组之中,readBuffer为全局变量,方便其他函数使用HAL_I2C_Master_Receive_DMA(&hi2c1, AHT20_ADDRESS, readBuffer, 6);
}
  • 完成修改,功能没变,只是IIC的模式改变而已。
  • 此文章仅自己学习记录用,是参考小破站keysking的教程。

http://www.mrgr.cn/news/55896.html

相关文章:

  • bug的定义和测试
  • nuScenes数据集使用的相机的外参和内参
  • 2024年9月电子学会青少年软件编程Python等级考试(一级)真题试卷
  • 代码随想录算法训练营第三十一天|56. 合并区间、738.单调递增的数字
  • 【网安第三章】——XSS
  • 配置文件get调用为null
  • vue3中el-select v-model=““给v-model默认值一些注意事项;
  • vscode 配置构建、调试QT项目
  • 超详细的总结!最新大模型算法岗面试题(含答案)来了!
  • YOLOv11快速上手:如何在本地使用TorchServe部署目标检测模型
  • 深入探索Python集合(Set)的高效应用:数据处理、性能优化与实际案例分析
  • 【python openai function2json小工具】
  • Vuejs设计与实现 —— 实现响应式系统
  • 【MATLAB源码-第186期】matlab基于MLE算法的8天线阵列DOA估计仿真,对比粗估计、精确估计输出RMSE对比图。
  • DeepSpeed:所有人都能用的超大规模模型训练工具
  • 开源神器!CodeFormer:一键去除马赛克,高清修复照片视频
  • 将VSCode界面的显示语言改为简体中文,切换VScode界面的显示语言
  • 智能码二维码ZHINENGMA.CN在设备巡检中的使用效果如何?
  • 前端性能优化之卡顿篇
  • 数据的全量加载和增量加载
  • pdman在关系图中展示表的后排字段
  • WORFBENCH:一个创新的评估基准,目的是全面测试大型语言模型在生成复杂工作流 方面的性能。
  • Centos7.6版本安装mysql详细步骤
  • Vue3 学习笔记(一)Vue3 介绍及环境部署
  • Docker 教程十一(Docker Machine)
  • 如何借助通达信API构建自动化交易系统?