您的位置:首页 > 科技 > 能源 > 工作室取名_广州互联网公司_成都sem优化_网站友情链接连接

工作室取名_广州互联网公司_成都sem优化_网站友情链接连接

2024/11/17 14:25:27 来源:https://blog.csdn.net/weixin_62567907/article/details/143044558  浏览:    关键词:工作室取名_广州互联网公司_成都sem优化_网站友情链接连接
工作室取名_广州互联网公司_成都sem优化_网站友情链接连接

一、温湿度传感器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的教程。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com