(学习日记)2024.03.24:UCOSIII第二十一节:创建任务:LED红绿蓝切换

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.03.24

  • 三十五、UCOSIII:创建任务
    • 1、硬件初始化
    • 2、创建单任务
      • 1. 定义任务栈
      • 2. 定义任务控制块
      • 3. 定义任务主体函数
      • 4. 创建任务
      • 5. 启动任务
      • 6. app.c全貌
    • 3、下载验证
    • 4、创建多任务
    • 5、下载验证

三十五、UCOSIII:创建任务

在上一章,我们已经基于野火STM32开发板创建好了μC/OS-III的工程模板,这章开始我们将真正进入如何使用μC/OS的征程, 先从最简单的创建任务开始,点亮一个LED。

1、硬件初始化

本章创建的任务需要用到开发板上的LED,所以先要将LED相关的函数初始化好。
为了方便以后统一管理板级外设的初始化, 我们在bsp.c文件中创建一个BSP_Init()函数,专门用于存放板级外设初始化函数

/***********************************************************************
* @ 函数名: BSP_Init
* @ 功能说明:板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数:
* @ 返回值:无
*********************************************************************/
static void BSP_Init(void)
{
/*
    * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
    * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
    * 都统一用这个优先级分组,千万不要再分组,切忌。
    */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

    /* LED 初始化 */
    LED_GPIO_Config();

    /* 串口初始化        */
    USART_Config();
}

执行到BSP_Init()函数的时候,操作系统完全都还没有涉及,即BSP_Init()函数所做的工作跟我们以前编写的裸机工程里面的硬件初始化工作是一模一样的。

运行完BSP_Init ()函数,接下来才慢慢启动操作系统,最后运行创建好的任务。
有时候任务创建好,整个系统跑起来了, 可想要的实验现象就是出不来,比如LED不会亮,串口没有输出,LCD没有显示等等。
如果是初学者,这个时候就会心急如焚, 四处求救,那怎么办?这个时候如何排除是硬件的问题还是系统的问题,这里面有个小小的技巧,即在硬件初始化好之后, 顺便测试下硬件,测试方法跟裸机编程一样

/* 开发板硬件bsp头文件 */
#include"bsp_led.h"
#include"bsp_usart.h"

/***********************************************************************
* @ 函数名: BSP_Init
* @ 功能说明:板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数:
* @ 返回值:无
*********************************************************************/
static void BSP_Init(void)
{
    /*
    * STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15
    * 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,
    * 都统一用这个优先级分组,千万不要再分组,切忌。
    */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

    /* LED 初始化 */
    LED_GPIO_Config();                      //(1)

    /* 测试硬件是否正常工作 */                //(2)
    LED1_ON;

    /* 其他硬件初始化和测试 */

    /* 让程序停在这里,不再继续往下执行 */
    while (1);                      //(3)

    /* 串口初始化        */
    USART_Config();

}
  • (1):初始化硬件后,顺便测试硬件,看下硬件是否正常工作。
  • (2):可以继续添加其他的硬件初始化和测试。 硬件确认没有问题之后,硬件测试代码可删可不删,因为BSP_Init()函数只执行一遍。
  • (3):方便测试硬件好坏,让程序停在这里,不再继续往下执行,当测试完毕后,这个while(1);必须删除。

2、创建单任务

这里,我们创建一个单任务,任务使用的栈和任务控制块都使用静态内存,即预先定义好的全局变量,这些预先定义好的全局变量都存在内部的SRAM中。

1. 定义任务栈

目前我们只创建了一个任务,当任务进入延时的时候,因为没有另外就绪的用户任务,那么系统就会进入空闲任务。

空闲任务是μC/OS系统自己创建并且启动的一个任务, 优先级最低。
当整个系统都没有就绪任务的时候,系统必须保证有一个任务在运行,空闲任务就是为这个设计的。当用户任务延时到期,又会从空闲任务切换回用户任务。

在μC/OS系统中,每一个任务都是独立的,他们的运行环境都单独的保存在他们的栈空间当中。那么在定义好任务函数之后,我们还要为任务定义一个栈。
目前我们使用的是静态内存,所以任务栈是一个独立的全局变量。

