【FreeRTOS】详细讲解FreeRTOS里中断管理并通过示例讲述其用法

news2024/10/5 17:26:09

文章目录

  • 中断
  • 函数解析
  • FreeRTOS中断使用示例

中断

  大家看到中断后,有没有想到一个名词——异常呢?若大家想到了,但是记不起相关概念;或者是,大家没想到这个名词,没关系, 下面小编就给大家伙讲讲中断异常相关知识。
异常
  异常,是指任何使CPU执行程序时脱离正常运行状态转而跑飞的任何事件,若不及时处理,系统可能会面临崩溃危机。
  异常,可分为同步异常异步异常。由内部事件,如零除引起的算术异常等一系列处理器指令故障引起的事件,称之为同步异常;而异步异常,主要只外部硬件装置产生的异常,若按键按下后产生的事件。
  同步异常与异步异常在程序执行上的区别是:当一个同步异常产生后,系统必须立刻处理该异常,而不能继续执行原程序;但是当异步异常发生后,系统可以缓处理或者是忽略不处理。其本质上的区别,个人认为还得是因为异常的来源不同。

中断
  中断,属于异步异常。用一个形象的现象来讲解中断:某天,小明(CPU)正在酣畅淋漓地打游戏(主程序),突然,其女友过来找他有急事(中断事件),这时小明是不是得优先处理女友的事情(中断服务),之后才能继续玩游戏(恢复主程序)。
  通过中断机制,CUP可以实现:当外设不需要CPU处理时,CPU可以干一些其他的事情,如轮询任务、动态内存管理等等;而不需要持续地查询外设状态,一旦外设状态符合条件,就使用中断机制启动特定任务即可。

  中断相关的硬件可划分为三类:

  • 外设:当外设请求CPU时,会产生一个中断信号,请求中断;
  • 中断控制器:中断控制器是CPU外设之一,其既能接收其他外设的中断信号,自己也能够发出中断信号给CPU。通过该外设,可以实现对中断源的优先级、触发方式、打开、关闭等操作进行设置
  • CPU:CPU能够响应中断请求,中断当前程序,进而执行中断服务程序。NVIC(中断控制器)最多支持240个中断,每个中断最多支持256个优先级。

中断处理过程
  某中断发送中断请求后,中断处理需要经过以下过程:

  • 步骤一:中断响应由硬件自动化完成);在此过程中主要任务为:保护现场找到中断服务程序地址
  • 步骤二:执行中断服务程序由用户编写);中断服务程序没有参数与返回值要求尽量简短,其调用不是由用户完成,而是由硬件自动调用
  • 步骤三:中断返回由硬件自动实现);此过程主要为恢复现场

  就拿上述小明女友让小明处理某事作为中断处理过程的示例,则其示意图可为下图:

中断处理示意图

中断机制的弊端
  尽管使用中断能够提高系统的实时性,但是使用中断也存在一定的弊端:

  • 中断会增加程序执行不确定性时间长度
  • 中断会增加栈空间
  • 中断会抢占正在使用的资源

FreeRTOS里中断管理支持

  • 开/关中断;
  • 恢复中断;
  • 中断使能;
  • 中断屏蔽;
  • 设置中断优先级

函数解析

  FreeRTOS中,实际上是没有中断的,中断还是由硬件产生。以STM32为例,中断请求的响应过程还是由STM32的中断服务函数完成,而FreeRTOS在其中的作用可以说成是唤醒某个阻塞或就绪任务。
  也就是说,在硬件STM32的中断函数中,需要使用信号量事件等完成中断与FreeRTOS系统任务的通信,实现通过中断函数来唤醒一次或多次FreeRTOS系统任务。

与中断管理相关的函数有:

  • portDISABLE_INTERRUPTS:中断暂停函数

  函数portDISABLE_INTERRUPTS()实际上还是使用声明重新定的一个函数:
  #define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
  函数vPortRaiseBASEPRI()的实现则是通过汇编完成的。

  • portENABLE_INTERRUPTS :使能中断函数

  与中断暂停函数一样,函数portENABLE_INTERRUPTS()实际上还是使用声明重新定的一个函数:
  #define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
  函数vPortRaiseBASEPRI()也是通过汇编完成的。

