【uC/OS-III篇】uC/OS-III 创建第一个任务(For STM32)

uC/OS-III 创建第一个任务(For STM32)

日期:2024-3-30 23:55,结尾总结了今天学习的一些小收获

本博客对应的项目源码工程
源码项目工程


1. 首先定义错误码变量

// 用于使用uC/OS函数时返回错误码
OS_ERR err;  

2. 定义任务控制块

// 定义任务控制块,用于描述一个任务
OS_TCB p_tcb;

3. 初始化OS,如果有错误则通过 err 判断

// 初始化 uC/OS-III 中的内部变量和数据结构
OSInit(&err);
  • OSInit() 会初始化 uC/OS-III 的内部变量和数据结构,并创建2~5个系统任务。例如至少会创建空闲任务(OS_IdleTask)和时钟节拍任务

  • 空闲任务主要在其他任务不运行的时候运行,空闲任务优先级最低,默认为63(uC/OS的优先级规则是数字越小优先级越高,默认0~63)

  • 还可能创建统计任务(OS_StackTask())、定时任务(OS_TmrTask())、中断处理队列管理任务(OS_IntQTask())

  • OSInit() 函数注释

/*
	注释者:晨少
	日期:2024年3月29日
	地点:宿舍
*/

void  OSInit (OS_ERR  *p_err)
{
#if (OS_CFG_ISR_STK_SIZE > 0u)
    CPU_STK      *p_stk;   // CPU_STK:     unsigned int 的宏定义
    CPU_STK_SIZE  size;    // CPU_STK_SIZE:unsigned int 的宏定义
#endif



#ifdef OS_SAFETY_CRITICAL   // 系统是否需要符合安全关键(Safety Critical)的需求,在航天、医疗、核电等领域需要用到
    						// 开启安全关键后,会自动检查栈溢出、检查系统各个地方是否有出现错误的可能
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

		// 在系统初始化时可插入一些自定义操作
    OSInitHook();                                               /* Call port specific initialization code */
		// 清除中断嵌套计数器
    OSIntNestingCtr       =           0u;                       /* Clear the interrupt nesting counter */
		// 初始化系统运行状态,当前未启动多任务
    OSRunning             =  OS_STATE_OS_STOPPED;               /* Indicate that multitasking has not started           */
		// 清除锁嵌套计数
    OSSchedLockNestingCtr =           0u;                       /* Clear the scheduling lock counter*/
		// 初始化两个指针,一个是指向当前正在运行的TCB的指针,一个是指向当前最高优先级的TCB的指针
    OSTCBCurPtr           = (OS_TCB *)0;                        /* Initialize OS_TCB pointers to a known state          */
    OSTCBHighRdyPtr       = (OS_TCB *)0;
		// 初始化当前运行任务的优先级 & 最高优先级任务的优先级
    OSPrioCur             =           0u;                    /* Initialize priority variables to a known state       */
    OSPrioHighRdy         =           0u;

#if (OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u)
    OSSchedLockTimeBegin  =           0u;
    OSSchedLockTimeMax    =           0u;
    OSSchedLockTimeMaxCur =           0u;
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    OSSafetyCriticalStartFlag = OS_FALSE;
#endif

#if (OS_CFG_SCHED_ROUND_ROBIN_EN > 0u)
		// 禁用/启动循环调度
    OSSchedRoundRobinEn             = OS_FALSE;
		// OSCfg_TickRate_Hz默认值1000u,即1s有1000个节拍,一个节拍是1ms
		// 那么时间片轮转时长就是 1000u/10u = 100u ,即100ms
    OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;  
#endif

#if (OS_CFG_ISR_STK_SIZE > 0u)
		// 清除异常堆栈,进行堆栈检查
		// 将p_stk设为ISR栈的基地址
    p_stk = OSCfg_ISRStkBasePtr;                             /* Clear exception stack for stack checking. */
    // 如果p_stk为空,说明没有分配ISR栈空间;
		// 反之如果不为空,说明分配了ISR栈空间,则需要对ISR栈空间清零初始化
		if (p_stk != (CPU_STK *)0) {
        size  = OSCfg_ISRStkSize;
        while (size > 0u) {
            size--;
           *p_stk = 0u;
            p_stk++;
        }
    }
		// 检查任务堆栈溢出功能
		// 根据栈的生长方向,将栈底的8个字节初始化为特定值0x5432DCBAABCD2345UL
		// 该区域叫做红区,通过判断红区数据是否被修改,来判断栈是否溢出
#if (OS_CFG_TASK_STK_REDZONE_EN > 0u)                           /* Initialize Redzoned ISR stack */
    OS_TaskStkRedzoneInit(OSCfg_ISRStkBasePtr, OSCfg_ISRStkSize);
#endif
#endif

    ...
    ...
        
		// 初始化优先级位表,将空闲任务插入到优先级列表中
    OS_PrioInit();                                              /* Initialize the priority bitmap table */
		// 初始化就绪优先级链表,链表结构体见 OS_RDY_LIST
    OS_RdyListInit();                                           /* Initialize the Ready List  */

    ...
    ...

		// 系统配置初始化,例如空闲任务、中断ISR、消息队列等
    OSCfg_Init();
		// 系统初始化完成
    OSInitialized = OS_TRUE;                                    /* Kernel is initialized  */
}

