今天看到大佬肖遥兄分享的一篇文章:【架构篇】嵌入式编程中如何给代码的结构分层
提到了高内聚,低耦合,软件分层等等的概念。之前又有小伙伴在后台留言说让我分享一篇这样的文章,所以今天它来了!
废话不多说,理论讲太多没啥感觉,这些条条框框本质就是基于面对对象的设计模式相关的一些理论,设计模式就是前人实践多了发现一些规律然后总结出来的那么一套好用的框架,所以咱们直接出干货,硬肝!以小熊派上的SPI OLED驱动为例,将原来开发包里的LCD驱动做一些简单的改造,然后我们根据需求设计如下的驱动模型框架,分为模型、驱动、设备三个部分,我们先不考虑太细节的东西,也不会把这个东西一开始就做得特别复杂,这样不利于理解,于是我们构建如下的框架思维导图:
1、LCD驱动框架数据结构
框架提供一些什么能力呢?我是这么来做的,非常简单:
这里提供了将驱动框架与驱动进行对接的能力,&lcd_driver
拿到的是定义在驱动文件里的一个已经赋值了的结构体lcd_driver
,这样,当我在别的地方定义一个LCD_Driver_Model
的变量,就可以将这个变量与驱动结构体进行对接,这样就可以通过这个变量来操作驱动结构体里的接口了。
2、LCD驱动数据结构
LCD驱动这个数据结构要做的事情就是提供操作LCD驱动能力的接口,这个接口的设计与硬件无关。
前面1小节说过,驱动框架依赖于驱动接口,这样的话我们需要实现驱动接口里的方法,在对应的方法里,我们要去调用LCD设备相关的接口,进而去操作LCD设备,以下是接口对应的实现:
3、LCD设备数据结构
LCD设备所需要做的事情就是将这个数据结构里的功能函数与真实的LCD驱动接口进行对接。比如我们看LCD_Init
这个接口的实现,这个就是真实调用LCD的真实硬件操作了:
4、使用方法
int main(void)
{
/* USER CODE BEGIN 1 */
LCD_Driver_Model lcd_model ;
LCD_Ascii_Show_Para ascii_para[] =
{
{80, 100, 240-80, "RED", BLACK, RED, 32},
{80, 100, 240-80, "GREEN", BLACK, GREEN, 32},
{80, 100, 240-80, "BLUE", BLACK, BLUE, 32},
};
LCD_Fill_Para fill_para[] =
{
{ascii_para[0].x,ascii_para[0].max_width,ascii_para[0].y,ascii_para[0].y+32},
{ascii_para[1].x,ascii_para[1].max_width,ascii_para[1].y,ascii_para[1].y+32},
{ascii_para[2].x,ascii_para[2].max_width,ascii_para[2].y,ascii_para[2].y+32},
} ;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_SPI2_Init();
/* USER CODE BEGIN 2 */
/*串口初始化后加这个延时,防止后面的printf打印乱码*/
HAL_Delay(200);
/*注册驱动模型*/
Register_Driver_Model(&lcd_model);
/*调用LCD初始化*/
lcd_model.lcd_driver->lcd_init();
/*调用LCD显示ASCII码字符串*/
lcd_model.lcd_driver->lcd_show_ascii_str(ascii_para[0]);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/*循环调用LCD显示ASCII码字符串*/
for(int i = 0 ; i < 3 ; i++)
{
lcd_model.lcd_driver->lcd_fill(fill_para[i]);
lcd_model.lcd_driver->lcd_show_ascii_str(ascii_para[i]);
HAL_Delay(100);
}
}
/* USER CODE END 3 */
}
这样我们就完成了LCD驱动最简单的分层设计了,当然我们的软件框架后续还需要不断的把它做得更健壮,这样以后随便一个LCD,我们都可以设计一套类似这样的固定模板,根据实际的业务需求,定义设计合适的接口,以后但凡换一个项目还是用同一个LCD的话就非常简单了!
5、思考
前面我开源了一个基于TencentOS tiny
的气体探测仪项目,你是否能在那个项目上继续进行优化改善呢?
本节代码已同步到码云的代码仓库中,获取方法如下:
1、新建一个文件夹
项目开源仓库:
https://gitee.com/morixinguan/bear-pi.git
这里我给大家申请到了福利,本公众号读者购买小熊派开发板可享受9折优惠,有需要购买小熊派以及腾讯物联网开发板的朋友,淘宝搜索即可,跟客服说你是公众号: 的粉丝,立享9折优惠!
软技能:人人皆可成为卓越的领导!
嵌入式软件解决ADC电量显示问题经验分享
一口气搞懂「文件系统」,就靠这 25 张图了
做了这么久的技术自媒体,杨工,您有什么感想要分享的吗?
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!