最近利用空闲时间跑了一下正点原子的stm32f4开发板的实时操作系统demo,发现了一个比较有意思的东西,分享如下:

硬件平台:正点原子stm32f4开发板

软件开发平台:MDK uVision v5.14.0.0

代码:正点原子官方例程 实验56 UCOSII实验1-2-任务创建删除挂起恢复

需要了解的基础知识:

  1、会点亮LED灯

  2、会读取按键输入

  3、会操作串口

  4、会RTOS基本知识

官方文档描述实验现象:首先下载代码之后可以看到 LED0 和 LED1 不断闪烁,同时蜂鸣器不
断鸣叫。这个时候我们按下 KEY0 之后 led_task 任务被挂起,我们可以看到 LED 不再闪烁。接
着我们按下 KEY2, led_task 任务重新恢复,可以看到 LED 恢复闪烁。然后我们按下 KEY_UP,
任务 beep_task 被删除,所以蜂鸣器不再鸣叫。这个时候我们再按下按键 KEY_DOWN,任务
beep_task 被重新创建,所以蜂鸣器恢复鸣叫。

一切工具准备就绪,烧录代码观察现象,神奇的bug出现了

首先,确实LED0 和 LED1 不断闪烁,但是一旦按下任意一个按键直接死机。

第一想法,分析代码,打印调试信息

测试现象:果然,按下按键后,所有用户任务停止运行了,可以初步得出结论:程序跑飞了(由于本例程未初始化看门狗,所以程序跑飞,就飞不回来了)

第二想法:调试

测试方法:进入调试模式后,run代码,点击stop,程序会停在正常的代码行,如停在用户代码区、内核代码区的正常逻辑区

进入调试模式后,run代码,按下按键,点击stop,会发现程序停在stm32f4xx_it.c这个文件的HardFault_Handler函数里,这是个死循环,就是这里导致程序跑飞了

cpu进入中断后一直执行死循环,回不来了,无法再进行任务切换了!可

以在这个中断函数里追加printf("HardFault_Handler\r\n");以观察现象如下:

串口助手打印的信息刚好验证了上述结论

整理思路如下:运行ucos ii 应用程序,按下按键后程序发生硬件错误,一般发生硬件错误,很可能就是跟内存有关,最典型的就是栈溢出了,

分析到这里,基本上排查bug就很easy了,检查代码各个任务栈大小发现:三个任务都是设置64字节,经过多次实验,发现只需把KEY_STK_SIZE设置

为大于64时,实验现象就正常了,说明再执行按键任务时,此任务堆栈大小超过64字节了。

#define KEY_TASK_PRIO       3
#define KEY_STK_SIZE 64
OS_STK KEY_TASK_STK[KEY_STK_SIZE];
void key_task(void *pdata); 

那么当我们在编写任务函数时,到底栈大小设置多少合适呢?我怎么知道新建的任务运行起来用了多少栈空间呢?

若栈空间设置过大,无疑会导致空间的浪费,这在嵌入式产品中简直就是极其浪费

若栈空间过小,那真运行起来,搞不好某个时间点,栈空间就溢出了,这个时间点可能是一触即发,可能会一年后,甚至10年后

经过一顿百度操作,发现ucosii 系统早都给你设计好了,通过下面的函数即可统计指定任务运行时用了多少栈空间,还剩多少栈空间

