嵌入式中的一种面向对象思维的架构

嵌入式大杂烩 2024-06-16 11:40

关注「嵌入式大杂烩」,选择「星标公众号」一起进步!

来源 | ERYUESANHI

编排 | strongerHuang


今天分享一篇单片机程序框架的文章。


程序架构重要性

很多人尤其是初学者在写代码的时候往往都是想一点写一点,最开始没有一个整体的规划,导致后面代码越写越乱,bug不断。

最终代码跑起来看似没有问题(有可能也真的没有问题),但是要加一个功能的时候会浪费大量的时间,甚至导致整个代码的崩溃。

所以,在一个项目开始的时候多花一些时间在代码的架构设计上是十分有必要的代码架构确定好了之后你会发现敲代码的时候会特别快,并且在后期调试的时候也不会像无头苍蝇一样胡乱找问题。当然,调试也是一门技术。

在学习实时操作系统的过程中,发现实时操作系统框架与个人的业务代码之间的耦合性就非常低,都是只需要将业务代码通过一定的接口函数注册好后就交给操作系统托管了,十分方便。

但是操作系统的调度过于复杂,这里就使用操作系统的思维方式来重构这个时间片轮询框架。实现该框架的完全解耦,用户只需要包含头文件,并且在使用过程中不需要改动已经写好的库文件。

Demo

首先来个demo,该demo是使用电脑开两个线程:一个线程模拟单片机的定时器中断产生时间片轮询个时钟,另一个线程则模拟主函数中一直运行的时间片轮询调度程序。
#include #include #include #include "timeslice.h"
// 创建5个任务对象TimesilceTaskObj task_1, task_2, task_3, task_4, task_5;
// 具体的任务函数void task1_hdl(){ printf(">> task 1 is running ...\n");}
void task2_hdl(){ printf(">> task 2 is running ...\n");}
void task3_hdl(){ printf(">> task 3 is running ...\n");}
void task4_hdl(){ printf(">> task 4 is running ...\n");}
void task5_hdl(){ printf(">> task 5 is running ...\n");}
// 初始化任务对象,并且将任务添加到时间片轮询调度中void task_init(){ timeslice_task_init(&task_1, task1_hdl, 1, 10); timeslice_task_init(&task_2, task2_hdl, 2, 20); timeslice_task_init(&task_3, task3_hdl, 3, 30); timeslice_task_init(&task_4, task4_hdl, 4, 40); timeslice_task_init(&task_5, task5_hdl, 5, 50); timeslice_task_add(&task_1); timeslice_task_add(&task_2); timeslice_task_add(&task_3); timeslice_task_add(&task_4); timeslice_task_add(&task_5);}

// 开两个线程模拟在单片机上的运行过程void timeslice_exec_thread(){ while (true) { timeslice_exec(); }}
void timeslice_tick_thread(){ while (true) { timeslice_tick(); Sleep(10); }}
int main(){ task_init();
printf(">> task num: %d\n", timeslice_get_task_num()); printf(">> task len: %d\n", timeslice_get_task_timeslice_len(&task_3));
timeslice_task_del(&task_2); printf(">> delet task 2\n"); printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
printf(">> task num: %d\n", timeslice_get_task_num());
timeslice_task_del(&task_5); printf(">> delet task 5\n");
printf(">> task num: %d\n", timeslice_get_task_num());
printf(">> task 3 is exist: %d\n", timeslice_task_isexist(&task_3)); timeslice_task_add(&task_2); printf(">> add task 2\n"); printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
timeslice_task_add(&task_5); printf(">> add task 5\n");
printf(">> task num: %d\n", timeslice_get_task_num());
printf("\n\n========timeslice running===========\n");
std::thread thread_1(timeslice_exec_thread); std::thread thread_2(timeslice_tick_thread);
thread_1.join(); thread_2.join();

return 0;}


运行结果如下:


由以上例子可见,这个框架使用十分方便,甚至可以完全不知道其原理,仅仅通过几个简单的接口就可以迅速创建任务并加入到时间片轮询的框架中,十分好用。