#define  APP_TASK_START_STK_SIZE                    128

static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];

任务的栈占用的是MCU内部的RAM,当任务越多的时候, 需要使用的栈空间就越大,即需要使用的RAM空间就越多。
一个MCU能够支持多少任务,就得看你的RAM空间有多少。

2. 定义任务控制块

定义好任务函数和任务栈之后,我们还需要为任务定义一个任务控制块,通常我们称这个任务控制块为任务的身份证。
在C代码上,任务控制块就是一个结构体, 里面有非常多的成员,这些成员共同描述了任务的全部信息。

static OS_TCB AppTaskStartTCB;

3. 定义任务主体函数

static void LED_Task (void* parameter)
{
    while (1)                                       //(1)
    {
        LED1_ON;
        OSTimeDly (500,OS_OPT_TIME_DLY,&err);/* 延时500个tick *///(2)

        LED1_OFF;
        OSTimeDly (500,OS_OPT_TIME_DLY,&err);/* 延时500个tick */

    }
}
  • (1):任务必须是一个死循环,否则任务将通过LR返回, 如果LR指向了非法的内存就会产生HardFault_Handler, 而μC/OS指向一个任务退出函数OS_TaskReturn(),它如果支持任务删除的话,则进行任务删除操作,否则就进入死循环中。
    这样子的任务是不安全的,所以避免这种情况,任务一般都是死循环并且无返回值的,只执行一次的任务在执行完毕要记得及时删除。
  • (2):任务里面的延时函数必须使用μC/OS里面提供的阻塞延时函数,并不能使用我们裸机编程中的那种延时。
    这两种的延时的区别是μC/OS里面的延时是阻塞延时,即调用OSTimeDly()函数的时候,当前任务会被挂起,调度器会切换到其他就绪的任务, 从而实现多任务。
    如果还是使用裸机编程中的那种延时,那么整个任务就成为了一个死循环,如果恰好该任务的优先级是最高的, 那么系统永远都是在这个任务中运行,比它优先级更低的任务无法运行,根本无法实现多任务,因此任务中必须有能阻塞任务的函数, 才能切换到其他任务中。

4. 创建任务

一个任务的三要素是任务主体函数,任务栈,任务控制块,那么怎么样把这三个要素联合在一起?
μC/OS里面有一个叫任务创建函数OSTaskCreate(), 它就是干这个活的。
它将任务主体函数,任务栈和任务控制块这三者联系在一起,让任务在创建之后可以随时被系统启动与调度
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)

OSTaskCreate的使用如下:

OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                        //(1)
            (CPU_CHAR   *)"App Task Start",                 //(2)
            (OS_TASK_PTR ) AppTaskStart,                    //(3)
            (void       *) 0,                                       //(4)
            (OS_PRIO     ) APP_TASK_START_PRIO,             //(5)
            (CPU_STK    *)&AppTaskStartStk[0],                      //(6)
            (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,    //(7)
            (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,         //(8)
            (OS_MSG_QTY  ) 5u,                              //(9)
            (OS_TICK     ) 0u,                              //(10)
            (void       *) 0,                                       //(11)
            (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), //(12)
            (OS_ERR     *)&err);                                    //(13)
  • (1):任务控制块,由用户自己定义。
  • (2):任务名称,字符串形式,这里任务名称最好要与任务函数入口名字一致,方便进行调试。
  • (3):任务入口函数,即任务函数的名称,需要我们自己定义并且实现。
  • (4):任务入口函数形参,不用的时候配置为0或者NULL即可,p_arg是指向可选数据区域的指针, 用于将参数传递给任务,因为任务一旦执行,那必须是在一个死循环中,所以传参只在首次执行时有效。
  • (5):任务的优先级,由用户自己定义。
  • (6):指向栈基址的指针(即栈的起始地址)。
  • (7):设置栈深度的限制位置。这个值表示任务的栈满溢之前剩余的栈容量。 例如,指定stk_size值的10%表示将达到栈限制,当栈达到90%满就表示任务的栈已满。
  • (8):任务栈大小,单位由用户决定,如果CPU_STK 被设置为CPU_INT08U, 则单位为字节,而如果CPU_STK 被设置为CPU_INT16U,则单位为半字,同理,如果CPU_STK被设置为CPU_INT32U, 单位为字。在32位的处理器下(STM32),一个字等于4个字节,那么任务大小就为APP_TASK_START_STK_SIZE * 4字节。
  • (9):设置可以发送到任务的最大消息数,按需设置即可。
  • (10):在任务之间循环时的时间片的时间量(以滴答为单位)。指定0则使用默认值。
  • (11):是指向用户提供的内存位置的指针,用作TCB扩展。例如, 该用户存储器可以保存浮点寄存器的内容在上下文切换期间,每个任务执行的时间,次数、任务已经切换等。
  • (12):用户可选的任务特定选项
  • (13):用于保存返回的错误代码。

用户可选的任务特定选项如下:

#define  OS_OPT_TASK_NONE         (OS_OPT)(0x0000u) //(1)
#define  OS_OPT_TASK_STK_CHK      (OS_OPT)(0x0001u) //(2)
#define  OS_OPT_TASK_STK_CLR      (OS_OPT)(0x0002u) //(3)
#define  OS_OPT_TASK_SAVE_FP      (OS_OPT)(0x0004u) //(4)
#define  OS_OPT_TASK_NO_TLS       (OS_OPT)(0x0008u) //(5)
  • (1):未选择任何选项。
  • (2):启用任务的栈检查。
  • (3):任务创建时清除栈。
  • (4):保存任何浮点寄存器的内容,这需要CPU硬件的支持, CPU需要有浮点运算硬件与专门保存浮点类型数据的寄存器。
  • (5):指定任务不需要TLS支持。

5. 启动任务

当任务创建好后,是处于任务就绪,在就绪态的任务可以参与操作系统的调度。
任务调度器只启动一次, 之后就不会再次执行了。
μC/OS中启动任务调度器的函数是OSStart(),并且启动任务调度器的时候就不会返回, 从此任务都由μC/OS管理,此时才是真正进入实时操作系统中的第一步

/* 启动任务,开启调度 */
OSStart(&err);

6. app.c全貌

现在我们把任务主体,任务栈,任务控制块这三部分代码统一放到app.c中。
我们在app.c文件中创建一个AppTaskStart任务,这个任务仅用于测试用户任务,以后为了方便管理,我们的所有的任务创建都统一放在这个任务中, 在这个任务中创建成功的任务就可以直接参与任务调度了

#include <includes.h>


int  main (void)
{
    OS_ERR  err;


    OSInit(&err);                     /* Init μC/OS-III.*/

    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB, /* Create the start task
                */
                (CPU_CHAR   *)"App Task Start",
                (OS_TASK_PTR ) AppTaskStart,
                (void       *) 0,
                (OS_PRIO     ) APP_TASK_START_PRIO,
                (CPU_STK    *)&AppTaskStartStk[0],
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                (OS_MSG_QTY  ) 5u,
                (OS_TICK     ) 0u,
                (void       *) 0,
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                (OS_ERR     *)&err);

    OSStart(&err);/* Start multitasking(i.e.give control to μC/OS-III).*/

}


/*
*********************************************************************
*                                          STARTUP TASK
* Description : This is an example of a startup task.  As mentioned in
*            the book's text, you MUSTinitialize the ticker only once
*              multitasking has started.
*
* Arguments   : p_arg   is the argument passed to 'AppTaskStart()' by
*           'OSTaskCreate()'.
* Returns     : none
* Notes: 1) The first line of code is used to prevent a compiler warning
*           because 'p_arg' is not
*used.  The compiler should not generate any code for this statement.
*****************************************************************
*/

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


    (void)p_arg;

    BSP_Init();  /* Initialize BSP functions
            */
    CPU_Init();
    /*Determine SysTick reference freq*/
    cpu_clk_freq = BSP_CPU_ClkFreq();
    /* Determine nbr SysTick increments */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;

    OS_CPU_SysTickInit(cnts); /* Init μC/OS periodic time src (SysTick).
    */

    Mem_Init();   /* Initialize Memory Management Module
    */