OSTaskCreateExt(key_task,(void *)0,(OS_STK *)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO, KEY_TASK_PRIO, KEY_TASK_STK, KEY_STK_SIZE, (void*)0,OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSTaskStkChk(KEY_TASK_PRIO, &StackBytes);
printf("%d\r\n", StackBytes.OSUsed); 

 这也只是一种估测栈空间使用量,测试时,得模拟各种极端条件,尽量让最大使用量测出来

最后,一般堆栈大小设置为任务实际使用量的1.5-2倍即可

具体原理,大家可自行百度理解,也可以自己尝试手撕一波栈空间检测算法(栈基地址----栈顶地址) 

UCOS-II 任务栈空间合理分配的更多相关文章

  1. Linux学习笔记4——函数调用栈空间的分配与释放

    一.函数执行时使用栈空间作为自己的临时栈,3种方式决定编译器清空栈的方式:__stdcall. __fastcall.__cdecl 1.__stdcall表示每个调用者负责清空自己调用的函数的临时栈 ...

  2. java虚拟机 jvm 出入java栈 栈空间内存分配

    java栈空间是一块线程私有的内存空间,java堆和程序数据密切相关,那么java栈就是和线程执行密切相关.线程最基本的执行行为就是函数的调用.每次函数调用其实是通过java栈传递数据的. 数据结构中 ...

  3. 更改Linux默认栈空间的大小

    有时候在Linux写C++程序处理大量的数据,程序内部需要分配很大的数组来存放一些数据,但有时候分配的数组太大的话运行时会出现段错误.这种情况可能是分配的数组大小超过了Linux系统的默认栈空间的大小 ...

  4. DE1-SOC开发板上搭建NIOS II处理器运行UCOS II

    DE1-SOC开发板上搭建NIOS II处理器运行UCOS II   今天在DE1-SOC的开发板上搭建NIOS II软核运行了UCOS II,整个开发过程比较繁琐,稍微有一步做的不对,就会导致整个过 ...

  5. (转)在.NET程序运行过程中,什么是堆,什么是栈?什么情况下会在堆(栈)上分配数据?它们有性能上的区别吗?“结构”对象可能分配在堆上吗?什么情况下会发生,有什么需要注意的吗?

    转自:http://www.cnblogs.com/xiaoyao2011/archive/2011/09/09/2172427.html 在.NET程序运行过程中,什么是堆,什么是栈? 堆也就是托管 ...

  6. [转帖] Linux 下面栈空间大小的实验

    比如局部变量是保存在栈空间中的,今天突然在想栈的上限是多大呢,什么时候才会栈溢出? ulimit 命令 linux下使用ulimit 命令可以查看系统的很多上限值. ulimit -a 查看所有 ul ...

  7. C语言中函数调用过程(如何管理栈空间)

    ps:先做草稿,以后有时间再整理并贴图,:) 主要是利用栈底寄存器(ebp).栈顶寄存器(esp)跟eax寄存器(存储返回值)来实现. 假设P调用Q: P() { Q(1,2); } (跟实际情况可能 ...

  8. 0xC0000005;Access Violation(栈区空间很宝贵, linux上栈区空间默认为8M,vc6下默认栈空间大小为1M)

    写C/C++程序最怕出现这样的提示了,还好是在调试环境下显示出来的,在非调试状态就直接崩溃退出. 从上述汇编代码发现在取内存地址 eax+38h 的值时出错, 那说明这个地址非法呗, 不能访问, 一般 ...

  9. 堆、栈、内存分配、==、equals、hashcode详解(转载)

    问题的引入: 问题一:String str1 = "abc";String str2 = "abc";System.out.println(str1==str2 ...

  10. 《浏览器工作原理与实践》 <12>栈空间和堆空间:数据是如何存储的?

    对于前端开发者来说,JavaScript 的内存机制是一个不被经常提及的概念 ,因此很容易被忽视.特别是一些非计算机专业的同学,对内存机制可能没有非常清晰的认识,甚至有些同学根本就不知道 JavaSc ...

随机推荐

  1. Git添加SSH密钥步骤

    1.先去本机上面看看用户主目录里面有没有.ssh这个文件夹 如果有的话,再看看该目录下有没有id_rsa和id_rsa_pub这两个文件: 若还是有,就直接跳过这一步到下一步:若是没有,我们需要创建S ...

  2. Python练习--简单练习(一看就能写出来的代码)

    两数之和 数字的阶乘 求圆的面积 (输入半径,求解圆的面积) 求区间内所有素数的和 求前N个数字的平方和

  3. linux 镜像备份

    linux 镜像备份 使用linux虚拟机的方法 优点 镜像大小比较小 缺点 速度可能比较慢 方法 1.打开虚拟机 我用的ubuntu,读卡器连接电脑虚拟机,ubuntu一般会自动挂载 df -h # ...

  4. PMP常见会议小结

    转载请注明出处: 会议是吸引项目团队和其他干系人参与的重要方式.它们是整个项目的主要沟通方式. 一. 项目启动会 召开时间:是启动阶段结束时召开的会议. 主要任务:发布项目章程,并任命项目经理,赋予项 ...

  5. 人脸关键点的应用场景及重难点解析丨Dev for Dev 专栏

    本文为「Dev for Dev 专栏」系列内容,作者为声网视频组 AI 算法工程师 周世付. 人脸检测.人脸关键点检测,是计算机视觉的基础算法.许多酷炫应用背后,例如美颜.贴纸.人脸驱动 avatar ...

  6. 【Unity3D】基于粒子系统实现烟花特效

    1 需求实现 ​ 粒子系统ParticleSystem 中介绍了粒子初始化.粒子发射.发射器形状.渲染器.碰撞.子发射器.拖尾等粒子系统的基本用法,本节将基于粒子系统实现烟花特效. ​ 实现需求如下( ...

  7. uniapp中easycom用法详解

    Uniapp中的easycom是一种组件自动注册机制,可以让开发者更加方便地使用和管理组件.下面详细介绍下关于easycom使用方法. 什么是easycom? easycom是Uniapp框架提供的一 ...

  8. Anconda、Pycharm下载、安装、配置教程(极其详细)

    Anacond的介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项. 因为包含了大量的科学包,Anaconda 的下载文件比较大( ...

  9. react之点语法(利用函数组件)

    index.js import React, { Component } from 'react' import MyCom from './MyCom'; export default class ...

  10. R语言文本数据挖掘(一)

    文本挖掘可以视为NLP(Natural language processing,自然语言处理)的一个子领域,目标是在大量非结构化文本中整理析取出有价值的内容.由于人类语言具有很高的复杂性,例如不同语言 ...