您的位置:首页 > 其它

使用SysTick的普通计数模式对延迟进行管理

2014-05-03 22:48 686 查看
/*************delay.h*************************/

#ifndef __DELAY_H

#define __DELAY_H

#include <stm32f10x_map.h>

//////////////////////////////////////////////////////////////////////////////////

//ALIENTEK STM32开发板

//使用SysTick的普通计数模式对延迟进行管理

//包括delay_us,delay_ms

//正点原子@ALIENTEK

//技术论坛:www.openedv.com

//修改日期:2012/9/2

//版本:V1.5

//版权所有,盗版必究。

//Copyright(C) 广州市星翼电子科技有限公司 2009-2019

//All rights reserved

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

//V1.2修改说明

//修正了中断中调用出现死循环的错误

//防止延时不准确,采用do while结构!

//V1.3修改说明

//增加了对UCOSII延时的支持.

//如果使用ucosII,delay_init会自动设置SYSTICK的值,使之与ucos的TICKS_PER_SEC对应.

//delay_ms和delay_us也进行了针对ucos的改造.

//delay_us可以在ucos下使用,而且准确度很高,更重要的是没有占用额外的定时器.

//delay_ms在ucos下,可以当成OSTimeDly来用,在未启动ucos时,它采用delay_us实现,从而准确延时

//可以用来初始化外设,在启动了ucos之后delay_ms根据延时的长短,选择OSTimeDly实现或者delay_us实现.

//V1.4修改说明 20110929

//修改了使用ucos,但是ucos未启动的时候,delay_ms中中断无法响应的bug.

//V1.5修改说明 20120902

//在delay_us加入ucos上锁,防止由于ucos打断delay_us的执行,可能导致的延时不准。

//////////////////////////////////////////////////////////////////////////////////

void delay_init(u8 SYSCLK);

void delay_ms(u16 nms);

void delay_us(u32 nus);

#endif

/*************delay.c******************/

#include "delay.h"

#include "sys.h"

//////////////////////////////////////////////////////////////////////////////////

//如果使用ucos,则包括下面的头文件即可.

#if SYSTEM_SUPPORT_UCOS

#include "includes.h" //ucos 使用

#endif

//////////////////////////////////////////////////////////////////////////////////

//本程序只供学习使用,未经作者许可,不得用于其它任何用途

//ALIENTEK STM32开发板

//使用SysTick的普通计数模式对延迟进行管理

//包括delay_us,delay_ms

//正点原子@ALIENTEK

//技术论坛:www.openedv.com

//修改日期:2012/9/2

//版本:V1.5

//版权所有,盗版必究。

//Copyright(C) 广州市星翼电子科技有限公司 2009-2019

//All rights reserved

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

//V1.2修改说明

//修正了中断中调用出现死循环的错误

//防止延时不准确,采用do while结构!

//V1.3修改说明

//增加了对UCOSII延时的支持.

//如果使用ucosII,delay_init会自动设置SYSTICK的值,使之与ucos的TICKS_PER_SEC对应.

//delay_ms和delay_us也进行了针对ucos的改造.

//delay_us可以在ucos下使用,而且准确度很高,更重要的是没有占用额外的定时器.

//delay_ms在ucos下,可以当成OSTimeDly来用,在未启动ucos时,它采用delay_us实现,从而准确延时

//可以用来初始化外设,在启动了ucos之后delay_ms根据延时的长短,选择OSTimeDly实现或者delay_us实现.

//V1.4修改说明 20110929

//修改了使用ucos,但是ucos未启动的时候,delay_ms中中断无法响应的bug.

//V1.5修改说明 20120902

//在delay_us加入ucos上锁,防止由于ucos打断delay_us的执行,可能导致的延时不准。

//////////////////////////////////////////////////////////////////////////////////

static u8 fac_us=0;//us延时倍乘数

static u16 fac_ms=0;//ms延时倍乘数,在ucos下,代表每个节拍的ms数

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

//systick中断服务函数,使用ucos时用到

void SysTick_Handler(void)

{

OSIntEnter();
//进入中断

OSTimeTick(); //调用ucos的时钟服务程序

OSIntExit(); //触发任务切换软中断

}

#endif

//初始化延迟函数

//当使用ucos的时候,此函数会初始化ucos的时钟节拍

//SYSTICK的时钟固定为HCLK时钟的1/8

//SYSCLK:系统时钟

void delay_init(u8 SYSCLK)

