7.1-I2C的中断

news2024/11/23 1:43:45

I2C的中断与DMA

回顾

HAL_I2C_MASTER_Transmit(&hi2c1,ADRESS,PDate,Size,Time);


HAL_I2C_MASTER_Receive(&hi2c1,ADRESS,PDate,Size,Time);

通信具体过程如下:
在这里插入图片描述

在I2C的轮询模式中

发送时:CPU将以主机0x70 发送 从机 ACK 回复 主机0xAC发送 ACK 回复 主机 0x33 从机ACK…全部发送且接收完成后,才会空闲下来,去处理其他指令,

接收时,也是类似,整个发送或者接收过程中,一直阻塞执行,占用着CPU资源。完成后才回去处理其他代码。

为了解决上述CPU阻塞情况,I2C也有中断模式与DMA模式

中断模式:

CPU发送一字节的数据0x70后,CPU就去执行其他正常任务,直到此字节数据发送成功后(从机返回ACK信号)产生中断 CPU 再来塞入下一字节的数据。

DMA模式:

整个发送或者接收的数据都交给小助手DMA去搬运,等数据接收或者发送完成过,再有DMA通过中断通知CPU前来处理

两种模式的用法与串口一样

I2C设置中断:

1.在图形界面开启NVIC Settings 中开启中断 ,本次主要用到事件中断向量。

在这里插入图片描述

下面用I2C的中断模式改造AHT20_Read()函数

HAL_I2C_Master_Transmit_IT(&hi2c1, ADDRESS, pData, Size);

参数与前面相同,不需要等待的时间

void AHT20_Read(float *Temperature, float *Humidty){
    uint8_t sendBuffer[3] = {0xAC,0x33,0x00};
    uint8_t readBuffer[6] = {0};

    HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
    HAL_Delay(75);
    HAL_I2C_Master_Receive_IT(&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);
    	*Humidty = data * 100.0f / (1<<20);

    	data = (((uint32_t)readBuffer[3]  &  0x0f )<<16 )  +   ((uint32_t)readBuffer[4]  << 8) + ((uint32_t)readBuffer[5]);
    	*Temperature = data *  200.0f/(1<<20) - 50;
	}
}

只是简单的修改并不能达到设想的效果,是因为

中断和DMA模式是非阻塞模式,他们将任务交给外设后就会接着向下执行。并不会等待数据的发送/接收完成,整个通信流程都交给外设与中断进行控制,通信完成后,再通过中断来通知我们。所以后面的对数据的处理前的Receive只是通知外设进行了读取。 但尚未读取完成,readBuffer里的数据都是我们初始化的0,解析出的数据自然就不对了

解决办法:将步骤拆解。将AHT20_Read()函数分解,分解成三个AHT20_Send()、AHT20_Get()、AHT20_Analysis().并在aht20.h中声明。


void AHT20_Send(){
	static uint8_t sendBuffer[3] = {0xAC,0x33,0x00};  //static将变量空间保留,不被回收
	HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
}


uint8_t readBuffer[6] = {0};


void AHT20_Get(){
	HAL_I2C_Master_Receive_IT(&hi2c1, AHT20_ADDRESS , readBuffer, 6);
}

void AHT20_Analysis(float *Temperature, float *Humidty){

	 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);
	    	*Humidty = data * 100.0f / (1<<20);

	    	data = (((uint32_t)readBuffer[3]  &  0x0f )<<16 )  +   ((uint32_t)readBuffer[4]  << 8) + ((uint32_t)readBuffer[5]);
	    	*Temperature = data *  200.0f/(1<<20) - 50;
		}
}

在main.c中编写状态机

  • 常用的一种编程方式:状态机编程

在这里插入图片描述