#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task
        running  */
#endif

    CPU_IntDisMeasMaxCurReset();


while (DEF_TRUE) {          /* Task body, always written as an
        infinite loop.*/
        macLED1_TOGGLE ();
        OSTimeDly ( 5000, OS_OPT_TIME_DLY, & err );
    }

3、下载验证

在编译无报错的情况下,按F8用DAP仿真器把程序下载到开发板(我用的是野火的指南者),可以看到板子上面的LED灯已经在闪烁,说明我们创建的单任务已经跑起来了。

4、创建多任务

创建多任务只需要按照创建单任务的套路依葫芦画瓢即可。
接下来我们创建四个任务,分别是起始任务、 LED1 任务、 LED2 任务和 LED3任务。
任务1让一个LED灯闪烁,任务2让另外一个LED闪烁,两个LED闪烁的频率不一样,三个任务的优先级不一样。
主函数运行时创建起始任务,起始任务运行时创建三个LED灯的任务和删除自身,之后就运行三个LED灯的任务。

三个 LED 灯的任务优先级不一样:

  • LED1任务为 LED1 每隔 1秒切换一次亮灭状态
  • LED2 任务为 LED2 每隔 5 秒切换一次亮灭状态
  • LED3 任务为 LED3 每隔 10 秒切换一次亮灭状态。

首先在“ app_cfg.h”里,增加定义三个 LED 灯任务的优先级和栈空间大小, 然后修改app.c的源码

/*
*********************************************************************************************************
*                                              EXAMPLE CODE
*
*                          (c) Copyright 2003-2013; Micrium, Inc.; Weston, FL
*
*               All rights reserved.  Protected by international copyright laws.
*               Knowledge of the source code may NOT be used to develop a similar product.
*               Please help us continue to provide the Embedded community with the finest
*               software available.  Your honesty is greatly appreciated.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                            EXAMPLE CODE
*
*                                     ST Microelectronics STM32
*                                              on the
*
*                                     Micrium uC-Eval-STM32F107
*                                        Evaluation Board
*
* Filename      : app.c
* Version       : V1.00
* Programmer(s) : EHS
*                 DC
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/

#include <includes.h>

#include "stm32f10x_rcc.h"
/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                                 TCB
*********************************************************************************************************
*/

static  OS_TCB   AppTaskStartTCB;

static  OS_TCB   AppTaskLed1TCB;
static  OS_TCB   AppTaskLed2TCB;
static  OS_TCB   AppTaskLed3TCB;


/*
*********************************************************************************************************
*                                                STACKS
*********************************************************************************************************
*/

static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];

static  CPU_STK  AppTaskLed1Stk [ APP_TASK_LED1_STK_SIZE ];
static  CPU_STK  AppTaskLed2Stk [ APP_TASK_LED2_STK_SIZE ];
static  CPU_STK  AppTaskLed3Stk [ APP_TASK_LED3_STK_SIZE ];


/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  void  AppTaskStart  (void *p_arg);

static  void  AppTaskLed1  ( void * p_arg );
static  void  AppTaskLed2  ( void * p_arg );
static  void  AppTaskLed3  ( void * p_arg );


/*
*********************************************************************************************************
*                                                main()
*
* Description : This is the standard entry point for C code.  It is assumed that your code will call
*               main() once you have performed all necessary initialization.
*
* Arguments   : none
*
* Returns     : none
*********************************************************************************************************
*/

int  main (void)
{
    OS_ERR  err;


    OSInit(&err);                                               /* Init uC/OS-III.                                      */

    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,                /* Create the start task                                */
                 (CPU_CHAR   *)"App Task Start",
                 (OS_TASK_PTR ) AppTaskStart,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_START_PRIO,
                 (CPU_STK    *)&AppTaskStartStk[0],
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                 (OS_MSG_QTY  ) 5u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);

    OSStart(&err);                                              /* Start multitasking (i.e. give control to uC/OS-III). */
		
		
}