4. 使用 OSTaskCreate 创建第一个任务,使用 OSStart 开始运行系统

...

/* 定义栈区域 */
#define		TASK_START_STK_SIZE		100    // 栈深度,单位4字节,最小 64 * 4字节
CPU_STK  MyTask1_StartStk[TASK_START_STK_SIZE];

/* 任务函数 */
void MyTask1(void *p_arg);    


int main(void)
{
    ...
    ...

    // 创建第一个uC/OS任务
    OSTaskCreate ((OS_TCB      *)&p_tcb,         	// 任务控制块地址
                  (CPU_CHAR     *)"MyTask1", 			// 任务名
                  (OS_TASK_PTR  )MyTask1,				// 任务函数地址
                  (void        *)0,								// 参数
                  (OS_PRIO      )3,								// 任务优先级
                  (CPU_STK     *)&MyTask1_StartStk[0],   // 任务栈空间基地址
                  (CPU_STK_SIZE )TASK_START_STK_SIZE/10, // 代表栈溢出警告之前栈内应该剩余的空间,即栈极限深度
                  (CPU_STK_SIZE )TASK_START_STK_SIZE,    // 任务栈深度,单位4字节
                  (OS_MSG_QTY   )0,
                  (OS_TICK      )0,
                  (void        *)0,
                  // 任务可选项,创建任务时清空栈空间,运行时检查任务栈的使用情况
                  (OS_OPT       )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                  (OS_ERR      *)&err);
    // 启动OS
    OSStart(&err);
}

5. 第一个任务,先使用不精确的演示来做

//微秒级的延时
void delay_us(uint32_t delay_us)
{    
  volatile unsigned int num;
  volatile unsigned int t;
 
  
  for (num = 0; num < delay_us; num++)
  {
    t = 11;
    while (t != 0)
    {
      t--;
    }
  }
}
//毫秒级的延时
void delay_ms(uint16_t delay_ms)
{    
  volatile unsigned int num;
  for (num = 0; num < delay_ms; num++)
  {
    delay_us(1000);
  }
}


/*
	uC/OS 任务
*/
char flag1 = 0;   // 需要定义成全局变量才能添加到仿真中的逻辑分析仪
void MyTask1(void *p_arg)
{
	
	while(1)
	{
		flag1 = 0;
		delay_ms(200);
		flag1 = 1;
		delay_ms(200);
	}
}

6. 使用仿真,使用逻辑分析仪来看变量的变化

需要先改几个地方

(1)设置频率为8MHz

在这里插入图片描述

 (2)勾选仿真

在这里插入图片描述

​ (3)将原本的DCM.DLL改成 DARMSTM.DLL ,Parameter 修改为自己的板子型号,例如 -pSTM32F103C8

在这里插入图片描述

​ (4)将 flag1 变量添加到逻辑分析仪中

在这里插入图片描述
在这里插入图片描述

​ (5)一键运行,观察逻辑分析仪

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以观察到 flag1 变量的变化,由于延时不是很精确,可以看到跳变周期为约为 0.3925s

