找回密码
 立即注册
查看: 72|回复: 6

请老师们帮忙解答关于定时器周期性调度任务程序的疑问

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:556
  • 最近打卡:2025-08-10 11:00:24

24

主题

188

回帖

1619

积分

金牌会员

积分
1619
发表于 2025-8-3 10:06:19 | 显示全部楼层 |阅读模式
最近在学习冲哥的“定时器周期性调度任务”程序,可以解决部分非阻塞执行问题。但感觉执行时间有问题,还请冲哥或其他老师有空帮忙解答一下,谢谢!

主要有两个问题:
第一,任务调度程序中的每一个模块执行程序时间不是设定的时间,而且相差很大。


static TASK_COMPONENTS Task_Comps[]=
{
//状态  计数  周期  函数
        {0, 1,   1,   Sample_Display},                /* task 1 Period: 1ms */
        {0, 10,  10,  Sample_MatrixKey},        /* task 2 Period: 10ms */
        {0, 10,  10,  Sample_adcKey},                /* task 3 Period: 10ms */
        {0, 300, 300, Sample_NTC},                        /* task 4 Period: 300ms */
        {0, 500, 500, Sample_RTC},                        /* task 5 Period: 500ms */
        /* Add new task here */
};

比如Sample_RTC模块中设定的是500ms。为观察RTC实时时钟的变化情况,在模块的函数中加入printf_usb打印观察,结果发现时间远大于设定的500ms,也不是(500+500=1S)。

void Sample_RTC(void)
{
    if(++msecond & 1)   //1秒到
    {
        RTC();
        printf_usb("d% %d %d\r\n",usrHour,usrMinute,usrSecond);
    }
   // DisplayRTC();
}

为进一步验证时间准确性,加入灯闪烁程序:
static TASK_COMPONENTS Task_Comps[]=
{
//状态  计数  周期  函数
        {0, 1,   1,   Sample_Display},                /* task 1 Period: 1ms */
        {0, 10,  10,  Sample_MatrixKey},        /* task 2 Period: 10ms */
        {0, 10,  10,  Sample_adcKey},                /* task 3 Period: 10ms */
        {0, 300, 300, Sample_NTC},                        /* task 4 Period: 300ms */
        {0, 500, 500, Sample_RTC},                        /* task 5 Period: 500ms */
        {0, 500, 500, led1_blink},              //P20=!P20
        {0, 1000, 1000, led2_blink},          //P21=!P21
        /* Add new task here */
};
用示波器查看P20/P21时间间隔,差别太大。P20/P21并不是按照设定的500ms/1000ms闪烁(不好意思未截图)

第二,这个RTC时钟模块以什么时钟为节拍进行计时的?在程序中找不到关联的传递参数。既没有设置内/外部晶振,也没有设置RTC相关寄存器,但它确实在走时?!是不是用的定时器0的节拍进行走时的?可是定时器是1ms定时,设置的参数不对呀?在config.h程序中修改:
#define Timer0_Reload   (MAIN_Fosc / 1000)      //Timer 0 中断频率, 1000次/秒。倒是可以改变走时速度,但时间走时不对。看程序他们并没有什么关联。唯一的传递变量msecond也是在局部程序中定义的,这个if(++msecond & 1)   //1秒到。怎么实现1S时间的?
附上官方源程序,请老师们指导!

新建 WinRAR 压缩文件.rar

236.46 KB, 下载次数: 3

回复

使用道具 举报 送花

3

主题

2076

回帖

1000

积分

等待验证会员

积分
1000
发表于 2025-8-3 10:08:00 | 显示全部楼层
针对您提出的关于定时器周期性调度任务程序执行时间不准确的问题,以下为专业分析与解答:

首先,从代码结构来看,您使用的是基于计数器的周期性任务调度机制。该机制通过在定时中断中递增全局计数器,并在主循环中根据各任务的周期进行判断和调用。这种方式在嵌入式系统中较为常见,但其精度依赖于定时器的配置、中断处理效率以及主循环的执行频率。

问题一:任务模块执行时间与设定周期不符

1. 定时器分辨率不足  
   若定时器的中断频率较低(如10ms或更低),则任务调度的最小单位较大,导致任务执行间隔误差累积。例如,若定时器每10ms触发一次中断,而某个任务设定为500ms,则实际执行间隔可能为500ms ± 10ms,这在某些应用中可能已足够,但在高精度需求下则不够。

2. 中断服务程序(ISR)延迟  
   在定时器中断服务程序中,若存在较长的处理逻辑或未及时退出,可能导致后续任务调度延迟。此外,若多个任务同时触发,也可能造成调度顺序混乱。

3. 主循环执行效率  
   主循环中的任务函数若执行时间过长,会导致下一个任务调度被推迟。例如,SampleRTC函数中包含printfusb打印操作,该操作可能涉及串口缓冲区处理,影响整体调度时序。

4. 计数器更新方式  
   您当前的计数器更新方式为在中断中递增全局变量msecond,而在主循环中检查该变量。若中断频繁发生,可能导致msecond值跳跃性增加,进而影响任务调度的准确性。

建议优化方案:
提高定时器分辨率:将定时器设置为更高频率(如1ms),以提升任务调度精度。
优化中断处理逻辑:确保中断服务程序尽可能简短,避免复杂计算或阻塞操作。
采用更精确的计时方式:可考虑使用硬件定时器捕获功能或系统时间戳来记录任务执行时间。
合理安排任务优先级:对于耗时较长的任务,应适当调整其执行频率或拆分处理流程。