{

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

u32 reload;

#endif

SysTick->CTRL&=~(1<<2);//SYSTICK使用外部时钟源

fac_us=SYSCLK/8;//不论是否使用ucos,fac_us都需要使用

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

reload=SYSCLK/8;//每秒钟的计数次数 单位为K

reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出时间

//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右

fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延时的最少单位

SysTick->CTRL|=1<<1;
//开启SYSTICK中断

SysTick->LOAD=reload;
//每1/OS_TICKS_PER_SEC秒中断一次

SysTick->CTRL|=1<<0;
//开启SYSTICK

#else

fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数

#endif

}

#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.

//延时nus

//nus为要延时的us数.

void delay_us(u32 nus)

{

u32 ticks;

u32 told,tnow,tcnt=0;

u32 reload=SysTick->LOAD;//LOAD的值

ticks=nus*fac_us;
//需要的节拍数

tcnt=0;

OSSchedLock();//阻止ucos调度,防止打断us延时

told=SysTick->VAL; //刚进入时的计数器值

while(1)

{

tnow=SysTick->VAL;

if(tnow!=told)

{

if(tnow<told)tcnt+=told-tnow;//这里注意一下SYSTICK是一个递减的计数器就可以了.

else tcnt+=reload-tnow+told;

told=tnow;

if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.

}

};

OSSchedUnlock();//开启ucos调度

}

//延时nms

//nms:要延时的ms数

void delay_ms(u16 nms)

{

if(OSRunning==TRUE)//如果os已经在跑了

{

if(nms>=fac_ms)//延时的时间大于ucos的最少时间周期

{

OSTimeDly(nms/fac_ms);//ucos延时

}

nms%=fac_ms;
//ucos已经无法提供这么小的延时了,采用普通方式延时

}

delay_us((u32)(nms*1000));//普通方式延时

}

#else//不用ucos时

//延时nus

//nus为要延时的us数.

void delay_us(u32 nus)

{

u32 temp;

SysTick->LOAD=nus*fac_us; //时间加载

SysTick->VAL=0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

//延时nms

//注意nms的范围

//SysTick->LOAD为24位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK单位为Hz,nms单位为ms

//对72M条件下,nms<=1864

void delay_ms(u16 nms)

{

u32 temp;

SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)

SysTick->VAL =0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

#endif

/*****************主程序 test.c**************/

#include "sys.h"

#include "usart.h"

#include "delay.h"

#include "led.h"

#include "includes.h"

//ALIENTEK战舰STM32开发板实验53

//UCOSII实验1-任务调度

//技术支持:www.openedv.com

//广州市星翼电子科技有限公司

/////////////////////////UCOSII任务设置///////////////////////////////////

//START 任务

//设置任务优先级

#define START_TASK_PRIO 10 //开始任务的优先级设置为最低

//设置任务堆栈大小

#define START_STK_SIZE 64

//任务堆栈

OS_STK START_TASK_STK[START_STK_SIZE];

//任务函数

void start_task(void *pdata);

//LED0任务

//设置任务优先级

#define LED0_TASK_PRIO 7

//设置任务堆栈大小

#define LED0_STK_SIZE 64

//任务堆栈

OS_STK LED0_TASK_STK[LED0_STK_SIZE];

//任务函数

void led0_task(void *pdata);

//LED1任务

//设置任务优先级

#define LED1_TASK_PRIO 6

//设置任务堆栈大小

#define LED1_STK_SIZE 64

//任务堆栈

OS_STK LED1_TASK_STK[LED1_STK_SIZE];

//任务函数

void led1_task(void *pdata);

int main(void)

{

Stm32_Clock_Init(9); //系统时钟设置

delay_init(72); //延时初始化

LED_Init();

LED_Init();
//初始化与LED连接的硬件接口

OSInit();

OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务

OSStart();

}

//开始任务

void start_task(void *pdata)

{

OS_CPU_SR cpu_sr=0;

pdata = pdata;

OS_ENTER_CRITICAL();//进入临界区(无法被中断打断)

OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);

OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);

OSTaskSuspend(START_TASK_PRIO);//挂起起始任务.

OS_EXIT_CRITICAL();//退出临界区(可以被中断打断)

}

//LED0任务

void led0_task(void *pdata)

{

while(1)

{

LED0=0;

delay_ms(50);

LED0=1;

delay_ms(50);

};

}

//LED1任务

void led1_task(void *pdata)

{

while(1)

{

LED1=0;

delay_ms(300);

LED1=1;

delay_ms(300);

};

}

/*********相关讲解*************/