ARM汇编指令

  • msr
      MSR指令,存储通用寄存器的值到特殊功能寄存器
      指令格式为:msr spec_reg, Rm spec_reg表示特殊寄存器,Rm表示通用寄存器。
  • isb
       指令同步隔离(与流水线、 MPU有关)。最严格:它会清洗流水线,以保证所有它前面的指令都执行完毕之后,才执行它后面的指令。
  • dsb
       数据同步隔离(与流水线、 MPU 和 cache等有关),较为严格: 仅当所有在它前面的存储器访问都执行完毕后,才执行它在后面的指令(亦即任何指令都要等待)。
  • basepri
      表示常规异常的优先级阈值寄存器

FreeRTOS中断使用示例

  示例的主要目的:是使用中断以及事件组完成基于FreeRTOS实时操作系统的中断处理功能。
  示例中详细任务为:

1.创建一个事件组以及两个个FreeRTOS任务,并且将是否创建成功显示到LCD屏上;
2.初始化两个按键外部中断,并且在回调函数中完成事件组的触发功能;
3.FreeRTOS任务1中接收两个事件,并完成预设功能——其中一个事件触发一次翻转一次LED状态;另一个事件触发后记录其触发次数,并且显示在LCD屏中。
4.FreeRTOS任务2需要完成的功能有:实现两个按键中任意一个按键按下后反转一个LED灯状态,并且要求按键消抖

示例代码

// 声明事件
#define EVENT7 (0x01 << 6)
#define EVENT8 (0x01 << 7)


//任务控制权柄
TaskHandle_t xHandleTsak[4];
// 事件控制权柄
EventGroupHandle_t myxEventGroupHandle_t = NULL;

int main(void)
{	
	//存储创建任务的返回值
	BaseType_t xReturn[5] ;
	//LCD显示
	char temp[30] = "task fail:";
	
	//动态创建任务
	xReturn[0] = xTaskCreate(
						(TaskFunction_t )eventTask2,(const char *)"task1",
						(uint16_t)128,(void*) NULL,1,&xHandleTsak[0]);
	if (pdPASS != xReturn[0])
		strcat(temp,"1");					
	xReturn[2] = xTaskCreate(
						(TaskFunction_t )eventTask4,(const char *)"task3",
						(uint16_t)128,(void*) NULL,1,&xHandleTsak[2]);
	if (pdPASS != xReturn[2])
		strcat(temp,"3");									
	if(strlen(temp) == 10)
		sprintf(temp,"task suc");
	
	// 创建事件
	myxEventGroupHandle_t = xEventGroupCreate();
	if(myxEventGroupHandle_t == 0)
		strcat(temp,"event fail");
	else
		strcat(temp,"event suc");
		
	// 显示任务 事件是否创建成功  
	LCD_DisplayStringLine(Line3,(uint8_t*)temp);
	changeAllLedByStateNumber(OFF);
	
	// 启动调度
	vTaskStartScheduler();
	
	return 0;
}
/********************************************
* 函数功能:事件测试函数2
* 函数参数:无
* 函数返回值:无
********************************************/
void eventTask2(void)
{
	// 设置变量接收事件
	EventBits_t r_event;
	// 保存LED的状态
	int ledState[] = {0,0,0,0,0,0,0};
	// 记录LED的位置
	uint16_t ledLocation[] = {LED1,LED2,LED3,LED4,LED5,LED6,LED7};
	// 记录EVENT8触发次数
	uint16_t eventTriggerCount = 0;
	// 保存显示到LCD中的数据
	char temp[30];
	// 用于循环
	int i = 0;
	
	while(1)
	{
		//阻塞等待8个事件中任意一个事件
		r_event = xEventGroupWaitBits(myxEventGroupHandle_t,EVENT7|EVENT8,
									  pdTRUE,pdFALSE,portMAX_DELAY);
		//判断事件类型
		if((r_event&EVENT7) !=0)
			++ledState[6];
		else if((r_event&EVENT8) !=0)
		{
			sprintf(temp," Event8 count:%d",++eventTriggerCount);
			LCD_DisplayStringLine(Line4,(uint8_t*)temp);
			changeAllLedByStateNumber(OFF);
		}
		// 设置每个LED灯状态
		for(i=0;i<7;++i)
			changeLedStateByLocation(ledLocation[i],ledState[i]%2);
		portDISABLE_INTERRUPTS();
	}
}