AHT20_Init();
  
  float temperature;
  float humidity;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  if (aht20State == 0) {
		AHT20_Send();
		aht20State == 1;
	}else if (aht20State == 1) {
		
	}else if (aht20State == 2) {
		HAL_Delay(75);
		AHT20_Get();
		aht20State = 3;
	}else if (aht20State == 3) {
		
	}else if (aht20State == 4) {
		AHT20_Analysis(&temperature, &humidity);
		sprintf(message,"温度:%.1f\t 湿度:%.1f%%\t\r",temperature,humidity);

		HAL_UART_Transmit(&huart2, (uint8_t *)message, strlen(message), HAL_MAX_DELAY);
		HAL_Delay(1000);
		aht20State = 0;
	}
	  

对于①②的代码,需要在stm32f1xx_hal_i2c.c中寻找这两个状态。

在这里插入图片描述

在这里插入图片描述

提示文件较大,点击YES后按下图更改

在这里插入图片描述

其中

__weak void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hi2c);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_I2C_MasterTxCpltCallback could be implemented in the user file
   */
}

__weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hi2c);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_I2C_MasterRxCpltCallback could be implemented in the user file
   */
}

MasterTxCpltCallback是I2C数据全部发送完成时的回调函数,MasterRxCpltCallback是I2C数据全部接收完成时的回调函数,

把他们在i2c.c文件中重新实现一下 USER CODE BEGIN0对儿中:

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
	  //此函数会在通过Transmit_IT函数发送的命令数据全部送达到从机后,由I2C中断调用
	 
   if (hi2c==&hi2c1) {  //判断是否是i2c1引起的中断
		aht20State = 2;
	}
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){
	if (hi2c==&hi2c1) {
    aht20State = 4;
	}
}

aht20State要在i2c.c中调用因此在mian.h的USER CODE BEGIN EC中将aht20State设置为 外部函数,可在i2c.c中使用。

extern uint8_t aht20State ;

完整代码

mian.c

----
/* USER CODE BEGIN PV */
uint8_t aht20State = 0;   //0初始状态   1 正在发送测量命令,
						  //2. 测量完成等待75ms后读取AHT20数据  3.读取中
						//4.读取完成,解析并展开数据然后恢复到初始状态
/* USER CODE END PV */
----
/* USER CODE BEGIN 2 */
  AHT20_Init();

  float temperature;
  float humidity;
  char message[50];

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
	  if (aht20State == 0) {
		AHT20_Send();
		aht20State = 1;
	}else if (aht20State == 1) {

	}else if (aht20State == 2) {
		HAL_Delay(75);
		AHT20_Get();
		aht20State = 3;
	}else if (aht20State == 3) {

	}else if (aht20State == 4) {
		AHT20_Analysis(&temperature, &humidity);
		sprintf(message,"温度:%.1f\t 湿度:%.1f%%\t\r",temperature,humidity);

		HAL_UART_Transmit(&huart2, (uint8_t *)message, strlen(message), HAL_MAX_DELAY);
		HAL_Delay(1000);
		aht20State = 0;
	}

    /* USER CODE BEGIN 3 */

mian.h中

/* USER CODE BEGIN EC */
extern uint8_t aht20State ;
/* USER CODE END EC */

aht20.h

#ifndef INC_AHT20_H_
#define INC_AHT20_H_

#include"i2c.h"


void AHT20_Init();
void AHT20_Send();
void AHT20_Get();
void AHT20_Analysis(float *Temperature, float *Humidty);

#endif /* INC_AHT20_H_ */

aht20.c

#include"aht20.h"

#define AHT20_ADDRESS 0x70

void AHT20_Init(){
    uint8_t readBuffer;
	HAL_Delay(40);

	HAL_I2C_Master_Receive(&hi2c1, AHT20_ADDRESS , &readBuffer, 1 , HAL_MAX_DELAY);

	if ((readBuffer  &  0x08) == 0x00) {
		uint8_t sendBuffer[3] = { 0xBE , 0x08 , 0x00 };
		HAL_I2C_Master_Transmit(&hi2c1, AHT20_ADDRESS, sendBuffer, 3, HAL_MAX_DELAY);
	}

}


void AHT20_Send(){
	static uint8_t sendBuffer[3] = {0xAC,0x33,0x00};  //static将变量空间保留,不被回收
	HAL_I2C_Master_Transmit_IT(&hi2c1, AHT20_ADDRESS, sendBuffer, 3);
}


