HAL库--LCD实验

屏幕这一块没什么搞头,直接用迪文屏 文章只起个记录作用

显示器分类

LCD简介

Liquid Crystal Display,即液晶显示器,由:玻璃基板、背光、驱动IC等组成。全彩LCD,是一种全彩显示屏(RGB565、RGB888),可以显示各种颜色。

LCD基本组成:

一个像素点有RGB三种色来表示。

LCD接口分类:

MCU屏接口由于自带SRAM,驱动简单,大部分单片机都能驱动!

一眼看过去排针多的基本上都是MCU接口的屏

LCD驱动原理

LCD屏(MCU接口)驱动的核心是:LCD驱动芯片 --- ILI9341

LCD驱动基本知识:

1,8080时序,LCD驱动芯片一般使用8080时序控制,实现数据写入/读取

2,初始化序列(数组),屏厂提供,用于初始化特定屏幕,不同屏幕厂家不完全相同!

3,画点函数、读点函数(非必需),基于这两个函数可以实现各种绘图功能!

LCD驱动的一般过程:

8080时序简介:

并口总线时序,常用于MCU屏驱动IC的访问,由Intel提出,也叫英特尔总线
8080时序信号说明
8080写时序
8080读时序

cpp 复制代码
/*8080时序简化写代码*/
void lcd_wr_data(uint16_t data)
{
    	LCD_RS(0);		/* 操作数据 */
    	LCD_CS(0);		/* 选中 */
    	LCD_DATA_OUT(data);	/* 数据 */
    	LCD_WR(0);		/* WR低电平 */
    	LCD_WR(1);		/* WR高电平 */
    	LCD_CS(1);		/* 释放片选 */
}
cpp 复制代码
/*8080简化读代码*/
uint16_t  lcd_rd_data(void)
{
	uint16_t ram;  			/* 定义变量 */
 	LCD_RS(1);              		/* 操作数据 */
    	LCD_CS(0);			/* 选中 */
    	LCD_RD(0);			/* RD低电平 */
   	ram = LCD_DATA_IN;    	/* 读取数据 */ 这个宏其实就是操作IDR寄存器
    	LCD_RD(1);			/* RD高电平 */
    	LCD_CS(1);			/* 释放片选 */
	return ram;			/* 返回读数 */
}

LCD驱动芯片简介

LCD驱动芯片用于控制LCD的各种显示功能和效果,整体功能复杂。常见型号:ILI9341/ST7789等

一般我们只需要:6条指令即可完成对LCD的基本使用(以9341为例)

|------------------|--------|---------------------------------|
| 指令 (HEX) | 名称 | 作用 |
| 0XD3 | 读ID | 用于读取LCD控制器的ID,区分型号用 |
| 0X36 | 访问控制 | 设置GRAM读写方向,控制显示方向(从左往右上到下还是右往左) |
| 0X2A | 列地址 | 一般用于设置X坐标 |
| 0X2B | 页地址 | 一般用于设置Y坐标 |
| 0X2C | 写GRAM | 用于往LCD写GRAM数据 |
| 0X2E | 读GRAM | 用于读取LCD的GRAM数据 |

读ID指令(0XD3)

读取LCD控制器型号,通过型号可以执行不同LCD初始化序列,以兼容不同LCD

|--------------|----|----|----|---------|----|----|----|----|----|----|----|----|---------|
| 顺序 | 控制 ||| 各位描述 ||||||||| HEX |
| 顺序 | RS | RD | WR | D15~D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | HEX |
| 指令 | 0 | 1 | ↑ | XX | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | D3H |
| 参数 1 | 1 | ↑ | 1 | XX | X | X | X | X | X | X | X | X | X |
| 参数 2 | 1 | ↑ | 1 | XX | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 00H |
| 参数 3 | 1 | ↑ | 1 | XX | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 93H |
| 参数 4 | 1 | ↑ | 1 | XX | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 41H |

参数一是一个假读,不需要关心读到的是什么

访问控制指令(0x36)

实现GRAM读写方向控制,即:控制GRAM自增方向,从而控制显示方向

MX,MY,MV:共同控制GRAM自增方向(扫描方向) BGR位:可以控制RGB、BGR顺序

MX、MY、MV扫描方向控制关系:

|--------|--------|--------|---------------------------------------------|
| 控制位 ||| 效果 LCD 扫描方向( GRAM 自增方式) |
| MY | MX | MV | 效果 LCD 扫描方向( GRAM 自增方式) |
| 0 | 0 | 0 | 从左到右, 从上到下 |
| 1 | 0 | 0 | 从左到右, 从下到上 |
| 0 | 1 | 0 | 从右到左, 从上到下 |
| 1 | 1 | 0 | 从右到左, 从下到上 |
| 0 | 0 | 1 | 从上到下, 从左到右 |
| 0 | 1 | 1 | 从上到下, 从右到左 |
| 1 | 0 | 1 | 从下到上, 从左到右 |
| 1 | 1 | 1 | 从下到上, 从右到左 |

X坐标设置指令(0X2A)

列地址设置指令,一般用于设置X坐标(其实就是窗口大小)

SC:起始坐标 设置关系:0≤SC≤EC≤239(LCD像素宽度)

EC:结束坐标

Y坐标设置指令(0X2B)

