STM32代码框架-任务轮询(1)

自述:自从入行单片机这一行业已经快快两年了,所以想在这个时间点给自己做个技术上的总结,毕竟马上就是我的24岁生日了,总是感觉要留下一些东西才好,想来想去,还是写点文章吧。想起上次写文章的时候还是两年多前的毕业论文,从那之后再也未对着电脑敲文章了。今天中秋节,人在上海,自从高中毕业之后,每年的中秋节都不是和家人一起过的,上海疫情之下,也未和同事一起出去玩或是吃个饭,想来我大抵是贪生怕死吧。

现在是上午九点,楼下大喇叭又在喊人去做核酸了,不是很想去,便不去了。于是坐在电脑前写下这篇文章,也只是想到哪写到哪吧。我是在一家汽车电子技术有限公司工作的,毕业后的第一家,当然现在还是第一家,哈哈。所负责的是根据STM32F407芯片开发出的一款控制盒,雅称control box,主要是接受串口通信,进而发出CAN/LIN报文去控制天窗电机/雨刮电机等等,主要用在一些天窗产线上或是公司自行开发的一些试验控制机柜。当然这个东西不是我做出来的,是一个博士画出的板子并写的代码,不得不承认的就是博士这种生物还是很厉害的。刚进公司的时候,基础很差,毕竟只在大二学过51单片机,还都是软件仿真的,未接触过实物,所以当博士给我讲代码的时候,我脑子懵懵的,气的他让我定义一个数组(估计想看看我水平有多差),当然了,这个我还是会的,但想来还是没有挽回我的尊严。不过现在都两年了,最早是在他的代码下修修改改,之后更是在重新换了一种任务轮询架构,在之后的项目中运行的还行吧,毕竟原本的项目要求都实现了,公司也没怎末看过我写的代码,他不问,我也不说,大抵如此了。

摘要:如大家所想我想介绍的就是这个单片机运行框架了,在我看来还是可以的,会让程序更模块化一些,也更容易移植。dq_os是一个基于systick定时器的时间片轮询框架,虽相比于RTOS缺少任务优先级之类的,但较之代码更少,只有两百行不到,可以全面通读并很容易掌握,同时很多MCU开发都是功能简单,并且实时性要求不强,所以就很适合。

单片机程序框架

dp_os是仿照RTOS写的多任务管理的OS,每个任务可以灵活的分配调度频率,可以大大提高项目代码的稳定性、可扩展性以及可移植性。

dp_os的内容如下:在这里插入图片描述
在这里插入图片描述
dp_os是框架的任务管理模块,主要负责创建和管理任务,通过面向对象的思维,把每个任务具备的属性封装在结构体里,如任务状态、任务调度频率以及任务函数指针,框架的所有功能,如任务创建及任务调度都是通过这些结构体组成的链表来操作的,每个结构体代表一个数组,每创建一个任务就是往任务链表里插入一个任务节点,对结构体的操作本质上就是对这些任务的操作。

**1、**如下为每个任务控制块的数据结构:

/**
 * @brief Task running status flag
 */
typedef enum
{
	OS_SLEEP,			
	OS_RUN,	
}OS_TaskStatusTypeDef;
/**
 * @brief task control block
 */
typedef struct task_s
{
    void (*fTask_cb)(void);         //task callback function
    OS_TaskStatusTypeDef RunFlag;   //run flag
    uint16_t RunTickPeriod;         //task scheduling cycle
    uint16_t RunTimer;              // run timer
    struct task_s *next;
}task_t;

**2、**TaskCreate函数是用来创建任务的,先是初始化任务结构体,给其赋值,再将这个任务节点插入到任务链表里,创建任务函数如下:

// task handle list head.
static struct task_s *head_handle = NULL;

/**
 * @brief Initializes the task struct handle.
 *
 * @param task: the task handle strcut
 * @param fTask_cb :task callback
 * @param run_period : task run period
 * @param runflag :task run flag
 */
int TaskCreate(task_t *task, void (*fTask_cb)(), uint16_t run_period, OS_TaskStatusTypeDef runflag)
{
    task_t *cur_task = head_handle;

    task->fTask_cb = fTask_cb;
    task->RunTickPeriod = run_period;
    task->RunFlag = OS_SLEEP;
    task->RunTimer = 0;
    // Traverse to find out whether the node already exists
    while (cur_task)
    {
        if (cur_task == task)
            return -1; // already exist.
        // Keep traversing the next node
        cur_task = cur_task->next;
    }
    /*Using the method of linked list front insertion,
    the latest timer is placed in the front and used as the head node*/
    task->next = head_handle;
    head_handle = task;
	return 0;
}

创建一个串口任务:

task_t Usart1Task;
task_t Usart2Task;
static void usart_send1(void)
{
	printf("阿秋的嵌入式!/r/n");
}
static void usart_send2(void)
{
	printf("阿秋单片机编程!/r/n");
}
TaskCreate(&Usart1Task,usart_send1,2000,OS_RUN);
TaskCreate(&Usart2Task,usart_send2,6000,OS_RUN);

创建任务是不是很简单啊!阿秋!shiji

**3、**dq_os是基于系统滴答定时器来进行任务管理的,时基为1ms;再1ms中断中不断轮询判断任务是否到达定时时间,如果到达将任务运行标志位置为运行状态,在while循环中如果检测到任务标志为为运行状态则执行该任务函数。

task_loop_handle函数须在滴答定时器中断中调用,时基为1ms;

/**
 * @brief Call the function in the timer interrupt
 *
 */
void task_loop_handle(void)
{
    task_t *cur_task;
    for (cur_task = head_handle; cur_task; cur_task = cur_task->next)
    {
        cur_task->RunTimer++;
        if (cur_task->RunTimer >= cur_task->RunTickPeriod)
        {
            cur_task->RunTimer = 0;
            cur_task->RunFlag = OS_RUN;
        }
    }
}
/**
 * @brief This function handles System tick timer.
 */
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
  task_loop_handle();
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

4、TaskStartScheduler为开始任务函数,在while循环中如果检测到任务标志为为运行状态则执行该任务函数。


void TaskStartScheduler(void)
{
    task_t *cur_task;
    while (1)
    {
        for (cur_task = head_handle; cur_task; cur_task = cur_task->next)
        {
            if(cur_task->RunFlag == OS_RUN)
            {
                cur_task->RunFlag = OS_SLEEP;
                cur_task->fTask_cb();
            }
        }
    }
}

5、主函数如下:

#include "rtos_main.h"

#include "dq_os.h"
#include "debug_printf.h"

task_t Usart1Task;
task_t Usart2Task;
static void usart_send1(void)
{
	printf("aqiu!\r\n");
}
static void usart_send2(void)
{
	printf("123456!\r\n");
}

void Hard_Init(void)
{

}

void Soft_Init(void)
{
	TaskCreate(&Usart1Task,usart_send1,2000,OS_RUN);
	TaskCreate(&Usart2Task,usart_send2,6000,OS_RUN);
	TaskStartScheduler();
	while(1)
	{		
	}  
} 

执行结果如下:
串口任务1(usart_send1)每2000ms执行一次;
串口任务2(usart_send2)每6000ms执行一次。
在这里插入图片描述

代码链接如下:
链接:https://pan.baidu.com/s/1sdsByPVV7XHXpRwBJfmjTw
提取码:aqiu
–来自百度网盘超级会员V5的分享

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值