时间片轮询架构

其实该部分主要使用了面向对象的思维,使用结构体作为对象,并使用结构体指针作为参数传递,这样作可以节省资源,并且有着极高的运行效率。


其中最难的部分是侵入式链表的使用,这种链表在一些操作系统内核中使用十分广泛,这里是参考RT-Thread实时操作系统中的侵入式链表实现。

h文件:
#ifndef _TIMESLICE_H#define _TIMESLICE_H
#include "./list.h"
typedef enum { TASK_STOP, TASK_RUN} IsTaskRun;
typedef struct timesilce{ unsigned int id; void (*task_hdl)(void); IsTaskRun is_run; unsigned int timer; unsigned int timeslice_len; ListObj timeslice_task_list;} TimesilceTaskObj;
void timeslice_exec(void);void timeslice_tick(void);void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len);void timeslice_task_add(TimesilceTaskObj* obj);void timeslice_task_del(TimesilceTaskObj* obj);unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj);unsigned int timeslice_get_task_num(void);unsigned char timeslice_task_isexist(TimesilceTaskObj* obj);
#endif

c文件:
#include "./timeslice.h"
static LIST_HEAD(timeslice_task_list);
void timeslice_exec(){ ListObj* node; TimesilceTaskObj* task;
list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (task->is_run == TASK_RUN) { task->task_hdl(); task->is_run = TASK_STOP; } }}
void timeslice_tick(){ ListObj* node; TimesilceTaskObj* task;
list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (task->timer != 0) { task->timer--; if (task->timer == 0) { task->is_run = TASK_RUN; task->timer = task->timeslice_len; } } }}
unsigned int timeslice_get_task_num(){ return list_len(×lice_task_list);}
void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len){ obj->id = id; obj->is_run = TASK_STOP; obj->task_hdl = task_hdl; obj->timer = timeslice_len; obj->timeslice_len = timeslice_len;}
void timeslice_task_add(TimesilceTaskObj* obj){ list_insert_before(×lice_task_list, &obj->timeslice_task_list);}
void timeslice_task_del(TimesilceTaskObj* obj){ if (timeslice_task_isexist(obj)) list_remove(&obj->timeslice_task_list); else return;}

unsigned char timeslice_task_isexist(TimesilceTaskObj* obj){ unsigned char isexist = 0; ListObj* node; TimesilceTaskObj* task;
list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (obj->id == task->id) isexist = 1; }
return isexist;}
unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj){ return obj->timeslice_len;}

底层侵入式双向链表

该链表是linux内核中使用十分广泛,也十分经典,其原理具体可以参考文章:
https://www.cnblogs.com/skywang12345/p/3562146.html

h文件:
#ifndef _LIST_H#define _LIST_H
#define offset_of(type, member) (unsigned long) &((type*)0)->member#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offset_of(type, member)))
typedef struct list_structure{ struct list_structure* next; struct list_structure* prev;} ListObj;
#define LIST_HEAD_INIT(name) {&(name), &(name)}#define LIST_HEAD(name) ListObj name = LIST_HEAD_INIT(name)
void list_init(ListObj* list);void list_insert_after(ListObj* list, ListObj* node);void list_insert_before(ListObj* list, ListObj* node);void list_remove(ListObj* node);int list_isempty(const ListObj* list);unsigned int list_len(const ListObj* list);
#define list_entry(node, type, member) \ container_of(node, type, member)
#define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next)
#endif

c文件:
#include "list.h"
void list_init(ListObj* list){ list->next = list->prev = list;}
void list_insert_after(ListObj* list, ListObj* node){ list->next->prev = node; node->next = list->next;
list->next = node; node->prev = list;}
void list_insert_before(ListObj* list, ListObj* node){ list->prev->next = node; node->prev = list->prev;
list->prev = node; node->next = list;}
void list_remove(ListObj* node){ node->next->prev = node->prev; node->prev->next = node->next;
node->next = node->prev = node;}
int list_isempty(const ListObj* list){ return list->next == list;}
unsigned int list_len(const ListObj* list){ unsigned int len = 0; const ListObj* p = list; while (p->next != list) { p = p->next; len++; }
return len;}

