查看: 4504|回复: 4

[原创] 【LPC54114】LPC5411x_FreeRTOS学习笔记

[复制链接]

该用户从未签到

16

主题

107

帖子

2

中级会员

Rank: 3Rank: 3

积分
365
最后登录
2022-12-14
发表于 2017-5-8 12:20:09 | 显示全部楼层 |阅读模式
LPC5411x_FreeRTOS学习笔记
文档编号
TN_TEMPLATE0101_A0
关键字
FreeRTOS, MCU, Embedded System,
摘要
本技术笔记对LPC5411x_FreeRTOS学习笔记进行说明


Mars4zhu
目 录
插图索引
表格索引
错误!未找到目录项。
1 总述
FreeRTOS是广泛使用的RTOS之一。LPC5411x系列MCU的LPCOpen以及SDK软件代码库提供了FreeRTOS的例程,本学习笔记采用截至目前(2017-05-07)最新版(LPCOpen_V3.01, SDK_V2.2)的代码、学习采用FreeRTOS开发LPC5411x系列MCU的应用。
LPC5411x的官方代码LPCOpen和SDK都FreeRTOS的范例代码,其中LPCOpen只是简单的一个Blinky例程。
SDK则提供了更多的范例,位于SDK_2.2_LPC54114J256\boards\lpcxpresso54114\rtos_examples目录下。
2 LPCOpen的FreeRTOS范例学习
使用相应的开发工具打开\lpc5411x_xpresso54114\lpc5411x\prj_xpresso54114\iar\examples_freertos.eww(或keil\freertos_blinky.uvprojx等其他工具的工程项目文件),
该例程创建两个分别按照不同的周期执行的LED亮灭的任务,和一个UART输出tickCnt计数值。
/* LED1 toggle thread */
static void vLEDTask1(void *pvParameters) {
bool LedState = false;
while (1) {
Board_LED_Set(0, LedState);
LedState = (bool) !LedState;
/* About a 3Hz on/off toggle rate */
vTaskDelay(configTICK_RATE_HZ / 6);
}
}
/* LED2 toggle thread */
static void vLEDTask2(void *pvParameters) {
bool LedState = false;
while (1) {
Board_LED_Set(1, LedState);
LedState = (bool) !LedState;
/* About a 7Hz on/off toggle rate */
vTaskDelay(configTICK_RATE_HZ / 14);
}
}
/* UART (or output) thread */
static void vUARTTask(void *pvParameters) {
int tickCnt = 0;
while (1) {
DEBUGOUT("Tick: %d \r\n", tickCnt);
tickCnt++;
/* About a 1s delay here */
vTaskDelay(configTICK_RATE_HZ);
}
}
完成编译后下载调试,点击运行即可看到两个LED在来回闪同时串口输出Tick计数信息。
21  LPC5411x_LPCOpen_freertos_blinky例程编译下载调试运行效果图
3 SDK_LPC5411x的FreeRTOS范例学习3.1 freertos_hello范例学习
SDK提供的freertos_hello是最简单的freertos程序,该程序创建一个执行函数为hello_task的任务,该执行函数向串口输出”Hello world.”字符串之后即挂起,之后任务调度器无限循环调度FreeRTOS的idle_task空闲任务。
/*!
* @brief Task responsible for printing of "Hello world." message.
*/
static void hello_task(void *pvParameters)
{
for (;;)
{
        PRINTF("Hello world.\r\n");
        vTaskSuspend(NULL);
}
}
完成编译后下载调试,点击运行即可串口输出”Hello world.”信息。
31  LPC5411x_SDK_freertos_hello例程编译下载调试运行效果图
3.2 Freertos_event范例学习
EventGroup事件组合消息提供比队列消息Queue、信号量消息Semaphore、更灵活的任务通讯机制,多个消息一起组合成一个组合消息等特点。
本例程跟FreeRTOS官方的source-code-for-book-examples有关EventGroup的例程类似。
首先创建一个事件组合消息event_group,然后创建三个任务,两个写入组合消息,一个读取该组合消息。
    event_group = xEventGroupCreate();
    xTaskCreate(write_task_1, "WRITE_TASK_1", configMINIMAL_STACK_SIZE + 38, NULL,tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(write_task_2, "WRITE_TASK_2", configMINIMAL_STACK_SIZE + 38, NULL,tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(read_task, "READ_TASK", configMINIMAL_STACK_SIZE + 38, NULL, tskIDLE_PRIORITY + 2,NULL);ranho
然后两个写任务分别独立设置event_group组合消息的B0和B1两个位,同时读任务读取event_group组合消息,并判断哪个bit位”1”,输出相关判断信息。
/*!
* @brief write_task_1 function
*/
static void write_task_1(void *pvParameters)
{
while (1)
{
        xEventGroupSetBits(event_group, B0);
}
}
/*!
* @brief write_task_2 function
*/
static void write_task_2(void *pvParameters)
{
while (1)
{
        xEventGroupSetBits(event_group, B1);
}
}
/*!
* @brief read_task function
*/
static void read_task(void *pvParameters)
{
    EventBits_t event_bits;
while (1)
{
        event_bits = xEventGroupWaitBits(event_group, /* The event group handle. */
                                         B0 | B1, /* The bit pattern the event group is waiting for. */
                                         pdTRUE, /* BIT_0 and BIT_4 will be cleared automatically. */
                                         pdFALSE, /* Don't wait for both bits, either bit unblock task. */
                                         portMAX_DELAY); /* Block indefinitely to wait for the condition to be met. */
if ((event_bits & (B0 | B1)) == (B0 | B1))
{
            PRINTF("Both bits are set.");
}
else if ((event_bits & B0) == B0)
{
            PRINTF("Bit B0 is set.\r\n");
}
else if ((event_bits & B1) == B1)
{
            PRINTF("Bit B1 is set.\r\n");
}
}
}
完成编译后下载调试,点击运行即可串口输出相关信息。
其中在IAR中可以在Options->Debugs->Plugins中选中FreeRTOS and OpenRTOS选项,这样在调试中就可以通过这个插件查看FreeRTOS中的任务Task、队列Queue等系统组件的信息。如下图:
32  IAR选中FreeRTOS and OpenRTOS选项
33  LPC5411x_SDK_freertos_event例程编译下载调试运行效果图
3.3 freertos_mutex范例学习
Mutex互斥量信息同一时刻只允许一个任务访问某个资源,防止资源乱序访问。
首先创建一个互斥信号量xMutex,然后创建两个任务,通过xMutex来互斥执行,即如果一个任务获得xMutex后,另一个任务必须等待它释放才能得以执行。
    xMutex = xSemaphoreCreateMutex();
    xTaskCreate(write_task_1, "WRITE_TASK_1", configMINIMAL_STACK_SIZE + 128, NULL,tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(write_task_2, "WRITE_TASK_2", configMINIMAL_STACK_SIZE + 128, NULL,tskIDLE_PRIORITY + 1, NULL);
然后两个任务各自的执行函数分别是先获取互斥量xMutex,获得后才可以执行后续程序,执行完毕后释放。
/*!
* @brief Write Task 1 function
*/
static void write_task_1(void *pvParameters)
{
while (1)
{
        xSemaphoreTake(xMutex, portMAX_DELAY);
        PRINTF("ABCD |");
        taskYIELD();
        PRINTF(" EFGH\r\n");
        xSemaphoreGive(xMutex);
        taskYIELD();
}
}
/*!
* @brief Write Task 2 function
*/
static void write_task_2(void *pvParameters)
{
while (1)
{
        xSemaphoreTake(xMutex, portMAX_DELAY);
        PRINTF("1234 |");
        taskYIELD();
        PRINTF(" 5678\r\n");
        xSemaphoreGive(xMutex);
        taskYIELD();
}
}

完成编译后下载调试,点击运行即可串口输出相关信息。
34  LPC5411x_SDK_freertos_mutex例程编译下载调试运行效果图
如果注释掉xMutex的获取和释放之后,则任务执行乱序,输出的字符串就有了混杂。
35  LPC5411x_SDK_freertos_mutex例程取消互斥量的运行效果图
3.4 freertos_queue范例学习
队列消息是任务间通讯常用的方式,通过一个个消息发送到队列中,则接受消息的任务可以获取该队列,并且顺序与发送顺序一样。实现任务间通讯。
首先创建一个队列,并提供添加到队列的函数log_add()。
/*!
* @brief log_init function
*/
void log_init(uint32_t queue_length, uint32_t max_log_lenght)
{
    log_queue = xQueueCreate(queue_length, max_log_lenght);
    xTaskCreate(log_task, "log_task", configMINIMAL_STACK_SIZE + 166, NULL, tskIDLE_PRIORITY + 1,NULL);
}
/*!
* @brief log_add function
*/
void log_add(char *log)
{
    xQueueSend(log_queue, log, 0);
}
然后创建两个任务write_task_1和write_task_2,分别向队列中发送消息。
/*!
* @brief write_task_1 function
*/
static void write_task_1(void *pvParameters)
{
char log[MAX_LOG_LENGTH + 1];
uint32_t i = 0;
for (i = 0; i < 5; i++)
{
        sprintf(log, "Task1 Message %d", (int)i);
        log_add(log);
        taskYIELD();
}
    vTaskSuspend(NULL);
}
/*!
* @brief write_task_2 function
*/
static void write_task_2(void *pvParameters)
{
char log[MAX_LOG_LENGTH + 1];
uint32_t i = 0;
for (i = 0; i < 5; i++)
{
        sprintf(log, "Task2 Message %d", (int)i);
        log_add(log);
        taskYIELD();
}
    vTaskSuspend(NULL);
}
最后创建一个消息接受任务log_task,不断从队列中读取消息并显示。
/*!
* @brief log_print_task function
*/
static void log_task(void *pvParameters)
{
uint32_t counter = 0;
char log[MAX_LOG_LENGTH + 1];
while (1)
{
        xQueueReceive(log_queue, log, portMAX_DELAY);
        PRINTF("Log %d: %s\r\n", counter, log);
        counter++;
}
}
完成编译后下载调试,点击运行即可串口输出相关信息。
36  LPC5411x_SDK_freertos_queue例程的运行效果图
3.5 freertos_sem范例学习
Semaphore信号量消息作为最简单的任务间通讯,通过给任务发送一个信号后,该任务执行该信号量相应的程序。
首先创建一个producer_task任务和三个consumer_task任务,然后创建两个信号量,xSemaphore_producer和xSemaphore_consumer。
i
}
完成编译后下载调试,点击运行即可串口输出相关信息。
37  LPC5411x_SDK_freertos_sem例程量的运行效果图
3.6 freertos_swtimer范例学习
Software_Timer软件定时器是FreeRTOS提供的一个定时服务,通过xTimerCreate()创建一个定时器,并设置回调函数SwTimerCallback(),执行定时循环程序。
int main(void)
{
    TimerHandle_t SwTimerHandle = NULL;
/*
for (;;)
;
}
/*!
* @brief Software timer callback.
*/
static void SwTimerCallback(TimerHandle_t xTimer)
{
    PRINTF("Tick.\r\n");
}
完成编译后下载调试,点击运行即可串口输出相关信息。同时可见Software_Timer定时服务运行在独立的TmrSvc任务中。
38  LPC5411x_SDK_freertos_swtimer例程量的运行效果图
3.7 freertos_tickless
Tickless实现了FreeRTOS对低功耗的需求,通过关闭tick,停止了整个FreeRTOS的调度,只通过外部中断来实现唤醒。
程序首先注册了RTC中断和EXT外部按键中断的回调函数,分别为pint_intr_callback()和BOARD_RTC_IRQ_HANDLER()。
pint_intr_callback提供信号量xSWSemaphore给SW_task,然后调度器调度执行SW_task,执行结束后进入Idle_Task,在里面调用__WFI()进入设定好的低功耗模式。
/*!
* @brief Call back for PINT Pin interrupt 0-7.
*/
void pint_intr_callback(pint_pin_int_t pintr, uint32_t pmatch_status)
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
/* Clear external interrupt flag. */
    PINT_PinInterruptClrFallFlag(PINT, kPINT_PinInt0);
    xSemaphoreGiveFromISR(xSWSemaphore, &xHigherPriorityTaskWoken);
}
BOARD_RTC_IRQ_HANDLER()则调用vPortRtcIsr(),该函数设置ulLPTimerInterruptFired=true,该条件触发FreeRTOS重新滴答Tick一次并调度。
/*!
* @brief Interrupt service fuction of UTICK timer.
*
* This function to call vPortUtickIsr
*/
void BOARD_RTC_IRQ_HANDLER(void)
{
    vPortRtcIsr();
}
void vPortRtcIsr(void)
{
  ulLPTimerInterruptFired = true;
  RTC_ClearStatusFlags(RTC, kRTC_WakeupFlag);
}
最后完成编译后下载调试,点击运行即可看到串口输出各类信息。并且IAR中显示对FreeRTOS系统内部Task、Queue等信息。
(注:其中对于万利电子的LPC54114开发板,需要注意led、key的引脚定义,可以修改代码中的配置,不修改的话,SW3为Manley_LPC54114开发板上的JP3.)
39  LPC5411x_SDK_freertos_tickless例程编译下载调试运行效果图
3.8 freertos_generic范例学习
Freertos_generic例程提供了对FreeRTOS的Task、Queue、Semaphore、Timer等多种系统服务组件的综合使用示范。
3.8.1 消息队列与任务管理
该例程通过创建一个xQueue队列消息,来实现队列消息通讯机制。
/* Create the queue used by the queue send and queue receive tasks. */
    xQueue = xQueueCreate(/* The number of items the queue can hold. */
                          mainQUEUE_LENGTH,
/* The size of each item the queue holds. */
sizeof(uint32_t));
同时创建两个Task,一个Task循环延时后发送队列,另一个Task则持续监听队列,收到队列消息后则打印累计收到的队列消息数量。
/
3.8.2 信号量消息管理
创建一个信号量xEventSemaphore。
/* Create the semaphore used by the FreeRTOS tick hook function and the
    event semaphore task. */
    vSemaphoreCreateBinary(xEventSemaphore);
并在vApplicationTickHook函数中发送信号量,该函数每次系统的滴答tick中都调用一次。
/*!
* @brief tick hook is executed every tick.
*/
void vApplicationTickHook(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
static uint32_t ulCount = 0;
/* The RTOS tick hook function is enabled by setting configUSE_TICK_HOOK to
    1 in FreeRTOSConfig.h.
    "Give" the semaphore on every 500th tick interrupt. */
    ulCount++;
if (ulCount >= 500UL)
{
/* This function is called from an interrupt context (the RTOS tick
        interrupt),    so only ISR safe API functions can be used (those that end
        in "FromISR()".
        xHigherPriorityTaskWoken was initialised to pdFALSE, and will be set to
        pdTRUE by xSemaphoreGiveFromISR() if giving the semaphore unblocked a
        task that has equal or higher priority than the interrupted task. */
        xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken);
        ulCount = 0UL;
}
/* If xHigherPriorityTaskWoken is pdTRUE then a context switch should
    normally be performed before leaving the interrupt (because during the
    execution of the interrupt a task of equal or higher priority than the
    running task was unblocked).  The syntax required to context switch from
    an interrupt is port dependent, so check the documentation of the port you
    are using.
    In this case, the function is running in the context of the tick interrupt,
    which will automatically check for the higher priority task to run anyway,
    so no further action is required. */
}
最后创建一个接受信号量的任务,该任务持续监听信号量,并输出信息。
/*!
* @brief task prvEventSemaphoreTask is waiting for semaphore.
*/
static void prvEventSemaphoreTask(void *pvParameters)
{
for (;;)
{
/* Block until the semaphore is 'given'. */
        xSemaphoreTake(xEventSemaphore, portMAX_DELAY);
/* Count the number of times the semaphore is received. */
        ulCountOfReceivedSemaphores++;
        PRINTF("Event task is running.\r\n");
}
}
3.8.3 定时器管理
创建一个xExampleSoftwareTimer的定时器,周期为mainSOFTWARE_TIMER_PERIOD_MS,定时器触发时调用vExampleTimerCallback()函数。
/
最后完成编译后下载调试,点击运行即可看到串口输出各类信息。并且IAR中显示对FreeRTOS系统内部Task、Queue等信息。
310  LPC5411x_SDK_freertos_generic例程编译下载调试运行效果图
4 LPC5411x_FreeRTOS+外设驱动例程学习4.1 freertos_i2c
TODO
4.2 freertos_spi
TODO
4.3 freertos_usart
FreeRTOS与USART驱动的集成采用了NXP(原Freescale软件开发部门,被NXP收购,但是代码依然保留fsl等前缀)提供的一套类似框架的代码。
USART在FreeRTOS的驱动主要是fsl_usart_freertos.h/fsl_usart_freertos.c,提供了usart_rtos_handle_t和rtos_usart_config等结构体,以及USART_RTOS_Init(), USART_RTOS_Deinit(), USART_RTOS_SendI(), USART_RTOS_Receive()等函数,采用了FreeRTOS的系统服务组件如Semaphore、Queue、EventGroup等,作为USART的读/写/中断等的消息传递机制。
/*! @brief FLEX USART FreeRTOS handle */
t
在ISR中断服务例程中调用回调函数USART_RTOS_Callback,通过设置rxEvent/txEvent的各个标志位,通知应用程序底层硬件的相关状态变化。

最后完成编译后下载调试,点击运行即可看到串口输出各类信息。并且IAR中显示对FreeRTOS系统内部Task、Queue等信息。
41  LPC5411x_SDK_freertos_usart例程编译下载调试运行效果图
5 版本历史(Revision History)
版本号
发布时间
内容
A0
2017-05-08
初次编写


首发CSDN: http://blog.csdn.net/zhu210/article/details/71405073
版权所有: mars4zhu

LPC5411x_FreeRTOS学习笔记.pdf (2.13 MB, 下载次数: 43)
回复

使用道具 举报

该用户从未签到

16

主题

107

帖子

2

中级会员

Rank: 3Rank: 3

积分
365
最后登录
2022-12-14
 楼主| 发表于 2017-5-8 12:21:06 | 显示全部楼层
帖子发帖字数最多50000字节,我的有83000字节以上,删掉了许多,

而且格式也变了许多,原版pdf整洁清楚,

请下载pdf查看。
回复 支持 反对

使用道具 举报

  • TA的每日心情
    开心
    2017-1-24 09:50
  • 签到天数: 2 天

    [LV.1]初来乍到

    654

    主题

    3262

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    11067
    最后登录
    2019-1-27
    发表于 2017-5-8 13:07:26 | 显示全部楼层
    支持下
    回复

    使用道具 举报

  • TA的每日心情

    2017-1-4 08:05
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    85

    主题

    1629

    帖子

    1

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    2569

    优秀版主

    最后登录
    2019-3-28
    发表于 2017-5-8 17:21:37 | 显示全部楼层
    楼主辛苦
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2023-9-15 08:42
  • 签到天数: 1952 天

    [LV.Master]伴坛终老

    1

    主题

    4686

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    9405
    最后登录
    2023-9-15
    发表于 2017-5-9 07:09:25 | 显示全部楼层
    谢谢分享!
    今天天气不错!签到!
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-27 06:29 , Processed in 0.127869 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表