/********************************************
* 函数功能:事件测试函数4
* 函数参数:无
* 函数返回值:无
********************************************/
void eventTask4(void)
{
	// 记录按键按下的位置 按键触发次数
	unsigned char keyNumber = 0;
	// 记录按键状态  0-按键空闲状态  1-按键按下状态 2-按键松开状态
	int state = 0;
	// 保存系统时间
	static portTickType myPreviousWakeTime;
	// 保存阻塞时间
	const volatile TickType_t xDelay10ms = pdMS_TO_TICKS( 50UL );
	// 获取当前时间
	myPreviousWakeTime = xTaskGetTickCount();
	
	while(1)
	{
		// 按键第一次按下 消抖
		if( state == 0 )
		{
			keyNumber = scanKeyNoTime();
			// 只有按键按下后才跳转
			if(keyNumber != 0)
			{
				HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0, GPIO_PIN_SET);
				HAL_GPIO_WritePin(GPIOB,GPIO_PIN_2, GPIO_PIN_SET);
				state = 1;
			}
		}
		// 按键真正按下状态  
		if( state == 1 )
		{
			/* 读取按键是否按下 若没按下则跳转到状态1  
			否则就执行按键服务函数  并且跳转到状态2*/
			keyNumber = scanKeyNoTime();
			if(keyNumber == 0)
				state = 0;
			else
			{
				if(keyNumber == 3 )
					rollbackLedByLocation(LED3);
				if(keyNumber == 4 )
					rollbackLedByLocation(LED4);
					state = 2;
			}
		}
		// 按键松开状态
		if( state == 2 )
		{
			keyNumber = scanKeyNoTime();
			// 判断按键是否松开  只有按键松开 才跳转到状态0
			if(keyNumber == 0)
				state = 0;
		}
		xTaskDelayUntil(&myPreviousWakeTime,xDelay10ms);
	}
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	// 记录当前某些信息
	BaseType_t pxHigherPriorityTaskWoken; 
	uint32_t ulReturn;
	uint16_t event;
	
	/* 进入临界段,临界段可以嵌套 */
	ulReturn = taskENTER_CRITICAL_FROM_ISR();
	
	// 读取对应按键的状态
	GPIO_PinState pinState = HAL_GPIO_ReadPin( GPIOB,GPIO_Pin );
	if(pinState == GPIO_PIN_RESET )
	{
		// 判断中断位置
		if(GPIO_Pin == GPIO_PIN_0 )
		{
			rollbackLedByLocation(LED1);
			event = EVENT7;
		}
		else if(GPIO_Pin == GPIO_PIN_1 )
		{		
			rollbackLedByLocation(LED2);
			event = EVENT8;
		}
		// 发送事件请求
		xEventGroupSetBitsFromISR(myxEventGroupHandle_t,event,
		&pxHigherPriorityTaskWoken);
		// 如果需要就切换任务
		portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
	}
	
	/* 退出临界段 */
	taskEXIT_CRITICAL_FROM_ISR( ulReturn ); 	
}

  上述测试中,STM32负责中断响应以及“虚假”中断服务函数执行,而FReeRTOS的任务eventTask2()才是真正的中断服务函数。“虚假”的中断服务函数与“真正的”中断服务函数间是通过事件来完成中断任务通信过程的。
  因此,在上述函数中,很明显的可以知道:eventTask2()才是真正的中断服务函数,因为每次外部中断触发后,任务eventTask2()也都会触发。
  其次,中断函数需要精简,遵循快进快出的原则。而在上述测试中,“虚假”中断服务函数HAL_GPIO_EXTI_Callback()还是没有做到这一点,应该要将函数内部翻转LED状态的函数删除,只留下唤醒事件的必要代码以及按键相关代码即可。
  至于小编为什么要这样子写呢?🤔一开始是为了测试外部中断是否可用,后面就懒得删了,毕竟还是可以观察到外部中断是否触发以及此时是否应该触发事件。😅
  至于函数eventTask4()中按键部分,小编是采用FreeRTOS的绝对延时进制以及状态机完成消抖。(状态机写的比较烂,大家将就将就吧!🤣🤣🤣)

