发新帖本帖赏金 25.00元(功能说明)我要提问
返回列表
打印
[单片机芯片]

CH32V003实现multiTimer软件定时不准原因与解决方案

[复制链接]
1770|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 lilijin1995 于 2022-12-13 13:09 编辑

序:MultiTimer这样一个软件定时器拓展模块真的很方便,但是如果如果任务回调函数中执行了太耗时的任务的话,可能会导致其他任务来不及执行,相关的tick没法实现自加,现在就我们使用过程遇到的一些问题与大家分享一下,由于楼主水平有限,文档和视频中难免有出错和讲得不好的地方,欢迎各位读者和观众善意地提出意见和建议,谢谢!
关于MultiTimer


MultiTimer 是一个软件定时器扩展模块,作者是0x1abin,可无限扩展你所需的定时器任务,取代传统的标志位判断方式, 更优雅更便捷地管理程序的时间触发时序。
功能限制,这里给出MultiTimer GitHub上的开源链接,:
https://github.com/0x1abin/MultiTimer
1.定时器的时钟频率直接影响定时器的精确度,尽可能采用1ms/5ms/10ms这几个精度较高的tick;
2.定时器的回调函数内不应执行耗时操作,否则可能因占用过长的时间,导致其他定时器无法正常超时;
3.由于定时器的回调函数是在 MultiTimerYield 内执行的,需要注意栈空间的使用不能过大,否则可能会导致栈溢出。

诚如以上功能限制中的描述,第一个点要求我们是满足了,在CH32V003中移植了,使用的是Systick配置的1ms作为时钟基准。

由于项目保密性的原因,部分代码删减,但不会影响大家理解的。
首先是配置Systick 1Ms进入中断,产生1ms的tick。
void SysTick_Handler(void) {
    uwTick += 1;
    SysTick->SR = 0;
}

uint64_t PlatformTicksGetFunc(void) {
    return uwTick;
}

/*********************************************************************
* @fn      main
*
* [url=home.php?mod=space&uid=247401]@brief[/url]   Main program.
*
* [url=home.php?mod=space&uid=266161]@return[/url]  none
*/
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("Demo:TM1650 Test!!!\r\n");
    printf("SystemClk:%d\r\n",SystemCoreClock);

    //systick
    NVIC_EnableIRQ(SysTicK_IRQn);
    SysTick->SR &= ~(1 << 0);
    SysTick->CMP = (SystemCoreClock/1000)-1;//1ms
    SysTick->CNT = 0;
    SysTick->CTLR = 0xF;
    PollSystemInit();
    while(1)
    {
        MultiTimerYield();
    }
}

我们创建了一个定时任务,用于执行按键数码管驱动的扫描,这是一个专门的驱动IC方案,使用软件I2C方案,从数码管数据的更新,再加上按键的扫描,其中有多个软件us延迟:
/*******************读按键命令************************/
u8 TM1650_read(void) {
    u8 key;
    IIC_Start();
    IIC_Send_Byte(0x49);   //读按键指令
    IIC_Wait_Ack();
    key = IIC_Read_Byte(0);
    IIC_Wait_Ack();
    IIC_Stop();
    return key;
}

/***显示1-99数据***/
void TM1650Disp2Num(unsigned char snum) {
    Dig1_Data = Digital_Table[snum / 10 % 10];
    Dig2_Data = Digital_Table[snum % 10];
    DigitalScan();
}

这样的话就违反了第二个限制,不能执行太耗时的操作。因为我们在第一个定时器任务里面执行了启动第二个定时器。如下:
void TM1650_Timer1Callback(MultiTimer* timer, void *userData) {

    switch (TM1650ReadKey(0)) {

    case ONOFF_KEY:     //KI6+DIG1    21
    {
        PowerSta = !PowerSta;
        if (PowerSta == PowerON) {
            WorkingTime=15;
            TM1650Disp2Num(WorkingTime);
            MultiTimerStart(&timer2, 1000, Remaining_WorkingPeriodTimer2Callback, NULL);
            break;
        } else {
            Display_0F();
        }
    }
        break;
    default:
        break;
    }
    MultiTimerStart(timer, 50, TM1650_Timer1Callback, userData);
}
在定时器1任务中,按下按键ON开启定时器2任务:
void Remaining_WorkingPeriodTimer2Callback(MultiTimer* timer, void *userData) {


    if (PowerSta == PowerON)
    {
        if(++RunTick1S==60)
        {
            RunTick1S=0;
            if(++RunTick1m==15)
            {
                TM1650Disp2Num(0);
            }else{
                TM1650Disp2Num(WorkingTime-RunTick1m);
            }

        }
        printf("RunTick1S=%d,RunTick1m=%d\r\n",RunTick1S,RunTick1m);
        MultiTimerStart(timer, 60000, Remaining_WorkingPeriodTimer1Callback, userData);
    }
}
在定时2中通过RunTick1S和RunTick1m计算1分钟,这是一个分钟计时器,然后我又想,Systick中断是不会被打断的,我可以1分钟执行一次定时器2的任务,如下:
void Remaining_WorkingPeriodTimer2Callback(MultiTimer* timer, void *userData) {


    if (PowerSta == PowerON)
    {
            if(++RunTick1m==15)
            {
                TM1650Disp2Num(0);
            }else{
                TM1650Disp2Num(WorkingTime-RunTick1m);
            }

        printf("RunTick1S=%d,RunTick1m=%d\r\n",RunTick1S,RunTick1m);
        MultiTimerStart(timer, 60000, Remaining_WorkingPeriodTimer2Callback, userData);
    }
}
现在是1min中进入一次定时器2回调,然后我们实测,2min,离晒大谱了。
最后猜测Systick的中断都不准,后来发现,我们用了HSE,而我们并没有外部晶振,这一切都说得通了


后来配置为HSI,完美,相差无几


总结
这是完全是粗心惹的祸,作为一名工程师,这种错误还是少犯才行,为避免这种错误,我觉得还是需要给自己安排一个软件设计流程,按流程来走,不然以后又出现这种笑掉诸位大牙的事件。






使用特权

评论回复

打赏榜单

21ic小管家 打赏了 25.00 元 2022-12-20
理由:签约作者奖励

沙发
daichaodai| | 2022-12-13 19:24 | 只看该作者
其实就是创建了多个软件定时器

使用特权

评论回复
板凳
witawat| | 2023-11-26 16:29 | 只看该作者
有没有实际可以使用的demo代码?

使用特权

评论回复
发新帖 本帖赏金 25.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

54

主题

162

帖子

7

粉丝