首页 > 解决方案 > 如何在 FreeRTOS 中创建第二个计数器

问题描述

我开始在带有 AVR 框架的 ESP32 上使用 FreeRTOS。我需要在调用任务/函数时激活计数器,一旦调用此函数,我的显示模块需要显示第二个计数器。到目前为止,我似乎无法计算秒数。

最初,我使用以下逻辑使其工作:


   unsigned long timeShowedS = 1000;
   unsigned long timeNowS = 0;
   unsigned long timeStartMs= 0;
   while (stpC <= 3600){
       timeNowS = (millis() - timeStartMs) / 1000;
       if (timeNowS != timeShowedS) {
           timeShowedS = timeNowS;
           updateTime(timeShowedS);// function that updates the screen
           delay (20);
           stpC++;
           }

   }

stpC 仅用于测试目的,我计划让它在 while 循环中运行。但是这种方法的问题是我能够计算和显示秒数,但我无法重置计时器。millis() 获取系统自启动以来的时间,因此重置这不是最好的主意。然后我尝试用 FreeRTOS 中的滴答声制作一个软件计时器

       unsigned long xStart, xEnd, xDifference;
       xDifference =0;
       while (1){
         xStart  = xTaskGetTickCount();
         vTaskDelay(pdMS_TO_TICKS(1000UL));
         xEnd  = xTaskGetTickCount();
         xDifference += (xEnd-xStart)/1000; 
         updateTime(xDifference);
        }

如果不调用 updateTime() 函数,计数器就可以工作。但是一旦我调用它没有按预期工作的函数,我的“秒数”就会变慢。我相信这是由于将任务延迟了 1000 个滴答声。

所以我的问题是,我怎样才能创建一个计时器作为我屏幕上的计数器?最后,我希望能够在调用 updateTime() 函数后显示一个计数器,完成后计数器应该被重置并等待下一次迭代。

- - 编辑 - -

所以我设法让它以某种方式工作,但我认为它离最佳解决方案还差得很远。我刚刚创建了两个不同的任务,并且两个任务共享一个全局变量 xDifference(我通常认为这是一个坏主意)。


uint32_t xDifference= 0; 

void taskCounter (void *parameter){

   TickType_t xStart, xEnd;//, xDifference;
   xDifference =0;

 while (1){
   xStart  = xTaskGetTickCount();
   vTaskDelay(pdMS_TO_TICKS(1000UL));
   xEnd  = xTaskGetTickCount();
   xDifference += (xEnd-xStart)/1000; 


 }
 vTaskDelete( NULL );
}

void taskOne( void * parameter )
{
   uint32_t ePapertime= 0;

   while (1){

     if (ePapertime != xDifference ){
     ePapertime = xDifference;
     updateTime(ePapertime);
     delay(20);
    }
   delay(20);
   }

   vTaskDelete( NULL );
  }

标签: timercounteravrfreertosesp32

解决方案


首先,我同意全局变量可能不是您的任务进行通信的方式。您可以查看此页面以获取替代方案。我个人喜欢排队;虽然它们对您的应用程序来说可能是轻微的过度杀伤,但它们运行良好并且开销很小。

关于计时器,我会像这样在你的事件循环中放置一些东西(仅作为示例):

while (true)
{
    stateTickStart = xTaskGetTickCount();
    while (xTaskGetTickCount() - stateTickStart ONE_SECOND)
    {
        // send a queue message.
        // do your other stuff.
        vTaskDelay(INTERVAL_TICKS); // like 20ms or so.
    }
}

您可能需要稍微调整一下逻辑,但这应该可行。在接收任务的事件循环中,您只需在队列中查找一条消息,而无需等待太久。


推荐阅读