结果



  小编也有其他的一些相关文章,欢迎各位看官点击观看😉😉😉

  • 【FreeRTOS】详细讲解FreeRTOS中任务管理并通过示例讲述其用法
  • 【FreeRTOS】详细讲解FreeRTOS的软件定时器及通过示例讲述其用法
  • 【FreeRTOS】详细讲解FreeRTOS中消息队列并通过示例讲述其用法
  • 【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法

    最后 ,欢迎大家留言或私信交流,咱们共同进步!😁😁😁

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

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

相关文章

VMware 虚拟机无法开机

在windows下安装VMware虚拟机&#xff0c;使用ubuntu18.04系统时&#xff0c;由于非正常关机或者硬盘内存不够&#xff0c;导致无法正常开机&#xff0c;现象如下&#xff1a;问题原因&#xff1a;第一&#xff1a;pillx4_smbus异常&#xff0c;需要禁用&#xff1b;第二&#…

全网最细------爬取4k高清大图

本次案例将教大家免费爬取4k高清大图&#xff0c;即使你是爬虫新手&#xff0c;也可以食用本次文章实现你的免费下载梦,话不多说&#xff0c;先看效果 网站视图: 看到这些图片你是否怦然心动&#xff0c;跟着我一起看下去. 一.思路分析 首先最基本的是获取每张图片的链接&a…

【JavaEE】并发编程(多线程)线程安全问题内存可见性指令重排序

目录 第一个问题&#xff1a;什么是线程安全问题&#xff1f; 第二个问题&#xff1a;为什么会出现线程安全问题&#xff1f; 第三个问题&#xff1a;如何解决多线程安全问题&#xff1f; 第四个问题&#xff1a;产生线程不安全的原因有哪些&#xff1f; 第五个问题&am…

模板进阶(包含特化)

非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当成常量…

CSS(基础,面试,常见用例)

CSS规则【*】CSS选择器一、 CSS选择器二、选择器匹配原理三、优先级 / 权重四、可继承 / 不可继承样式属性【*】盒模型一、盒模型二、box-sizing属性三、offsetWidth、clientWidth、scrollWidth**【*】em/px/rem/vh/vw的区别一、CSS单位二、px三、em四、rem五、vh、vw六、%百分…

基于spring生态的基础后端开发及渗透测试流程

这是一篇记录如何从建仓开始到最后安全测试完整流程的笔记&#xff0c;使用的spring生态&#xff0c;目的是为spring的基础后端开发及后期渗透测试打一个模板。本篇采用springSecurity作为安全框架&#xff0c;搭载了redis-cache、spring-valid等功能&#xff0c;并开放了OAuth…

实测十款连锁店管理系统,专为纠结的连锁店老板打造!

普通的数据工具、人工管理难以满足连锁店老板们的需求&#xff0c;正所谓“有需求就有市场”&#xff0c;随着连锁店、加盟店如雨后春笋般在城市里出现&#xff0c;连锁店管理系统也越来越多。究竟哪一款连锁店管理系统&#xff0c;才能满足老板们的需求&#xff1f;不用纠结了…

park unpark 原理

1、基本使用 // 暂停当前线程 LockSupport.park();// 恢复某个线程的运行 LockSupport.unpark(暂停线程对象) 先 park 再 unpark public class Test1 {public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(() -> {log.debug(&q…

「自控元件及线路」1.2 电机中的磁性材料与磁场

本节介绍磁性材料的性能、分类 本节介绍电机中永磁材料的工作曲线 本节介绍电机中主磁极、电枢的磁场及电枢反应 文章目录磁性材料的基本概念磁性材料的磁性能高导磁性 饱和性 磁滞性 非线性温度特性 电阻率特性铁耗磁性材料的分类电机中的永磁材料永磁电机概述永磁材料的磁性能…

mysql:聊聊mysql学完之后心得,从哪里学,学哪些,怎么选课程,学到什么程度。

mysql&#xff1a;聊聊mysql学完之后心得&#xff0c;从哪里学&#xff0c;学哪些&#xff0c;怎么选课程&#xff0c;学到什么程度。 学习完一套课程之后习惯性总结一下。首先说一下&#xff0c;咕咕是跟着尚硅谷的康老师学习的mysql&#xff0c;大家想学习的话可以直接去b站…