到此,一个全新的,完全解耦的,十分方便易用时间片轮询框架完成。

本文来源网络版权归原作者所有。如涉及作品版权问题,请联系我进行删除。

精彩内容:
移植boa服务器的方法
易懂 | 手把手教你编写你的第一个上位机

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论 (0)
  •   高空 SAR 目标智能成像系统软件:多领域应用的前沿利器   高空 SAR(合成孔径雷达)目标智能成像系统软件,专门针对卫星、无人机等高空平台搭载的 SAR传感器数据,融合人工智能与图像处理技术,打造出的高效目标检测、识别及成像系统。此软件借助智能算法,显著提升 SAR图像分辨率、目标特征提取能力以及实时处理效率,为军事侦察、灾害监测、资源勘探等领域,提供关键技术支撑。   应用案例系统软件供应可以来这里,这个首肌开始是幺伍扒,中间是幺幺叁叁,最后一个是泗柒泗泗,按照数字顺序组合
    华盛恒辉l58ll334744 2025-04-14 16:09 96浏览
  • 亥姆霍兹线圈的应用领域‌物理学研究‌:在原子物理中,用于研究塞曼效应;在磁学研究中,用于测试磁性材料的磁滞回线等特性;还可用于研究电子荷质比等实验‌。‌工程与技术领域‌:用于电子设备校准和测试,提供标准磁场环境;在大型加速器中用于磁场校准;用于电磁干扰模拟实验,测试电子设备在不同磁场干扰下的性能‌。‌生物医学领域‌:研究生物磁场效应,如探索磁场对生物细胞的影响;在生物医学工程基础研究中,提供可控磁场环境‌。‌其他应用‌:作为磁场发生装置产生标准磁场;用于地球磁场的抵消与补偿、地磁环境模拟;还可用
    锦正茂科技 2025-04-14 10:41 51浏览
  • 在当今汽车电子化和智能化快速发展的时代,车规级电子元器件的质量直接关系到汽车安全性能。三星作为全球领先的电子元器件制造商,其车规电容备受青睐。然而,选择一个靠谱的三星车规电容代理商至关重要。本文以行业领军企业北京贞光科技有限公司为例,深入剖析如何选择优质代理商。选择靠谱代理商的关键标准1. 授权资质与行业地位选择三星车规电容代理商首先要验证其授权资质及行业地位。北京贞光科技作为中国电子元器件行业的领军者,长期走在行业前沿,拥有完备的授权资质。公司专注于市场分销和整体布局,在电子元器件领域建立了卓
    贞光科技 2025-04-14 16:18 94浏览
  •  亥姆霍兹线圈的制造材料选择需兼顾导电性、绝缘性、机械强度及磁场性能,具体分类如下:一、‌导线材料1、‌高纯度铜线:‌作为线圈绕制的核心材料,铜因其you异的导电性(电阻率低)和热稳定性成为shou选。漆包铜线通过表面绝缘漆层实现匝间绝缘,避免短路‌。2、‌其他导电材料‌ 铝线等材料可用于特定场景(如轻量化需求),但导电性和抗氧化性较铜略逊二、‌磁源材料‌1、‌永磁体‌如钕铁硼(NdFeB)或铁氧体,适用于无需外部电源的静态磁场生成,但磁场强度有限。2、‌电磁铁‌通过电流控制磁场强度,
    锦正茂科技 2025-04-14 10:22 32浏览
  • 软瓦格化 RISC-V 处理器集群可加速设计并降低风险作者:John Min John Min是Arteris的客户成功副总裁。他拥有丰富的架构专业知识,能够成功管理可定制和标准处理器在功耗、尺寸和性能方面的设计权衡。他的背景包括利用 ARC、MIPS、x86 和定制媒体处理器来设计 CPU SoC,尤其擅长基于微处理器的 SoC。RISC-V 指令集架构 (ISA) 以其强大的功能、灵活性、低采用成本和开源基础而闻名,正在经历各个细分市场的快速增长。这种多功能 ISA 支持汽车、航空航天、国防
    ArterisIP 2025-04-14 10:52 68浏览
  •   电磁干扰测试系统:电子设备电磁兼容性保障利器   北京华盛恒辉电磁干扰测试系统作为评估电子设备在电磁环境中电磁兼容性(EMC)的关键工具,主要用于检测与分析设备在电磁干扰环境下的性能表现,确保其符合相关标准,能够在实际应用中稳定运行。   应用案例   目前,已有多个电磁干扰测试系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁干扰测试系统。这些成功案例为电磁干扰测试系统的推广和应用提供了有力支持。   系统组成   电磁干扰测试系统一般由以下核心部分构成:  
    华盛恒辉l58ll334744 2025-04-14 10:40 39浏览
  • 你知道精益管理中的“看板”真正的意思吗?在很多人眼中,它不过是车间墙上的一块卡片、一张单子,甚至只是个用来控制物料的工具。但如果你读过大野耐一的《丰田生产方式》,你就会发现,看板的意义远不止于此。它其实是丰田精益思想的核心之一,是让工厂动起来的“神经系统”。这篇文章,我们就带你一起从这本书出发,重新认识“看板”的深层含义。一、使“看板”和台车结合使用  所谓“看板”就是指纸卡片。“看板”的重要作用之一,就是连接生产现场上道工序和下道工序的信息工具。  “看板”是“准时化”生产的重要手段,它总是要
    优思学院 2025-04-14 15:02 81浏览
  • 时源芯微 专业EMC解决方案提供商  为EMC创造可能(适用于高频时钟电路,提升EMC性能与信号稳定性)一、设计目标抑制电源噪声:阻断高频干扰(如DC-DC开关噪声)传入晶振电源。降低时钟抖动:确保晶振输出信号纯净,减少相位噪声。通过EMC测试:减少晶振谐波辐射(如30MHz~1GHz频段)。二、滤波电路架构典型拓扑:电源输入 → 磁珠(FB) → 大电容(C1) + 高频电容(C2) → 晶振VDD1. 磁珠(Ferrite Bead)选型阻抗特性:在目标频段(如100MHz~1GH
    时源芯微 2025-04-14 14:53 58浏览
  • 在制造业或任何高度依赖产品质量的行业里,QA(质量保证)经理和QC(质量控制)经理,几乎是最容易被外界混淆的一对角色。两者的分工虽清晰,但职责和目标往往高度交叉。因此,当我们谈到“谁更有可能升任质量总监”时,这并不是一个简单的职位比较问题,而更像是对两种思维方式、职业路径和管理视角的深度考察。QC经理,问题终结者QC经理的世界,是充满数据、样本和判定标准的世界。他们是产品出厂前的最后一道防线,手里握着的是批次报告、不合格品记录、纠正措施流程……QC经理更像是一位“问题终结者”,目标是把不合格扼杀
    优思学院 2025-04-14 12:09 56浏览
  • 一、磁场发生设备‌电磁铁‌:由铁芯和线圈组成,通过调节电流大小可产生3T以下的磁场,广泛应用于工业及实验室场景(如电磁起重机)。‌亥姆霍兹线圈‌:由一对平行共轴线圈组成,可在线圈间产生均匀磁场(几高斯至几百高斯),适用于物理实验中的磁场效应研究。‌螺线管‌:通过螺旋线圈产生长圆柱形均匀磁场,电流与磁场呈线性关系,常用于磁性材料研究及电子束聚焦。‌超导磁体‌:采用超导材料线圈,在低温下可产生3-20T的强磁场,用于核磁共振研究等高精度科研领域。‌多极电磁铁‌:支持四极、六极、八极等多极磁场,适用于
    锦正茂科技 2025-04-14 13:29 53浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