/*
*********************************************************************************************************
*                                          STARTUP TASK
*
* Description : This is an example of a startup task.  As mentioned in the book's text, you MUST
*               initialize the ticker only once multitasking has started.
*
* Arguments   : p_arg   is the argument passed to 'AppTaskStart()' by 'OSTaskCreate()'.
*
* Returns     : none
*
* Notes       : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
*                  used.  The compiler should not generate any code for this statement.
*********************************************************************************************************
*/

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


   (void)p_arg;

    BSP_Init();                                                 /* Initialize BSP functions                             */
    CPU_Init();

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;        /* Determine nbr SysTick increments                     */
    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

    Mem_Init();                                                 /* Initialize Memory Management Module                  */

#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

    CPU_IntDisMeasMaxCurReset();


    OSTaskCreate((OS_TCB     *)&AppTaskLed1TCB,                /* Create the Led1 task                                */
                 (CPU_CHAR   *)"App Task Led1",
                 (OS_TASK_PTR ) AppTaskLed1,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_LED1_PRIO,
                 (CPU_STK    *)&AppTaskLed1Stk[0],
                 (CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_TASK_LED1_STK_SIZE,
                 (OS_MSG_QTY  ) 5u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);
								 
    OSTaskCreate((OS_TCB     *)&AppTaskLed2TCB,                /* Create the Led2 task                                */
                 (CPU_CHAR   *)"App Task Led2",
                 (OS_TASK_PTR ) AppTaskLed2,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_LED2_PRIO,
                 (CPU_STK    *)&AppTaskLed2Stk[0],
                 (CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_TASK_LED2_STK_SIZE,
                 (OS_MSG_QTY  ) 5u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);

    OSTaskCreate((OS_TCB     *)&AppTaskLed3TCB,                /* Create the Led3 task                                */
                 (CPU_CHAR   *)"App Task Led3",
                 (OS_TASK_PTR ) AppTaskLed3,
                 (void       *) 0,
                 (OS_PRIO     ) APP_TASK_LED3_PRIO,
                 (CPU_STK    *)&AppTaskLed3Stk[0],
                 (CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE / 10,
                 (CPU_STK_SIZE) APP_TASK_LED3_STK_SIZE,
                 (OS_MSG_QTY  ) 5u,
                 (OS_TICK     ) 0u,
                 (void       *) 0,
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR     *)&err);
		
		
		OSTaskDel ( & AppTaskStartTCB, & err );
		
		
}


/*
*********************************************************************************************************
*                                          LED1 TASK
*********************************************************************************************************
*/

static  void  AppTaskLed1 ( void * p_arg )
{
    OS_ERR      err;


   (void)p_arg;


    while (DEF_TRUE) {                                          /* Task body, always written as an infinite loop.       */
			macLED1_TOGGLE ();
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			
			macLED1_TOGGLE ();
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
    }
		
		
}


/*
*********************************************************************************************************
*                                          LED2 TASK
*********************************************************************************************************
*/

static  void  AppTaskLed2 ( void * p_arg )
{
    OS_ERR      err;


   (void)p_arg;


    while (DEF_TRUE) {                                          /* Task body, always written as an infinite loop.       */
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			macLED2_TOGGLE ();
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			macLED2_TOGGLE ();
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			//OSTimeDly ( 5000, OS_OPT_TIME_DLY, & err );
    }
		
		
}


/*
*********************************************************************************************************
*                                          LED3 TASK
*********************************************************************************************************
*/

static  void  AppTaskLed3 ( void * p_arg )
{
    OS_ERR      err;


   (void)p_arg;


    while (DEF_TRUE) {                                          /* Task body, always written as an infinite loop.       */
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			macLED3_TOGGLE ();
			OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );
			macLED3_TOGGLE ();
			//OSTimeDly ( 10000, OS_OPT_TIME_DLY, & err );
    }
		
		
}

5、下载验证