​ (6)将flag1改为LED闪烁功能

void MyTask1(void *p_arg)
{
	
	while(1)
	{
		LED(ON);
		delay_ms(200);
		LED(OFF);
		delay_ms(200);
	}
}

在这里插入图片描述


PS:

收获1:局部变量和 static 类型的变量不能添加到仿真中的逻辑分析仪

收获2:UCOS-III 的任务栈有最小显示,单位不是字,而是4个字节

// 在 os_cfg.h 中

// 最小任务栈大小(单位4字节)
#define OS_CFG_STK_SIZE_MIN                       64u           /* Minimum allowable task stack size   

收获3:了解到任务栈的深度标记,代表栈溢出警告之前栈内应该剩余的空间,即栈极限深度,在本例中,当剩余栈空间小于任务栈空间的10%时,就达到了栈极限深度。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

非NVIDIA平台下的CUDA的替代方案OpenCL,第一步如何获取PlatformInfo、DeviceInfo

非NVIDIA平台下的CUDA的替代方案OpenCL&#xff0c;第一步如何获取PlatformInfo、DeviceInfo 介绍 当谈到高性能计算&#xff0c;NVIDIA的CUDA框架无疑是一个强大的工具。OpenC&#xff08;Open Computing Language&#xff09;是一个更为通用的解决方案&#xff0c;或者你使用…

MySQL面试必备一之索引

本文首发于公众号&#xff1a;Hunter后端 原文链接&#xff1a;MySQL面试必备一之索引 在面试过程中&#xff0c;会有一些关于 MySQL 索引相关的问题&#xff0c;以下总结了一些&#xff1a; MySQL 的数据存储使用的是什么索引结构B 树的结构是什么样子什么是复合索引、聚簇索…

SVFormer: Semi-supervised Video Transformer for Action Recognition

标题&#xff1a;SVFormer&#xff1a;用于动作识别的半监督视频Transformer 原文链接&#xff1a;https://doi.org/10.48550/arXiv.2211.13222 源码链接&#xff1a;GitHub - ChenHsing/SVFormer 发表&#xff1a;CVPR 摘要 半监督动作识别是一项具有挑战性但至关重要的任…

2024年道路运输企业安全生产管理人员证模拟考试题库及道路运输企业安全生产管理人员理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年道路运输企业安全生产管理人员证模拟考试题库及道路运输企业安全生产管理人员理论考试试题是由安全生产模拟考试一点通提供&#xff0c;道路运输企业安全生产管理人员证模拟考试题库是根据道路运输企业安全生产…

day58 动态规划part15

392. 判断子序列 简单 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde&q…

通天星CMSV6 车载定位监控平台 任意文件上传漏洞复现(XVE-2023-23454)

0x01 产品简介 通天星CMSV6车载定位监控平台拥有以位置服务、无线3G/4G视频传输、云存储服务为核心的研发团队,专注于为定位、无线视频终端产品提供平台服务,通天星CMSV6产品覆盖车载录像机、单兵录像机、网络监控摄像机、行驶记录仪等产品的视频综合平台。 0x02 漏洞概述 …

汇编语言第四版-王爽第2章 寄存器

二进制左移四位&#xff0c;相当于四进制左移一位。 debug命令实操&#xff0c;win11不能启动&#xff0c;需要配置文件 Windows64位系统进入debug模式_window10系统64位怎么使用debugger-CSDN博客

DeepL Pro3.1 下载地址及安装教程

DeepL Pro是DeepL公司推出的专业翻译服务。DeepL是一家专注于机器翻译和自然语言处理技术的公司&#xff0c;其翻译引擎被认为在质量和准确性方面表现优秀.DeepL Pro提供了一系列高级功能和服务&#xff0c;以满足专业用户的翻译需求。其中包括&#xff1a; 高质量翻译&#xf…

vue3 视频播放功能整体复盘梳理

回顾工作中对视频的处理&#xff0c;让工作中处理的问题的经验固化成成果&#xff0c;不仅仅是完成任务&#xff0c;还能解答任务的知识点。 遇到的问题 1、如何隐藏下载按钮&#xff1f; video 标签中的controlslist属性是可以用来控制播放器上空间的显示&#xff0c;在原来默…

