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

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

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-05-02 07:00:13
已绑定手机

151

主题

589

回帖

1200

积分

金牌会员

积分
1200
发表于 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();

}

回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:217
  • 最近打卡:2024-11-15 09:12:27

29

主题

722

回帖

2790

积分

荣誉版主

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

这是操作系统

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

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


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








回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-05-02 07:00:13
已绑定手机

151

主题

589

回帖

1200

积分

金牌会员

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

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

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

点评

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

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-30 07:46:22

33

主题

1079

回帖

2319

积分

荣誉版主

积分
2319
发表于 2024-2-22 10:25:10 | 显示全部楼层
38009*** 发表于 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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-05-02 07:00:13
已绑定手机

151

主题

589

回帖

1200

积分

金牌会员

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

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-05-02 07:00:13
已绑定手机

151

主题

589

回帖

1200

积分

金牌会员

积分
1200
发表于 2024-2-22 13:50:06 | 显示全部楼层
本帖最后由 380091044 于 2024-2-22 13:51 编辑
tzz1*** 发表于 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
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-30 07:46:22

33

主题

1079

回帖

2319

积分

荣誉版主

积分
2319
发表于 2024-2-22 14:21:06 | 显示全部楼层
本帖最后由 tzz1983 于 2024-2-22 14:46 编辑
38009*** 发表于 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(); //退出临界区
}





回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-04-30 07:46:22

33

主题

1079

回帖

2319

积分

荣誉版主

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

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-05-02 07:00:13
已绑定手机

151

主题

589

回帖

1200

积分

金牌会员

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

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

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-2 08:55 , Processed in 0.130001 second(s), 106 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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