【实战篇】模块化编程之LCD驱动框架详解
ID:嵌入式云IOT技术圈
作者:杨源鑫
废话不多说,理论讲太多没啥感觉,这些条条框框本质就是基于面对对象的设计模式相关的一些理论,设计模式就是前人实践多了发现一些规律然后总结出来的那么一套好用的框架,所以咱们直接出干货,硬肝!以小熊派上的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、新建一个文件夹
2、使用git clone远程获取小熊派例程存放的代码仓库
项目开源仓库:
https://gitee.com/morixinguan/bear-pi.git
嵌入式编程专辑 Linux 学习专辑 C/C++编程专辑 Qt进阶学习专辑 关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容;扫描下方微信,加作者微信进技术交流群,请先自我介绍喔。