FreeRTOS+STM32F103中断中发送任务通知单片机死机问题
最近在调试FreeRTOS系统遇到了一个比较奇怪的问题,在STM32F103最小系统上调试任务通知模拟事件标志组功能时,中断一触发,单片机就会死机。通过查询方式发送任务通知没任何问题,一旦用按键触发外部中断,在中断中发送任务通知时,单片机就死机。在编译时程序无任何报错。
相关代码如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "exti.h"#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"TaskHandle_t EventGroupHandler; //事件标志组句柄#define EVENTBIT_0 (1<<0) //事件位
#define EVENTBIT_1 (1<<1)
#define EVENTBIT_2 (1<<2)#define EVENTBIT_ALL (EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)void start_task(void *pvParameters);
void eventSetBit_task(void *pvParameters);
void eventGroup_task(void *pvParameters);
void eventQuery_task(void *pvParameters);int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4delay_init(); //延时函数初始化uart_init(115200); //初始化串口LED_Init(); //初始化LEDKEY_Init();IO_Exti_Init();//创建开始任务xTaskCreate(start_task, //任务函数的指针"start_task", //任务的文本名字,只会在调试中用到100, //栈深度NULL, //没有任务参数1, //任务优先级NULL //不会用到任务句柄);vTaskStartScheduler(); //开启任务调度
}
void start_task(void *pvParameters)
{taskENTER_CRITICAL();xTaskCreate(eventSetBit_task, "eventSetBit_task", 100, NULL, 2, NULL); //创建设置事件位任务xTaskCreate(eventGroup_task, "eventGroup_task", 100, NULL, 3, &EventGroupHandler); //创建事件标志组处理任务vTaskDelete(NULL);taskEXIT_CRITICAL();
}
//设置事件位任务
void eventSetBit_task(void *pvParameters)
{u8 key = 0;u8 i = 0;while(1){if(EventGroupHandler != NULL){key = KEY_Scan( 0 );switch( key ){case 1:xTaskNotify(EventGroupHandler, EVENTBIT_1, eSetBits);break;case 2:xTaskNotify(EventGroupHandler, EVENTBIT_2, eSetBits);break;}}i++;if(i > 50){i = 0;LED1 = !LED1;}vTaskDelay(10);}
}
//事件标志组处理任务
void eventGroup_task(void *pvParameters)
{u8 num = 0;BaseType_t err;uint32_t NotifyValue;static u8 event0flag, event1flag, event2flag;while(1){if(EventGroupHandler != NULL){err = xTaskNotifyWait((uint32_t )0x00, //进入函数不清除bit(uint32_t )0xFFFFFFFF, //退出函数清除所有bit(uint32_t* )&NotifyValue, //存储任务通知值(TickType_t )portMAX_DELAY); //阻塞时间if(err == pdPASS){if((NotifyValue & EVENTBIT_0) != 0){event0flag = 1;printf("事件0发生\r\n");}if((NotifyValue & EVENTBIT_1) != 0){event1flag = 1;printf("事件1发生\r\n");}if((NotifyValue & EVENTBIT_2) != 0){event2flag = 1;printf("事件2发生\r\n");}if(event0flag && event1flag && event2flag){printf("所有事件都发生了\r\n");event0flag = 0;event1flag = 0;event2flag = 0;}}else{printf("任务获取失败\r\n");}}else{vTaskDelay(10);}}
}
中断部分代码如下:
#include "exti.h"
#include "key.h"
#include "led.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"#define EVENTBIT_0 (1<<0)
extern TaskHandle_t EventGroupHandler;void IO_Exti_Init(void)
{EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;KEY_Init();RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);EXTI_InitStructure.EXTI_Line = EXTI_Line0;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x05; //抢占优先级6NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}
void EXTI0_IRQHandler(void)
{BaseType_t xHigherPriorityTaskWoken;delay_xms(20);if(KEY == 1){xTaskNotifyFromISR((TaskHandle_t )EventGroupHandler, //任务句柄(uint32_t )EVENTBIT_0, //要更新的位(eNotifyAction )eSetBits, //按位更新(BaseType_t* )xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}EXTI_ClearITPendingBit(EXTI_Line0);
}
通过单步调试后发现代码一执行到
xTaskNotifyFromISR((TaskHandle_t )EventGroupHandler, //任务句柄(uint32_t )EVENTBIT_0, //要更新的位(eNotifyAction )eSetBits, //按位更新(BaseType_t* )xHigherPriorityTaskWoken);
这块时单片机就会死机,也就是在中断中一发送任务通知,程序出现了异常,通过对比原子的代码和PDF上的说明没发现这段代码有什么问题,对比FreeRTOS的配置文件也没有发现有什么问题,网上搜索了一下,也没找到有效的解决办法,最后没办法了只能把中断函数中的代码一行一行屏蔽找原因,后来发现将 BaseType_t xHigherPriorityTaskWoken; 这个变量的定义放到中断外部时,代码就可以正常运行,难道是在中断执行的时候,内部变量xHigherPriorityTaskWoken存储地址被覆盖了?于是将这个变量在中断函数内部声明为静态变量,代码也可以正常运行。
这说明了xHigherPriorityTaskWoken这个变量的确是在中断函数运行过程中存储的数据丢失了,导致任务通知的返回值存储失效,代码出现了异常。
通过观察FreeRTOS中调试的其他项目代码,这个变量一般都是在函数内部定义的,在中断中也是在函数内部定义的,代码都可以正常运行。唯独在使用发送任务通知xTaskNotifyFromISR()这个功能时,出现了这样情况。不知道是代码其他地方有问题,还是这时FreeRTOS本身的BUG。
不过程序死机的问题暂时只能这样解决了。
修改后的代码如下:
BaseType_t xHigherPriorityTaskWoken; //必须定义在中断外面,如果定义在中断代码内,程序会死机
void EXTI0_IRQHandler(void)
{//static BaseType_t xHigherPriorityTaskWoken; //如果要定义在函数内部时,这个变量必须声明为静态变量,否则程序会死机delay_xms(20);if(KEY == 1){xTaskNotifyFromISR((TaskHandle_t )EventGroupHandler, //任务句柄(uint32_t )EVENTBIT_0, //要更新的位(eNotifyAction )eSetBits, //按位更新(BaseType_t* )xHigherPriorityTaskWoken);portYIELD_FROM_ISR(xHigherPriorityTaskWoken);}EXTI_ClearITPendingBit(EXTI_Line0);
}
解决方法暂时为 xHigherPriorityTaskWoken 变量要么定义在中断函数外,如果要定义在中断函数内部时,必须声明为静态变量。
FreeRTOS+STM32F103中断中发送任务通知单片机死机问题相关推荐
- 单片机 架构 程序 经验总结_单片机“死机”了怎么办?看看一个资深工程师的经验总结...
原标题:单片机"死机"了怎么办?看看一个资深工程师的经验总结 单片机(Microcontroller,MCU) 又称为微控制器或嵌入式控制器,体积虽小,但使用方便,应用范围广泛,在 ...
- 单片机死机了,该怎么办?
一.振荡器停止振荡 又可以分为电源电压不稳,或者强干扰引起的振荡器停振. 二.PC指针跑飞 电源电压不稳或强干扰引起PC跑飞,如果看门狗不好,也会引起死机. 三. 设计上对长引出线的IO没有保护,静电 ...
- 单片机c语言调用函数费时,下头函数,只要被调用就会导致单片机死机,请大家帮忙分析...
当前位置:我的异常网» C语言 » 下头函数,只要被调用就会导致单片机死机,请大家帮 下头函数,只要被调用就会导致单片机死机,请大家帮忙分析 www.myexceptions.net 网友分享于:2 ...
- enc28j60发送大量数据时死机
我用的是lwip,enc28j60作为网卡,发送大量数据时死机,无法ping通,一度以为是lwip协议栈的问题. 经过半个月的查询,发现时enc28j60电流的问题. 可以加大电流,enc28j60即 ...
- 单片机死机常见原因分析
在日常的单片机开发中,不可避免会遇上死机的现象,让人摸不着头脑,更严重的是死机并不能轻易复现的情况,下面我就说一些我在开发过程中遇到过的情况. 变量溢出或变量未初始化 这里的变量溢出指的是变量定义的数 ...
- 问题二十三:C++中debug简单的运行死机问题
其实,"模拟不同材料颜色"章节中,刚添加完相关code之后,运行出现过死机. 将采样次数尽可能降低,简化过程,方便分析问题. 在main()函数添几条log,为了判断死在main( ...
- 关于解决windows10运行机械硬盘中的游戏时遭遇死机重启后硬盘消失的方法
事情的起因是:当在windows10中运行机械硬盘F盘的英雄联盟客户端时出现死机,用任务管理器也无法解决时,直接关机重启. 特点:重启后发现开机很慢,F盘消失了,并且电脑变得很卡,每次点开一个应用进程 ...
- 单片机程序跑飞死机的几种原因
在使用单片机过程中,经常会出现程序运行一段时间后,不能够正常相应的情况.一般分为软件原因和硬件原因,其中硬件原因比较容易查,软件原因就较为复杂. 软件导致单片机死机的原因 1.指针异常 指针未初始化或 ...
- 【5种灵活有效方式】如何从死机手机中恢复内部数据?
我的手机掉在地上,现在无法开机.我丢失了所有联系人.图片和重要文件.无奈之下,我需要恢复数据.但是如何从死机中恢复内部数据呢? 我们使用移动设备的最重要原因之一是打电话和发送消息.但有时,我们使用相同 ...
最新文章
- Java NIO理解与使用
- dozer bean_使用Dozer框架进行Bean操作
- 2019贵州大学计算机研究生,贵州大学2019年硕士研究生招生拟录取名单公示(一)...
- Class 18 - 1 图形验证码的识别
- 戴尔推出PowerEdge T30,主打小型办公和家庭办公市场
- C# Global定时执行Global文件aTimer处理
- UItextInput-Protocol
- 对java类中注释的认识
- imagenet2012数据集
- mysql列行条件,返回满足mysql表中列的多个条件的行
- Oracle9i中监视索引的使用
- snmpwalk工具使用
- iOS13.0上适配深色模式
- 你创业为什么会失败?
- 2023年徐汇区文化发展专项资金扶持项目申报指南
- 凌晨 12 点突发 Istio 生产事故!一顿操作猛如虎解决了
- Ajax速通(四)——axios
- 一键分享到新浪微博、腾讯微博、搜狐微博、人人网、开心网、百度收藏等js代码大全...
- kubernetes 【组件】ingress 如何通过域名访问您的应用
- 发光二极管的keil代码c语言,用Keil点亮一个发光二极管
热门文章
- Fedora10使用若干问题
- Dockerfile封装Django镜像
- [洛谷P2073] 送花
- 每天CookBook之Python-048
- 【Java】关于Java编程软件idea快捷键的使用
- c语言的44种运算符,C语言重要知识点总结【9】:C语言运算符(详解)
- mysql ext_RHEL5+postfix+mysql+extmai(源代码)(一)
- dbutils mysql_使用DBUtils控制mysql事务
- avs3 ts格式封装 标准_第480期【软件】吊打格式工厂—高清视频转换器WonderFox HD Video便携版...
- txt替换回车键符号怎么打_电脑键盘上那个点符号怎么打出来的?