4

我在 PIC32MX 入门套件上为 PIC32 微控制器使用 FreeRTOS 端口。只是在玩任务,但任务不是上下文切换。这是我的主要配置设置:

#define configMAX_PRIORITIES    ( ( unsigned portBASE_TYPE ) 5 )
#define configKERNEL_INTERRUPT_PRIORITY         0x01
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    0x03
#define configTICK_RATE_HZ              ( ( portTickType ) 100 )

现在我定义了两个任务,它们使两个 LED 闪烁。两者的优先级均为 4(最高)。在正常操作下,LED 应每隔 100 个滴答声交替闪烁。但这不会发生。第二个 LED 闪烁 100 次,然后控制转到通用异常处理程序。为什么会这样?好像根本没有安排。

4

5 回答 5

6

FreeRTOS 是一个基于优先级的抢先式调度程序,不产生处理器时间的同等优先级的任务将被轮询调度。依靠轮询调度很少适合实时任务,并且根据配置的时间片,这可能会弄乱你的时间。甚至可以禁用时间片。

您的任务必须进入Blocked状态,等待某个事件(例如经过的时间)以允许彼此按预期运行。

也就是说,进入异常处理程序而不是简单地让一个任务饿死另一个或没有按预期的时间运行是另一回事。为此,您需要发布其他信息,但您的第一种方法应该是部署调试器。

于 2011-02-28T19:57:47.900 回答
5

首先要检查的是你的“滴答”中断。通常没有启用中断,没有正确设置定时器,在设置 PIC32 的#pragma 中没有正确配置时钟。所有这些问题首先表现为缺乏“滴答声”。

这是没有任务切换的#1 原因:如果你没有得到滴答中断。这就是正常的先发制人任务切换发生的地方。

假设您正在使用 MPLAB 中的“现成演示”,请在void vPortIncrementTick( void )函数中设置一个断点(在 FreeRTOS\Source\portable\MPLAB\PIC32MX\port.c 中的第 177 行附近)并运行您的代码。如果它在那里断点,则您的计时器滴答声正在工作。

于 2011-03-15T14:20:35.093 回答
4

您确定这两个任务都已注册好并且调度程序已启动吗?

类似以下代码的东西可以完成这项工作:

xTaskCreate( yourFirstTask, "firstTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
xTaskCreate( yourSecondTask, "secondTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
vTaskStartScheduler();

您还可以添加应用程序滴答挂钩以查看滴答中断是否正确发生或滴答计时器是否存在问题。

于 2011-02-28T16:41:14.690 回答
4

你有循环调度程序吗?您的任务是休眠了任何时间,还是只是让步(或忙于等待)?

嵌入式操作系统中一个非常常见的问题是调度程序经常不会尝试公平地调度具有相同优先级的多个进程。也就是说,一旦 A 屈服,如果 A 是可运行的,即使 B 已经很长时间没有任何 CPU,A 也可以立即再次调度。如果您习惯于桌面操作系统,这是非常违反直觉的,因为桌面操作系统会付出很多努力来进行公平调度(或者至少对我来说是这样)。

如果您遇到这种情况,您需要确保您的任务如下所示:

for (;;)
{
  led(on); sleep(delay);
  led(off); sleep(delay);
}

...以确保任务实际上停止在闪烁之间运行。如果它看起来像这样,它将不起作用:

for (;;)
{
  led(on);
  led(off);
}

(此外,作为一般规则,您希望使用普通优先级而不是高优先级,除非您知道自己真的需要它 --- 如果您让系统任务饿死,系统可能会表现异常或崩溃。)

于 2011-02-28T16:17:34.680 回答
3

在 FreeRTOS/Demo/Common/Minimal/flash.c 源文件中,有一些标准的演示任务只是让 LED 闪烁。在该文件中创建的任务包含在标准 PIC32 演示应用程序(针对 Microchip Explorer16 开发板)中。

以最简单的形式,每 500 毫秒切换一次 LED 的任务如下所示:

/* Standard task prototype, the parameter is not used in this case. */    
void vADummyTask( void *pvParameters )
{
const portTickType xDelayTime = 500 / portTICK_RATE_MS;

    for( ;; )
    {
        ToggleLED();
        vTaskDelay( xDelayTime );
    }        
}
于 2011-03-02T18:56:58.463 回答