在编译无报错的情况下,按F8用DAP仿真器把程序下载到开发板(我用的是野火的指南者),可以看到板子上面的LED灯以红绿蓝的顺序在闪烁,说明我们创建的多任务已经跑起来了。

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

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

相关文章

详细分析axios.js:72 Uncaught (in promise) Error: 未知错误 的解决方法(图文)

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 调试接口的时候,打开一个网页,在终端出现如下错误: axios.js:72 Uncaught (in promise) Error: 未知错误at __webpack_exports__.default (axios.js:72:1)截图如下所示: 2. 原理分析 点击浏览器的Bug出错: // 如果…

C/C++语言学习路线: 嵌入式开发、底层软件、操作系统方向(持续更新)

初级&#xff1a;用好手上的锤子 1 【感性】认识 C 系编程语言开发调试过程 1.1 视频教程点到为止 1.2 炫技视频看看就行 1.3 编程游戏不玩也罢 有些游戏的主题任务就是编程&#xff0c;游戏和实际应用环境有一定差异&#xff08;工具、操作流程&#xff09;&#xff0c;在…

进程知识点

引用的文章&#xff1a;操作系统——进程通信&#xff08;IPC&#xff09;_系统ipc-CSDN博客 面试汇总(五)&#xff1a;操作系统常见面试总结(一)&#xff1a;进程与线程的相关知识点 - 知乎 (zhihu.com) 二、进程的定义、组成、组成方式及特征_进程的组成部分必须包含-CSDN博…

2024年北京事业单位报名照片要求,注意格式

2024年北京事业单位报名照片要求&#xff0c;注意格式

【C语言】预处理常见知识详解(宏详解)

文章目录 1、预定义符号2、define2.1 define 定义常量2.2 define 定义宏 3、#和##3.1 **#**3.2 **##** 4、条件编译&#xff08;开关&#xff09; 1、预定义符号 在C语言中内置了一些预定义符号&#xff0c;可以直接使用&#xff0c;这些符号实在预处理期间处理的&#xff0c;…

工控安全双评合规:等保测评与商用密码共铸新篇章

01.双评合规概述 2017年《中华人民共和国网络安全法》开始正式施行&#xff0c;网络安全等级测评工作也在全国范围内按照相关法律法规和技术标准要求全面落实实施。2020年1月《中华人民共和国密码法》开始正式施行&#xff0c;商用密码应用安全性评估也在有序推广和逐步推进。…

信息安全之网络安全防护

先来看看计算机网络通信面临的威胁&#xff1a; 截获——从网络上窃听他人的通信内容中断——有意中断他人在网络上的通信篡改——故意篡改网络上传送的报文伪造——伪造信息在网络上传送 截获信息的攻击称为被动攻击&#xff0c;而更改信息和拒绝用户使用资源的攻击称为主动…

深入了解高压电阻器的世界,探索其操作、类型和在各种高压应用中的关键作用

高压电阻器是高压条件下的专用元件&#xff0c;对于管理电压和散热至关重要 它们的工作原理是欧姆定律 类型包括线绕电阻、碳复合电阻、金属氧化物膜电阻、厚膜电阻和薄膜电阻这些电阻器在电力系统、医疗设备、汽车电子和电信设备中是必不可少的。 额定电压从600V到48KV 80p…

fastadmin学习04-一键crud

FastAdmin 默认内置一个 test 表&#xff0c;可根据表字段名、字段类型和字段注释通过一键 CRUD 自动生成。 create table fa_test (id int unsigned auto_increment comment ID primary key,user_id int(10) default 0 null…

基础算法-去重字符串,辗转相除法,非递归前序遍历二叉树题型分析

目录 不同子串 辗转相除法-求最大公约数 二叉树非递归前序遍历 不同子串 从a开始&#xff0c;截取 a aa aaa aaab 从第二个下标开始a aa aab 从第三个 a ab 从第四个 b 使用set的唯一性&#xff0c;然后暴力遍历来去去重&#xff0c;从第一个下标开始截取aaab a aa aaa aaab…

代码随想录算法训练营第36天|738.单调递增的数字|968.监控二叉树|总结

