freeRTOS在atmega32A上不能正常工作。

问题描述 投票:1回答:1

我是Free RTOS的新手,我按照一些教程一行一行地做,但事情没有总结正确,我用free RTOS来切换3个LEDs,但它只点亮了其中的2个,没有切换!随机的2个LED,无论我改变优先级或切换的延迟时间,随机的2个LED只是打开,没有更多的东西,我在proteus模拟和真实的硬件上尝试了代码,同样的问题存在,谁能帮我解决这个问题?

MC:ATMEGA32A

实时操作系统:FreeRTOS

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
/* FreeRTOS files. */
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
#include "FreeRTOSConfig.h"


/* Define all the tasks */
static void ledBlinkingtask1(void* pvParameters);
static void ledBlinkingtask2(void* pvParameters);
static void ledBlinkingtask3(void* pvParameters);

int main(void) {

    /* Call FreeRTOS APIs to create tasks, all tasks has the same priority "1" with the
    same stack size*/
    xTaskCreate( ledBlinkingtask1,"LED1",
    configMINIMAL_STACK_SIZE, NULL, 1, NULL );
    xTaskCreate( ledBlinkingtask2,"LED2",
    configMINIMAL_STACK_SIZE, NULL,1, NULL );
    xTaskCreate( ledBlinkingtask3,"LED3",
    configMINIMAL_STACK_SIZE, NULL,1, NULL );

    // Start the RTOS kernel
    vTaskStartScheduler();
    /* Do nothing here and just run infinte loop */
    while(1){};
    return 0;
}

static void ledBlinkingtask1(void* pvParameters){
    /* Define all variables related to ledBlinkingtask1*/
    const uint8_t blinkDelay = 100 ;
    /* make PB0 work as output*/
    DDRB |= (1<<0); //PB0
    /* Start the infinte task 1 loop */
    while (1)
    {
        PORTB ^= (1<<0); //toggle PB0 //PB0
        vTaskDelay(blinkDelay); //wait some time
    }
}

static void ledBlinkingtask2(void* pvParameters){
    /* Define all variables related to ledBlinkingtask2*/
    const uint8_t blinkDelay = 100;
    /* make PB1 work as output*/
    DDRB |= (1<<1);//PB0
    /* Start the infinte task 2 loop */
    while (1)
    {
        PORTB ^= (1<<1); //toggle PB0 //PB0
        vTaskDelay(blinkDelay); //wait some time
    }
}




static void ledBlinkingtask3(void* pvParameters){
    /* Define all variables related to ledBlinkingtask3*/
    const uint16_t blinkDelay = 100;
    /* make PB2 work as output*/
    DDRB |= (1<<2); //PB2
    /* Start the infinte task 3 loop */
    while (1)
    {
        PORTB ^= (1<<2); //toggle PB0 //PB0
        vTaskDelay(blinkDelay); //wait some time
    }
}

ps:每个任务都能单独工作,但不能一起工作!

c atmega freertos rtos
1个回答
0
投票

正如评论中已经提到的那样--主要问题似乎是访问驱动LEDs的端口寄存器既不

PORTB ^= (1<<0); // in task 1
[...]
PORTB ^= (1<<1); // in task 2
[...]
PORTB ^= (1<<2); // in task 3
  1. 原子
  2. 保护(通过在访问过程中禁用中断,或通过RTOS措施,如mutex)。
  3. 部署到一个独特的任务上。

每次使用C代码中的一条指令访问HW寄存器可能会引起误解.不过,这并没有什么帮助,因为编译器会生成几条汇编器指令(例如,将以前的端口值加载到寄存器,修改该寄存器值,将其写回端口)。这样一来,一个任务可以中断另一个任务 在这些汇编器CPU指令之间 几个任务依次向 port 写回 "他们 "的寄存器值,可能会使其他任务刚刚写到 port 的值恢复原样,因此您会错过一个(或几个)闪烁事件。

因此,解决的办法是互相保护分配.按照上面的编号顺序,这可能意味着以下任何一种情况。

  1. 检查硬件是否提供了 "设定值 "或 "重置值 "的寄存器,就在主寄存器旁边。PORTB 端口寄存器。如果是这样,那么向该端口写入一个位就会成为一个 原子 的方式来进行LED的切换。很抱歉,我不知道Atmega的硬件接口。也许,这是不可能的,你必须直接进入2.和3.
  2. a. 在改变端口寄存器之前禁用中断,之后重新启用。这样,任务调度器就不会在那段时间(=关键部分)运行,没有人打扰访问硬件的任务。

    b. 使用 taskENTER_CRITICAL()taskEXIT_CRITICAL()c. 使用mutex或类似的方法。

  3. 创建第四个任务,它在邮箱队列中等待(阻塞).每当它收到一个来自邮箱的值时,它就会对其进行处理(例如,通过对端口寄存器进行XOR-ing).现有的三个任务本身并不访问LED端口寄存器,而是将这样的值(=请求消息)发送给新的任务.给新的任务分配一个较高的优先级,以获得一个平滑的闪烁模式。

如果选项1.在你的控制器上是可行的,那么它是最快的(但它需要硬件平台的某些功能...)。否则,我同意@Richard的提示,选项2.b.是最快的(2.a.同样快,但不是那么干净,因为你打破了FreeRTOS库的分层)。

选项2.c.可能会引入一个显著的开销,而选项3.是非常干净的,但在你的情况下是完全矫枉过正的。如果你的问题只是关于LED灯的闪烁 请把推土机留在车库里,选择方案2.

© www.soinside.com 2019 - 2024. All rights reserved.