Java文件IO操作及案例

文章目录一. 文件概述1. 狭义和广义上的文件2. 文件的分类3. 文件的路径二. 针对文件系统的操作1. File类的属性和构造2. File类的获取操作3. File类的判断操作4. 文件的创建和删除5. 其他的常用方法三. 对文件内容进行读写1. IO流对象2. 文件的读操作3. 文件的写操作4. Scanne…

vim使用入门

目录vim模式介绍1.1 模式介绍1.2 模式之间切换1.3 进入vim1.4 退出vimvim模式介绍 1.1 模式介绍 vim具有6种基本模式和5种派生模式。 6种基本模式如下&#xff1a; 普通模式 vim启动后的默认模式。使用编辑器命令&#xff0c;比如移动光标&#xff0c;删除文本等等 普通模式进…

智能指针(二)—— unique_ptr、shared_ptr 的简单模拟实现

智能指针其实就是资源管理权限的转移&#xff0c;自己不想手动释放&#xff0c;交给一个对象管理&#xff0c;对象什么时候被销毁&#xff0c;这块资源也就什么时候被释放。unique_ptr 、shared_ptr 和weak_ptr 之间的区别如下&#xff1a; unique_ptr&#xff1a;字面意思是…

非全研究生开题-室内定位最新研究论文总结-1

序言 时间飞逝,23年3月底之前要把开题报告和综述写好。开学后研究了2个方向:serverless冷启动和室内定位; 春节期间在这2个选题之间犹豫不决,不断在心里面分析 经过反复比较对比,决定研究室内定位,也可以为后续完善产品,甚至后面创业打下基础。 后面我会持续深入,在…

【数据结构】链表必做题

写在开头学完链表&#xff0c;我们就要适当做一些题目来巩固知识&#xff0c;下面的一些精选题难度适中&#xff0c;很适合初学者练手。做题之前我们来了解一点概念&#xff0c;就是链表调用传参时&#xff0c;我们什么时候使用一级指针&#xff0c;什么时候使用二级指针&#…

在Linux上安装Maven和配置Maven仓库(v3.8.7)

记录&#xff1a;369场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;使用apache-maven-3.8.7安装Maven和配置Maven仓库。版本&#xff1a;JDK 1.8apache-maven-3.8.7名词&#xff1a;Apache Maven&#xff1a;Apache Maven is a software project management and comprehe…

31_内存马

内存马 一、php内存马(不死马) 原不死马文件是生成一个一句话木马文件之后,自动删除自身,并且抑制报错 即使删除生成的一句话木马文件 也会不断的继续生成一句话木马文件 除非重启服务,才能停止继续生成 <?php error_reporting(0);//抑制报错 unlink(__FILE__);//删除…

【工具】iOS代码混淆工具-iOS源码混淆

最新更新记录 V2.0.3&#xff08;2022年12月11日&#xff09;更新内容&#xff1a; 1、新增导入映射列表的逻辑&#xff1b; 2、优化修复其他混淆逻辑&#xff1b; 3、更新地址 - github 主要功能 ZFJObsLib是专业的iOS源码混淆工具&#xff0c;具体功能有方法混淆、属性…

AcWing 1082. 数字游戏(数位DP)

AcWing 1082. 数字游戏&#xff08;数位DP&#xff09;一、问题二、数位DP三、思路分析四、代码一、问题 二、数位DP 这道题是在一个区间内挑选满足某个条件的数&#xff0c;这是一个非常典型的数位DP的特点。 这道题是一道数位DP的题目&#xff0c;其实数位DP更像我们在高中…

5-TAMRA-TSA,5-TAMRA-Tyramide,5-四甲基罗丹明-酪酰胺

【中文名称】5-四甲基罗丹明-酪酰胺&#xff0c;5四甲基罗丹明酪酰胺【英文名称】 5-Tamra-Tyramide&#xff0c;5-TAMRA-Tyramide&#xff0c;5-Tamra-TSA&#xff0c;5-TAMRA-TSA【CAS】N/A【纯度标准】95%【包装规格】5mg&#xff0c;10mg&#xff0c;25mg【是否接受定制】可…