嘉兴本地推广网站,如何查看网站是否开启gzip,互联网推广属于什么经营范围,现在很多网站都是wordpress大家好#xff0c;今天分享一篇嵌入式软件架构设计相关的文章。 软件架构这东西#xff0c;众说纷纭#xff0c;各有观点。在我看来#xff0c;软件架构是软件系统的基本结构#xff0c;包含其组件、组件之间的关系、组件设计与演进的规则#xff0c;以及体现这些规则的基…大家好今天分享一篇嵌入式软件架构设计相关的文章。 软件架构这东西众说纷纭各有观点。在我看来软件架构是软件系统的基本结构包含其组件、组件之间的关系、组件设计与演进的规则以及体现这些规则的基础设施。
软件架构从来不是一件容易事它贯穿在产品的整个生命周期需要所有团队成员遵守并自律才能将架构思想在软件中体现。新手工程师由于经历的项目太少看不到项目全貌很难从全局理解软件架构。但软件架构真的只是资深工程师的专利吗这个也不见得。
古人作文讲究立意为先。今天工程师做项目和产品也应该先立意。这个意就是指要有高度。工程师入门能从软件架构的高度出发看待软件问题相信对软件的理解会更加深刻一些。因此我总结了软件架构的六个步骤供嵌入式工程师参考。
上次谈到了嵌入式软件架构的第一个步骤抽象层。建立抽象层HAL或者DAL的目的是为了隔离硬件让代码与硬件无关。即使整个项目的代码由某工程师一个人完成抽象层仍是是有必要的。
但这次我们要聊的是统一的基础设施这是针对多人合作一个项目或者多个项目共享同一个系统架构的情况。
如果说你手头的项目没有与他人合作也不会有后续的相关项目软件基础设施这一步可以直接跳过。
基础设施分为硬件基础设施和软件基础设施。硬件基础设施包含常用器件库、封装库、原理图库和硬件参考设计等等而今天我们讨论的重点主要在于软件基础设施。软件基础设施包含以下内容 • 基础数据结构。 • 底层库。比如C标准库、加密库、校验库、工具库等等。 • 操作系统/调度机制。包含操作系统以及调度相关服务。 • 中间件。比如文件系统、协议栈、数据库等。 • 框架与机制。比如消息通信机制、事件驱动机制、状态机框架、行为树框架。 • 工具支持。 • 统一的编程工具链。 • 统一的代码风格和编程规范。
在一些小公司粗放的开发模式中并不规定工程师所依赖的软件平台、硬件平台和工具而是由工程师自己决定。很多工程师也喜欢这种自由奔放的开发模式认为只有在这种环境中才能发挥自身创造力。这种认知是有偏差的这个我们后续找机会详细讨论。
随着小公司研发能力的提升对软件基础设施进行约束和规定几乎是注定的事情。因为软件区别于其他技术的本质是在于其复用性。
复用程度越高的软件质量越高对开发效率和开发质量的提升就越大。无论从公司的降本增效还是科学管理的角度都有着强大的动机去统一软件基础设施。当软件的基础设施统一之后会产生如下优点 • 软件质量提升风格的高度一致性 • 软件复用性会提升至一个新的水平 • 将可复用的功能尽量抽象到基础设施层减少软件冗余提升开发效率。 • 为高层模块提供约束和纪律 • 有利于团队的技术积累和技术传承 • 有利于团队的技术培训 • 是团队进行单元测试和测试驱动开发以及跨平台开发的前提。
因此是否统一根本不是一个有争议的问题如何统一才是今天我们的重点。
一、基础类型与宏定义
统一的软件基础设施的前提就是声明统一的基础数据类型和宏以克服不同的硬件平台和编译器的差异性。
比如下面是我从开源项目EventOS中摘录出来的代码不见得很完整只能代表在我在项目里需求。
#include stdbool.htypedef unsigned int eos_u32_t;
typedef signed int eos_s32_t;
typedef unsigned short eos_u16_t;
typedef signed short eos_s16_t;
typedef unsigned char eos_u8_t;
typedef signed char eos_s8_t;
typedef bool eos_bool_t;#define EOS_NULL ((void *)0)#define EOS_U32_MAX (0xffffffffU)
#define EOS_U32_MIN (0U)
#define EOS_U16_MAX (0xffffU)
#define EOS_U16_MIN (0U)
#define EOS_U8_MAX (0xffU)
#define EOS_U8_MIN (0U)
编译器相关的宏定义。使用宏屏蔽掉编译器的差异会
/* Compiler Related Definitions */
#if defined(__ARMCC_VERSION) /* ARM Compiler */#define eos_section(x) __attribute__((section(x)))#define eos_used __attribute__((used))#define eos_align(n) __attribute__((aligned(n)))#define eos_weak __attribute__((weak))#define eos_inline static __inline#elif defined (__GNUC__) /* GNU GCC Compiler */#define eos_section(x) __attribute__((section(x)))#define eos_used __attribute__((used))#define eos_align(n) __attribute__((aligned(n)))#define eos_weak __attribute__((weak))#define eos_inline static __inline#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */#define eos_section(x) x#define eos_used __root#define eos_align(n) PRAGMA(data_alignmentn)#define eos_weak __weak#define eos_inline static inline#else#error The current compiler is not supported.
#endif
一些常用的数据结构。这些数据结构与硬件和编译器无关是在代码中频繁使用并在多个模块间共享的数据结构有必要将其提升至基础设施的层面进行支持以避免各个模块对同一个数据类型进行不同的定义带来的数据转换问题。
这些数据结构与产品紧密相关不同的产品类型之间各自是不同的。比如下面的定义。
typedef struct eos_date
{eos_u32_t year : 16;eos_u32_t month : 8;eos_u32_t day : 8;
} eos_date_t;typedef struct eos_time
{eos_u32_t hour : 8;eos_u32_t minute : 8;eos_u32_t second : 6;eos_u32_t ms : 10;
} eos_time_t;typedef struct eos_imu_data
{float acc[3];float gyr[3];float mag[3];
} eos_imu_data_t;
二、操作系统
有些芯片的资源太小是不能运行操作系统的。这些芯片一般而言也没有办法建立严谨的嵌入式软件架构我们会在后续《小资源芯片的软件开发平台》中单独进行讨论。这里只讨论芯片的。
不同的芯片所能跑的操作系统是不同的。但如果要建立软件基础设施应该尽量选取同一个操作系统。
在现存的操作系统中FreeRTOS和国产RT-Thread对各种不同的硬件架构的芯片支持比较广泛可以作为RTOS的首选。
而当产品线异常丰富时特别是使用了某些小众芯片或者使用芯片商提供的操作系统时就没有办法建立统一的软件基础设施。这时有两个办法解决这一问题 • 编写高层模块时使用宏定义和条件编译选择对应的RTOS API。这种一般用于所使用的操作系统较少的情况比如说只有两三种。
static void *task_handler NULL;static void task_func_module_one(void *parameter);void module_one_init(void)
{/* Newly creating a task to run the module. */
#if (EOS_RTOS_NAME EOS_RTOS_NAME_FREERTOS)xTaskCreate(task_func_module_one,TaskModule, 2048, NULL, 2,(TaskHandle_t *)task_handler);
#elif (EOS_RTOS_NAME EOS_RTOS_NAME_RTTHREAD)task_handler rt_thread_create(led1, task_func_module_one, NULL,2048, 2, 20);
#elseeos_assert(false);
#endifeos_assert(task_handler ! NULL);
}/* The task function of the module one. */
static void task_func_module_one(void *parameter)
{(void)parameter;/* Initialization. */while (1){/* Add the task function. */}
} • 建立操作系统抽象层OSALOperating System Abstraction Layer以屏蔽操作系统的差异使高层模块依赖于OSAL。这种情况适合于资源丰富的情况。 著名的POSIX标准就是为了建立OSAL的FreeRTOS和RT-Thread都在不同程度上对POSIX标准进行了支持在 v嵌入式领域CMSIS_OS也是为了建立操作系统的统一接口但无论是POSIX和CMSIS_OS被各RTOS支持的力度是不同因此如果我们产品中需要建立严谨的嵌入式软件架构还是要建立属于自己的OSAL以便屏蔽掉操作系统的不同带来的差异。
三、中间件
中间件有很多类型文件系统、各种协议栈、数据库、日志模块、Shell模块都属于中间件的范畴。但在大部分情况下这些也都属于软件基础设施的范畴。
因为我们一旦选择某个中间件一般来说是没有必要更换的正是由于这种稳定性中间件也可以纳入软件基础设施的范畴。以下是我经常使用的开源中间件 • FatFS • LwIP • FlashDB • uC/Modbus • CAN Festival • letter-shell
开源中间件只占据了一小部分。实际产品中中间件的大部分都是产品或者项目私有的代码。我日常所使用的主要有 日志模块 数据采集模块 通讯传输层协议 通讯应用层协议 文件传输协议 OTA功能 * 时间同步
中间件占据了软件基础设施的大部分内容。在产品开发中之所以软件复用性能够做到越来越高中间件的积累是一个很重要的原因。
四、框架与机制
在不同的产品上开发嵌入式软件除了RTOS之外很多产品还需要一些框架的支持。常见的框架包括 外设与驱动框架 设备框架 消息框架 状态机框架 行为树框架 事件驱动框架
这些框架的使用与产品的特性相关由产品和需求所决定。比如家庭服务机器人中需要应用状态机框架和行为树框架来应对复杂的应用层逻辑。而某些应用层逻辑比较简单的产品就不需要使用状态机和行为树。
软件基础设施与硬件的关系
嵌入式软件有一个区别于其他软件领域的重要特性那就是直接依赖于硬件。软件基础设施有很多也是需要硬件去体现和承载。比如文件系统在规定某个源代码比如FatFS作为其文件系统解决方案的同时所伴随的硬件驱动程序和硬件推荐设计也往往被固化以便在下一个项目中进行复用并节约时间。
对于一些重要的且复杂的软件基础设施如文件系统、网络等由于调试和测试都比较耗时一般推荐固化硬件设计的方式。硬件工程师应优先对这些重要且复杂的软件基础设置分配硬件资源而硬件的其他工程比如IO、ADC等再行分配。
结论
嵌入式软件基础设施非常重要根据项目与产品的不同它所包含的内容也不尽相同。一般在项目启动时就会初步选定一些软件基础设施的内容比如RTOS、协议栈、文件系统等等。
需要指出的是软件基础设施也不是不变的而是随着产品开发发展不断会有新的组件和元素加入到软件基础设施中去也有可能会剥离掉旧的组件就像生物的新陈代谢。
软件基础设施的新陈代谢要温和要相对稳定添加和删除都要执行谨慎原则。