当前位置:网站首页>基于链表管理的单片机轮询程序框架
基于链表管理的单片机轮询程序框架
2022-07-04 12:44:00 【李肖遥】
关注、星标公众号,直达精彩内容
来源:ERYUESANHI
大家好,我是肖遥,今天分享单片机裸机程序框架的文章。
1
总程序架构的重要性
很多人尤其是初学者在写代码的时候往往都是想一点写一点,最开始没有一个整体的规划,导致后面代码越写越乱,bug不断。
最终代码跑起来看似没有问题(有可能也真的没有问题),但是要加一个功能的时候会浪费大量的时间,甚至导致整个代码的崩溃。
所以,在一个项目开始的时候多花一些时间在代码的架构设计上是十分有必要的。代码架构确定好了之后你会发现敲代码的时候会特别快,并且在后期调试的时候也不会像无头苍蝇一样胡乱找问题。当然,调试也是一门技术。
在学习实时操作系统的过程中,发现实时操作系统框架与个人的业务代码之间的耦合性就非常低,都是只需要将业务代码通过一定的接口函数注册好后就交给操作系统托管了,十分方便。
但是操作系统的调度过于复杂,这里就使用操作系统的思维方式来重构这个时间片轮询框架。实现该框架的完全解耦,用户只需要包含头文件,并且在使用过程中不需要改动已经写好的库文件。
2
参考代码
首先来个demo,该demo是使用电脑开两个线程:一个线程模拟单片机的定时器中断产生时间片轮询个时钟,另一个线程则模拟主函数中一直运行的时间片轮询调度程序。
1#include <thread>
2#include <stdio.h>
3#include <windows.h>
4#include "timeslice.h"
5
6// 创建5个任务对象
7TimesilceTaskObj task_1, task_2, task_3, task_4, task_5;
8
9// 具体的任务函数
10void task1_hdl()
11{
12 printf(">> task 1 is running ...\n");
13}
14
15void task2_hdl()
16{
17 printf(">> task 2 is running ...\n");
18}
19
20void task3_hdl()
21{
22 printf(">> task 3 is running ...\n");
23}
24
25void task4_hdl()
26{
27 printf(">> task 4 is running ...\n");
28}
29
30void task5_hdl()
31{
32 printf(">> task 5 is running ...\n");
33}
34
35// 初始化任务对象,并且将任务添加到时间片轮询调度中
36void task_init()
37{
38 timeslice_task_init(&task_1, task1_hdl, 1, 10);
39 timeslice_task_init(&task_2, task2_hdl, 2, 20);
40 timeslice_task_init(&task_3, task3_hdl, 3, 30);
41 timeslice_task_init(&task_4, task4_hdl, 4, 40);
42 timeslice_task_init(&task_5, task5_hdl, 5, 50);
43 timeslice_task_add(&task_1);
44 timeslice_task_add(&task_2);
45 timeslice_task_add(&task_3);
46 timeslice_task_add(&task_4);
47 timeslice_task_add(&task_5);
48}
49
50
51// 开两个线程模拟在单片机上的运行过程
52void timeslice_exec_thread()
53{
54 while (true)
55 {
56 timeslice_exec();
57 }
58}
59
60void timeslice_tick_thread()
61{
62 while (true)
63 {
64 timeslice_tick();
65 Sleep(10);
66 }
67}
68
69int main()
70{
71 task_init();
72
73 printf(">> task num: %d\n", timeslice_get_task_num());
74 printf(">> task len: %d\n", timeslice_get_task_timeslice_len(&task_3));
75
76 timeslice_task_del(&task_2);
77 printf(">> delet task 2\n");
78 printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
79
80 printf(">> task num: %d\n", timeslice_get_task_num());
81
82 timeslice_task_del(&task_5);
83 printf(">> delet task 5\n");
84
85 printf(">> task num: %d\n", timeslice_get_task_num());
86
87 printf(">> task 3 is exist: %d\n", timeslice_task_isexist(&task_3));
88 timeslice_task_add(&task_2);
89 printf(">> add task 2\n");
90 printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
91
92 timeslice_task_add(&task_5);
93 printf(">> add task 5\n");
94
95 printf(">> task num: %d\n", timeslice_get_task_num());
96
97 printf("\n\n========timeslice running===========\n");
98
99 std::thread thread_1(timeslice_exec_thread);
100 std::thread thread_2(timeslice_tick_thread);
101
102 thread_1.join();
103 thread_2.join();
104
105
106 return 0;
107}运行结果如下:

由以上例子可见,这个框架使用十分方便,甚至可以完全不知道其原理,仅仅通过几个简单的接口就可以迅速创建任务并加入到时间片轮询的框架中,十分好用。
3
时间片轮询架构
其实该部分主要使用了面向对象的思维,使用结构体作为对象,并使用结构体指针作为参数传递,这样作可以节省资源,并且有着极高的运行效率。
其中最难的部分是侵入式链表的使用,这种链表在一些操作系统内核中使用十分广泛,这里是参考RT-Thread实时操作系统中的侵入式链表实现。
h文件:
1#ifndef _TIMESLICE_H
2#define _TIMESLICE_H
3
4#include "./list.h"
5
6typedef enum {
7 TASK_STOP,
8 TASK_RUN
9} IsTaskRun;
10
11typedef struct timesilce
12{
13 unsigned int id;
14 void (*task_hdl)(void);
15 IsTaskRun is_run;
16 unsigned int timer;
17 unsigned int timeslice_len;
18 ListObj timeslice_task_list;
19} TimesilceTaskObj;
20
21void timeslice_exec(void);
22void timeslice_tick(void);
23void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len);
24void timeslice_task_add(TimesilceTaskObj* obj);
25void timeslice_task_del(TimesilceTaskObj* obj);
26unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj);
27unsigned int timeslice_get_task_num(void);
28unsigned char timeslice_task_isexist(TimesilceTaskObj* obj);
29
30#endif.c文件:
1#include "./timeslice.h"
2
3static LIST_HEAD(timeslice_task_list);
4
5void timeslice_exec()
6{
7 ListObj* node;
8 TimesilceTaskObj* task;
9
10 list_for_each(node, ×lice_task_list)
11 {
12
13 task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
14 if (task->is_run == TASK_RUN)
15 {
16 task->task_hdl();
17 task->is_run = TASK_STOP;
18 }
19 }
20}
21
22void timeslice_tick()
23{
24 ListObj* node;
25 TimesilceTaskObj* task;
26
27 list_for_each(node, ×lice_task_list)
28 {
29 task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
30 if (task->timer != 0)
31 {
32 task->timer--;
33 if (task->timer == 0)
34 {
35 task->is_run = TASK_RUN;
36 task->timer = task->timeslice_len;
37 }
38 }
39 }
40}
41
42unsigned int timeslice_get_task_num()
43{
44 return list_len(×lice_task_list);
45}
46
47void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len)
48{
49 obj->id = id;
50 obj->is_run = TASK_STOP;
51 obj->task_hdl = task_hdl;
52 obj->timer = timeslice_len;
53 obj->timeslice_len = timeslice_len;
54}
55
56void timeslice_task_add(TimesilceTaskObj* obj)
57{
58 list_insert_before(×lice_task_list, &obj->timeslice_task_list);
59}
60
61void timeslice_task_del(TimesilceTaskObj* obj)
62{
63 if (timeslice_task_isexist(obj))
64 list_remove(&obj->timeslice_task_list);
65 else
66 return;
67}
68
69
70unsigned char timeslice_task_isexist(TimesilceTaskObj* obj)
71{
72 unsigned char isexist = 0;
73 ListObj* node;
74 TimesilceTaskObj* task;
75
76 list_for_each(node, ×lice_task_list)
77 {
78 task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
79 if (obj->id == task->id)
80 isexist = 1;
81 }
82
83 return isexist;
84}
85
86unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj)
87{
88 return obj->timeslice_len;
89}4
底层侵入式双向链表
该链表是linux内核中使用十分广泛,也十分经典,其原理具体可以参考文章:
https://www.cnblogs.com/skywang12345/p/3562146.html
.h文件:
1#ifndef _LIST_H
2#define _LIST_H
3
4#define offset_of(type, member) (unsigned long) &((type*)0)->member
5#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offset_of(type, member)))
6
7typedef struct list_structure
8{
9 struct list_structure* next;
10 struct list_structure* prev;
11} ListObj;
12
13#define LIST_HEAD_INIT(name) {&(name), &(name)}
14#define LIST_HEAD(name) ListObj name = LIST_HEAD_INIT(name)
15
16void list_init(ListObj* list);
17void list_insert_after(ListObj* list, ListObj* node);
18void list_insert_before(ListObj* list, ListObj* node);
19void list_remove(ListObj* node);
20int list_isempty(const ListObj* list);
21unsigned int list_len(const ListObj* list);
22
23#define list_entry(node, type, member) \
24 container_of(node, type, member)
25
26#define list_for_each(pos, head) \
27 for (pos = (head)->next; pos != (head); pos = pos->next)
28
29#define list_for_each_safe(pos, n, head) \
30 for (pos = (head)->next, n = pos->next; pos != (head); \
31 pos = n, n = pos->next)
32
33#endif.c文件:
1#include "list.h"
2
3void list_init(ListObj* list)
4{
5 list->next = list->prev = list;
6}
7
8void list_insert_after(ListObj* list, ListObj* node)
9{
10 list->next->prev = node;
11 node->next = list->next;
12
13 list->next = node;
14 node->prev = list;
15}
16
17void list_insert_before(ListObj* list, ListObj* node)
18{
19 list->prev->next = node;
20 node->prev = list->prev;
21
22 list->prev = node;
23 node->next = list;
24}
25
26void list_remove(ListObj* node)
27{
28 node->next->prev = node->prev;
29 node->prev->next = node->next;
30
31 node->next = node->prev = node;
32}
33
34int list_isempty(const ListObj* list)
35{
36 return list->next == list;
37}
38
39unsigned int list_len(const ListObj* list)
40{
41 unsigned int len = 0;
42 const ListObj* p = list;
43 while (p->next != list)
44 {
45 p = p->next;
46 len++;
47 }
48
49 return len;
50}到此,一个全新的,完全解耦的,十分方便易用时间片轮询框架完成。
版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧
关注我的微信公众号,回复“加群”按规则加入技术交流群。点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。边栏推荐
- 「小技巧」给Seurat对象瘦瘦身
- 洞见科技解决方案总监薛婧:联邦学习助力数据要素安全流通
- CVPR 2022 | transfusion: Lidar camera fusion for 3D target detection with transformer
- Commvault 和 Oracle 合作,在 Oracle 云上提供 Metallic数据管理即服务
- 使用宝塔部署halo博客
- When MDK uses precompiler in header file, ifdef is invalid
- WPF double slider control and forced capture of mouse event focus
- runc hang 导致 Kubernetes 节点 NotReady
- SQL language
- iptables基础及Samba配置举例
猜你喜欢