问题二:SampleRTC函数执行时间远大于设定周期

1. printfusb打印耗时  
   printfusb函数通常涉及串口发送操作,若未采用缓冲机制,每次调用都会阻塞主循环,导致任务执行时间延长。建议使用异步打印或降低打印频率。

2. RTC函数内部处理  
   RTC()函数可能包含读取实时时钟寄存器、校验数据等操作,若这些操作耗时较长,也会导致整体执行时间增加。

3. 条件判断逻辑  
   if(++msecond & 1) 判断条件可能存在逻辑错误。由于msecond为全局变量,在多任务环境下可能出现竞态条件,导致判断结果不稳定。

建议修改如下:
  1. c
  2. void SampleRTC(void)
  3. {
  4.     static uint32t lasttime = 0;
  5.     uint32t currenttime = msecond;
  6.     if(currenttime - lasttime >= 500)
  7.     {
  8.         lasttime = currenttime;
  9.         RTC();
  10.         printfusb("d% %d %d\r\n",usrHour,usrMinute,usrSecond);
  11.     }
  12. }
复制代码

此方式通过记录上一次执行时间,避免因msecond值跳跃导致的误判。

总结:

您的定时器周期性调度任务程序在实现上基本符合常规设计,但在实际运行中需关注定时器配置、中断处理效率及任务函数执行时间。通过优化上述方面,可有效提升任务调度的准确性和稳定性。如需进一步调试,建议使用示波器或逻辑分析仪观察任务执行时序,以定位具体瓶颈。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:556
  • 最近打卡:2025-08-10 11:00:24

24

主题

188

回帖

1619

积分

金牌会员

积分
1619
发表于 7 天前 | 显示全部楼层
第一个问题已解决。把官方的程序
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
改为:
TH0=(65536-Timer0_Reload)/256;
TL0=(65536-Timer0_Reload)%256;
就正常了

第二个问题还是不明白:RTC计时是以什么时间为节拍计时的?知道是用定时器定时的,但不知道这个变量是怎么传递的?


void Timer0_config(void)//1毫秒@24.000MHz
{
        AUXR |= 0x80;                        //定时器时钟1T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TH0=(65536-Timer_Reload)/256;
        TL0=(65536-Timer_Reload)%256;
        
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}

u8  usrHour,usrMinute,usrSecond; //RTC变量
u8  msecond;
void RTC(void)
{
        if(++usrSecond >= 60)
        {
                usrSecond = 0;
                if(++usrMinute >= 60)
                {
                        usrMinute = 0;
                        if(++usrHour >= 24)
                                usrHour = 0;
                }
        }
}

void Sample_RTC(void)
{
    if(++msecond & 1)   //1秒到
    {
                        printf_usb("Hour=%d,Minute=%d,Second=%d\r\n",usrHour,usrMinute,usrSecond);        
                        RTC();
    }
//    DisplayRTC();
}
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:264
  • 最近打卡:2025-08-11 08:50:56
已绑定手机

78

主题

2838

回帖

5879

积分

荣誉版主

无情的代码机器

积分
5879
发表于 7 天前 | 显示全部楼层

这不是有时钟源选择吗~
截图202508041212163526.jpg

截图202508041212417364.jpg
截图202508041212549476.jpg

三天不学习,赶不上刘少奇~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:487
  • 最近打卡:2025-08-11 08:59:14
已绑定手机

44

主题

2153

回帖

7493

积分

论坛元老

积分
7493
发表于 7 天前 | 显示全部楼层
Sample_RTC是软件模拟RTC,使用定时器0产生节拍判断是否进行调度。
Sample_RTC的设置是500ms执行一次:
{0, 500, 500, Sample_RTC},

if(++msecond & 1)  每次执行的时候 msecond 加1,判断 msecond 的bit0为 1 执行一次 RTC();
这样就会每1秒钟执行一次RTC(); 因为Sample_RTC需要执行2次,msecond =1,3,5,7,9...时才执行RTC();
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:556
  • 最近打卡:2025-08-10 11:00:24

24

主题

188

回帖

1619

积分

金牌会员

积分
1619
发表于 7 天前 | 显示全部楼层
乘风*** 发表于 2025-8-4 15:06
Sample_RTC是软件模拟RTC,使用定时器0产生节拍判断是否进行调度。
Sample_RTC的设置是500ms执行一次:
{0, ...

谢谢乘风大侠的回复!我想搞明白(++msecond)和(++usrSecond)是怎么以定时器0的时间节拍进行自加的。根据乘风大侠的回复,原来是以{0, 500, 500, Sample_RTC}中的(500+500)为节拍进行自加的。

       一般地,自加变量会放在定时器中断里,方便用中断或查询方式进行传递和调用。所以,开始没明白这个程序的时间节拍。这个例程让我们学到一点新东西,再次谢谢乘风大侠!
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:556
  • 最近打卡:2025-08-10 11:00:24

24

主题

188

回帖

1619

积分

金牌会员

积分
1619
发表于 7 天前 | 显示全部楼层
erci*** 发表于 2025-8-4 12:13
这不是有时钟源选择吗~

这个明白。我想弄懂本程序的变量msecond自加的时间节拍。谢谢!
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-8-11 13:18 , Processed in 0.123439 second(s), 90 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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