STM32-01-认识单片机
STM32-02-基础知识
STM32-03-HAL库
STM32-04-时钟树
STM32-05-SYSTEM文件夹
STM32-06-GPIO
STM32-07-外部中断
STM32-08-串口
STM32-09-IWDG和WWDG
STM32-10-定时器
STM32-11-电容触摸按键
STM32-12-OLED模块
STM32-13-MPU
STM32-14-FSMC_LCD
STM32-15-DMA
STM32-16-ADC
STM32-17-DAC
显示器 | 举例 | 优点 | 缺点 |
---|---|---|---|
断码屏 | 数码管、计算器、遥控器 | 成本低,驱动简单,稳定 | 色彩单一,显示内容少 |
点阵屏 | 户外广告屏 | 任意尺寸,亮度高 | 贵,耗电,体积大 |
LCD屏 | 显示器、电视屏、手机屏 | 成本低,色彩好,薄,寿命长 | 全彩稍差,漏光,拖影 |
OLED屏 | 显示器、电视屏、手机屏 | 自发光,色彩最好,超薄,功耗低 | 比较贵,寿命短 |
简介:
Liquid Crystal Display
,即液晶显示器,利用液晶导电后透光性可变的特性,配合显示器光源、彩色滤波片和电压控制等工艺,最终可以在液晶阵列上显示彩色的图像。目前,液晶显示技术以TN、STN、TFT三种技术为主,TFT-LCD即采用了TFT技术的液晶显示器,也叫薄膜晶体管液晶显示器。
优点:
LCD的组成:
LCD(液晶显示器)的基本组成包括以下几个主要部分:
玻璃基板(Glass Substrates)
背光源(Backlight)
背光源提供必要的光源,通常由LED组成,光通过液晶层后形成可见图像。背光源的重要组成部分有:
驱动IC
LCD接口分类:
接口 | 分辨率 | 特性 |
---|---|---|
MCU | ≤800*480 | 带SRAM,无需频繁刷新,无需大内存,驱动简单 |
RGB | ≤1280*800 | 不带SRAM,需要实时刷新,需要大内存,驱动稍微复杂 |
MIPI | 4K | 不带SRAM,支持分辨率高,省电,大部分手机屏用此接口 |
特点:
8080
和6800
并行接口是常见的MCU接口类型,通常有8位、16位、18位和24位数据线。优缺点:
特点:
优缺点:
特点:
优缺点:
总结:
- MCU接口适合低分辨率、低刷新率的显示应用,控制简单、成本低,但传输速度慢。
- RGB接口适合高分辨率、高刷新率的显示应用,传输速度快、色彩表现力强,但布线复杂、成本高。
- MIPI接口则适合移动设备和便携式电子设备,具有高带宽、低功耗和强抗干扰能力的特点,但实现较复杂。
ILI9341驱动芯片:
三基色原理:
在计算机中,颜色通常使用32位的格式表示,称为ARGB888格式,其中A表示Alpha通道,R、G、B分别表示红、绿、蓝三个颜色通道。在单片机中,由于资源限制,颜色通常以16位或24位表示,分别称为RGB565和RGB888格式,其中RGB565使用16位来表示颜色,而RGB888使用24位来表示颜色。
LCD驱动原理:
LCD屏(MCU接口)驱动的核心是:驱动LCD驱动芯片
LCD驱动过程:
8080时序:
信号 | 名称 | 控制状态 | 作用 |
---|---|---|---|
CS | 片选 | 低电平 | 选中器件,低电平有效,先选中,后操作 |
WR | 写 | ↑ | 写信号,上升沿有效,用于数据/命令写入 |
RD | 读 | ↑ | 读信号,上升沿有效,用于数据/命令读取 |
RS | 数据/命令 | 0=命/1=数 | 表示当前是读写数据还是命令,也叫DC信号 |
D[15:0] | 数据线 | 无 | 双向数据线,可以写入/读取驱动IC数据 |
写时序
void lcd_wr_data(uint16_t data)
{
LCD_RS(1); /* 操作数据 */
LCD_CS(0); /* 选中 */
LCD_DATA_OUT(data); /* 数据 */
LCD_WR(0); /* WR低电平 */
LCD_WR(1); /* WR高电平 */
LCD_CS(1); /* 释放片选 */
}
读时序
uint16_t lcd_rd_data(void)
{
uint16_t ram; /* 定义变量 */
LCD_RS(1); /* 操作数据 */
LCD_CS(0); /* 选中 */
LCD_RD(0); /* RD低电平 */
ram = LCD_DATA_IN; /* 读取数据 */
LCD_RD(1); /* RD高电平 */
LCD_CS(1); /* 释放片选 */
return ram; /* 返回读数 */
}
驱动芯片用于控制LCD的各种显示功能,整体功能复杂。常见型号ILI9341/ST7789等 。
一般我们只需要6条指令即可完成对LCD的基本使用
指令(HEX) | 名称 | 作用 |
---|---|---|
0XD3 | 读ID | 用于读取LCD控制器的ID,区分型号用 |
0X36 | 访问控制 | 设置GRAM读写方向,控制显示方向 |
0X2A | 列地址 | 一般用于设置X坐标 |
0X2B | 页地址 | 一般用于设置Y坐标 |
0X2C | 写GRAM | 用于往LCD写GRAM数据 |
0X2E | 读GRAM | 用于读取LCD的GRAM数据 |
读ID指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0xD3(读ID指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 将RS设置为高电平(1),表示要读取数据;
- 将CS信号保持低电平,继续选中LCD驱动IC;
- 触发RD信号的上升沿,从LCD驱动IC读取数据
- 读取数据线D[15:0]上的数据,这就是LCD控制器型号。
访问控制指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0x36(访问控制指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 设置RS为高电平(1),表示要写入参数数据;
- 将参数数据(MX, MY, MV, BGR)写入数据线D[15:0];
- 再次触发WR信号的上升沿,将参数数据写入LCD驱动IC;
- 将CS信号置为高电平,取消对LCD驱动IC的选中状态。
X坐标设置指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0x2A(X坐标设置指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 设置RS为高电平(1),表示要写入参数数据;
- 将起始坐标(SC)写入数据线D[15:0];
- 再次触发WR信号的上升沿,将起始坐标写入LCD驱动IC;
- 将结束坐标(EC)写入数据线D[15:0];
- 再次触发WR信号的上升沿,将结束坐标写入LCD驱动IC;
- 将CS信号置为高电平,取消对LCD驱动IC的选中状态。
Y坐标设置指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0x2B(Y坐标设置指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 设置RS为高电平(1),表示要写入参数数据;
- 将起始坐标(SP)写入数据线D[15:0];
- 再次触发WR信号的上升沿,将起始坐标写入LCD驱动IC;
- 将结束坐标(EP)写入数据线D[15:0];
- 再次触发WR信号的上升沿,将结束坐标写入LCD驱动IC;
- 将CS信号置为高电平,取消对LCD驱动IC的选中状态。
写GRAM指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0x2C(写GRAM指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 设置RS为高电平(1),表示要写入数据;
- 准备要写入的像素点的颜色值(RGB565格式),写入数据线D[15:0];
- 再次触发WR信号的上升沿,将像素点的颜色值写入LCD驱动IC;
- 如果需要连续写入多个像素点,数据线会自动自增,无需重新设置坐标。
读GRAM指令
具体步骤:
- 设置RS为低电平(0),表示要发送命令;
- 将命令0x2E(读GRAM指令)写入数据线D[15:0];
- 将CS信号置为低电平,选中LCD驱动IC;
- 触发WR信号的上升沿,将命令写入LCD驱动IC;
- 设置RS为高电平(1),表示要读取数据;
- 发送dummy数据,读取GRAM中的垃圾数据(dummy);
- 依次读取R1G1和B1R2数据,每次读取一个像素点的颜色;
- 根据RGB565格式的颜色值,提取出红色、绿色和蓝色通道的值,并返回合并后的颜色值。
在这个过程中,需要连续读取3次数据,每次读取一个像素点的颜色值。其中,dummy数据用于丢弃GRAM中的垃圾数据,实际上不会被使用。而读取R1G1和B1R2数据则是实际的颜色值数据,需要根据RGB565格式进行处理,提取出红色、绿色和蓝色通道的值,最终合并成完整的颜色值。
读取某个点颜色函数代码:
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); /* 设置坐标 */ 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)); }
将红色、绿色和蓝色分量组合成一个16位的颜色值并返回:
- 红色分量:将
r
右移11位,获得红色分量的高5位,再左移11位放到返回值的高5位。- 绿色分量:将
g
右移2位,获得绿色分量的高6位,再左移5位放到返回值的中6位。- 蓝色分量:将
b
右移11位,获得蓝色分量的高5位,直接放到返回值的低5位。这段代码通过指定坐标,发送读取命令,读取并组合红、绿、蓝三种颜色的分量,最后返回组合后的16位颜色值。每个颜色分量都经过适当的移位和合并操作,以符合16位颜色格式。
LCD驱动的一般过程
电源初始化:
硬件接口初始化:
寄存器配置:
内存映射:
显示测试:
8080底层操作函数
8080接口是一种并行通信接口,常用于LCD与MCU之间的数据传输。8080底层操作函数:
/* 8080 写数据 */
void lcd_wr_data (uint16_t data)
{
LCD_RS(1); /* 操作数据 */
LCD_CS(0); /* 选中 */
LCD_DATA_OUT(data); /* 数据 */
LCD_WR(0); /* WR低电平 */
LCD_WR(1); /* WR高电平 */
LCD_CS(1); /* 释放片选 */
}
/* 8080 写命令 */
void lcd_wr_regno(uint16_t regno)
{
LCD_RS(0); /* RS=0,表示写寄存器 */
LCD_CS(0); /* 选中 */
LCD_DATA_OUT(regno);/* 命令 */
LCD_WR(0); /* WR低电平 */
LCD_WR(1); /* WR高电平 */
LCD_CS(1); /* 释放片选 */
}
初始化LCD
初始化LCD的过程包括设置电源、配置寄存器和初始化显示内存等步骤。
/* 初始化LCD */
void lcd_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
LCD_BL_GPIO_CLK_ENABLE(); /* LCD_BL脚时钟使能 */
LCD_CS_GPIO_CLK_ENABLE(); /* LCD_CS脚时钟使能 */
LCD_WR_GPIO_CLK_ENABLE(); /* LCD_WR脚时钟使能 */
LCD_RD_GPIO_CLK_ENABLE(); /* LCD_RD脚时钟使能 */
LCD_RS_GPIO_CLK_ENABLE(); /* LCD_RS脚时钟使能 */
LCD_DATA_GPIO_CLK_ENABLE(); /* LCD_DATA脚时钟使能 */
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_SWJ_NOJTAG(); /* 禁止JTAG, 使能SWD, 释放PB3,PB4两个引脚做普通IO用 */
gpio_init_struct.Pin = LCD_BL_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽复用 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct); /* LCD_BL引脚模式设置(推挽输出) */
gpio_init_struct.Pin = LCD_CS_GPIO_PIN;
HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_CS引脚 */
gpio_init_struct.Pin = LCD_WR_GPIO_PIN;
HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_WR引脚 */
gpio_init_struct.Pin = LCD_RD_GPIO_PIN;
HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RD引脚 */
gpio_init_struct.Pin = LCD_RS_GPIO_PIN;
HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RS引脚 */
gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct); /* LCD_DATA引脚模式设置 */
LCD_WR(1); /* WR 默认高电平 */
LCD_RD(1); /* RD 默认高电平 */
LCD_CS(1); /* CS 默认高电平 */
LCD_RS(1); /* RS 默认高电平 */
LCD_DATA_OUT(0XFFFF); /* DATA 默认高电平 */
/* 读取ID */
lcd_wr_regno(0xD3);
lcddev.id = lcd_rd_data(); /* 假读 */
lcddev.id = lcd_rd_data(); /* 00 */
lcddev.id = lcd_rd_data(); /* 93 */
lcddev.id <<= 8;
lcddev.id |= lcd_rd_data(); /* 41 */
printf("lcddev_id:%#x \r\n", lcddev.id);
/* 完成初始化序列 */
if (lcddev.id == 0x9341)
lcd_ex_ili9341_reginit();
else
lcd_ex_st7789_reginit();
/* 对LCD控制结构体赋值 */
lcddev.width = 240;
lcddev.height = 320;
lcddev.setxcmd = 0x2A;
lcddev.setycmd = 0x2B;
lcddev.wramcmd = 0x2C;
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);
/* 设置扫描方向 */
lcd_write_reg(0x36, 1 << 3);
/* 点亮背光 */
LCD_BL(1);
/* lcd_clear */
lcd_clear(0xFFFF);
}
实现画点函数
画点函数用于在指定位置显示一个像素点。
/* 画点 */
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
lcd_set_cursor(x, y);
lcd_write_ram_prepare();
lcd_wr_data(color);
}
实现读点函数
读点函数用于读取指定位置的像素点颜色值。
/* LCD读数据 */
uint16_t lcd_rd_data(void)
{
volatile uint16_t ram; /* 防止被优化 */
GPIO_InitTypeDef gpio_init_struct;
/* LCD_DATA 引脚模式设置, 上拉输入, 准备接收数据 */
gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);
LCD_RS(1); /* RS=1,表示操作数据 */
LCD_CS(0);
LCD_RD(0);
lcd_opt_delay(2);
ram = LCD_DATA_IN; /* 读取数据 */
LCD_RD(1);
LCD_CS(1);
/* LCD_DATA 引脚模式设置, 推挽输出, 恢复输出状态 */
gpio_init_struct.Pin = LCD_DATA_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LCD_DATA_GPIO_PORT, &gpio_init_struct);
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); /* 设置坐标 */
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));
}
Flexible Static Memory Controller
,灵活的静态存储控制器。时钟逻辑控制
时钟控制逻辑负责生成和管理FSMC操作所需的时钟信号。这些时钟信号用于同步FSMC内部操作以及与外部设备的通信。主要功能包括:
控制单元
FSMC控制单元是FSMC的核心部分,负责管理与外部存储器的交互。主要功能包括:
通信引脚
通信引脚是FSMC与外部设备(如SRAM、NOR Flash、NAND Flash等)进行实际物理连接的接口。主要引脚包括:
使用FSMC驱动LCD
右边是FSMC控制屏幕的过程,使用的是HADDR
总线, CPU通过HADDR
总线将控制信息发送给FSMC,然后FSMC再控制SRAM。 8080总线是CPU直接控制屏幕的方式,而HADDR总线是通过配置FSMC来控制屏幕的方式 。
针对FSMC存储块划分,可以进一步解释如下:
HADDR与FSMC_A关系
LCD的RS信号线与地址线关系
FSMC_BCR4
、FSMC_BTR4
、FSMC_BWTR4
寄存器
FSMC_BCRx
寄存器
FSMC_BTRx
寄存器
FSMC_BWTRx
寄存器
HAL_StatusTypeDef HAL_SRAM_Init ( SRAM_HandleTypeDef *hsram,
FSMC_NORSRAM_TimingTypeDef *Timing,
FSMC_NORSRAM_TimingTypeDef *ExtTiming )
参数:
- SRAM_HandleTypeDef *hsram:这是指向 SRAM 句柄结构的指针。该结构包含了 SRAM 模块的配置信息,如 SRAM 的基地址、数据宽度、存储器库编号等。
- FSMC_NORSRAM_TimingTypeDef *Timing:这是指向 SRAM 读写访问时序结构的指针。
FSMC_NORSRAM_TimingTypeDef
结构定义了时序参数,如地址设置时间、数据保持时间、总线转换时间、时钟分频、数据延迟和访问模式等。- FSMC_NORSRAM_TimingTypeDef *ExtTiming:这是指向扩展模式时序结构的指针(如果使用的话)。扩展模式允许在某些操作需要不同的时序时应用额外的时序配置。
功能:
HAL_SRAM_Init
函数通过配置 FSMC 接口中的时序参数来初始化 SRAM 设备。具体步骤如下:
- 句柄初始化:函数首先初始化 SRAM 句柄 (
hsram
),包括设置基地址和其他配置参数。- 时序配置:设置 FSMC 的读写时序参数,这包括:
- 地址设置时间:在片选之前设置地址的时间。
- 数据保持时间:在操作完成之前保持数据的时间。
- 访问模式:如异步模式。
- FSMC 配置:配置 FSMC 外设的时序参数,具体包括:
- 设置 FSMC 控制寄存器,定义存储器类型、数据宽度、存储器库和读写时序参数。
- 配置控制信号,如片选、输出使能和写入使能线。
- 扩展模式(可选):如果提供了
ExtTiming
参数(非空),函数将配置扩展模式时序参数。扩展模式允许对某些操作使用不同的读写时序。- 启用 FSMC:一旦设置了时序配置,启用 FSMC 控制器开始与 SRAM 通信。
LCD初始化函数
void lcd_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
FSMC_NORSRAM_TimingTypeDef fsmc_read_handle;
FSMC_NORSRAM_TimingTypeDef fsmc_write_handle;
LCD_CS_GPIO_CLK_ENABLE(); /* LCD_CS脚时钟使能 */
LCD_WR_GPIO_CLK_ENABLE(); /* LCD_WR脚时钟使能 */
LCD_RD_GPIO_CLK_ENABLE(); /* LCD_RD脚时钟使能 */
LCD_RS_GPIO_CLK_ENABLE(); /* LCD_RS脚时钟使能 */
LCD_BL_GPIO_CLK_ENABLE(); /* LCD_BL脚时钟使能 */
gpio_init_struct.Pin = LCD_CS_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽复用 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_CS引脚 */
gpio_init_struct.Pin = LCD_WR_GPIO_PIN;
HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_WR引脚 */
gpio_init_struct.Pin = LCD_RD_GPIO_PIN;
HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RD引脚 */
gpio_init_struct.Pin = LCD_RS_GPIO_PIN;
HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RS引脚 */
gpio_init_struct.Pin = LCD_BL_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct); /* LCD_BL引脚模式设置(推挽输出) */
g_sram_handle.Instance = FSMC_NORSRAM_DEVICE;
g_sram_handle.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
g_sram_handle.Init.NSBank = FSMC_NORSRAM_BANK4; /* 使用NE4 */
g_sram_handle.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; /* 地址/数据线不复用 */
g_sram_handle.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; /* 16位数据宽度 */
g_sram_handle.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */
g_sram_handle.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */
g_sram_handle.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */
g_sram_handle.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; /* 存储器写使能 */
g_sram_handle.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; /* 等待使能位,此处未用到 */
g_sram_handle.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE; /* 读写使用不同的时序 */
g_sram_handle.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; /* 是否使能同步传输模式下的等待信号,此处未用到 */
g_sram_handle.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* 禁止突发写 */
/* FSMC读时序控制寄存器 */
fsmc_read_handle.AddressSetupTime = 0; /* 地址建立时间(ADDSET)为1个HCLK 1/72M = 13.9ns (实际 > 200ns) */
fsmc_read_handle.AddressHoldTime = 0; /* 地址保持时间(ADDHLD) 模式A是没有用到 */
/* 因为液晶驱动IC的读数据的时候,速度不能太快,尤其是个别奇葩芯片 */
fsmc_read_handle.DataSetupTime = 15; /* 数据保存时间(DATAST)为16个HCLK = 13.9 * 16 = 222.4ns */
fsmc_read_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */
/* FSMC写时序控制寄存器 */
fsmc_write_handle.AddressSetupTime = 0; /* 地址建立时间(ADDSET)为1个HCLK = 13.9ns */
fsmc_write_handle.AddressHoldTime = 0; /* 地址保持时间(ADDHLD) 模式A是没有用到 */
/* 某些液晶驱动IC的写信号脉宽,最少也得50ns */
fsmc_write_handle.DataSetupTime = 1; /* 数据保存时间(DATAST)为2个HCLK = 13.9 * 2 = 27.8ns (实际 > 200ns) */
fsmc_write_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */
HAL_SRAM_Init(&g_sram_handle, &fsmc_read_handle, &fsmc_write_handle);
delay_ms(50);
/* 尝试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,尝试看看是不是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高8位 */
lcddev.id = lcd_rd_data(); /* 读回0X55 */
lcddev.id <<= 8;
lcd_wr_regno(0xC501); /* 读取ID低8位 */
lcddev.id |= lcd_rd_data(); /* 读回0X10 */
delay_ms(5);
if (lcddev.id != 0X5510) /* 也不是NT5510,尝试看看是不是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 == 0x5510)
{
lcd_ex_nt35510_reginit(); /* 执行NT35510初始化 */
}
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);
}
主函数
int main(void)
{
uint8_t lcd_id[12];
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
oled_init();
lcd_init(); /* 初始化LCD */
sprintf((char *)lcd_id, "LCD ID:%04X", lcddev.id); /* 将LCD ID打印到lcd_id数组 */
while (1)
{
lcd_show_string(10, 40, 240, 32, 32, "STM32", GREEN);
lcd_show_string(10, 80, 240, 24, 24, "TFTLCD TEST", BLUE);
lcd_show_string(10, 110, 240, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(10, 130, 240, 16, 12, (char *)lcd_id, RED); /* 显示LCD ID */
oled_show_string(0, 5, "STM32", 24);
oled_show_string(0, 33, "TFTLCD TEST", 16);
oled_show_string(0, 51, "ATOM@ALIENTEK", 12);
oled_refresh_gram();
LED0_TOGGLE(); /*红灯闪烁*/
delay_ms(1000);
}
}
实验结果
声明:资料来源(战舰STM32F103ZET6开发板资源包)
- Cortex-M3权威指南(中文).pdf
- STM32F10xxx参考手册_V10(中文版).pdf
- STM32F103 战舰开发指南V1.3.pdf
- STM32F103ZET6(中文版).pdf
- 战舰V4 硬件参考手册_V1.0.pdf