uint8_t readBuffer[6] = {0};


void AHT20_Get(){
	HAL_I2C_Master_Receive_IT(&hi2c1, AHT20_ADDRESS , readBuffer, 6);
}

void AHT20_Analysis(float *Temperature, float *Humidty){

	 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);
	    	*Humidty = data * 100.0f / (1<<20);

	    	data = (((uint32_t)readBuffer[3]  &  0x0f )<<16 )  +   ((uint32_t)readBuffer[4]  << 8) + ((uint32_t)readBuffer[5]);
	    	*Temperature = data *  200.0f/(1<<20) - 50;
		}
}

i2c.c中

/* USER CODE BEGIN 0 */

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
	  //此函数会在通过Transmit_IT函数发送的命令数据全部送达到从机后,由I2C中断调用

   if (hi2c==&hi2c1) {  //判断是否是i2c1引起的中断
		aht20State = 2;
	}
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c){
	if (hi2c==&hi2c1) {
    aht20State = 4;
	}
}
/* USER CODE END 0 */

以上就是i2c的中断模式的应用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211565.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

⽂件的操作

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久化…

深圳大学-Java程序设计-必实验2 类的高级应用

实验目的与要求&#xff1a; 实验目的&#xff1a;熟悉面向对象编程中类的编写。 实验要求&#xff1a; (1).请自行选择2023年成都大运会或2023杭州亚运会。大型运动会通常包括众多比赛项目。请通过分析&#xff0c;抽象它们所共有的性质&#xff0c;定义一个关于比赛项目的抽…

点评项目-6-缓存更新策略、缓存穿透、雪崩

缓存更新策略 使用 redis 缓存记录的信息&#xff0c;有可能在数据库被信息被修改导致信息不一致&#xff0c;使用缓存更新来解决这个问题 缓存更新策略主要有三种&#xff1a; 1.内存淘汰(redis默认开启) 2.超时剔除(给key添加TTL时间) 3.主动更新(编写业务逻辑) 主动更新策…

网络通信与并发编程(一)网络通信、osi五层模型、tcp协议的三次握手与四次挥手

网络通信、osi五层模型、tcp协议的三次握手与四次挥手 文章目录 网络通信、osi五层模型、tcp协议的三次握手与四次挥手一、网络通信二、osi五层模型1.物理层2.数据链路层3.网络层4.传输层5.应用层 三、tcp协议的三次握手与四次挥手 一、网络通信 网络通信是指在网络中的两个或…

Java ==> 数组(入门)

文章目录 前言一、一维数组1.入门操作2.何为null&#xff1f;3.数组可以作为函数的参数4.数组可以作为函数的返回值 二、二维数组1.基础操作2.不规则的二维数组 总结 前言 在Java语言当中&#xff0c;数组是一种基本的数据结构&#xff0c;它存储了固定大小的同类型元素的集合…

告别卡顿!五款Windows录屏工具,让每一帧都清晰流畅

小伙伴们&#xff0c;是不是在寻找一款好用、实用的Windows录屏工具呢&#xff1f;别担心&#xff0c;这次我给大家带来了一款热门录屏工具的详细评测和使用感受&#xff0c;包括福昕录屏、转转录屏、爱拍录屏、OBS录屏和EV录屏。快来看看哪款最适合你吧&#xff01; 一、福昕录…

反射的学习

1、什么是反射 反射允许对封装类的字段&#xff0c;方法和构造函数的信息进行编程访问。 也就是&#xff1a; 反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问。 2、获取class对象 获取一个类的字节码文件对象&#xff1a; 方式1&#xff1a;Class.…

linux 环境运行 jenkins.war包,有可能会出现字体问题,jdk版本:11 jenkins 版本:2.420

jenkins的目录&#xff1a; /usr/jenkins 启动命令 java -Djava.awt.headlesstrue sudo timedatectl set-timezone Asia/Shanghai-Xmx1024m -jar jenkins.war --httpPort8090 任意目录启动&#xff1a; nohup java -Djava.awt.headlesstrue -Xms1024m -Xmx1024m -jar /usr/j…

