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

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

日期:2024-3-30 23:55

结尾总结了今天学习的一些小收获

1. 首先定义错误码变量

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

2. 定义任务控制块

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

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

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

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

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

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

c 复制代码
...

/* 定义栈区域 */
#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. 第一个任务,先使用不精确的演示来做

c 复制代码
//微秒级的延时
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闪烁功能

c 复制代码
void MyTask1(void *p_arg)
{
	
	while(1)
	{
		LED(ON);
		delay_ms(200);
		LED(OFF);
		delay_ms(200);
	}
}

PS:

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

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

c 复制代码
// 在 os_cfg.h 中

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

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

相关推荐
可待电子单片机设计定制(论文)7 小时前
【STM32设计】基于STM32的智能门禁管理系统(指纹+密码+刷卡+蜂鸣器报警)(代码+资料+论文)
stm32·单片机·嵌入式硬件
了一li12 小时前
STM32实现一个简单电灯
stm32·单片机·嵌入式硬件
可待电子单片机设计定制(论文)14 小时前
【STM32设计】数控直流稳压电源的设计与实现(实物+资料+论文)
stm32·嵌入式硬件·mongodb
小麦嵌入式15 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
触角0101000117 小时前
STM32F103低功耗模式深度解析:从理论到应用实践(上) | 零基础入门STM32第九十二步
驱动开发·stm32·单片机·嵌入式硬件·物联网
昊虹AI笔记17 小时前
使用STM32CubeMX和Keil在STM32上创建并运行一个简单的FreeRTOS多任务程序
stm32·单片机·嵌入式硬件
阿超爱嵌入式19 小时前
STM32学习笔记之RCC模块(实操篇)
笔记·stm32·学习
charlie11451419120 小时前
STM32F103C8T6单片机硬核原理篇:讨论GPIO的基本原理篇章1——只讨论我们的GPIO简单输入和输出
c语言·stm32·单片机·嵌入式硬件·gpio·数据手册
阿让啊20 小时前
bootloader+APP中,有些APP引脚无法正常使用?
c语言·开发语言·stm32·单片机·嵌入式硬件
Lhj06161 天前
stm32 can 遥控帧的问题
stm32·单片机·嵌入式硬件