FreeRTOS在TM4C单片机上的移植:任务的创建、挂起与恢复

准备工作

在上一篇文章里, 我们已经通过空白工程配置好了系统框架. 这一篇文章我们将在框架的基础上实现按键控制LED灯闪烁功能
FreeRTOS在Keil里的简单配置, 可以参考这一篇文章: 使用Keil内置工具一键为工程安装FreeRTOS

注意事项

  • 在本例程中, 没有用到软件定时器, 所以我们在配置工程时, 不要选择Timers选项, 可如图配置:
    在这里插入图片描述
    将FreeRTOSConfig.h中configUSE_TIMERS参数设为0, 避免任务无法正常运行的情况.
  • 为了正常运行程序, 空白工程需包含串行输出的初始化, 在TM4C单片机中, 特别的, 是UART0.

亮灯原理

系统运行了两个任务, 分别是Task1和Task2, 其中, Task1执行时间为1000个机器周期, 而Task2为100个. Task1中, 始终执行亮灯语句, 即

GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,GPIO_PIN_1);
printf("task1 working\n");
vTaskDelay(1000);

而Task2为:

GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1,0);
printf("task2 working\n");
vTaskDelay(100);

将Task1的任务优先级设置成高于Task2的任务优先级. 由于Task1执行时间为Task2的10倍, 故在10份时间内, 将会有1份时间执行优先级高的Task1的命令即亮灯, 而其余时间LED灯则会被Task2控制熄灭.
其实如果将两者优先级设置成一样的, 也能够观察到相同时间间隔的亮灯现象, 说明在同优先级下, 先声明的函数具有更高的支配权?(还没研究明白FreeRTOS的任务调度机制)

按键原理

按下按键1, 调用vTaskSuspend函数, 将亮灯任务挂起.
按下按键2, 调用vTaskResume函数, 将亮灯任务恢复.

特别的, TM4C的按键初始化代码如下:

void Key_Init()
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  //  Unlock PF0 so we can change it to a GPIO input
  //  Once we have enabled (unlocked) the commit register then re-lock it
  //  to prevent further changes.  PF0 is muxed with NMI thus a special case.
  HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
  HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
  HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
  GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_DIR_MODE_IN); // SW1
  GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
  GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN); // SW2
  GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
}

代码

#include "tiva_sys.h"
#include "freeRTOS.h"
#include "task.h"
int fputc(int ch, FILE *f)
{
    UARTCharPut(UART0_BASE, ch);
    return (ch);
} //重新映射printf函数
int fgetc(FILE *f)
{
    int ch = UARTCharGet(UART0_BASE);
    return (ch);
}
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务堆栈
StackType_t StartTaskStack[START_STK_SIZE];
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define TASK1_TASK_PRIO 2
//任务堆栈大小
#define TASK1_STK_SIZE 128
//任务堆栈
StackType_t Task1TaskStack[TASK1_STK_SIZE];
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);

//任务优先级
#define TASK2_TASK_PRIO 3
//任务堆栈大小
#define TASK2_STK_SIZE 128
//任务堆栈
TaskHandle_t Task2Task_Handler;
//任务函数
void task2_task(void *pvParameters);
//任务优先级
#define TASK3_TASK_PRIO 1
//任务堆栈大小
#define TASK3_STK_SIZE 128
//任务堆栈
TaskHandle_t Task3Task_Handler;
//任务函数
void task3_task(void *pvParameters);

void ConfigureUART0(void) //串口0初始化
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); //使能GPIO外设
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); //使能UART外设
    GPIOPinConfigure(GPIO_PA0_U0RX);             // GPIO模式配置 PA0--RX PA1--TX
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // GPIO的UART模式配置
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    UARTStdioConfig(0, 115200, 16000000);
    // UART协议配置 波特率115200 8位 1停止位  无校验位
    printf("Init uart0");
}

int main(void)
{
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_16MHZ); //设置系统时钟为80MHz
    Led_init();
    Key_Init();
    ConfigureUART0();
    xTaskCreate((TaskFunction_t)start_task,      //任务函数
                (const char *)"start_task",      //任务名称
                (uint16_t)START_STK_SIZE,        //任务堆栈大小
                (void *)NULL,                    //传递给任务函数的参数
                (UBaseType_t)START_TASK_PRIO,    //任务优先级
                (TaskHandle_t *)StartTaskStack); //任务堆栈
    vTaskStartScheduler();                       //开启任务调度
}
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL(); //进入临界区
    //创建 TASK1 任务
    xTaskCreate((TaskFunction_t)task1_task,
                (const char *)"task1_task",
                (uint16_t)TASK1_STK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK1_TASK_PRIO,
                (TaskHandle_t *)&Task1Task_Handler);
    //创建 TASK2 任务
    xTaskCreate((TaskFunction_t)task2_task,
                (const char *)"task2_task",
                (uint16_t)TASK2_STK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK2_TASK_PRIO,
                (TaskHandle_t *)&Task2Task_Handler);
    xTaskCreate((TaskFunction_t)task3_task,
                (const char *)"task3_task",
                (uint16_t)TASK3_STK_SIZE,
                (void *)NULL,
                (UBaseType_t)TASK3_TASK_PRIO,
                (TaskHandle_t *)&Task3Task_Handler);
    vTaskDelete(StartTask_Handler); //删除开始任务 (2)
    taskEXIT_CRITICAL();            //退出临界区
}
void task1_task(void *pvParameters)
{
    while (1)
    {
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
        printf("task1 working\n");
        vTaskDelay(1000);
    }
}

void task2_task(void *pvParameters)
{
    while (1)
    {
        GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0);
        printf("task2 working\n");
        vTaskDelay(100);
    }
}

void task3_task(void *pvParameters)
{
    bool print_flag1 = 0, print_flag2 = 0;
    while (1)
    {
        if (TactKey1 == 0 && print_flag1 == 0)
        {
            vTaskDelay(10);
            if (TactKey1 == 0 && print_flag1 == 0)
            {
                print_flag2 = 0;
                printf("suspending task 1\n\n");
                print_flag1 = 1;
                vTaskSuspend(Task1Task_Handler);
            }
        }
        if (TactKey2 == 0 && print_flag2 == 0)
        {
            print_flag1 = 0;
            printf("resuming task 1\n\n");
            print_flag2 = 1;
            vTaskResume(Task1Task_Handler);
        }
    }
}

工程文件在此

  1. FreeRTOS_Blinky(点灯)
  2. 完整项目
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值