页地址设置指令,一般用于设置Y坐标(其实就是窗口大小)

SP:起始坐标 设置关系:0≤SP≤EP≤319(LCD像素高度)

EP:结束坐标

写GRAM指令(0X2C)

发送该指令后,数据线变成16位,可以开始写入GRAM数据,支持地址自增

|--------------|----|----|----|---------|----|----|----|----|----|----|----|----|---------|
| 顺序 | 控制 ||| 各位描述 ||||||||| HEX |
| 顺序 | RS | RD | WR | D15~D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | HEX |
| 指令 | 0 | 1 | ↑ | XX | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 2CH |
| 参数 1 | 1 | 1 | ↑ | D1[15:0] ||||||||| XX |
| ...... | 1 | 1 | ↑ | D2[15:0] ||||||||| XX |
| 参数 N | 1 | 1 | ↑ | Dn[15:0] ||||||||| XX |

每次写入1个像素点的颜色值(RGB565),地址自增方向由MX/MY/MV控制 无需重新设置坐标,可实现连续写入,大大提高写入速度

读GRAM指令(0X2E)

发送该指令后,数据线变成16位,可以开始读取GRAM数据,支持地址自增

读1个点的颜色,要读3次

1,dummy 假读

2,R1G1 //读该点的R1和G1

3,B1R2 //读该点的B1和下个点的R2 这样设计连读时一个点3次,两个点4次,效率就高了

cpp 复制代码
uint16_t r, g, b;
r = lcd_rd_data(); //读r1
g = lcd_rd_data(); //读g1
b  = lcd_rd_data();//读b1

g = r & 0XFF;
return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11)); //获取包含RGB值的16位
cpp 复制代码
/*驱动芯片读数据操作*/
uint16_t  lcd_rd_data(void)
{
	uint16_t ram;  		/* 定义变量 */
	DATA_IN_MODE();	/* 设置数据输入 */
 	LCD_RS(1);              	/* 操作数据 */
    	LCD_CS(0);			/* 选中 */
    	LCD_RD(0);		/* RD低电平 */
   	ram = LCD_DATA_IN;    	/* 读取数据 */
    	LCD_RD(1);		/* RD高电平 */
    	LCD_CS(1);			/* 释放片选 */
	DATA_OUT_MODE();	/* 设置数据输出 */
	return ram;		/* 返回读数 */
}
/*读点函数代码精简*/
uint16_t  lcd_read_point (uint16_t x, uint16_t y)
{
	uint16_t r = 0, g = 0, b = 0;	/* 定义变量 */
	lcd_set_cursor(x, y);		/* 设置坐标 其实就是2a/2b指令*/
 	lcd_wr_regno(0X2E);		/* 发读点命令 */
 	r = lcd_rd_data();  		/* 假读 */
	r = lcd_rd_data();  		/* 读rg */
	b = lcd_rd_data(); 		/* 读b */
    	g = r & 0XFF;       			/* 得到g值 */
	return (((r >> 11) << 11) | ((g >> 2) << 5) | (b >> 11));
    //移位得到含RGB565三色的16位值
}

LCD基本驱动步骤

目标:用最简单代码,点亮开发板LCD屏,实现任意位置画点和读点

1,确定IO连接关系 LCD模块原理图、开发板液晶接口原理图

2,初始化IO口 初始化连接LCD的各个IO口

初始化FSMC外设 可选,某些芯片是没有FSMC外设,MINI板是没有的

3,编写读写接口函数 lcd_wr_data、lcd_wr_regno、lcd_write_reg、lcd_rd_data

4,编写LCD初始化函数 编写lcd_init函数,完成初始化序列配置,点亮背光等

5,编写LCD画和读点函数 编写lcd_draw_point函数,实现LCD任意位置画点

IO硬件连接关系查表看原理图

LCD控制结构体

cpp 复制代码
/* LCD重要参数集 */
typedef struct
{
    uint16_t 	width;     		/* LCD 宽度 */
    uint16_t 	height;    		/* LCD 高度 */
    uint16_t 	id;        		/* LCD ID */
    uint8_t 	dir;        /* 横屏还是竖屏控制:0,竖屏;1,横屏 */
    uint16_t 	wramcmd;   	/* 开始写gram指令 */
    uint16_t 	setxcmd;   	/* 设置x坐标指令 */
    uint16_t 	setycmd;  	/* 设置y坐标指令 */
} _lcd_dev;

编程实战1

1,使用8080时序在LCD上实现任意位置画点和读点

2,在LCD屏幕上能支持12*12、16*16、24*24、32*32大小的ASCII字符显示

任意字符显示的关键是要制作字库,有了字库就能实现任意字符显示

1,字库制作

根据字体大小(12/16/24/32),制作对应的字库

2,编写任意字符显示函数

根据字库生成方式,编写对应的字符显示函数

相关推荐
scan11 小时前
单片机串口接收状态机STM32
stm32·单片机·串口·51·串口接收
Mortal_hhh3 小时前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器
Mr.谢尔比4 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie4 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
鹿屿二向箔4 小时前
STM32外设之SPI的介绍
stm32
西瓜籽@5 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
极客小张8 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
m0_7393128711 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
嵌入式小章11 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
徐嵌12 小时前
STM32项目---水质水位检测
stm32·单片机·嵌入式硬件