第五章 SYSTEM 文件夹介绍

上一章,我们介绍了如何在 MDK3.80A 下建立 STM32 工程,在这个新建的工程之中,我

们用到了一个 SYSTEM 文件夹里面的代码,此文件夹里面的代码由 ALIENTEK 提供,是

STM32F103 系列的底层核心驱动函数,可以用在 STM32F103 系列的各个型号上面,方便大家

快速构建自己的工程。

SYSTEM 文件夹下包含了 delay、 sys、 usart 等三个文件夹。分别包含了 delay.c、 sys.c、 usart.c

及其头文件。通过这 3 个 c 文件,可以快速的给任何一款 STM32 构建最基本的框架。使用起来

是很方便的。

本章,我们将向大家介绍这些代码,通过这章的学习,大家将了解到这些代码的由来,也

希望大家可以灵活使用 SYSTEM 文件夹提供的函数,来快速构建工程,并实际应用到自己的项

目中去。

本章包括如下 3 个小结:

5.1,delay 文件夹代码介绍;

5.2,sys 文件夹代码介绍;

5.3,usart 文件夹代码介绍;

5.1 delay 文件夹代码介绍

delay 文件夹内包含了 delay.c 和 delay.h 两个文件,这两个文件用来实现系统的延时功能,

其中包含 3 个函数(这里我们不讲 SysTick_Handler 函数,该函数在讲 ucos 的时候再介绍) :

void delay_init(u8 SYSCLK);

void delay_ms(u16 nms);

void delay_us(u32 nus);

下面分别介绍这三个函数,在介绍之前,我们先了解一下编程思想:CM3 内核的处理器,

内部包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从

RELOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能

位清除,就永不停息。SysTick 在《STM32 的参考手册》(这里是指 V10.0 版本,下同)里面介

绍的很简单,其详细介绍,请参阅《Cortex-M3 权威指南》第 133 页。我们就是利用 STM32 的

内部 SysTick 来实现延时的,这样既不占用中断,也不占用系统定时器。

这里我们将介绍的是 ALIENTEK 提供的最新版本的延时函数,该版本的延时函数支持在

ucos 下面使用,它可以和 ucos 共用 systick 定时器。首先我们简单介绍下 ucos 的时钟:ucos 运

行需要一个系统时钟节拍(类似 “心跳”),而这个节拍是固定的(由 OS_TICKS_PER_SEC 设

置),比如 5ms(设置:OS_TICKS_PER_SEC=200 即可),在 STM32 下面,一般是由 systick

来提供这个节拍,也就是 systick 要设置为 5ms 中断一次,为 ucos 提供时钟节拍,而且这个时

钟一般是不能被打断的(否则就不准了)。

因为在 ucos 下 systick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者

delay_ms 的延时,就必须想点办法了,这里我们利用的是时钟摘取法。以 delay_us 为例,比如

