使用的是正点原子的精英版,单片机是STM32F103ZET6,使用开发板的 MCU 屏接口连接正点原子 TFTLCD 模块(仅限 MCU 屏模块),实现 TFTLCD 模块的显示。通过把 LCD 模块插入底板上的 TFTLCD 模块接口,按下复位之后, 就可以看到 LCD 模块不停的显示一些信息并不断切换底色。同时该实验会显示 LCD 驱动器 的 ID,并且会在串口打印(按复位一次,打印一次)。LED0 闪烁用于提示程序正在运行。
首先来介绍一下这个TFTLCD屏,













了解完之后我们直接复制之前做过的USART的代码改名为14_TFTLCD,打开图形化配置,
接 着 双 击 13_TFTLCD.ioc 进 入 STM32CubeMX 插 件 配 置 界 面 后 , 在 Pinout & Configuration 处,配置 LCD 的背光引脚 PB0,如下图所示:

这个不属于 FSMC 的内容,如果下载程序后屏幕亮不起来那么八成是这里出问题了。
配置
FSMC
参数
接着,在
Connectivity
→
FSMC
中配置
FSMC
的参数:
⚫
NOR Flash/PSRAM/SRAM/ROM/LCD 1
,这里选择这个代表我们使用的是
STM32
的
FSMC
存储块
1
(
Bank1
);
⚫
Chip Select
,我们这里选择
NE4
,代表是
Bank1
的第四区,这部分是根据原理图的
映射管脚进行选择的,这里选择不同区对应的引脚是不同的;
⚫
Memory type
,存储类型,这里我们驱动的是
LCD
设备,所以选择
LCD
接口。该
选项还有其它类型的存储设备,感兴趣可自行了解;
⚫
LCD Register Select
,这里是选择
RS
脚,也就是命令
/
数据选择位,同样是根据原
理图得知这里应该选择
A10
;
⚫
Data
,数据位,我们的
TFTLCD
使用的是
16
位数据宽度,所以这里选择
16bits
就
好。
接着来到
FSMC
的参数配置,如下图所示:

这里需要使能读写不同的时序,也就是使能
Write operation
和
Extended mode
;接着由上
往下介绍这些参数,分别是:
⚫
Address setup time in HCLK clock cycles
:地址建立的时钟周期
⚫
Data setup time in HCLK clock cycles
:数据建立的时钟周期
⚫ Bus turn around time in HCLK clock cycles:总线转阶段持续时间;
⚫
Extended address setup time
:扩展地址建立时间;
⚫
Extended data setup time
:扩展数据建立时间;
⚫
Extended bus turn around time
:扩展总线建立时间;
⚫
Access mode
和
Extended access mode
代表的读写时序控制模式,我们选择模式
A
代
表支持独立的读写时序控制;
上述参数中,扩展属于写时序,其他的属于读时序。这些参数设置,是根据
LCD
芯片
手册中的驱动时序填写的,不同的芯片需要根据不同的手册进行计算,但计算的方法都是一
样的。
配置好之后,按下键盘的
“Ctrl+S”
组合键保存
13_TFTLCD.ioc
文件,系统开始生成初始
化代码。然后接着我们在
Drivers/BSP
文件夹中,新建
LCD
文件夹,然后再
LCD
文件夹下新
建
4
个文件,分别是
lcd.c
和
lcd.h
、
lcd_ex.c
和
lcdfont.h
文件,如下图所示:

lcd.c
和
lcd.h
文件是驱动函数和引脚接口宏定义以及函数声明等。
lcd_ex.c
存放各个
LCD
驱动
IC
的寄存器初始化部分代码,是
lcd.c
文件的补充文件,起到简化
lcd.c
文件的作用。
lcdfont.h
头文件存放了
4
种字体大小不一样的
ASCII
字符集(
12*12
、
16*16
、
24*24
和
32*32
)。这个跟
oledfont.h
头文件一样的,只是这里多了
32*32
的
ASCII
字符集。
接下来我把这四个代码放在下面:
lcd.c
#include "stdlib.h"
#include "lcd.h"
#include "lcdfont.h"
#include "usart.h"
#include "../../SYSTEM/delay/delay.h"
/* lcd_ex.c存放各个LCD驱动IC的寄存器初始化部分代码,以简化lcd.c,该.c文件
* 不直接加入到工程里面,只有lcd.c会用到,所以通过include的形式添加.(不要在
* 其他文件再包含该.c文件!!否则会报错!)
*/
#include "lcd_ex.c"
SRAM_HandleTypeDef g_sram_handle; /* SRAM句柄(用于控制LCD) */
/* LCD的画笔颜色和背景色 */
uint32_t g_point_color = 0XF800; /* 画笔颜色 */
uint32_t g_back_color = 0XFFFF; /* 背景色 */
/* 管理LCD重要参数 */
_lcd_dev lcddev;
/**
* @brief LCD写数据
* @param data: 要写入的数据
* @retval 无
*/
void lcd_wr_data(volatile uint16_t data)
{
data = data; /* 使用-O2优化的时候,必须插入的延时 */
LCD->LCD_RAM = data;
}
/**
* @brief LCD写寄存器编号/地址函数
* @param regno: 寄存器编号/地址
* @retval 无
*/
void lcd_wr_regno(volatile uint16_t regno)
{
regno = regno; /* 使用-O2优化的时候,必须插入的延时 */
LCD->LCD_REG = regno; /* 写入要写的寄存器序号 */
}
/**
* @brief LCD写寄存器
* @param regno:寄存器编号/地址
* @param data:要写入的数据
* @retval 无
*/
void lcd_write_reg(uint16_t regno, uint16_t data)
{
LCD->LCD_REG = regno; /* 写入要写的寄存器序号 */
LCD->LCD_RAM = data; /* 写入数据 */
}
/**
* @brief LCD延时函数,仅用于部分在mdk -O1时间优化时需要设置的地方
* @param t:延时的数值
* @retval 无
*/
static void lcd_opt_delay(uint32_t i)
{
while (i--);
}
/**
* @brief LCD读数据
* @param 无
* @retval 读取到的数据
*/
static uint16_t lcd_rd_data(void)
{
volatile uint16_t ram; /* 防止被优化 */
lcd_opt_delay(2);
ram = LCD->LCD_RAM;
return ram;
}
/**
* @brief 准备写GRAM
* @param 无
* @retval 无
*/
void lcd_write_ram_prepare(void)
{
LCD->LCD_REG = lcddev.wramcmd;
}
/**
* @brief 读取个某点的颜色值
* @param x,y:坐标
* @retval 此点的颜色(32位颜色,方便兼容LTDC)
*/
uint32_t lcd_read_point(uint16_t x, uint16_t y)
{
uint16_t r = 0, g = 0, b = 0;
if (x >= lcddev.width || y >= lcddev.height)return 0; /* 超过了范围,直接返回 */
lcd_set_cursor(x, y); /* 设置坐标 */
if (lcddev.id == 0X5510)
{
lcd_wr_regno(0X2E00); /* 5510 发送读GRAM指令 */
}
else
{
lcd_wr_regno(0X2E); /* 9341/5310/1963/7789/7796/9806 等发送读GRAM指令 */
}
r = lcd_rd_data(); /* 假读(dummy read) */
if (lcddev.id == 0x1963)
{
return r; /* 1963直接读就可以 */
}
r = lcd_rd_data(); /* 实际坐标颜色 */
if (lcddev.id == 0x7796) /* 7796 一次读取一个像素值 */
{
return r;
}
/* ILI9341/NT35310/NT35510/ST7789/ILI9806 要分2次读出 */
b = lcd_rd_data();
g = r & 0XFF; /* 对于 9341/5310/5510/7789/9806, 第一次读取的是RG的值,R在前,G在后,各占8位 */
g <<= 8;
return (((r >> 11) << 11) | ((g >> 10) << 5) | (b >> 11)); /* 9341/5310/5510/7789/9806 需要公式转换一下 */
}
/**
* @brief LCD开启显示
* @param 无
* @retval 无
*/
void lcd_display_on(void)
{
if (lcddev.id == 0X5510)
{
lcd_wr_regno(0X2900); /* 开启显示 */
}
else /* 9341/5310/1963/7789/7796/9806 等发送开启显示指令 */
{
lcd_wr_regno(0X29); /* 开启显示 */
}
}
/**
* @brief LCD关闭显示
* @param 无
* @retval 无
*/
void lcd_display_off(void)
{
if (lcddev.id == 0X5510)
{
lcd_wr_regno(0X2800); /* 关闭显示 */
}
else /* 9341/5310/1963/7789/7796/9806 等发送关闭显示指令 */
{
lcd_wr_regno(0X28); /* 关闭显示 */
}
}
/**
* @brief 设置光标位置(对RGB屏无效)
* @param x,y: 坐标
* @retval 无
*/
void lcd_set_cursor(uint16_t x, uint16_t y)
{
if (lcddev.id == 0X1963)
{
if (lcddev.dir == 0) /* 竖屏模式, x坐标需要变换 */
{
x = lcddev.width - 1 - x;
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(0);
lcd_wr_data(0);
lcd_wr_data(x >> 8);
lcd_wr_data(x & 0XFF);
}
else /* 横屏模式 */
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(x >> 8);
lcd_wr_data(x & 0XFF);
lcd_wr_data((lcddev.width - 1) >> 8);
lcd_wr_data((lcddev.width - 1) & 0XFF);
}
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(y >> 8);
lcd_wr_data(y & 0XFF);
lcd_wr_data((lcddev.height - 1) >> 8);
lcd_wr_data((lcddev.height - 1) & 0XFF);
}
else if (lcddev.id == 0X5510)
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(x >> 8);
lcd_wr_regno(lcddev.setxcmd + 1);
lcd_wr_data(x & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(y >> 8);
lcd_wr_regno(lcddev.setycmd + 1);
lcd_wr_data(y & 0XFF);
}
else /* 9341/5310/7789/7796/9806 等 设置坐标 */
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(x >> 8);
lcd_wr_data(x & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(y >> 8);
lcd_wr_data(y & 0XFF);
}
}
/**
* @brief 设置LCD的自动扫描方向(对RGB屏无效)
* @note
* 9341/5310/5510/1963/7789/7796/9806等IC已经实际测试
* 注意:其他函数可能会受到此函数设置的影响(尤其是9341),
* 所以,一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
*
* @param dir:0~7,代表8个方向(具体定义见lcd.h)
* @retval 无
*/
void lcd_scan_dir(uint8_t dir)
{
uint16_t regval = 0;
uint16_t dirreg = 0;
uint16_t temp;
/* 横屏时,对1963不改变扫描方向, 其他IC改变扫描方向!竖屏时1963改变方向, 其他IC不改变扫描方向 */
if ((lcddev.dir == 1 && lcddev.id != 0X1963) || (lcddev.dir == 0 && lcddev.id == 0X1963))
{
switch (dir) /* 方向转换 */
{
case 0:
dir = 6;
break;
case 1:
dir = 7;
break;
case 2:
dir = 4;
break;
case 3:
dir = 5;
break;
case 4:
dir = 1;
break;
case 5:
dir = 0;
break;
case 6:
dir = 3;
break;
case 7:
dir = 2;
break;
}
}
/* 根据扫描方式 设置 0X36/0X3600 寄存器 bit 5,6,7 位的值 */
switch (dir)
{
case L2R_U2D:/* 从左到右,从上到下 */
regval |= (0 << 7) | (0 << 6) | (0 << 5);
break;
case L2R_D2U:/* 从左到右,从下到上 */
regval |= (1 << 7) | (0 << 6) | (0 << 5);
break;
case R2L_U2D:/* 从右到左,从上到下 */
regval |= (0 << 7) | (1 << 6) | (0 << 5);
break;
case R2L_D2U:/* 从右到左,从下到上 */
regval |= (1 << 7) | (1 << 6) | (0 << 5);
break;
case U2D_L2R:/* 从上到下,从左到右 */
regval |= (0 << 7) | (0 << 6) | (1 << 5);
break;
case U2D_R2L:/* 从上到下,从右到左 */
regval |= (0 << 7) | (1 << 6) | (1 << 5);
break;
case D2U_L2R:/* 从下到上,从左到右 */
regval |= (1 << 7) | (0 << 6) | (1 << 5);
break;
case D2U_R2L:/* 从下到上,从右到左 */
regval |= (1 << 7) | (1 << 6) | (1 << 5);
break;
}
dirreg = 0X36; /* 对绝大部分驱动IC, 由0X36寄存器控制 */
if (lcddev.id == 0X5510)
{
dirreg = 0X3600; /* 对于5510, 和其他驱动ic的寄存器有差异 */
}
/* 9341 & 7789 & 7796 要设置BGR位 */
if (lcddev.id == 0X9341 || lcddev.id == 0X7789 || lcddev.id == 0x7796)
{
regval |= 0X08;
}
lcd_write_reg(dirreg, regval);
if (lcddev.id != 0X1963) /* 1963不做坐标处理 */
{
if (regval & 0X20)
{
if (lcddev.width < lcddev.height) /* 交换X,Y */
{
temp = lcddev.width;
lcddev.width = lcddev.height;
lcddev.height = temp;
}
}
else
{
if (lcddev.width > lcddev.height) /* 交换X,Y */
{
temp = lcddev.width;
lcddev.width = lcddev.height;
lcddev.height = temp;
}
}
}
/* 设置显示区域(开窗)大小 */
if (lcddev.id == 0X5510)
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(0);
lcd_wr_regno(lcddev.setxcmd + 1);
lcd_wr_data(0);
lcd_wr_regno(lcddev.setxcmd + 2);
lcd_wr_data((lcddev.width - 1) >> 8);
lcd_wr_regno(lcddev.setxcmd + 3);
lcd_wr_data((lcddev.width - 1) & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(0);
lcd_wr_regno(lcddev.setycmd + 1);
lcd_wr_data(0);
lcd_wr_regno(lcddev.setycmd + 2);
lcd_wr_data((lcddev.height - 1) >> 8);
lcd_wr_regno(lcddev.setycmd + 3);
lcd_wr_data((lcddev.height - 1) & 0XFF);
}
else
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(0);
lcd_wr_data(0);
lcd_wr_data((lcddev.width - 1) >> 8);
lcd_wr_data((lcddev.width - 1) & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(0);
lcd_wr_data(0);
lcd_wr_data((lcddev.height - 1) >> 8);
lcd_wr_data((lcddev.height - 1) & 0XFF);
}
}
/**
* @brief 画点
* @param x,y: 坐标
* @param color: 点的颜色(32位颜色,方便兼容LTDC)
* @retval 无
*/
void lcd_draw_point(uint16_t x, uint16_t y, uint32_t color)
{
lcd_set_cursor(x, y); /* 设置光标位置 */
lcd_write_ram_prepare(); /* 开始写入GRAM */
LCD->LCD_RAM = color;
}
/**
* @brief SSD1963背光亮度设置函数
* @param pwm: 背光等级,0~100.越大越亮.
* @retval 无
*/
void lcd_ssd_backlight_set(uint8_t pwm)
{
lcd_wr_regno(0xBE); /* 配置PWM输出 */
lcd_wr_data(0x05); /* 1设置PWM频率 */
lcd_wr_data(pwm * 2.55); /* 2设置PWM占空比 */
lcd_wr_data(0x01); /* 3设置C */
lcd_wr_data(0xFF); /* 4设置D */
lcd_wr_data(0x00); /* 5设置E */
lcd_wr_data(0x00); /* 6设置F */
}
/**
* @brief 设置LCD显示方向
* @param dir:0,竖屏; 1,横屏
* @retval 无
*/
void lcd_display_dir(uint8_t dir)
{
lcddev.dir = dir; /* 竖屏/横屏 */
if (dir == 0) /* 竖屏 */
{
lcddev.width = 240;
lcddev.height = 320;
if (lcddev.id == 0x5510)
{
lcddev.wramcmd = 0X2C00;
lcddev.setxcmd = 0X2A00;
lcddev.setycmd = 0X2B00;
lcddev.width = 480;
lcddev.height = 800;
}
else if (lcddev.id == 0X1963)
{
lcddev.wramcmd = 0X2C; /* 设置写入GRAM的指令 */
lcddev.setxcmd = 0X2B; /* 设置写X坐标指令 */
lcddev.setycmd = 0X2A; /* 设置写Y坐标指令 */
lcddev.width = 480; /* 设置宽度480 */
lcddev.height = 800; /* 设置高度800 */
}
else /* 其他IC, 包括: 9341 / 5310 / 7789 / 7796 / 9806 等IC */
{
lcddev.wramcmd = 0X2C;
lcddev.setxcmd = 0X2A;
lcddev.setycmd = 0X2B;
}
if (lcddev.id == 0X5310 || lcddev.id == 0x7796) /* 如果是5310/7796 则表示是 320*480分辨率 */
{
lcddev.width = 320;
lcddev.height = 480;
}
if (lcddev.id == 0X9806) /* 如果是9806 则表示是 480*800 分辨率 */
{
lcddev.width = 480;
lcddev.height = 800;
}
}
else /* 横屏 */
{
lcddev.width = 320; /* 默认宽度 */
lcddev.height = 240; /* 默认高度 */
if (lcddev.id == 0x5510)
{
lcddev.wramcmd = 0X2C00;
lcddev.setxcmd = 0X2A00;
lcddev.setycmd = 0X2B00;
lcddev.width = 800;
lcddev.height = 480;
}
else if (lcddev.id == 0X1963 || lcddev.id == 0x9806)
{
lcddev.wramcmd = 0X2C; /* 设置写入GRAM的指令 */
lcddev.setxcmd = 0X2A; /* 设置写X坐标指令 */
lcddev.setycmd = 0X2B; /* 设置写Y坐标指令 */
lcddev.width = 800; /* 设置宽度800 */
lcddev.height = 480; /* 设置高度480 */
}
else /* 其他IC, 包括: 9341 / 5310 / 7789 / 7796 等IC */
{
lcddev.wramcmd = 0X2C;
lcddev.setxcmd = 0X2A;
lcddev.setycmd = 0X2B;
}
if (lcddev.id == 0X5310 || lcddev.id == 0x7796) /* 如果是5310/7796 则表示是 320*480分辨率 */
{
lcddev.width = 480;
lcddev.height = 320;
}
}
lcd_scan_dir(DFT_SCAN_DIR); /* 默认扫描方向 */
}
/**
* @brief 设置窗口(对RGB屏无效),并自动设置画点坐标到窗口左上角(sx,sy).
* @param sx,sy:窗口起始坐标(左上角)
* @param width,height:窗口宽度和高度,必须大于0!!
* @note 窗体大小:width*height.
*
* @retval 无
*/
void lcd_set_window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
uint16_t twidth, theight;
twidth = sx + width - 1;
theight = sy + height - 1;
if (lcddev.id == 0X1963 && lcddev.dir != 1) /* 1963竖屏特殊处理 */
{
sx = lcddev.width - width - sx;
height = sy + height - 1;
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_data(sx & 0XFF);
lcd_wr_data((sx + width - 1) >> 8);
lcd_wr_data((sx + width - 1) & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_data(sy & 0XFF);
lcd_wr_data(height >> 8);
lcd_wr_data(height & 0XFF);
}
else if (lcddev.id == 0X5510)
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_regno(lcddev.setxcmd + 1);
lcd_wr_data(sx & 0XFF);
lcd_wr_regno(lcddev.setxcmd + 2);
lcd_wr_data(twidth >> 8);
lcd_wr_regno(lcddev.setxcmd + 3);
lcd_wr_data(twidth & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_regno(lcddev.setycmd + 1);
lcd_wr_data(sy & 0XFF);
lcd_wr_regno(lcddev.setycmd + 2);
lcd_wr_data(theight >> 8);
lcd_wr_regno(lcddev.setycmd + 3);
lcd_wr_data(theight & 0XFF);
}
else /* 9341/5310/7789/1963/7796/9806横屏 等 设置窗口 */
{
lcd_wr_regno(lcddev.setxcmd);
lcd_wr_data(sx >> 8);
lcd_wr_data(sx & 0XFF);
lcd_wr_data(twidth >> 8);
lcd_wr_data(twidth & 0XFF);
lcd_wr_regno(lcddev.setycmd);
lcd_wr_data(sy >> 8);
lcd_wr_data(sy & 0XFF);
lcd_wr_data(theight >> 8);
lcd_wr_data(theight & 0XFF);
}
}
/**
* @brief 初始化LCD
* @note 该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
*
* @param 无
* @retval 无
*/
void lcd_init(void)
{
delay_ms(50); /* 初始化FSMC后,必须等待一定时间才能开始初始化 */
/* 尝试9341 ID的读取 */
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X00 */
lcddev.id = lcd_rd_data(); /* 读取0X93 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X41 */
if (lcddev.id != 0X9341) /* 不是 9341 , 尝试看看是不是 ST7789 */
{
lcd_wr_regno(0X04);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X85 */
lcddev.id = lcd_rd_data(); /* 读取0X85 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X52 */
if (lcddev.id == 0X8552) /* 将8552的ID转换成7789 */
{
lcddev.id = 0x7789;
}
if (lcddev.id != 0x7789) /* 也不是ST7789, 尝试是不是 NT35310 */
{
lcd_wr_regno(0xD4);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0x01 */
lcddev.id = lcd_rd_data(); /* 读回0x53 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 这里读回0x10 */
if (lcddev.id != 0x5310) /* 也不是NT35310,尝试看看是不是ST7796 */
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读到0X00 */
lcddev.id = lcd_rd_data(); /* 读取0X77 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读取0X96 */
if (lcddev.id != 0x7796) /* 也不是ST7796,尝试看看是不是NT35510 */
{
/* 发送密钥(厂家提供) */
lcd_write_reg(0xF000, 0x0055);
lcd_write_reg(0xF001, 0x00AA);
lcd_write_reg(0xF002, 0x0052);
lcd_write_reg(0xF003, 0x0008);
lcd_write_reg(0xF004, 0x0001);
lcd_wr_regno(0xC500); /* 读取ID低八位 */
lcddev.id = lcd_rd_data(); /* 读回0x55 */
lcddev.id <<= 8;
lcd_wr_regno(0xC501); /* 读取ID高八位 */
lcddev.id |= lcd_rd_data(); /* 读回0x10 */
delay_ms(5); /* 等待5ms, 因为0XC501指令对1963来说就是软件复位指令, 等待5ms让1963复位完成再操作 */
if (lcddev.id != 0x5510) /* 也不是NT5510,尝试看看是不是ILI9806 */
{
lcd_wr_regno(0XD3);
lcddev.id = lcd_rd_data(); /* dummy read */
lcddev.id = lcd_rd_data(); /* 读回0X00 */
lcddev.id = lcd_rd_data(); /* 读回0X98 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0X06 */
if (lcddev.id != 0x9806) /* 也不是ILI9806,尝试看看是不是SSD1963 */
{
lcd_wr_regno(0xA1);
lcddev.id = lcd_rd_data();
lcddev.id = lcd_rd_data(); /* 读回0x57 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 读回0x61 */
if (lcddev.id == 0x5761) lcddev.id = 0x1963; /* SSD1963读回的ID是5761H,为方便区分,我们强制设置为1963 */
}
}
}
}
}
}
/* 特别注意, 如果在main函数里面屏蔽串口1初始化, 则会卡死在printf
* 里面(卡死在f_putc函数), 所以, 必须初始化串口1, 或者屏蔽掉下面
* 这行 printf 语句 !!!!!!!
*/
printf("LCD ID:%x\r\n", lcddev.id); /* 打印LCD ID */
if (lcddev.id == 0X7789)
{
lcd_ex_st7789_reginit(); /* 执行ST7789初始化 */
}
else if (lcddev.id == 0X9341)
{
lcd_ex_ili9341_reginit(); /* 执行ILI9341初始化 */
}
else if (lcddev.id == 0x5310)
{
lcd_ex_nt35310_reginit(); /* 执行NT35310初始化 */
}
else if (lcddev.id == 0x7796)
{
lcd_ex_st7796_reginit(); /* 执行ST7796初始化 */
}
else if (lcddev.id == 0x5510)
{
lcd_ex_nt35510_reginit(); /* 执行NT35510初始化 */
}
else if (lcddev.id == 0x9806)
{
lcd_ex_ili9806_reginit(); /* 执行ILI9806初始化 */
}
else if (lcddev.id == 0x1963)
{
lcd_ex_ssd1963_reginit(); /* 执行SSD1963初始化 */
lcd_ssd_backlight_set(100); /* 背光设置为最亮 */
}
lcd_display_dir(0); /* 默认为竖屏 */
LCD_BL(1); /* 点亮背光 */
lcd_clear(WHITE);
}
/**
* @brief 清屏函数
* @param color: 要清屏的颜色
* @retval 无
*/
void lcd_clear(uint16_t color)
{
uint32_t index = 0;
uint32_t totalpoint = lcddev.width;
totalpoint *= lcddev.height; /* 得到总点数 */
lcd_set_cursor(0x00, 0x0000); /* 设置光标位置 */
lcd_write_ram_prepare(); /* 开始写入GRAM */
for (index = 0; index < totalpoint; index++)
{
LCD->LCD_RAM = color;
}
}
/**
* @brief 在指定区域内填充单个颜色
* @param (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
* @param color:要填充的颜色(32位颜色,方便兼容LTDC)
* @retval 无
*/
void lcd_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)
{
uint16_t i, j;
uint16_t xlen = 0;
xlen = ex - sx + 1;
for (i = sy; i <= ey; i++)
{
lcd_set_cursor(sx, i); /* 设置光标位置 */
lcd_write_ram_prepare(); /* 开始写入GRAM */
for (j = 0; j < xlen; j++)
{
LCD->LCD_RAM = color; /* 显示颜色 */
}
}
}
/**
* @brief 在指定区域内填充指定颜色块
* @param (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex - sx + 1) * (ey - sy + 1)
* @param color: 要填充的颜色数组首地址
* @retval 无
*/
void lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
uint16_t height, width;
uint16_t i, j;
width = ex - sx + 1; /* 得到填充的宽度 */
height = ey - sy + 1; /* 高度 */
for (i = 0; i < height; i++)
{
lcd_set_cursor(sx, sy + i); /* 设置光标位置 */
lcd_write_ram_prepare(); /* 开始写入GRAM */
for (j = 0; j < width; j++)
{
LCD->LCD_RAM = color[i * width + j]; /* 写入数据 */
}
}
}
/**
* @brief 画线
* @param x1,y1: 起点坐标
* @param x2,y2: 终点坐标
* @param color: 线的颜色
* @retval 无
*/
void lcd_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
uint16_t t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy, row, col;
delta_x = x2 - x1; /* 计算坐标增量 */
delta_y = y2 - y1;
row = x1;
col = y1;
if (delta_x > 0)incx = 1; /* 设置单步方向 */
else if (delta_x == 0)incx = 0; /* 垂直线 */
else
{
incx = -1;
delta_x = -delta_x;
}
if (delta_y > 0)incy = 1;
else if (delta_y == 0)incy = 0; /* 水平线 */
else
{
incy = -1;
delta_y = -delta_y;
}
if ( delta_x > delta_y)distance = delta_x; /* 选取基本增量坐标轴 */
else distance = delta_y;
for (t = 0; t <= distance + 1; t++ ) /* 画线输出 */
{
lcd_draw_point(row, col, color); /* 画点 */
xerr += delta_x ;
yerr += delta_y ;
if (xerr > distance)
{
xerr -= distance;
row += incx;
}
if (yerr > distance)
{
yerr -= distance;
col += incy;
}
}
}
/**
* @brief 画水平线
* @param x,y: 起点坐标
* @param len : 线长度
* @param color: 矩形的颜色
* @retval 无
*/
void lcd_draw_hline(uint16_t x, uint16_t y, uint16_t len, uint16_t color)
{
if ((len == 0) || (x > lcddev.width) || (y > lcddev.height))return;
lcd_fill(x, y, x + len - 1, y, color);
}
/**
* @brief 画矩形
* @param

实验&spm=1001.2101.3001.5002&articleId=148782752&d=1&t=3&u=f5fb3c44ae864545b1f32d701855aaa7)
2万+

被折叠的 条评论
为什么被折叠?