基于opencv答题卡识别判卷

我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&#xff1a;深度实…

Excel使用技巧:数据-》分列:处理log数据,把有用的信息提取出来;查找Ctrl+F,替换Ctrl+H;通配符

Excel的正确用法&#xff1a; Excel是个数据库&#xff0c;不要随意合并单元格。 数据输入的时候一定要按照行列输入&#xff0c;中间不要留空&#xff0c;不然就没有关联。 数据-》分列&#xff1a;处理log数据&#xff0c;把有用的信息提取出来。 按照向导一步一步操作。…

D36【python 接口自动化学习】- python基础之函数

day36 函数的定义 学习日期&#xff1a;20241013 学习目标&#xff1a;输入输出与文件操作&#xfe63;-49 函数定义&#xff1a;如何优雅地反复引用同一段代码&#xff1f; 学习笔记&#xff1a; 函数的用途 定义函数 调用函数 # 定义函数 def foo():print(foo)print(foo …

数据传送指令

文章目录 MOVXCHGPUSH和POPIN和OUTXLATLEA LDS LESLEALDSLES LAHF SAHFPUSHF POPF总结 MOV MOV dst, src ; dst <-- src可以进行8位或16位数据的传送源操作数可为立即数、寄存器、存储器操作数目的操作数不可为立即数&#xff0c;CS、IP寄存器两操作数必有一个寄…

Hi3244 应用指导

Hi3244 是一款DIP8封装高性能、多模式工作的原边控制功率开关。Hi3244内高精度的恒流、恒压控制机制结合完备的保护功能&#xff0c;使其适用于小功率离线式电源应用中。在恒压输出模式中&#xff0c;Hi3244 采用多模式工作方式&#xff0c;即调幅控制&#xff08;AM&#xff0…

LLM - 配置 ModelScope SWIFT 环境与 Qwen2-VL 模型推理 教程 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/142827217 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 SWIFT …

AI 工具大比拼:ChatGPT 与豆包的魅力与未来展望

&#x1f9d1; 博主简介&#xff1a;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编程&#xff0c;…

C++的类和动态内存分配(深拷贝与浅拷贝)并实现自己的string类

首先&#xff0c;我们先写一个并不完美的类&#xff1a; #include<iostream> #include<cstring> using namespace std;class Mystring{private:char *p;int len;static int num;friend ostream& operator<<(ostream& os, const Mystring& c);pu…

QT开发--多线程

第十四章 多线程 QThread 是 Qt 中实现多线程编程的核心类&#xff0c;提供跨平台线程管理。 使用 QThread 有两种方法&#xff1a; 1、 继承 QThread&#xff1a;重写 run() 方法&#xff0c;实现线程的具体操作。Qt4.8 之前较常用。 2、 使用 QObject 和 moveToThread()&…

2024-10-13 NO.1 Quest3 激活教程

文章目录 1 下载 Occlus 助手2 打开 quest 热点3 Quest3 连接 wifi4 详细文档5 参考教程 1 下载 Occlus 助手 ​ 网址&#xff1a;https://ochelper.xlemon.cn/home.html。 2 打开 quest 热点 ​ 下载 Occlus 助手后&#xff0c;双击 exe 文件打开。 ​ 过程中按照程序提示执…

各类排序详解

前言 本篇博客将为大家介绍各类排序算法&#xff0c;大家知道&#xff0c;在我们生活中&#xff0c;排序其实是一件很重要的事&#xff0c;我们在网上购物&#xff0c;需要根据不同的需求进行排序&#xff0c;异或是我们在高考完报志愿时&#xff0c;需要看看院校的排名&#…

【动手学深度学习】6.2 图像卷积(个人向笔记)

1. 互相关运算 严格来说&#xff0c;卷积层是一个错误的叫法&#xff0c;因为它本质上是互相关运算而不是卷积运算。我们暂时忽略通道看看二维图像数据和隐藏表示。那么输出大小可以表示为 我们自己实现一个二维互相关运算 2. 卷积层 卷积层中有两个参数&#xff1a;卷积核权…