Samsung's mass production of 3nm products has attracted the attention of Taiwan media: whether it can improve the input-output rate in the short term is the key to compete with TSMC

Xue Jing, director of insight technology solutions: Federal learning helps secure the flow of data elements

When MDK uses precompiler in header file, ifdef is invalid

A data person understands and deepens the domain model

Flet教程之 03 FilledButton基础入门(教程含源码)(教程含源码)

After installing vscode, the program runs (an include error is detected, please update the includepath, which has been solved for this translation unit (waveform curve is disabled) and (the source fil

Building intelligent gray-scale data system from 0 to 1: Taking vivo game center as an example

高质量软件架构的唯一核心指标

Is the outdoor LED screen waterproof?

CA:用于移动端的高效坐标注意力机制 | CVPR 2021
随机推荐
游戏启动后提示安装HMS Core,点击取消,未再次提示安装HMS Core(初始化失败返回907135003)
Dgraph: large scale dynamic graph dataset
Etcd storage, watch and expiration mechanism
实时云交互如何助力教育行业发展
求解:在oracle中如何用一条语句用delete删除两个表中jack的信息
Agile development / agile testing experience
Optional values and functions of the itemized contenttype parameter in the request header
在 Apache 上配置 WebDAV 服务器
WPF double slider control and forced capture of mouse event focus
Apache server access log access Log settings
AI 绘画极简教程
7 月数据库排行榜:MongoDB 和 Oracle 分数下降最多
CVPR 2022 | TransFusion:用Transformer进行3D目标检测的激光雷达-相机融合
从0到1建设智能灰度数据体系:以vivo游戏中心为例
SQL statement syntax error in test SQL statement deletion in eclipse linked database
Building intelligent gray-scale data system from 0 to 1: Taking vivo game center as an example
微服务入门
Cors: standard scheme of cross domain resource request
How real-time cloud interaction helps the development of education industry
It is six orders of magnitude faster than the quantum chemical method. An adiabatic artificial neural network method based on adiabatic state can accelerate the simulation of dual nitrogen benzene der