代码随想录算法训练营第36天|738.单调递增的数字|968.监控二叉树|总结 738.单调递增的数字 https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html class Solution { public:int monotoneIncreasingDigits(int n) {string s…

R语言批量计算t检验,输出pvalue和均值

1.输入数据如下&#xff1a; 2.代码如下 setwd("E:/R/Rscripts/rG4相关绘图") # 读取CSV文件 data <- read.csv("box-cds-ABD-不同类型rg4-2.csv", stringsAsFactors FALSE)# 筛选出Type2列为指定五种类型的数据 filtered_data <- subset(data, …

【分类评估指标,精确率,召回率,】from sklearn.metrics import classification_report

from&#xff1a; https://zhuanlan.zhihu.com/p/368196647 多分类 from sklearn.metrics import classification_report y_true [0, 1, 2, 2, 2] y_pred [0, 0, 2, 2, 1] target_names [class 0, class 1, class 2] # print(classification_report(y_true, y_pred, targe…

学浪m3u8视频解密

学浪视频在网页上并不是mp4&#xff0c;而是以m3u8进行传输&#xff0c;使用m3u8可以有效解决服务器的压力&#xff0c;而且不仅仅是m3u8&#xff0c;还加密了key&#xff0c;需要逆向key算法得到真实key 下面是学浪m3u8视频解密的工具&#xff0c;全程自动化&#xff0c;不需…

MobileSAM 项目排坑

MobileSAM 项目排坑 任务过程记录创建环境交互式测试notebookV2测试 任务 把MobileSAM这个项目跑通&#xff0c;明天就可以集中学习SAM、MobileSAM、EfficientSAM和Segformer的论文和代码了。 过程记录 创建环境 老样子&#xff1a; git clone https://github.com/Chaonin…

《系统架构设计师教程(第2版)》第8章-系统质量属性与架构评估-01-软件系统质量属性

文章目录 1. 质量属性概念1.1 软件系统质量1.2 软件质量属性概述1.3 各生命周期的质量属性1.2.1 开发期质量属性1.2.2 运行期质量属性 2. 面向架构评估的质量属性2.1 性能(Performance)2.2 可靠性 (Reliability)2.2.1 容错2.2.2 健壮性 2.3 可用性 (Availability)2.4 安全性 (S…

macOS Sonoma如何查看隐藏文件

在使用Git进行项目版本控制时&#xff0c;我们可能会遇到一些隐藏文件&#xff0c;比如.gitkeep文件。它通常出现在Git项目的子目录中&#xff0c;主要作用是确保空目录也可以被跟踪。 终端命令 在尝试查看.gitkeep文件时&#xff0c;使用Terminal命令来显示隐藏文件 default…

c(RGDfK)-Biotin,生物素Biotin标记细胞穿膜环肽c(RGDfk)

c(RGDfK)-Biotin&#xff0c;生物素Biotin标记细胞穿膜环肽c&#xff08;RGDfk&#xff09; 中文名称 &#xff1a;生物素Biotin标记c&#xff08;RGDfk&#xff09;环肽 英 文 名 &#xff1a;c(RGDfK)-Biotin 品 牌 &#xff1a;Tanshtech 单字母&#xff1…

Autodesk Maya 2025---智能建模与动画创新,重塑创意工作流程

Autodesk Maya 2025是一款顶尖的三维动画软件&#xff0c;广泛应用于影视广告、角色动画、电影特技等领域。新版本在功能上进行了全面升级&#xff0c;新增了对Apple芯片的支持&#xff0c;建模、绑定和角色动画等方面的功能也更加出色。 在功能特色方面&#xff0c;Maya 2025…

基于 RisingWave 和 ScyllaDB 构建事件驱动应用

概览 在构建事件驱动应用时&#xff0c;人们面临着两大挑战&#xff1a;1&#xff09;低延迟处理大量数据&#xff1b;2&#xff09;实现流数据的实时摄取和转换。 结合 RisingWave 的流处理功能和 ScyllaDB 的高性能 NoSQL 数据库&#xff0c;可为构建事件驱动应用和数据管道…
最新文章