找回密码
 立即注册
查看: 355|回复: 8

uCOSII-STC8-V1.06系统的任务A与任务BC之间是如何切换的?谁能看出来,指点一下?

[复制链接]
  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 172 天

    [LV.7]常住居民III

    116

    主题

    475

    回帖

    638

    积分

    高级会员

    积分
    638
    发表于 2024-2-5 09:07:21 | 显示全部楼层 |阅读模式
    uCOSII-STC8-V1.06系统的任务A与任务BC之间是如何切换的?谁能看出来,指点一下?代码如下:


    /******************************************************

    uC/OS-II 移植到STC8H单片机
    uC/OS-II Version  : V2.93.01
    修改版本: V1.03
    修改时间: 2023-08-27
    作者:熊仔
    QQ:   616421684

    ******************************************************/

    #include "config.h"
    #include "os.h"



    #define ET2 0x04
    #define ET3 0x20
    #define ET4 0x40

    // ==== 实时任务函数定义 ============
    void Task_A(void *p_arg) reentrant;
    void Task_B(void *p_arg) reentrant;
    void Task_C(void *p_arg) reentrant;


    #define TASKA_STK_SIZE 64
    #define TASKB_STK_SIZE 64
    #define TASKC_STK_SIZE 64

    // ==== 实时任务堆栈定义 ============
    OS_STK Task_STK_A[TASKA_STK_SIZE];  
    OS_STK Task_STK_B[TASKB_STK_SIZE];
    OS_STK Task_STK_C[TASKC_STK_SIZE];

    long  aa = 123456789 ;   //测试任务传参

    #define  UART1_BAUD  115200
    void UartInit(void)
    {
        SCON = 0x50;        //8位数据,可变波特率
        AUXR |= 0x01;       //串口1选择定时器2为波特率发生器
        AUXR |= 0x04;       //定时器时钟1T模式
        T2L = -((MAIN_Fosc / UART1_BAUD+2) / 4);
        T2H = -((MAIN_Fosc / UART1_BAUD+2) / 4) >> 8;
        AUXR |= 0x10;       //定时器2开始计时
    }



    char putchar(char c)
    {
        SBUF = c;
        while(TI == 0);
        TI = 0;
        return c;
    }



    // ==== 端口初始化 准双向模式 ========
    void PortX_Init(void)
    {
        P0M1 = 0x00;
        P0M0 = 0x00;   //设置为准双向口
        P1M1 = 0x00;
        P1M0 = 0x00;   //设置为准双向口
        P2M1 = 0x00;
        P2M0 = 0x00;   //设置为准双向口
        P3M1 = 0x00;
        P3M0 = 0x00;   //设置为准双向口
        P4M1 = 0x00;
        P4M0 = 0x00;   //设置为准双向口
        P5M1 = 0x00;
        P5M0 = 0x00;   //设置为准双向口
        P6M1 = 0x00;
        P6M0 = 0x00;   //设置为准双向口
        P7M1 = 0x00;
        P7M0 = 0x00;   //设置为准双向口

        P0 = 0xFF;
        P1 = 0xFF;
        P2 = 0xFF;
        P3 = 0xFF;
        P4 = 0xFF;
        P5 = 0xFF;
        P6 = 0xFF;
        P7 = 0xFF;
    }

    void Delay_MS(unsigned int ms) //reentrant  //没必要弄重入函数
    {
        unsigned int i;
        do
        {
            i = MAIN_Fosc / 10000;
            while(--i);
        }
        while(--ms);
    }

    // ---- 定时器1初始化,用于测试 ----------
    #define Timer1_HZ  10000UL        // 10KHz

    void Timer1_Init(void)
    {
        AUXR |= 0x40;   //定时器时钟1T模式
        TMOD &= 0x0F;   //设置定时器模式
        TL1 = -(MAIN_Fosc / Timer1_HZ);
        TH1 = -(MAIN_Fosc / Timer1_HZ) >> 8;
        TF1 = 0;        //清除TF1标志
        TR1 = 1;        //定时器1开始计时
    }

    // ---- 定时器3初始化,用于测试 ----------
    #define Timer3_HZ  10000UL        // 10KHz

    void Timer3_Init(void)
    {
        T4T3M &= 0xF0;     //停止计数, 定时模式, 1T模式, 不输出时钟
        T4T3M |= 0x02;      //定时器时钟1T模式
        T3L = -(MAIN_Fosc / Timer3_HZ);
        T3H = -(MAIN_Fosc / Timer3_HZ) >> 8;
        T4T3M |=  0x08;    //开始运行
    }



    // **** 实时任务 ***************
    // ==== 任务 A ====================
    void Task_A(void *p_arg) reentrant
    {
    //    long  v;
    //    v = *( long*)p_arg;
    //    printf("p_arg=%ld\n",v);
        p_arg = p_arg;

        // ==== 无限循环 ============
        while (1)
        {
            P22 = ~P22;
            OSTimeDly(OS_TICKS_PER_SEC / 2);        // 500毫秒
        }
    }

    // ==== 任务 B ====================
    void Task_B(void *p_arg) reentrant
    {
        int n;
        p_arg = p_arg;

        // ==== 无限循环 ============
        while(1)
        {
            P24 = 1;
            for(n = 0; n < 3; n++)
            {
                //                                P23=1;
                P1 = 0x0F;
                Delay_MS(50);            // 50毫秒
                P1 = 0xF0;
                //                                P23=0;
                Delay_MS(100);            // 100毫秒
            }
            OSTaskResume(4);
            P24 = 0;
    //        OSTimeDly(OS_TICKS_PER_SEC / 100);
            OSTaskSuspend(OS_PRIO_SELF);
        }
    }

    // ==== 任务 C ====================
    void Task_C(void *p_arg) reentrant
    {
        char i, m;
        p_arg = p_arg;

        // ==== 无限循环 ============
        while(1)
        {
            m = 0x04;
            P25 = 1;
            for(i = 0; i < 6; i++)
            {
                P3 = ~m;
                m <<= 1;
                Delay_MS(100);    // 100毫秒
            }
            P25 = 0;
    //        OSTimeDly(OS_TICKS_PER_SEC / 100);
            OSTaskResume(3);
        }
    }


    // **** 单片机程序入口 *********
    void main(void)
    {
        char i;
        EAXSFR();  //使能XSFR访问
        // ==== 端口初始化 准双向模式 ========
        PortX_Init();
    //    UartInit();

        // ==== LOGO ============
        for(i = 0; i < 3; i++)          // LOGO
        {
            P2 = 0x00;
            Delay_MS(50);
            P2 = 0xFF;
            Delay_MS(500);
        }

    //    printf("start\r\n");
        // ==== 定时器1 初始化 ===========
    //    Timer1_Init();
    //    ET1 = 1;

    //    // ==== 定时器3 初始化 ===========
    //    Timer3_Init();
    //    IE2  |=  ET3;         //允许中断



        // ==== uCOS-II RTOS 初始化 ===============
        OSInit();
        //系统滴答定时器初始化
        Timer0_Init();

        // ==== uCOS-II 建立任务 ===============
        OSTaskCreate(Task_A, ( void * )&aa, &Task_STK_A[0], TASKA_STK_SIZE, 2);
        OSTaskCreate(Task_B, (void *)0, &Task_STK_B[0], TASKB_STK_SIZE, 3);
        OSTaskCreate(Task_C, (void *)0, &Task_STK_C[0], TASKC_STK_SIZE, 4);
        // ==== uCOS-II 开始任务调度 不会返回 ==========
        OSStart();

    }

    回复 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-5-5 08:35
  • 签到天数: 143 天

    [LV.7]常住居民III

    29

    主题

    558

    回帖

    2144

    积分

    荣誉版主

    积分
    2144
    发表于 2024-2-5 13:09:38 | 显示全部楼层

    这是操作系统

    宏观上 任务创建完就是  “同时运行”的

    当然 cpu只有一个,同一时刻只能运行一个任务


    按照优先级和任务建立顺序运行(遇到延时就进入堵塞状态,运行下一个任务)








    回复 支持 1 反对 0 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 172 天

    [LV.7]常住居民III

    116

    主题

    475

    回帖

    638

    积分

    高级会员

    积分
    638
     楼主| 发表于 2024-2-5 15:35:17 | 显示全部楼层
    gentleman 发表于 2024-2-5 13:09
    这是操作系统

    宏观上 任务创建完就是  “同时运行”的

    就是没有裸机程序那种明显的逻辑关系,搞的不是太好看,

    点评

    @3800***,RTOS学得怎么样了, 挂起自己这个操作在实际应该用中并不多, 最常用的是OSTimeDly(x); 去了解一下 建议你删除掉例程中三个任务while(1){}中的所有代码. 分别改成这样: while(1) { P02=~P02;  详情 回复 发表于 2024-2-22 10:25
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1201

    积分

    荣誉版主

    积分
    1201
    发表于 2024-2-22 10:25:10 | 显示全部楼层
    380091044 发表于 2024-2-5 15:35
    就是没有裸机程序那种明显的逻辑关系,搞的不是太好看,

    @3800***,RTOS学得怎么样了, 挂起自己这个操作在实际应该用中并不多, 最常用的是OSTimeDly(x); 去了解一下

    建议你删除掉例程中三个任务while(1){}中的所有代码. 分别改成这样:
    while(1)
    {
            P02=~P02;
            OSTimeDly(200); //阻塞延时200个时钟滴答,并立即切换至下一个任务, 200个时钟滴答后重新运行本任务, 理解一下
    }

    while(1)
    {
            P03=~P03;
            OSTimeDly(200);
    }

    while(1)
    {
            P04=~P04;
            OSTimeDly(200);
    }


    这样就可以看到3个LED同时闪烁的效果,表示三个任务在运行,之后自己改代码,玩一些自己喜欢有花样, 有助于理解

    回复 支持 1 反对 0 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 172 天

    [LV.7]常住居民III

    116

    主题

    475

    回帖

    638

    积分

    高级会员

    积分
    638
     楼主| 发表于 2024-2-22 13:13:11 | 显示全部楼层
    tzz1983 发表于 2024-2-22 10:25
    @3800***,RTOS学得怎么样了, 挂起自己这个操作在实际应该用中并不多, 最常用的是OSTimeDly(x); 去了解 ...

    感谢老师指点,感谢STC老师们帮助和支持,给老师汇报一下我进度:我已经采用打狗棒硬件,测试了,明了很多,我也在看一些网上资料,注释源码,任务切换也有了一定的理解了,但是不是很透彻,邮箱和消息队列,这些还没有接触到,
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 172 天

    [LV.7]常住居民III

    116

    主题

    475

    回帖

    638

    积分

    高级会员

    积分
    638
     楼主| 发表于 2024-2-22 13:50:06 | 显示全部楼层
    本帖最后由 380091044 于 2024-2-22 13:51 编辑
    tzz1983 发表于 2024-2-22 10:25
    @3800***,RTOS学得怎么样了, 挂起自己这个操作在实际应该用中并不多, 最常用的是OSTimeDly(x); 去了解 ...

    老师:你看一下这个延时函数,如下:
    void  OSTimeDly (INT32U ticks) large reentrant
    {
        INT8U      y;
    #if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */
        OS_CPU_SR  cpu_sr = 0u;
    #endif



        if (OSIntNesting > 0u) {                     /* See if trying to call from an ISR                  */
            return;
        }
        if (OSLockNesting > 0u) {                    /* See if called with scheduler locked                */
            return;
        }
        if (ticks > 0u) {                            /* 0 means no delay!                                  */
            OS_ENTER_CRITICAL();
            y            =  OSTCBCur->OSTCBY;        /* Delay current task                                 */
            OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
            OS_TRACE_TASK_SUSPENDED(OSTCBCur);
            if (OSRdyTbl[y] == 0u) {
                OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
            }
            OSTCBCur->OSTCBDly = ticks;              /* Load ticks in TCB                                  */
            OS_TRACE_TASK_DLY(ticks);
            OS_EXIT_CRITICAL();
            OS_Sched();                              /* Find next task to run!                             */
        }
    }

    这其中的 OS_Sched();    是切换下一个任务,我看网上资料说,如果当前任务已经是最高级,则退出,那是不是就接着找已就绪的次有优先级任务切换执行?

    OS_Sched();  源码如下:
    void  OS_Sched (void) large reentrant
    {
    #if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
        OS_CPU_SR  cpu_sr = 0u;
    #endif



        OS_ENTER_CRITICAL();
        if (OSIntNesting == 0u) {                          /* Schedule only if all ISRs done and ...       */
            if (OSLockNesting == 0u) {                     /* ... scheduler is not locked                  */
                OS_SchedNew();
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
                if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
    #if OS_TASK_PROFILE_EN > 0u
                    OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
    #endif
                    OSCtxSwCtr++;                          /* Increment context switch counter             */

    #if OS_TASK_CREATE_EXT_EN > 0u
    #if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u)
                    OS_TLS_TaskSw();
    #endif
    #endif
    //                OS_EXIT_CRITICAL();    //需要提前退出临界区再切换任务
                    OS_EXIT_CRITICAL_NOT_INT();
                    OS_TASK_SW();                          /* Perform a context switch                     */
                    return;               //前面已经退出临界区,这里直接返回
                }
            }
        }
        OS_EXIT_CRITICAL();
    }

    点评

    你说的次优先级。。。 是不是有些误解了, 如果当前任务调用了 OSTimeDly (),则当前任务进入阻塞,已经不再是最高优先级, 这种情况下,切换的目标绝对不会指向自己  详情 回复 发表于 2024-2-22 15:11
    if (OSPrioHighRdy != OSPrioCur) 这一句就是你说的那个判断了, 如果当前任务的优先级不是最高优先级,才做任务切换, 否则不需要做切换,(自己切换到自己,没必要,所以不切换了, 直接退出)  详情 回复 发表于 2024-2-22 14:21
    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1201

    积分

    荣誉版主

    积分
    1201
    发表于 2024-2-22 14:21:06 | 显示全部楼层
    本帖最后由 tzz1983 于 2024-2-22 14:46 编辑
    380091044 发表于 2024-2-22 13:50
    老师:你看一下这个延时函数,如下:
    void  OSTimeDly (INT32U ticks) large reentrant
    {

    if (OSPrioHighRdy != OSPrioCur)  这一句就是你说的那个判断了, 如果当前任务的优先级不是最高优先级,才做任务切换, 否则不需要做切换,(自己切换到自己,没必要,所以不切换了, 直接退出)

    自己是最高优先级的, 那就退出切换函数,接着运行自己, 没有必要找次优先级, UCOS里没有这种说法, 只关心最高优先级, 等高优先级阻塞了,次优先级就自动成为最高优先级了

    下面是OS_Sched 函数我添加的注释

    void  OS_Sched (void)
    {
    #if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */
        OS_CPU_SR  cpu_sr = 0u;
    #endif

        OS_ENTER_CRITICAL();            //进临界区
        if (OSIntNesting == 0u) {                          /* 确保当前不是中断例程       */
            if (OSLockNesting == 0u) {                     /* 如果调度器没有被锁定                 */
                OS_SchedNew();          //查找可运行的最高优先级任务
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; //可运行的最高任务优先级
                if (OSPrioHighRdy != OSPrioCur) {          /* 如果当前任务不是最高优先级任务     */
    #if OS_TASK_PROFILE_EN > 0u
                    OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
    #endif
                    OSCtxSwCtr++;                          /* 切换计数加1             */

    #if OS_TASK_CREATE_EXT_EN > 0u
    #if defined(OS_TLS_TBL_SIZE) && (OS_TLS_TBL_SIZE > 0u)
                    OS_TLS_TaskSw();
    #endif
    #endif

                    OS_TASK_SW();                          /* 任务切换宏                     */
                }
            }
        }
        OS_EXIT_CRITICAL(); //退出临界区
    }





    回复 支持 反对 送花

    使用道具 举报

    该用户从未签到

    20

    主题

    576

    回帖

    1201

    积分

    荣誉版主

    积分
    1201
    发表于 2024-2-22 15:11:22 | 显示全部楼层
    380091044 发表于 2024-2-22 13:50
    老师:你看一下这个延时函数,如下:
    void  OSTimeDly (INT32U ticks) large reentrant
    {

    你说的次优先级。。。 是不是有些误解了, 如果当前任务调用了 OSTimeDly (),则当前任务进入阻塞,已经不再是最高优先级, 这种情况下,切换的目标绝对不会指向自己
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 172 天

    [LV.7]常住居民III

    116

    主题

    475

    回帖

    638

    积分

    高级会员

    积分
    638
     楼主| 发表于 2024-2-22 17:14:49 | 显示全部楼层
    tzz1983 发表于 2024-2-22 15:11
    你说的次优先级。。。 是不是有些误解了, 如果当前任务调用了 OSTimeDly (),则当前任务进入阻塞,已 ...

    老师:我被误导了,你说的我茅塞顿开,是这样的,
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-5-21 09:48 , Processed in 0.075058 second(s), 65 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表