MySQL数据库高阶语句②

目录 一.子查询与多表查询 1.子查询 2.update子查询 3.多表查询 4.delete子查询 5.exists关键字也用于子查询 6.结果集 二.MySQL视图 1.定义 2.作用场景 3.视图与表的区别与联系 &#xff08;1&#xff09;区别 ①视图是已经编译好的sql语句。而表不是 ②视图没有…

unity 打包安卓错误汇集

Failed to find target with hash string "android-34’ in: D:Pr 他说找不到sdk34level的我用as打开后卸载又重装&#xff0c;最后解决了 我放到Plugins/Android/下面的Java代码没有被编译 这个不知道为什么。我故意把代码写的有问题&#xff0c;会报错那种&#xff…

linux自定义命令

文章目录 1、自定义命令介绍2、自定义命令步骤 (centos7)2.1 新建隐藏目录存放自定义命令脚本文件2.2 将新建的目录配置环境变量2.3 取别名的方式简化已有命令2.4 编写自定义命令脚本 1、自定义命令介绍 不管是linux系统还是windows系统都支持自定义命令&#xff0c;windows端…

MIPI CSI-2 Low Level Protocol解读

一、Low Level Protocol介绍 LLP 是一种面向字节的基于数据包的协议&#xff0c;支持使用短数据包和长数据包格式传输任意数据。为简单起见&#xff0c;本节中的所有示例均为单通道配置。 LLP特性&#xff1a; 传输任意数据&#xff08;与有效载荷无关&#xff09; 8 位字大…

代码随想录第二十五天 | 回溯算法P2 | ● 216● 17

216.组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7 输出…

解决AD使用交互式BOM插件时,插入make点导致显示异常的问题

记得上次写了一篇关于使用这个插件时出现这个问题的解决方法&#xff0c;具体可查看&#xff1a;AD使用交互式BOM插件时应该注意到的一个问题_ad的bom插件-CSDN博客 当时的解决办法就是删除后再运行脚本生成&#xff0c;这些天经过多次实验&#xff0c;发现是当时那个封装有问…

健身房预约管理系统(源码+文档)

健身房预约管理系统&#xff08;小程序、ios、安卓都可部署&#xff09; 文件包含内容程序简要说明含有功能&#xff1a;项目截图客户端首页我的预约登录教练预约时间我的注册页个人资料课程预约课程预约 管理端订单管理团课管理教练管理分类管理用户管理 文件包含内容 1、搭建…

vulnhub靶场之driftingblues-4

一.环境搭建 1.靶场描述 get flags difficulty: easy about vm: tested and exported from virtualbox. dhcp and nested vtx/amdv enabled. you can contact me by email for troubleshooting or questions. This works better with VirtualBox rather than VMware. 2.靶场…

Segger Embedded Studio IDE使用体验——默认的Section和Linker的设置

Segger Embedded Studio IDE使用体验之一——默认的Section和Linker的设置 一、简介二、操作2.1 编译后代码分析2.1.1 符号浏览器2.1.2 读取elf文件和map文件 2.2 调试2.2.1 查看变量2.2.2 设置供电 2.3 运行环境设置2.3.1 编译器2.3.2 汇编器2.3.3 包含其他文件2.3.4 .bss和.d…

【MATLAB源码-第24期】基于matlab的水声通信中海洋噪声的建模仿真,对比不同风速的影响。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 水声通信&#xff1a; 水声通信是一种利用水中传播声波的方式进行信息传递的技术。它在水下环境中被广泛应用&#xff0c;特别是在海洋科学研究、海洋资源勘探、水下军事通信等领域。 1. **传输媒介**&#xff1a;水声通信利…

Postgresql导出数据和结构后再去另外一个Postgresql数据库中导入失败

参考教程&#xff1a; postgresql 在导入建表sql时 遇到错误 &#xff1a;https://blog.csdn.net/weixin_37706944/article/details/132321731 是因为原表定义了自增字段&#xff0c;解决办法&#xff1a; 解决方法&#xff1a; 执行如下sql后再新建表&#xff0c;就可以了 DR…