分享一个在单片机中使用的RTOS代码框架

本文介绍了在单片机开发中使用FreeRTOS进行任务管理的经验,强调了良好代码框架的重要性。作者通过创建接收、处理和发送消息的线程,以及管理其他功能的线程,展示了如何构建高效、低耦合的代码结构。文章详细阐述了CAN中断接收消息、消息处理线程以及消息发送线程的实现,利用消息队列进行线程间的通信和同步,确保了系统的实时性和稳定性。
摘要由CSDN通过智能技术生成

最近在进行一个项目的开发和调试,使用的是单片机 + freeRTOS进行开发,通过一段时间的码代码和调试,各个方面都已经调通,功能也顺利的实现,也在挂机测试了。

在这次开发中,也是遇到了很多的问题,主要的感想是关于代码的框架。在单片机开发中,特别是使用了RTOS的时候,一个良好的代码框架真的是相当的必要的。

如果一开始没有仔细的考虑好该怎么搭载一个代码框架,写代码时想写什么就写什么,有什么功能要加找个地方就随便插入进入,当代码量大的时候就会看起来很乱。甚至将来接手代码的人,估计内心一万个CNM从心中飞过,时刻游走在崩溃的边缘,即使是想改点什么功能也不知道从哪里开始着手,估计会烦躁到喜提地中海!!!

本文就想分享一个我个人使用的单片机+freeRTOS的代码框架,框架涉及到消息接收、消息处理、消息发送、其他动作的处理。下面一步步说明代码框架的搭建过程。

1、创建任务

当开始一个项目代码的编写之前,都要考虑这份代码要实现一些什么样的功能,并将要实现的功能进行分类,根据功能的各自属性可以归纳出几个Module,然后想想在代码中哪些功能要放在一块,哪些功能要区分开等等的细节问题。

并且还需要考虑代码的耦合性,好的代码是要能够做到高内聚低耦合的,各个功能模块之间能够独立区分开,需要产生联系的功能代码,要通过某些通信手段实现(共享内存、信号量、消息队列等等),不要互相拉扯,像你中有我,我中有你这种情况要尽可能的避免。

比如,我手上的项目通过功能归类划分,就可以分为接收消息、处理消息、发送消息、其他功能处理,由此便可以考虑划分出4个线程去处理。

但是,考虑到项目中使用的是CAN通信的方式,接收消息就可以考虑使用CAN接收中断的方式,能够做到及时的响应接收消息,所以这个时候只需要3个线程即可。并且消息的接收使用队列的方式接收,方便管理消息和进行线程之间的同步。消息的发送也采用先压入队列再发送的方式。

freeRTOS中创建3个线程如下:

#define OTHER_HANDLE_TASK_PRIO         2
#define OTHER_HANDLE_STK_SIZE          256 
TaskHandle_t OtherHandleTask_Handler;#define CAN_HANDLE_MSG_TASK_PRIO     3 
#define CAN_HANDLE_MSG_STK_SIZE      256  
TaskHandle_t Can_HandleMsgTask_Handler;#define CAN_SEND_MSG_TASK_PRIO         2
#define CAN_SEND_MSG_STK_SIZE          256  
TaskHandle_t Can_SendMsgTask_Handler;
​
​
    // 其他功能的管理线程
    xTaskCreate((TaskFunction_t )OtherHandle_Task,
                (const char *   )"OtherHandle_Task",
                (uint16_t       )OTHER_HANDLE_STK_SIZE,
                (void *         )NULL,
                (UBaseType_t    )OTHER_HANDLE_TASK_PRIO,
                (TaskHandle_t * )&OtherHandleTask_Handler);
​
​
    // 接收消息的处理线程
   xTaskCreate((TaskFunction_t )Can_HandleMsg_Task,
               (const char *   )"Can_HandleMsg_Task",
               (uint16_t       )CAN_HANDLE_MSG_STK_SIZE,
               (void *         )NULL,
               (UBaseType_t    )CAN_HANDLE_MSG_TASK_PRIO,
               (TaskHandle_t * )&Can_HandleMsgTask_Handler);
    
    // 发送消息的处理线程
   xTaskCreate((TaskFunction_t )Can_SendMsg_Task,
               (const char *   )"Can_SendMsg_Task",
               (uint16_t       )CAN_SEND_MSG_STK_SIZE,
               (void *         )NULL,
               (UBaseType_t    )CAN_SEND_MSG_TASK_PRIO,
               (TaskHandle_t * )&Can_SendMsgTask_Handler);

消息接收队列、消息发送队列的创建,如下:

// 消息接收队列
QueueHandle_t CanRxQueue;
CanRxQueue = xQueueCreate(xxxxxx, xxxxxx);
​
​
// 消息发送队列
QueueHandle_t CanTxQueue;
CanTxQueue = xQueueCreate(xxxxxx, xxxxxx);

2、CAN中断接收消息 & 消息处理线程

2.1、CAN中断接收消息

如下:

void CAN1_RX0_IRQHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken;
    
    /* 其他代码 */
    
    xResult = xQueueSendFromISR(CanRxQueue, &ptwCanRxMsg, &xHigherPriorityTaskWoken);
​
​
    portYIELD_FROM_ISR (xHigherPriorityTaskWoken);
}

注意:接收很多时候不一定要使用中断的方式,用查询的方式也是可以的,只是在RTOS中,查询接收的话,要考虑消息接收是否及时,接收消息的线程优先级要比较高,否则容易造成处理的动作的延迟。

2.2、消息的处理线程

消息处理的线程任务函数如下:

void Can_HandleMsg_Task(void *pvParameters)
{
    while (1)
    {
        xQueueReceive(CanRxQueue, xxxxxx, portMAX_DELAY);
        /*
            处理部分
        */
     }
}

消息处理中使用了消息队列的阻塞的特性,在队列为空的时候阻塞挂起线程,可以减少CPU调度线程的压力;当消息队列不为空的时候,队列不再阻塞,线程从挂起中恢复,参与调度并处理任务。

注意:在freeRTOS中可以用于阻塞的还有信号量、事件标志组、消息邮箱。

3、消息的发送线程

消息的发送如下:

void Can_SendMsg_Task(void *pvParameters)
{
    while (1)
    {
        xQueueReceive(CanTxQueue, xxxxxx, portMAX_DELAY);
        /*
            处理部分
        */
     }
}

消息的发送中也使用了消息队列,需要发送的消息可以先压入队列,然后由发送线程去发送。同样使用队列的阻塞特性,在队列为空的时候阻塞挂起发送线程,减少CPU调度线程的压力;当发送消息的队列不为空的时候,队列不再阻塞,线程从挂起中恢复,参与调度并将消息发送出去。

4、其他功能的处理线程

void OtherHandle_Task(void *pvParameters)
{
    while (1)
    {
          /*
            处理部分
          */
     }
}

其他功能的处理就放在其他任务线程中处理,比如GUI显示、按键扫描、和传感器通信等等的。具体需要几个线程管理需要根据实际的项目情况进行安排。另外各个线程的优先级也要根据情况进行安排,确保重要的功能部分能被及时的执行到!

对嵌入式技术感兴趣的,欢迎关注微信公众号“嵌入式之入坑笔记”,一起学习讨论啊!
在这里插入图片描述

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式之入坑笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值