delay_us (50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里

为 50*9 (假设系统时钟为 72Mhz,那么 systick 每增加 1,就是 1/9us) ,然后我们就一直统计 systick

的计数变化,直到这个值变化了 50*9,一旦检测到变化达到或者超过这个值,就说明延时 50us

时间到了。

下面我们开始介绍这几个函数。

ALIENTEK 战舰STM32开发板 www.openedv.com

79

5.1.1 delay_init 函数

该函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外

部时钟,如果使用了 ucos,那么还会根据 OS_TICKS_PER_SEC 的配置情况,来配置 SysTick

的中断时间,并开启 SysTick 中断。具体代码如下:

//初始化延迟函数

//当使用 ucos 的时候,此函数会初始化 ucos 的时钟节拍

//SYSTICK 的时钟固定为 HCLK 时钟的 1/8

//SYSCLK:系统时钟

void delay_init(u8 SYSCLK)

{

#ifdef OS_CRITICAL_METHOD //如果 OS_CRITICAL_METHOD 定义了, 则使用了 ucosII.

u32 reload;

#endif

SysTick->CTRL&=~(1<<2); //SYSTICK 使用外部时钟源

fac_us=SYSCLK/8; //不论是否使用 ucos,fac_us 都需要使用

#ifdef OS_CRITICAL_METHOD//如果 OS_CRITICAL_METHOD 定义了,则使用了 ucosII.

reload=SYSCLK/8; //每秒钟的计数次数 单位为 K

reload*=1000000/OS_TICKS_PER_SEC;//根据 OS_TICKS_PER_SEC 设定溢出时间

//reload 为 24 位寄存器,最大值:16777216,在 72M 下,约合 1.86s 左右

fac_ms=1000/OS_TICKS_PER_SEC;//代表 ucos 可以延时的最少单位

SysTick->CTRL|=1<<1; //开启 SYSTICK 中断

SysTick->LOAD=reload; //每 1/OS_TICKS_PER_SEC 秒中断一次

SysTick->CTRL|=1<<0; //开启 SYSTICK

#else

fac_ms=(u16)fac_us*1000; //非 ucos 下,代表每个 ms 需要的 systick 时钟数

#endif

}

可以看到,delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 ucos

的时候,就和《不完全手册》介绍的方法是一样的,而如果使用 ucos 的时候,则会进行一些不

同的配置,这里的条件编译是根据 OS_CRITICAL_METHOD 这个宏来确定的,因为只要使用

了 ucos,就一定会定义 OS_CRITICAL_METHOD 这个宏。

SysTick 是 MDK 定义了的一个结构体(在 stm32f10x_map.h 里面),里面包含 CTRL、 LOAD、

VAL、CALIB 等 4 个寄存器,

SysTick->CTRL 的各位定义如图 5.1.1.1 所示:


SysTick-> CALIB 不常用,在这里我们也用不到,故不介绍了。

SysTick->CTRL&=0xfffffffb;这一句把 SysTick 的时钟选择外部时钟,这里需要注意的是:

SysTick 的时钟源自 HCLK 的 8 分频,假设我们外部晶振为 8M,然后倍频到 72M,那么 SysTick

的时钟即为 9Mhz,也就是 SysTick 的计数器 VAL 每减 1,就代表时间过了 1/9us。

在不使用 ucos 的时候:fac_us,为 us 延时的基数,也就是延时 1us,SysTick->LOAD 所应

设置的值。 fac_ms 为 ms 延时的基数,也就是延时 1ms, SysTick->LOAD 所应设置的值。 fac_us

为 8 位整形数据, fac_ms 为 16 位整形数据。 Systick 的时钟来自系统时钟 8 分频, 正因为如此,

系统时钟如果不是 8 的倍数(不能被 8 整除),则会导致延时函数不准确,这也是我们推荐外部

时钟选择 8M 的原因。这点大家要特别留意。

当使用 ucos 的时候, fac_us,还是 us 延时的基数,不过这个值不会被写到 SysTick->LOAD

寄存器来实现延时,而是通过时钟摘取的办法实现的(后面会介绍)。而 fac_ms 则代表 ucos 自

带的延时函数所能实现的最小延时时间(如 OS_TICKS_PER_SEC=200,那么 fac_ms 就是 5ms)。

5.1.2 delay_us 函数

该函数用来延时指定的 us,其参数 nus 为要延时的微秒数。该函数有使用 ucos 和不使用

ucos 两个版本,这里我们分别介绍,首先是不使用 ucos 的时候,实现函数如下:

//延时 nus

//nus 为要延时的 us 数.

void delay_us(u32 nus)

{

ALIENTEK 战舰STM32开发板 www.openedv.com

81

u32 temp;

SysTick->LOAD=nus*fac_us; //时间加载

SysTick->VAL=0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

有了上面对 SysTick 寄存器的描述,这段代码不难理解。其实就是先把要延时的 us 数换算

成 SysTick 的时钟数,然后写入 LOAD 寄存器。然后清空当前寄存器 VAL 的内容,再开启倒数

功能。等到倒数结束,即延时了 nus。最后关闭 SysTick,清空 VAL 的值。实现一次延时 nus

的操作,但是这里要注意 nus 的值,不能太大,必须保证 nus<=(2^24)/fac_us,否则将导致

延时时间不准确。这里特别说明一下:temp&0x01,这一句是用来判断 systick 定时器是否还处

于开启状态,可以防止 systick 被意外关闭导致的死循环。

再来看看使用 ucos 的时候,delay_us 的实现函数如下:

//延时 nus

//nus 为要延时的 us 数.

void delay_us(u32 nus)

{

u32 ticks;

u32 told,tnow,tcnt=0;

u32 reload=SysTick->LOAD; //LOAD 的值

ticks=nus*fac_us; //需要的节拍数

tcnt=0;

OSSchedLock(); //阻止 ucos 调度,防止打断 us 延时

told=SysTick->VAL; //刚进入时的计数器值

while(1)

{

tnow=SysTick->VAL;

if(tnow!=told)

{

if(tnow<told)tcnt+=told-tnow;//这里注意:SYSTICK 是一个递减的计数器就.

else tcnt+=reload-tnow+told;

told=tnow;

if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.

}

};

OSSchedUnlock(); //开启 ucos 调度

}

ALIENTEK 战舰STM32开发板 www.openedv.com

82

这里就正是利用了我们前面提到的时钟摘取法,ticks 是延时 nus 需要等待的 SysTick 计数

次数(也就是延时时间),told 用于记录最近一次的 SysTick->VAL 值,然后 tnow 则是当前的

SysTick->VAL 值,通过他们的对比累加,实现 SysTick 计数次数的统计,统计值存放在 tcnt 里

面,然后哦通过对比 tcnt 和 ticks,来判断延时是否到达,从而达到不修改 SysTick 实现 nus 的

延时,从而可以和 ucos 共用一个 SysTick。

上面的 OSSchedLock 和 OSSchedUnlock 是 ucos 提供的两个函数,用于调度上锁和解锁,

这里为了防止 ucos 在 delay_us 的时候打断延时,可能导致的延时不准,所以我们利用这两个函

数来实现免打断,从而保证延时精度!同时,此时的 delay_us,可以实现最长 2^32us 的延时,

大概是 4294 秒。

5.1.3 delay_ms 函数

该函数用来延时指定的 ms,其参数 nms 为要延时的微秒数。该函数同样有使用 ucos 和不

使用 ucos 两个版本,这里我们分别介绍,首先是不使用 ucos 的时候,实现函数如下:

//延时 nms

//注意 nms 的范围

//SysTick->LOAD 为 24 位寄存器,所以,最大延时为:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK 单位为 Hz,nms 单位为 ms

//对 72M 条件下,nms<=1864

void delay_ms(u16 nms)

{

u32 temp;

SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD 为 24bit)

SysTick->VAL =0x00; //清空计数器

SysTick->CTRL=0x01 ; //开始倒数

do

{

temp=SysTick->CTRL;

}

while((temp&0x01)&&!(temp&(1<<16)));//等待时间到达

SysTick->CTRL=0x00; //关闭计数器

SysTick->VAL =0X00; //清空计数器

}

此部分代码和 5.1.2 节的 delay_us(非 ucos 版本)大致一样,但是要注意因为 LOAD 仅仅

是一个 24bit 的寄存器,延时的 ms 数不能太长。否则超出了 LOAD 的范围,高位会被舍去,导

致延时不准。最大延迟 ms 数可以通过公式:nms<=0xffffff*8*1000/SYSCLK 计算。SYSCLK

单位为 Hz,nms 的单位为 ms。如果时钟为 72M,那么 nms 的最大值为 1864ms。超过这个值,

建议通过多次调用 delay_ms 实现,否则就会导致延时不准确。

再来看看使用 ucos 的时候,delay_ms 的实现函数如下:

//延时 nms

//nms:要延时的 ms 数

void delay_ms(u16 nms)

ALIENTEK 战舰STM32开发板 www.openedv.com

83

{

if(OSRunning==TRUE)//如果 os 已经在跑了

{

if(nms>=fac_ms)//延时的时间大于 ucos 的最少时间周期

{

OSTimeDly(nms/fac_ms);//ucos 延时

}

nms%=fac_ms;//ucos 已经无法提供这么小的延时了,采用普通方式延时

}

delay_us((u32)(nms*1000)); //普通方式延时

}

该函数中,OSRunning 是 ucos 正在运行的一个标志,OSTimeDly 是 ucos 提供的一个基于

ucos 时钟节拍的延时函数,其参数代表延时的时钟节拍数(假设 OS_TICKS_PER_SEC=200,

那么 OSTimeDly(1),就代表延时 5ms)。

当 ucos 还未运行的时候,我们的 delay_ms 就是直接由 delay_us 实现的, ucos 下的 delay_us

可以实现很长的延时而不溢出! ,所以放心的使用 delay_us 来实现 delay_ms,不过由于 delay_us

的时候,任务调度被上锁了,所以还是建议不要用 delay_us 来延时很长的时间,否则影响整个

系统的性能。

当 ucos 运行的时候,我们的 delay_ms 函数将先判断延时时长是否大于等于 1 个 ucos 时钟

节拍 (fac_ms) ,当大于这个值的时候,我们就通过调用 ucos 的延时函数来实现 (此时任务可以

调度) ,不足 1 个时钟节拍的时候,直接调用 delay_us 函数实现(此时任务无法调度) 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: