【STM32】入门(十一):初识uCOS-III

2023-05-16

【STM32】STM32单片机总目录

1、轮询、中断、多任务对比

在这里插入图片描述

2、什么是任务

如果您学过linux,那么任务可以理解为线程。在代码中的体现就是线程函数,一个函数中有个无限循环函数,并且永不返回。例如:

void Task (void *arg)
{
	while(1)
	{
		。。。
	}
}

3、任务栈

3.1 栈

栈stack是一块程序运行时用来存储临时变量的内存RAM空间。栈一般静态分配,并且后进先出,栈的生命周期从程序的起始直到程序结束。一个函数返回,其用到的栈空间就被释放给后续函数使用。

不带操作系统的裸机中,可以视为只有一个任务,任务栈也只有一个,可以在启动文件中看到相关代码:

Stack_Size		EQU     0x400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size

Stack栈的大小为:0x400(1024Byte),一个函数中定义的所有局部变量,加起来不能大于工程的栈大小,否则程序肯定会出现内存溢出,导致复位。

3.2 堆

与栈相类似的还有堆空间,当工程中使用了malloc动态分配内存空间时,这时分配的空间就为堆的空间,同样在启动代码中也能看到堆空间的分配的代码:

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

Heap堆的大小为:0x200(512Byte)

3.3 多任务中栈分配

在操作系统,如ucosIII中,每个任务都需要分配堆栈(如果不需要动态分配内存,可以不分配堆)。
栈空间的分配其实就是,创建一个数组,即连续的内存分配,例如:

__align(8)  CPU_STK  STkTask1[512];

宏CPU_STK其实就是 unsigned int ,源码如下

typedef  CPU_INT32U               CPU_STK;
typedef  unsigned  int         CPU_INT32U;

4、任务控制块TCB

任务函数写好后,uCOSIII系统如何调度我们写的任务函数?这就需要通过任务控制块TCB来让uCOSIII识别、调度任务。

任务控制块TCB相当于任务的身份证,里面存有任务的所有信息,比如任务的堆栈,任务名称,任务的形参等。

任务控制块TCB源码如下:
最主要的有两个任务函数指针 (CPU_STK *StkPtr)和任务栈大小(CPU_STK_SIZE StkSize;)

struct os_tcb {
    CPU_STK             *StkPtr;                            /* Pointer to current top of stack                        */
    void                *ExtPtr;                            /* Pointer to user definable data for TCB extension       */
    CPU_STK             *StkLimitPtr;                       /* Pointer used to set stack 'watermark' limit            */
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    CPU_CHAR            *NamePtr;                           /* Pointer to task name                                   */
#endif
    OS_TCB              *NextPtr;                           /* Pointer to next     TCB in the TCB list                */
    OS_TCB              *PrevPtr;                           /* Pointer to previous TCB in the TCB list                */
#if (OS_CFG_TICK_EN == DEF_ENABLED)
    OS_TCB              *TickNextPtr;
    OS_TCB              *TickPrevPtr;
#endif
#if ((OS_CFG_DBG_EN == DEF_ENABLED) || (OS_CFG_STAT_TASK_STK_CHK_EN == DEF_ENABLED) || (OS_CFG_TASK_STK_REDZONE_EN == DEF_ENABLED))
    CPU_STK             *StkBasePtr;                        /* Pointer to base address of stack                       */
#endif
#if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
    OS_TLS               TLS_Tbl[OS_CFG_TLS_TBL_SIZE];
#endif
#if (OS_CFG_DBG_EN == DEF_ENABLED)
    OS_TASK_PTR          TaskEntryAddr;                     /* Pointer to task entry point address                    */
    void                *TaskEntryArg;                      /* Argument passed to task when it was created            */
#endif
    OS_TCB              *PendNextPtr;                       /* Pointer to next     TCB in pend list.                  */
    OS_TCB              *PendPrevPtr;                       /* Pointer to previous TCB in pend list.                  */
    OS_PEND_OBJ         *PendObjPtr;                        /* Pointer to object pended on.                           */
    OS_STATE             PendOn;                            /* Indicates what task is pending on                      */
    OS_STATUS            PendStatus;                        /* Pend status                                            */
    OS_STATE             TaskState;                         /* See OS_TASK_STATE_xxx                                  */
    OS_PRIO              Prio;                              /* Task priority (0 == highest)                           */
...

5、任务创建函数

任务控制块TCB就是一个结构体,需要封装了任务信息,uCOS提供一个函数将任务信息填充到TCP中,并将它注册到uCOS操作系统中去。让uCOS知道它的存在,并调度它。这个函数在uCOS中就是OSTaskCreate,函数原型如下:

void  OSTaskCreate (OS_TCB        *p_tcb,		/* 任务控制块地址 */
                    CPU_CHAR      *p_name,		/* 任务名 */
                    OS_TASK_PTR    p_task,		/* 启动任务函数地址 */
                    void          *p_arg,		/* 传递给任务的参数 */
                    OS_PRIO        prio,		/* 任务优先级 */
                    CPU_STK       *p_stk_base,	/* 堆栈基地址 */
                    CPU_STK_SIZE   stk_limit,	/* 堆栈监测区 */
                    CPU_STK_SIZE   stk_size,	/* 堆栈空间大小 */
                    OS_MSG_QTY     q_size,		/* 本任务支持接受的最大消息数 */
                    OS_TICK        time_quanta, /* 设置时间片 */
                    void          *p_ext,		/* 堆栈空间大小 */ 
                    OS_OPT         opt,			/* 选择设置 */ 
                    OS_ERR        *p_err)		/* 错误返回值 */ 

6、任务就绪列表

所有任务都在一个列表中,供系统切换,这个列表叫做任务就绪列表:OSRdyList

任务就绪列表的定义:OS_RDY_LIST OSRdyList[OS_CFG_PRIO_MAX]
节点个数最大64个,也就是说,最多可以创建64个任务:#define OS_CFG_PRIO_MAX 64u
节点类型 OS_RDY_LIST 其实就是组成双向列表的结构体,原代码如下

typedef struct os_rdy_list OS_RDY_LIST;
struct os_rdy_list{
    OS_TCB  *HeadPtr;  /* Pointer to task that will run at selected priority */
    OS_TCB  *TailPtr;  /* Pointer to last task at selected priority */
};

7、任务初始化OSInit

系统初始化一般都是在硬件初始化完后再执行。代码如下,系统初始化函数OSInit在时钟初始化、外部设备初初始化以后运行

int main(void)
{
	OS_ERR  err;
	
	/* HAL库,MPU,Cache,时钟等系统初始化 */
	System_Init();

	/*初始化GPIO引脚*/	
	MX_GPIO_Init();

	/* 初始化uC/OS-III 内核 */
	OSInit(&err);  
	。。。
}

OSInit主要完成的工作:初始化全局变量、初始化任务就绪列表。

初始化的全局变量包括:

OSRunning 系统的运行状态,默认是停止状态OS_STATE_OS_STOPPED
OSTCBCurPtr:当前正在运行的任务TCB指针
OSTCBHighRdyPtr:任务就绪列表中,优先级最高的任务TCB指针

8、任务启动OSStart

先装载最高优先级任务到当前任务指针,然后执行任务切换函数:OSStartHighRdy

void  OSStart (OS_ERR  *p_err)
{
    OS_OBJ_QTY  kernel_task_cnt;
    kernel_task_cnt = 0u;                                       
    if (OSRunning == OS_STATE_OS_STOPPED) {
        OSPrioHighRdy   = OS_PrioGetHighest();                  
        OSPrioCur       = OSPrioHighRdy;
        OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
        OSTCBCurPtr     = OSTCBHighRdyPtr;
        OSRunning       = OS_STATE_OS_RUNNING;
        OSStartHighRdy();                                       
       *p_err           = OS_ERR_FATAL_RETURN;                  
    } else {
       *p_err           = OS_ERR_OS_RUNNING;                    
    }
}

9、任务切换OSStartHighRdy

任务切换函数OSStartHighRdy是汇编写的,在os_cpu_a.asm中,部分源码如下,本人不懂汇编,不在展开解释

主要完成的工作是:

保存上下文(将当前任务的各个CPU寄存器中值保存到任务栈中)
切换上下文(将下个任务栈中的内容加到CPU寄存器中)
OSStartHighRdy
    CPSID   I                                                   ; Prevent interruption during context switch
    MOV32   R0, NVIC_SYSPRI14                                   ; Set the PendSV exception priority
    MOV32   R1, NVIC_PENDSV_PRI
    STRB    R1, [R0]
。。。

10、任务调度

在每个任务函数的循环中会需要执行一个函数: OSTimeDly;
OSTimeDly中会调用OSSched;
OSSched会切换下一个任务

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32】入门(十一):初识uCOS-III 的相关文章

随机推荐

  • 得到一个数字中每一位的数字

    学习编程也有一段时间了 xff0c 随着学习的不断深入 xff0c 我越来越体会到了算法的重要性 xff0c 最近遇到了一些非常有意思的算法 xff0c 比如打印水仙花数 将数字逆置 xff0c 在这两个算法中会用到一个数字钟每一位的值 如
  • 使用C++实现学生管理系统

    我在前面的博客中分别使用C语言的动态数组和链表实现了学生成绩管理系统 xff0c 最近正好在学习C 43 43 xff0c 于是我便使用C 43 43 实现了学生成绩管理系统 xff0c 算法和前面的C语言的动态数组实现的学生成绩管理系统差
  • 制作一个简单的Android版的音乐播放器

    音乐播放器是一个非常常见的应用 xff0c 这篇博客就是介绍如何制作一个简单的音乐播放器 xff0c 这款音乐播放器具有以下的功能 xff1a 播放歌曲 暂停播放歌曲 显示歌曲的总时长 显示歌曲的当前播放时长 调节滑块可以将歌曲调节到任何时
  • 使用Less

    为什么要使用预处理CSS 在使用CSS过程中会遇到一个非常头疼的问题 xff0c 因为CSS中没有像java C 43 43 或者PHP等程序语言一样有有自己的变量 常量 条件语句以及一些编程语法 xff0c 只是一行行单纯的属性描述 xf
  • 使用Gulp

    为什么要使用Gulp 在前端开发中通常需要做 xff0c 预处理语言的编译 js文件的压缩 css文件的压缩 图片的压缩等一系列工作 xff0c 而使用Gulp可以自动化的完成这些工作 xff0c 从而提高网站的开发效率 xff0c 在我的
  • 欢迎使用CSDN-markdown编辑器

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传
  • CMakeList的基本写法

    最近需要自己写CMakaList xff0c 所以简要写一下一些基本的操作 为图实用 xff0c 只写了常用的简单操作 1 确定cmake最低版本需求 span class hljs function span class hljs tit
  • SLAM的一点认识

    SLAM的一点认识 本人邮箱 xff1a sylvester0510 64 163 com xff0c 欢迎交流讨论 xff0c 欢迎转载 xff0c 转载请注明网址http blog csdn net u010128736 一 我与SLA
  • ORB-SLAM2详解(六)闭环检测

    ORB SLAM2详解 xff08 六 xff09 闭环检测 本人邮箱 xff1a sylvester0510 64 163 com xff0c 欢迎交流讨论 xff0c 欢迎转载 xff0c 转载请注明网址http blog csdn n
  • FreeRTOS系列|任务创建和删除

    任务创建和删除 1 任务创建和删除API函数 xTaskCreate 函数 xff1a 动态创建一个新的任务 xff0c 每个任务都需要RAM来保存任务状态 任务控制块 43 任务栈 xff0c 此接口采用动态分配内存资源 BaseType
  • 深度学习如何做特征工程?

    深度能自动获取特征 只是对某些领域而言的 实际上深度学习只是能自动对输入的低阶特征进行组合 变换 xff0c 得到高阶特征 对于图像处理之类的领域来说 xff0c 像素点就可以作为低阶特征输入 xff0c 组合 变换得到的高阶特征也有比较好
  • Git:《Git学习视频》学习笔记

    视频地址 xff1a 黑马程序员 Git学习视频 目录 xff1a 一Git介绍二Git与SVN的区别 速度结构其他 三Git基本命令的使用掌握 如何学习git指令常见命令单人开发配置帐号信息一般只需配置一次全局帐号即可查看日志起别名版本回
  • 海康云台摄像机 ISAPI 的签名机制与语音传输

    由于海康HikVision Hik 平台摄像机的SDK不支持Arm Linux平台 xff0c 为了跨平台的兼容性 xff0c 只能使用ISAPI作为控制或接收相机数据的方式 xff0c ISAPI是Hik的一套HTTP通信协议 xff0c
  • 无人机中的坐标系与相机姿态计算

    球坐标系 球坐标系是三维坐标系中的一种 xff0c 在无人机中一般使用球坐标系来表示相机姿态 xff0c 相机姿态的坐标是相对于无人机的 xff0c 而无人机的飞行姿态则是相对于大地坐标系的 这里我们使用的相机是2自由度的相机 xff0c
  • 【Ubuntu】安装中文输入法、终端不支持中文的解决方法

    一 中文输入法安装 1 安装汉语语言包 sudo apt install fcitx sudo apt install language pack zh hans 2 安装google拼音输入法 sudo apt install fcitx
  • 【Qt】QtCreator中配置clang-format

    1 安装clang format sudo apt install clang format 2 添加插件Beautifier 在QtCreator gt Help gt About Plugins 中添加插件Beautifer 添加后要重
  • 【TX2】TX2开发板系统默认串口有ttyS0(调试口)、ttyTHS1、ttyTHS2、ttyTHS3,通过修改设备树文件,可以新增三个串口

    1 简述 TX2开发板系统默认串口有ttyS0 调试口 ttyTHS1 ttyTHS2 ttyTHS3 通过修改设备树文件 可以新增三个串口 2 设备树 设备树中关于串口部分的描述 2 1 基础配置 注意 在这里状态都配置成禁止 statu
  • 【STM32】入门(六):I2C协议

    STM32 STM32单片机总目录 1 常见I2C设备 EEPROM 温湿度传感器 xff0c 例如 xff1a AHT10 电量计 xff0c 例如 xff1a TI的BQ34Z100 日历时钟 模数或数模转换器 2 I2C总线结构 I2
  • 【STM32】入门(九):HAL库学习

    STM32 STM32单片机总目录 1 简述 STD xff08 Standard Peripheral Libraries xff09 标准库 xff1a 面向过程 xff0c 仅仅是在寄存器上的一层封装操作 HAL xff08 Hard
  • 【STM32】入门(十一):初识uCOS-III

    STM32 STM32单片机总目录 1 轮询 中断 多任务对比 2 什么是任务 如果您学过linux xff0c 那么任务可以理解为线程 在代码中的体现就是线程函数 xff0c 一个函数中有个无限循环函数 xff0c 并且永不返回 例如 x