STM32 物联网智能家居 (四) 设备子系统之分层框架
STM32 物联网智能家居 (四) 设备子系统之分层框架
一、设备子系统简介
前面我们讲述了输入子系统中的按键输入和标准输入,我们学习了函数指针的调用方法,这种方法一般在裸机程序中使用的比较少,但在Linux、FreeRTOS和RT-Thread操作系统中使用的比较多。这种方法有利于函数的封装、扩展。方便后续再给软件增加新的接口提供便利。
下面我们继续采用上面面向对象的方法,来讲解我们的设备子系统。
设备子系统分为三类,GPIO控制、风扇控制和OLED显示这三部分。
我们可能会在思考,怎么用同一套代码,访问不同的设备呢,如果每进来一个设备的子模块,我都要重新写一个函数去操纵它,那随着我的这个系统逐渐壮大,我的程序也必定变得非常臃肿,也就是那种所谓的“屎山”,很多实验室的祖传代码都是这样,能跑就行,如果要将代码重构的话,那必定会引出很多新的bug,重构简直是一门大的学问,有一本计算机的书籍叫《重构-改善既有代码的设计》,据说是一代神书,等我有机会了一定去看看。
二、怎样访问设备呢?
2.1 裸机里怎么访问设备
在裸机中,我们使用HAL库,或者厂家自己封装的库,甚至自己编写代码直接访问寄存器。
2.2 FreeRTOS怎么访问设备
FreeRTOS中没有驱动程序框架,它访问设备时方法跟裸机一样,直接操纵寄存器或使用芯片厂商提供的HAL库。
2.3 RT-Thread怎么访问设备
RT-Thread可以使用两种方法去访问设备:
- 像裸机一样
- 使用RT-Thread的驱动程序框架
所谓"驱动框架",如上图RT-Thread框架所示,就是事先定义好的接口函数,你要添加新设备就必须实现这些接口函数。
好处是:无论硬件怎么改,驱动程序的接口不变,上面的应用程序也就不需要改变。
“I/O设备管理” 接口如下:
应用程序通过标准的接口来访问设备:rt_device_find/rt_device_open/rt_device_read/rt_device_write等等。这里IO设备是这样,Wifi设备也是这样,显示设备也是这样,都是使用的这一套统一的标准接口。
2.4 Linux下怎么访问设备
在Linux系统中,APP和驱动程序严格分离开:
- APP无法直接读写寄存器
- APP必须通过驱动程序访问设备
- APP使用的接口只有:open/read/write/ioctl等
你没有办法再APP层直接操作底层硬件,必须APP层调用内核层,内核层调用驱动层,最后驱动层来操纵底层硬件的寄存器。通过将应用程序和驱动程序分离,可以减少驱动程序受到恶意应用程序攻击的风险。应用程序通常运行在用户空间,而驱动程序在内核空间,内核空间具有更高的权限,因此分离可以有效地隔离潜在的安全漏洞。并且由于驱动和应用程序做到了分离,使得应用层的代码具有良好的可移植性,简化了开发和维护的花费。
三、 有必要统一设备的访问吗?
我们先把设备子系统分层:
至少有2层:虚线上下
- 虚线之上:写出统一的API接口
- 虚线之下:根据不同的系统,调用不同的函数
对于开发应用程序的人:
- 他不关心LED使用哪个GPIO引脚
- 他不关心GPIO是输出高还是低来控制LED
- 他不关心open什么、read/write什么
- 我们不应该要求他:
- 阅读原理图
- 阅读芯片手册
- 研究HAL库、RT-Thread或者Linux的驱动函数怎么调用
- 甚至不应该要求他去理解你抽象出来的某个结构体
- 你可以抽象出一个LEDDevice
- 但是LEDDevice里,他只关心怎么使用Init/Control中2个函数指针
- 其他成员一概不关心
所以,我们很有必要提供更高层次的API,以LED为例:
- 可以提供:LEDInit/LedControl,这2个函数可以放入LEDDevice结构体里
- 应用开发者,只需要调用这2个函数
四、设计原则:驱动和应用分开
在Linux驱动开发中,有一句话:驱动只提供功能,不提供策略。
什么意思呢?就是各司其职,不要越界。
以LCD显示的使用为例,可以分为3层:
- 驱动程序:
- 提供像素操作的功能
- 但是怎么显示字符、显示多大、在哪显示,这不关我的事
- 库函数/功能函数:
- 提供显示字符、显示图片的功能
- 但是显示什么字符、在哪显示,这不关我的事
- APP:
- 使用库函数来显示字符、显示图片
- 我甚至不需要看驱动程序
我们实现各类子系统时,要划分层次的时候,也要理清楚:
- 有哪些功能
- 这些功能怎么细分?得到层次
- 每个层次各司其职,不要越界
五、设计思路
使用面向对象的思想,对于每一种设备,抽象出一个结构体,结构体里有设备相关的函数指针。
不同设备,不强求统一,不强求用一个结构体类型,支持所有设备。
编写函数时,要注意:
- 头文件:这些函数是面向APP开发者,假设他们对硬件一无所知
- C文件:函数内部,再根据不同系统、不同芯片,调用其他函数
综上,我们将我们的整个系统划分为下面四个部分,APPL层是最上层的应用层,与硬件和操作系统无关,专注于应用层的逻辑。KAL层是内核抽象层(Kernel Abstraction Layer),这一层可以将整个软件分为不同的操作系统平台,通过简单的切换,可以让系统跑在裸机、FreeRTOS或者RT-Thread上面。CAL层是芯片抽象层(Chip Abstraction Layer)这一层来区分不同的芯片,来解决移植到不同的问题。HAL层(Hardware Abstraction Layer)是硬件抽象层,是决定是调用Hal库、寄存器还是库函数来操作底层硬件。以上就是为本项目设计的分层架构的逻辑,借由此软件框架做到容易扩展、容易维护的目的。
六、往期文章
STM32 物联网智能家居 (一) 方案设计STM32+ESP8266+TCP/UDP/MQTT
STM32 物联网智能家居 (二)-开发环境及工程搭建(STM32CubeMX)
STM32 BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建
STM32 BootLoader 刷新项目 (二) 方案介绍
STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示
STM32 BootLoader 刷新项目 (四) 通信协议
STM32 BootLoader 刷新项目 (十三) Python上位机介绍
STM32 BootLoader 刷新项目 (十四) 所有源代码获取
原文地址:https://blog.csdn.net/qq_35057766/article/details/145193935
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!