标签:消息 and 记录 应该 bind 包含 删除 酷炫 匹配
够用的硬件
能用的代码
使用的教程(拷贝过来的代码有点乱,请下载附件查看文档)
1 分层不清晰,通俗讲就是模块化太差。
2 接口乱。其实只要接口不乱,分层就会好很多了。
3 可移植性差。
4 通用性差。
1 代码空间不够,只能保留9341的驱动,其他LCD驱动全部删除。能一键(一个宏定义)删除吗?删除后要改多少地方才能编译通过?
2 有一个新产品,收银设备。系统有两个LCD,一个叫做主显示,收银员用;一个叫顾显,顾客看金额。怎么办?这些例程代码要怎么改才能支持两个屏幕?复制一套然后改函数名称?这样确实能完成任务,只不过程序从此就进入恶性循环了。
3 一个OLED,原来接在这些IO,后来改到别的IO,容易改吗?
4 原来只是支持中文,现在要卖到南美,要支持多米尼加语言,好改吗?
LCD种类概述
TFT lcd
COG lcd
COG是Chip On Glass的缩写,就是驱动芯片直接绑定在玻璃上,透明的。
OLED lcd
硬件场景
预备知识
面向对象
u8 ledsta = 0;void ledset(u8 sta)
{
}
/*定义一个结构体,将LED这个对象的属性跟方法封装。这个结构体就是一个对象。
但是这个不是一个真实的存在,而是一个对象的抽象。*/
typedef struct{
u8 sta;
void (*setsta)(u8 sta);
}LedObj;
/*
声明一个LED对象,名称叫做LED1,
并且实现它的方法drv_led1_setsta
*/
void drv_led1_setsta(u8 sta)
{
}
LedObj LED1={
.sta = 0,
.setsta = drv_led1_setsta,
};
/*
声明一个LED对象,名称叫做LED2,
并且实现它的方法drv_led2_setsta*/
void drv_led2_setsta(u8 sta)
{
}
LedObj LED2={
.sta = 0,
.setsta = drv_led2_setsta,
};
/*
操作LED的函数,参数指定哪个led*/
void ledset(LedObj *led, u8 sta)
{
led->setsta(sta);
}
抛砖引玉,很多地方不正确,但是不想展开,大家自己搜索资料学习。
驱动与设备分离
如果要深入了解驱动与设备分离,请看LINUX驱动的书籍。
驱动IC是STR7565
128*64像素
用SPI3
背光用PF5
命令线用PF4
复位脚用PF3
2 有一个新产品,收银设备,系统有两个LCD,一个叫做主显示,收银员用,一个叫顾显,顾客看金额使用。怎么办?这些例程代码要怎么改才能支持两个屏幕?复制一套然后改函数名称?这样确实能完成任务,只不过程序从此就进入恶性循环了。
在驱动程序接口中增加设备参数,驱动用到的所有资源从设备参数传入。
模块化
LCD到底是什么
1 首先,需要一个像是汉字的接口,APP调用这个接口就可以显示汉字了。假设接口叫做lcd_display_hz。
2 汉字从哪来?从点阵字库来,所以在lcd_display_hz函数内就要调用一个叫做find_font的函数获取点阵。
3 获取点阵后要将点阵显示到LCD上,那么我们调用一个ILL9341_dis的接口,将点阵刷新到驱动IC型号为ILI9341的LCD上。
4 ILI9341_dis怎么将点阵显示上去?调用一个8080_WRITE的接口。
1 LCD可以一个点一个点显示内容。
2 要LCD显示汉字或图片-----转化后就是显示一堆点
3 APP想要LCD显示图片或问题。
/* LCD驱动定义*/
typedef struct
{
u16 id;
s32 (*init)(DevLcd *lcd);
s32 (*draw_point)(DevLcd *lcd, u16 x, u16 y, u16 color);
s32 (*color_fill)(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey, u16 color);
s32 (*fill)(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey,u16 *color);
s32 (*onoff)(DevLcd *lcd, u8 sta);
s32 (*prepare_display)(DevLcd *lcd, u16 sx, u16 ex, u16 sy, u16 ey);
void (*set_dir)(DevLcd *lcd, u8 scan_dir);
void (*backlight)(DevLcd *lcd, u8 sta);
}_lcd_drv;
1 id,驱动型号
2 初始化
3 画点
4 将一片区域的点显示某种颜色
5 将一片区域的点显示某些颜色
6 显示开关
7 准备刷新区域(主要彩屏直接DMA刷屏使用)
8 设置扫描方向
9 背光控制
LCD驱动框架
由于嵌入式实际没那么复杂,在例程中我们将GUI跟LCD驱动层放到一起。
TFT LCD的两个驱动也放到一个文件,但是逻辑是分开的。
OLED除初始化,其他接口跟COG LCD基本一样,因此这两个驱动也放在一个文件。
代码分析
GUI和LCD层
/* 各种LCD的规格参数*/
_lcd_pra LCD_IIL9341 =
{
.id = 0x9341,
.width = 240, //LCD 宽度
.height = 320, //LCD 高度
};
...
/*各种LCD列表*/
_lcd_pra *LcdPraList[5=
{
&LCD_IIL9341,
&LCD_IIL9325,
&LCD_R61408,
&LCD_Cog12864,
&LCD_Oled12864,
};
/* 所有驱动列表 驱动列表*/
_lcd_drv *LcdDrvList[ = {
&TftLcdILI9341Drv,
&TftLcdILI9325Drv,
&CogLcdST7565Drv,
&OledLcdSSD1615rv,
/*设备树定义*/
#define DEV_LCD_C 3//系统存在3个LCD设备
LcdObj LcdObjList[DEV_LCD_C={
{"oledlcd", LCD_BUS_VSPI, 0X1315},
{"coglcd", LCD_BUS_SPI, 0X7565},
{"tftlcd", LCD_BUS_8080, NULL},
};
void dev_lcd_setdir(DevLcd *obj, u8 dir, u8 scan_dir)
s32 dev_lcd_init(void)
DevLcd *dev_lcd_open(char *name)
s32 dev_lcd_close(DevLcd *dev)
s32 dev_lcd_drawpoint(DevLcd *lcd, u16 x, u16 y, u16 color)
s32 dev_lcd_prepare_display(DevLcd *lcd, u16 sx, u16 ex, u16 sy, u16 ey)
s32 dev_lcd_display_onoff(DevLcd *lcd, u8 sta)
s32 dev_lcd_fill(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey,u16 *color)
s32 dev_lcd_color_fill(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey,u16 color)
s32 dev_lcd_backlight(DevLcd *lcd, u8 sta)
s32 dev_lcd_put_string(DevLcd *lcd, FontType font, int x, int y, char *s, unsigned colidx)
驱动IC层
_lcd_drv CogLcdST7565Drv = {
.id = 0X7565,
.init = drv_ST7565_init,
.draw_point = drv_ST7565_drawpoint,
.color_fill = drv_ST7565_color_fill,
.fill = drv_ST7565_fill,
.onoff = drv_ST7565_display_onoff,
.prepare_display = drv_ST7565_prepare_display,
.set_dir = drv_ST7565_scan_dir,
.backlight = drv_ST7565_lcd_bl
};
接口层
extern s32 mcu_spi_init(void);
extern s32 mcu_spi_open(SPI_DEV dev, SPI_MODE mode, u16 pre);
extern s32 mcu_spi_close(SPI_DEV dev);
extern s32 mcu_spi_transfer(SPI_DEV dev, u8 *snd, u8 *rsv, s32 len);
extern s32 mcu_spi_cs(SPI_DEV dev, u8 sta);
总体流程
/* 初始化的时候会根据设备数定义,
并且匹配驱动跟参数,并初始化变量。
打开的时候只是获取了一个指针*/
struct _strDevLcd{
s32 gd;//句柄,控制是否可以打开
LcdObj *dev;
/* LCD参数,固定,不可变*/
_lcd_pra *pra;
/* LCD驱动 */
_lcd_drv *drv;
/*驱动需要的变量*/
u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
u8 scandir;//扫描方向
u16 width; //LCD 宽度
u16 height; //LCD 高度
void *pri;//私有数据,黑白屏跟OLED屏在初始化的时候会开辟显存
};
typedef struct{
char *name;//设备名字
LcdBusType bus;//挂在那条LCD总线上
u16 id;
}LcdObj;
typedef struct{
u16 id;
u16 width; //LCD 宽度 竖屏
u16 height; //LCD 高度 竖屏
}_lcd_pra;
typedef struct {
u16 id;
s32 (*init)(DevLcd *lcd);
s32 (*draw_point)(DevLcd *lcd, u16 x, u16 y, u16 color);
s32 (*color_fill)(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey, u16 color);
s32 (*fill)(DevLcd *lcd, u16 sx,u16 ex,u16 sy,u16 ey,u16 *color);
s32 (*prepare_display)(DevLcd *lcd, u16 sx, u16 ex, u16 sy, u16 ey);
s32 (*onoff)(DevLcd *lcd, u8 sta);
void (*set_dir)(DevLcd *lcd, u8 scan_dir);
void (*backlight)(DevLcd *lcd, u8 sta);
}_lcd_drv;
1 初始化,根据设备树,找到驱动跟参数,然后初始化上面说的结构体。
2 要使用LCD前,调用dev_lcd_open函数。打开成功就返回一个上面的结构体指针。
3 显示字符,接口找到点阵后,通过上面结构体的drv,调用对应的驱动程序。
4 驱动程序根据这个结构体,决定操作哪个LCD总线,并且使用这个结构体的变量。
用法和好处
void dev_lcd_test(void)
{
DevLcd *LcdCog;
DevLcd *LcdOled;
DevLcd *LcdTft;
/* 打开三个设备 */
LcdCog = dev_lcd_open("coglcd");
if(LcdCog==NULL)
uart_printf("open cog lcd err\r\n");
LcdOled = dev_lcd_open("oledlcd");
if(LcdOled==NULL)
uart_printf("open oled lcd err\r\n");
LcdTft = dev_lcd_open("tftlcd");
if(LcdTft==NULL)
uart_printf("open tft lcd err\r\n");
/*打开背光*/
dev_lcd_backlight(LcdCog, 1);
dev_lcd_backlight(LcdOled, 1);
dev_lcd_backlight(LcdTft, 1);
dev_lcd_put_string(LcdOled, FONT_SONGTI_1212, 10,1, "ABC-abc,", BLACK);
dev_lcd_put_string(LcdOled, FONT_SIYUAN_1616, 1, 13, "这是oled lcd", BLACK);
dev_lcd_put_string(LcdOled, FONT_SONGTI_1212, 10,30, "www.wujique.com", BLACK);
dev_lcd_put_string(LcdOled, FONT_SIYUAN_1616, 1, 47, "屋脊雀工作室", BLACK);
dev_lcd_put_string(LcdCog, FONT_SONGTI_1212, 10,1, "ABC-abc,", BLACK);
dev_lcd_put_string(LcdCog, FONT_SIYUAN_1616, 1, 13, "这是cog lcd", BLACK);
dev_lcd_put_string(LcdCog, FONT_SONGTI_1212, 10,30, "www.wujique.com", BLACK);
dev_lcd_put_string(LcdCog, FONT_SIYUAN_1616, 1, 47, "屋脊雀工作室", BLACK);
dev_lcd_put_string(LcdTft, FONT_SONGTI_1212, 20,30, "ABC-abc,", RED);
dev_lcd_put_string(LcdTft, FONT_SIYUAN_1616, 20,60, "这是tft lcd", RED);
dev_lcd_put_string(LcdTft, FONT_SONGTI_1212, 20,100, "www.wujique.com", RED);
dev_lcd_put_string(LcdTft, FONT_SIYUAN_1616, 20,150, "屋脊雀工作室", RED); while(1);}
LcdObj LcdObjList[DEV_LCD_C={
{"oledlcd", LCD_BUS_VSPI, 0X1315},
{"coglcd", LCD_BUS_SPI, 0X7565},
{"tftlcd", LCD_BUS_8080, NULL},
};
LcdObj LcdObjList[DEV_LCD_C={
{"oledlcd", LCD_BUS_SPI, 0X1315},
{"tftlcd", LCD_BUS_8080, NULL},
};
字库
声明
LCD驱动应该怎么写?–基于stm32F407 [复制链接]
标签:消息 and 记录 应该 bind 包含 删除 酷炫 匹配
原文地址:https://www.cnblogs.com/tianqiang/p/9315716.html