配置 FreeRTOS 计时器滴答持续时间的问题

Problems configuring duration of FreeRTOS timer tick

我决定尝试将 FreeRTOS 与 Arduino Uno (ATmega 328p) 结合使用,并使计时器挂钩的 LED 闪烁。但是,似乎我在 FreeRTOS 中设置了错误的计时器,并且找不到错误。我认为 LED 每 1 秒会变为 on/off(频率为 1 kHz,计数器限制为 1000),但它是 ~14 秒。有什么问题吗?

这是我的 main.c

#include <avr/io.h>
#include "FreeRTOS.h"
#include "task.h"

#define hookTICK_CALLS_BEFORE_POST    ( 1000 )

void vApplicationTickHook( void );

static uint16_t uxCallCounter = 0;
void vApplicationTickHook( void ){
    uxCallCounter++;
    if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST ){
        uxCallCounter = 0;
        PORTD ^= 1 << 2;
    }
}   


int main(void)
{
    DDRD |= 1 << 2;
    /* Replace with your application code */
    vTaskStartScheduler();
    while (1) 
    {
    }
}

这里是FreeRTOSConfig.h

#define configUSE_PREEMPTION        1
#define configUSE_IDLE_HOOK         0
#define configUSE_TICK_HOOK         1
#define configCPU_CLOCK_HZ          ( ( unsigned long ) 8000000 ) /*According to fuses, 0xFF 0xDA 0xFD mean using external oscillator at 16MHz with internal set to 8MHz */
#define configTICK_RATE_HZ          ( (portTickType ) 1000 )
#define configMAX_PRIORITIES        ( 4 )
#define configMINIMAL_STACK_SIZE    ( ( unsigned short ) 85 )
#define configTOTAL_HEAP_SIZE       ( (size_t ) ( 1500 ) )
#define configMAX_TASK_NAME_LEN     ( 8 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS      1
#define configIDLE_SHOULD_YIELD     0
#define configQUEUE_REGISTRY_SIZE   0

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES       0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        0
#define INCLUDE_uxTaskPriorityGet       0
#define INCLUDE_vTaskDelete             1
#define INCLUDE_vTaskCleanUpResources   0
#define INCLUDE_vTaskSuspend            0
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay              1

构建选项 (Atmel studio 7)

-x c -funsigned-char -funsigned-bitfields -I"C:\Program Files (x86)\Atmel\Studio.0\Packs\atmel\ATmega_DFP.6.364\include" -I"../FreeRTOS" -I"../FreeRTOS/Source/include" -I"../FreeRTOS/Source/Portable/Thirdparty/GCC/ATmega"  -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -Wall -mmcu=atmega328p -B "C:\Program Files (x86)\Atmel\Studio.0\Packs\atmel\ATmega_DFP.6.364\gcc\dev\atmega328p" -c -std=gnu99 -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" 

一些 AVR 使用看门狗定时器作为节拍源(参见 atmega328pb 示例),而其他使用 Timer0(参见 atmega323 示例)。这取决于 MCU 是否具有带中断功能的增强型 WDT。 FreeRTOS\Source\portable\ThirdParty\GCC\ATmega\portmacro.h 第 89 行 FreeRTOS\Source\portable\ThirdParty\GCC\ATmega\port.c 第 46 行和 FreeRTOS\Source\portable\ThirdParty\GCC\ATmega\readme.md

中提供了详细信息

如果使用WDT,定时器滴答频率在portmacro.h中配置(默认为15ms,最小周期)并且不受configTICK_RATE_HZ值的影响。要切换到 TIMER0(预配置),只需将字符串 #if defined(WDIE) && defined(WDIF) ... #endif 替换为 #define portUSE_TIMER0 。使用 -DportUSE_TIMER0 -UportUSE_WDTO 作为全局编译器键不起作用。您可以使用其他定时器,请参阅 port.c 等有关如何配置 Timer0 的信息。

当我如上所述切换到 Timer0 并在 FreeRTOSConfig.h

中进行更改时
#define configCPU_CLOCK_HZ          ( ( unsigned long ) 16000000 )
#define configTICK_RATE_HZ          ( ( TickType_t ) 1000 )

并在 main.c 中使 uxCallCounter 可变,我得到了我想要的行为。滴答误差 <5%(#define hookTICK_CALLS_BEFORE_POST ( 50000 ) 滴答周期为 47.9 秒)与外部振荡器文档相匹配。