1、概述
本次实验的名称叫做“基于正点原子探索者开发板的简易音乐播放器”。本实验的功能框图如下:
从图上我们可以清晰的看到本实验所需的实现的功能、以及每个功能需要怎么实现。
这次实验使用的是正点原子的探索者开发板,此开发板采用的MCU是STM32F407ZGT6,其资源如下:
正点原子的探索者开发板硬件资源丰富,分布图如下:
本次实验使用的外设有:LCD、SRAM、TF卡接口、音频解码、按键、LED。对于不同版本的板子对本次实验有一定的影响:
- V2版本的开发板SD卡接口是SD卡接口(大卡),音频解码芯片采用的是WM8978。
- V3版本的开发板SD卡接口是microSD卡接口(小卡),音频解码芯片采用的是ES8388。
在实验中会对这两颗不同的音频解码芯片做不同的驱动。
2、相关知识讲解
2.1 FSMC知识
2.1.1 FMC接口介绍
FMC 接口(即可变存储控制器)是一种用于管理外部存储器的外设接口,支持多种类型的存储器,主要分为三大类:NOR/SRAM/PSRAM设备(TFTLCD相当于SRAM)、NOR FLASH/NAND FLASH/PC卡设备和SDRAM 设备。他们共用地址数据总线等信号,他们具有不同的CS以区分不同的设备。FMC 的框图如下图所示,从图中可以看到FMC接口中那些信号接口是所有设备共享,哪些信号接口是某些类型设备独享。
FMC接口一共管理1.5GB空间,拥有6个存储块(Bank),每个存储块256MB空间,不同类型的设备占用不同的Bank,它们的地址映射如下表。
FMC地址映射表 | |||
Bank号 | 大小 | 地址映射 | 设备类型 |
Bank1 | 4*64MB | 0X6000 0000 - 0X6FFF FFFF | NOR/SRAM/PSRAM设备 |
Bank2 | 4*64MB | 0X7000 0000 - 0X7FFF FFFF | NOR FLASH设备/ NAND FLASH设备 |
Bank3 | 4*64MB | 0X8000 0000 - 0X8FFF FFFF | |
Bank4 | 4*64MB | 0X9000 0000 - 0X9FFF FFFF | PC卡设备 |
Bank5 | 4*64MB | 0XC000 0000 - 0XCFFF FFFF | SDRAM设备 |
Bank6 | 4*64MB | 0XD000 0000 - 0XDFFF FFFF |
NOR/SRAM/PSRAM设备占用的是FMC接口的Bank1,它们内部再次被分割成了4个区,每个区64M的空间,通过FMC_NE1、FMC_NE2、FMC_NE3、FMC_NE4这4个脚来确定使用的是哪个区。
SDRAM设备占用的是Bank5和Bank6,通过(SDNE0、SDCKE0)和(SDNE1、SDCKCKE1)两组引脚来确定使用的是哪个Bank。
NAND FLASH设备占用的是Bank2和Bank3,通过NCE2和NCE3两个脚来确定使用的是哪个Bank。
2.1.2 使用FMC接口驱动TFT LCD
使用FMC解接口驱动TFT LCD时实际是把LCD当成SRAM设备使用。
SRAM设备的控制有以下接口:地址线( A0~A25最多)、数据线(如 D0~D31最多)、写信号(WE)、读信号(OE)、片选信号(CS),如果 SRAM支持字节控制,那么还有 UB/LB信号。
TFT LCD设备的控制有以下接口:RS(命令/数据标志:0,读写命令;1,读写数据)、D0~D15(16 位双向数据线)、WR(向 TFTLCD 写入数据标志)、RD(从 TFTLCD 读取数据标志)、CS(片选)、RST(硬件复位) 和 BL(背光控制)。
通过SRAM设备和TFT LCD设备控制接口对比可以发现,两者控制方式完全类似,唯一不同的是TFT LCD 有 RS 信号,但是没有地址信号。TFT LCD 通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FMC控制器写地址0的时候会使得A0变为0,对TFT LCD来说就是写命令。而FMC 写地址1的时候,A0将会变为1,对TFT LCD 来说就是写数据了。这样就把数据和命令区分开了。他们其实就是对应 SRAM 操作的两个连续地址,当然 RS 也可以接在其他地址线上,正点原子的开发板把 RS 连接在 A18 上面的。
SRAM设备占用的是FMC接口的Bank1,它内部再次被分割成了4个区,每个区64M的空间,通过单片机内部的AHB地址总线HADDR[27:0]进行寻址,其中AHB地址总线HADDR[25:0]对应FMC的地址线 A0~A25,而HADDR[27:26]则由片选信号决定,从FMC_NE1到FMC_NE4对应的HADDR[27:26]分别是:00 01 10 11。
由于单片机内部的AHB地址总线HADDR[27:0]是按字节寻址,而FMC外接的存储器按字寻址,所以根据存储器数据宽度的不同,单片机通过FMC访问外部存储器时发送的地址也不同,地址的偏移情况与存储器数据宽度的关系如下:
因此,FMC 内部 HADDR 与存储器寻址地址的实际对应关系就是:
当接的是 32 位宽度存储器的时候:HADDR[25:2]→ FMC_A [23:0]。
当接的是 16 位宽度存储器的时候:HADDR[25:1]→ FMC_A [24:0]。
当接的是 8 位宽度存储器的时候:HADDR[25:0]→ FMC_A [25:0]。
注意:这里的偏移只是FMC访问外部存储器时的地址偏移(软件上的偏移),但硬件连接时FMC的地址线A0到A25还是要和存储器的A0到A25对应连接。
正点原子的TFT LCD都是16位的数据宽度,所以单片机内部的AHB地址总线的HADDR[0]没有用到,只有HADDR[25:1]是有效的,对应关系变为:HADDR[25:1]→ FMC_A[24:0],相当于右移了一位。
在了解了SRAM设备的寻址方式和FMC访问SRAM设备时的地址偏移以后接下来就是要知道FMC给LCD发送数据时的地址计算了。
首先是确定SRAM的基地址。当我们决定了接哪一个片选信号时,那就决定了用的是Bank1的哪一个区,也就决定了SRAM的基地址。每个区的基地址都不一样,计算公式为[ 0x6000 0000 + (X-1)*0x400 0000](X表示哪一个区)。
接下来就是根据RS脚确定给LCD发送命令/数据时的地址了,RS=0是命令;RS=1是数据。正点原子F429开发板中RS接的是A18,所以当A18脚为0时发送的是命令,为1时发送的是数据。由于FMC是并行通信,所以当地址线为0时表示发送的是命令,当地址线为0x80000时表示发送的是数据。计算公式为:数据地址=[2^(y+1)](y表示RS脚接的地址线的编号,比如此时接的A18,则数据地址等于0x80000)。
经过上述计算得到FMC给LCD发送数据的地址:0x6008 0000,即&LCD_RAM = 0x6008 0000,而FMC给LCD时的地址只要不等于给LCD发命令的地址就行。为了方便,通常会使用一个 LCD 地址结构体进行管理:
typedef struct
{
volatile uint16_t LCD_REG;
volatile uint16_t LCD_RAM;
} LCD_TypeDef;
LCD_TypeDef LCD={ NULL };
通过上述计算的得知,LCD结构体中LCD_RAM的地址为0x6008 0000,所以LCD的首地址就是(0x6008 0000 - 2 = 0x6007 FFFE),所以定义时LCD结构体的地址就需要手动指定,上述语句需要写成:LCD_TypeDef LCD __attribute__((at(0x6007 FFFE))) = { NULL };
除了这种方法外,正点原子还提供了一种结构体指针的管理方式:
#define LCD ((LCD_TypeDef *) 0x6007 FFFE);
声明LCD是一个LCD_TypeDef类型的指针,并且指向0x6007 FFFE这个地址,所以结构体指针中的变量LCD->LCD_RAM的地址就是0x6008 0000,一样的效果。
一般TFT LCD的驱动流程如下:首先是硬件复位(LCD_RST先拉低100毫秒再拉高),然后发送LCD驱动芯片的初始化序列(厂家提供),初始化完成后就可以进行访问了。如果要写数据时先设置坐标,之后再发送写GRAM指令,发送颜色数据,LCD收到后就显示;如果要读数据同样要先设置坐标,之后再发送读GRAM指令,之后再读出颜色数据,单片机获取到数据后再进行处理。
2.2 SDIO相关知识
2.2.1 SDIO接口介绍
SDIO接口全称为“安全数字输入/输出接口”,是基于“SD标准”的一种外设接口,常见的使用场景主要有:SDI/O 卡、SD 存储卡、多媒体卡(MMC 卡)、和CE-ATA 设备。
注:SD I/O 卡本身不是用于存储的卡,它是指利用 SDIO 传输协议的一种外设,如SDIO WiFi模块、SDIO GPS模块、SDIO 以太网模块等。
“SD标准”指的是SD协会发布的SD卡技术规范,具有不同的协议版本,不同的版本规定了不同的速度和容量。由于STM32F4的SDIO接口只支持“SD标准”V2.0,下面简述下SD2.0规范:
- SD2.0规范也叫SDHC规范,符合该规范的卡称为SDHC(SD High Capacity)卡。该规范规定SDHC卡采用FAT32文件系统,最大可以支持32GB的容量;同时规范也对读写速度做了分级,速度等级以Class 0/Class 2/Class 4/Class 6/Class 10划分,它们的最低速度分别是:低于2MB/s、2MB/s、4MB/s、6MB/s、10MB/s。
“SD标准”规定SD卡共有2种类型:SD卡 和microSD卡(原名TF卡)(Mini SD卡已被取代这里就不再细说),它们只有引脚和形状大小不同(SD卡侧面具有一个防写开关),内部结构类似,操作时序完全相同,可以使用完全相同的代码驱动。
2.2.2 SDIO总线
SDIO总线的拓扑结构如下:
接口说明如下:
- CLK:时钟线,由 SDIO 主机产生,即由 STM32 控制器输出,通信时 CLK 时钟线的上升沿时数据才有效有效;
- CMD:命令控制线,SDIO 主机通过该线发送命令控制SD卡,如果命令要求SD卡提供应答 (响应),SD 卡也是通过该线传输应答信息;
- D0-3:数据线,传输读写数据;SD 卡可将 D0 拉低表示忙状态;
- VDD、VSS1、VSS2:电源和地信号。
SD 总线通信是基于命令和数据传输的。SD 通信一般是主机通过 CMD 线(数据线不参与)发送一个命令 (Command),从设备在接收到命令后作出响应 (Response),如有需要会有数据 (Data) 传输参与。注意:SD命令发送时的顺序是从最高位到最低位。
SD 卡的命令固定为48位长,由6个字节组成,格式如下:
- 最高字节的最高2位固定为01(0是起始位,1是传输标志表示主机发送给从机),低6位为命令号 (代号:CMD0~CMD63);
- 字节 2~5为命令地址或者参数,有些命令是没有参数的。
- 最低字节的高七位为CRC值,最低位恒定为1(停止位)。
2.2.3 STM32F4的SDIO接口介绍
STM32F4有一个SDIO接口,支持符合SD协议的各种设备,与 SD 存储卡规格版本 2.0 全兼容。此SDIO接口由SDIO 适配器和 AHB 接口两部分组成:SDIO 适配器提供 SDIO 主机功能,可以提供 SD 时钟、发送命令和进行数据传输;AHB 接口用于控制器访问 SDIO 适配器寄存器并且可以产生中断和 DMA 请求信号。功能框图如下:
SDIOCLK是SDIO适配器时钟,控制单元、命令通道和数据通道都使用这个时钟,SDIOCLK的时钟来源是PLL48CK,即SDIOCLK=PLL48CK=48M。
HCLK/2时钟主要是适配器寄存器和 FIFO 使用,一般情况下HCLK/2=90M(HCK就是单片机的系统主频)。
SDIO_CK 是 SDIO 接口与 SD 卡用于同步的时钟信号,它的时钟来源是SDIOCLK。
如果设置BYPASS模式,SDIO_CK = SDIOCLK48M。若禁止BYPASS 模式,可以通过配置时钟寄存器的 CLKDIV 位控制分频系数,即 SDIO_CK=SDIOCLK/(2+CLKDIV)= HCLK/(2+CLKDIV)。注意:SD 卡普遍要求 SDIO_CK 时钟频率不能超过 25MHz。
SDIO_D[7:0]是SDIO接口的7根数据线,在驱动SD卡时最多使用4根线。STM32F4的SDIO接口支持三种不同的数据总线模式:1 位(默认)、4 位 和 8 位。SD主机复位后默认使用SDIO_D0 用于数据传输。初始化后主机可以改变数据总线的宽度(通过 ACMD6 命令设置)。
2.3 FATFS知识
FATFS 是一个完全免费开源的 FAT/exFAT 文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准 C 语言(ANSI C C89)编写,所以具有良好的硬件平台独立性,只需做简单的修改就可以移植到常见的单片机上。它支持 FATl2、FATl6 和 FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写。
FATFS 模块最顶层是应用层,使用者只需要调用FATFS 模块提供给用户的一系列应用接口函数即可实现文件读写,如 f_open、f_read、f_write和f_close等。
中间层 FATFS 模块,实现了 FAT 文件读/写协议。FATFS 模块提供的是 ff.c 和 ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。
需要我们编写移植代码的是 FATFS 模块提供的底层接口,它包括存储媒介读/写接口(diskI/O)和供给文件创建修改时间的实时时钟。
FATFS 的源码及英文详述,大家可以在:http://elm-chan.org/fsw/ff/00index_e.html 这个网站下载到,本实验目前使用的版本为 R0.14,下载解压后真正的源码是“source”文件夹里的7个c/h文件,它们的功能如下:
2.4 I2S知识
2.4.1 I2S接口介绍
I2S接口是一种专门用来传输音频的接口。它采用串行通信,支持全双工和半双工,最少仅需3根信号线即可进行通讯(SCK、LRCK、SDATA中的任意一跟),接口如下:
SCK:主机发送,也叫SCLK(串行时钟)、BCLK(位时钟),每一个时钟传输一个位。SCK频率=声道数*采样率*采样位数。
LRCK:主机发送,也叫LRCLK(帧时钟)、WS(声道选择、字段选择),用于表示当前传输的数据是哪一个声道,为0是表示左声道,为1时表示的是右声道。LRCK频率=采样频率。
SDATA:也叫SD(串行数据),有2根,分别是SDATAI和SDATDO,传输的是用二进制补码表示的音频数据,MSB在前,LSB在后(大端格式)。
MCLK:主时钟,也叫系统时钟,作用是为了使I2S系统之间更好的同步,非必须,由芯片决定(ES8388必须接256倍的fs时钟),MCLK频率=128/256/512*采样频率;
2.4.2 I2S数据格式
常见的I2S的数据格式有以下三种:飞利浦标准(SAI标准)、左对齐标准(MSB标准)和右对齐标准(LSB标准)。通常情况下飞利浦标准(SAI标准)用得较多,这也就介绍飞利浦标准(SAI标准)的数据格式,特别注意的是:I2S传输数据时数据在跟随 LRCK 变化后的 BCLK 的第二个上升沿时传输 MSB,其他位一直到 LSB 按顺序传输,数据不够时补0。时序图如下:
2.4.3 STM32F4的I2S接口特性
- 数据传输方向固定为MSB在前;
- I2S数据寄存器为16位,每次发送的数据是16的倍数,数据长度不够时自动补0;
- 支持主时钟(MCLK)输出,固定为256倍的fs;
- I2S接口与SPI部分共用,I2S接口使用了几乎和SPI相同的引脚、标志和中断,通过设置SPI_I2SCFGR 寄存器的 I2SMOD 位即可开启 I2S 功能。
2.4.4 STM32F4的I2S信号线
- SD[=SDATAO]:串行数据(映射到 MOSI 引脚),用于发送或接收两个时分复用的数据通道上的数据(仅半双工模式)。
- WS[=LRCK]:字选择(映射到 NSS 引脚),即帧时钟,用于切换左右声道的数据。WS 频率等于音频信号采样率(fs)。
- CK[=SCK]:串行时钟(映射到 SCK 引脚),即位时钟,是主模式下的串行时钟输出以及从模式下的串行时钟输入。CK 频率=采样率*采样位数*声道数;
- I2S2ext_SD 和 I2S3ext_SD[=SDATAI]:仅用于控制 I2S 全双工模式的附加引脚(映射到 MISO 引脚),始终工作在从模式下。
- MCK[=MCLK]:即主时钟输出,当 I2S 配置为主模式(并且 SPI_I2SPR 寄存器中的 MCKOE 位 置 1)时,使用此时钟,该时钟输出频率 256×fs,fs 即音频信号采样频率(fs)。
2.4.5 STM32F4的I2S时钟
STM32F4单片机的I2S时钟是PLLI2SCLK,来源主要有2个:一个是外部时钟I2S_CKIN;另一个则来自系统时钟源(外部高速时钟HSE[看接的晶振的大小]或内部高速时钟HSI[固定16M])经过M分频、再经过PLLI2S锁相环的R分频得到,当系统时钟源为HSE时PLLI2SCLK的计算公式为:PLLI2SCLK=HSE/M*N/R。
当MCK输出使能时,fs=PLLI2SCLK/[256*(2*I2SDIV+ODD)],PLLI2SCLK=[HSE或者HSI]/M*N/R,合并在一起就是:fs=[HSE或者HSI]/M*N/R/[256*(2*I2SDIV+ODD)],单位是Hz。其中N的取值范围是192~432,R的取值范围是2~7,I2SDIV的取值范围是2~255,ODD的取值只有0和1这两个选择。
常用的音频采样率有:22.05Khz、44.1Khz、48Khz、96Khz、196Khz 等。
注意:很多时候经过这个公式得到的fs一般都会有一定的误差,如果需要非常精确的fs则可以采用外部晶振输入。
2.5字库相关知识
2.5.1 字符编码
众所周知,计算机只能识别0和1,所有信息都是以0和1的形式在计算机里面进行存储,文字信息也是一样。那么如何进行区分文字信息呢?这里就引出了字符编码这个概念,就是对字符进行编码,用规定的 01 数字串来表示特定的文字,最简单的字符编码例子是 ASCII 码。此外还有中文编码,中文编码又可以细分 GB2312,GB13000,GBK,BIG5(繁体)等几种。
由于英文文字是由 26 个字母排列组合而成的,所以 ASCII 表就可以适用于表达英文词典库。在汉字系统中,每一个汉字都是一个独立的个体,但是汉字可以以偏旁以及笔画进行划分,不过也是十分杂乱,毕竟汉字现在已经有 8 万多个了,常用的只有 3500 个。所以中文编码是直接对方块字进行编码的,一个汉字使用一个编码。
GBK编码即汉字内码扩展规范,采用的是双字节表示,总体编码范围为0x8140~0xFEFE,第一个字节在 0x81~0xFE 之间,第二个字节分为两个部分,一是 0x40~0x7E,二是 0x80~0xFE。可表示的汉字数达到了 2 万多个,完全能满足我们的一般应用的要求。
有了编码,我们就能可以在计算机上对字符进行操作,但是如果计算机处理完字符后直接以编码的形式输出,我们很难一下子知道究竟是什么图形的字符。因为我们平常看到的都是字符的图形化显示,这里呢,就需要我们提供配套的字符图形。字符图形又称为字模,多个字模组成的文件就叫做字库。当我们为计算机提供了编码和字库的前提下,计算机就可以把字符编码转化成对应的字符图形,我们才能清晰识别。
2.5.2 字库制作
这里采用正点原子开发的取模软件“ATK-XFONT”来制作GBK编码的24*24大小的字库,步骤如下:
在生成字库前可以点击根据下列步骤查看相关参数参数是否异常,操作步骤和正确参数如下图:
生成字库后打开保存文件夹就可以得到一个bin文件和一个txt文件,bin文件则是我们后面需要使用的字库文件:
3、CubeMX配置
3.1 版本信息
CubeMX版本:6.4.0
F4驱动包版本:1.26.0
3.2 配置过程
3.2.1 新建工程,芯片选择STM32F407ZGT6;
3.2.2 进入Project Manager页面
- 首先进入Project选项
- 设置工程名称以及保存地址,我这里就设为MUSIC_Player,保存在桌面的MUSIC_Player文件夹;
- 设置生成代码的IDE,这里选择MDK-ARM;
- 修改堆栈空间:将Min Stack 修改为0X800;
- 修改F4驱动包的版本:去除使用最新版本的勾,手动修改为V1.26.0版本;
- 然后进入Code Generator选项,勾选“Generate peripheral initialization as a pair of ".c/h' fles per periphera”,其含义是生成的外设初始化代码是否要拆分成.c和.h文件。
- 点击最上面的file——>Save Project。
3.2.3 进入Pinout & Configeration页面
- 点击System——>RCC,将High Speek Clock(HSE)设置为“Crystal/Ceramic Resonator”;
- 设置LED、按键和LCD背光控制IO,设置结果如下:
- 点击Connectivity——>USART1,将模式设置为Asynchronous,其余参数保持默认;
- 点击Connectivity——>SDIO,将模式设置为SD 4bits Write bus,其余参数保持默认;
- 点击Connectivity——>I2C1,将模式设置为I2C,在下面的“Parameter Settings”将Primary slave address的值设为26,之后将I2C1的GPIO设置为PB8和PB9。
- 点击Connectivity——>FSMC,找到NOR Flash/PSRAM/ROM/LDC3,将Chip Select设为NE3,Memory type设为SRAM,Address设为19bits,Date bits设为16bits,勾选Byte enable。然后就是下面的NOR/PSRAM3选项中,将 Write operation设为Enable,然后后面的3个参数分别设置为:2-8-0。
- 3.7 点击Connectivity——>FSMC,找到NOR Flash/PSRAM/ROM/LDC4,将Chip Select设为NE4,Memory type设为LCD Interface,LCD Register Select设为A6,Date bits设为16bits。然后就是下面的NOR/PSRAM4选项中,将 Extended mode设为Enable,然后后面的8个参数分别设置为:15-60-0-A,9-9-0-A。
- 3.8 点击Multimedia——>I2S2,将模式设置为Full-Duplex Master,勾选下方的Master Clock Output,之后将下面的“Parameter Settings”中将Date and Frame Format项设为16Bits Date on 32 Bits Frame;
- 3.9 下面的“DMA Settings”中点击Add,上面会弹出一个DMA设置项,DMA Request设为SPI2_TX,之后将Priority设为High,设置完后再单击SPI2_TX会弹出DMA Requset Settings页面,将Mode设为Circular,将Date Width设为Half World。
- 3.10 将I2S2的I2S2_CK脚设为PB13。
3.2.4 进入Clock Configuration页面
时钟树按下图进行设置:
最后点击右上角的“GENENATE CODE”即可生成代码。
4、代码修改
4.1串口和LED驱动
- 修改MDK设置:
- main.h添加头文件:
#include "stdio.h"
#include "string.h"
- 添加串口重定向:"usart.c"文件开头添加以下内容:
int fputc(int ch, FILE *f)
{
//具体哪个串口可以更改huart1为其它串口
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1 , 0x0f);
return ch;
}
- 添加程序运行指示灯LED
stm32f4xx_it.c开头添加:static uint16_t led_count = 0;
SysTick_Handler函数中“ HAL_IncTick();”后添加以下代码:
led_count++;
if(led_count >= 250)
{
led_count = 0;
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);//LED0翻转
}
- 修改main函数
注销其它外设初始化函数,只保留“MX_GPIO_Init();”和“MX_USART1_UART_Init();”;
在while(1)前添加:printf("Syetem Init success\n");
修改完成后编译0错误0警告,烧录到开发板可以看到现象为:开发板的串口打印“Syetem Init success”,同时LED0不停翻转。
4.2 按键驱动
- 在“Drives”文件夹中新建BSP文件夹,之后在“BSP”文件夹中新建key文件夹;
- 在“key”文件夹中新建“key.c” 和“key.h”两个文件;
- 打开工程,新建BSP分组,并将“key.c”添加进工程以及添加编译路径;
- 向“key.c”中添加代码
-
#include "key.h" #define KEY_SCAN_CNT (10-1) //消抖 10ms key_state_t Key_flag[3] = { NULL }; uint8_t Key_State = 0;//全局储存按键状态变量 void Key_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOE_CLK_ENABLE(); /*Configure GPIO pins : PEPin PEPin PEPin */ GPIO_InitStruct.Pin = KEY2_Pin|KEY1_Pin|KEY0_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); } void Key_Scan(void) { uint8_t i = 0; //Key_State = 0;//每次开始扫描前清楚一次案件的按键的状态 for(i=0;i<3;i++)//3个按键 { if(i==0) Key_flag[i].level_state = HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin); else if(i==1) Key_flag[i].level_state = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin); else if(i==2) Key_flag[i].level_state = HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin); else break; switch(Key_flag[i].key_flag) { case KeyState_IDLE: //空闲状态 { if(Key_flag[i].level_state == User_Level) //按下 { Key_flag[i].key_flag = KeyState_CUT; //将状态定义为消抖状态,在下次进入时开始消抖 Key_flag[i].key_cut = KEY_SCAN_CNT; //消抖 } break; } case KeyState_CUT: //消抖状态 { if ( Key_flag[i].key_cut == 0 ) { if(Key_flag[i].level_state == User_Level) //10ms消抖后按键状态为按下 { Key_flag[i].key_flag = KeyState_PRESSED; //将状态定义为按下状态 } else //消抖后按键未按下认为是误触 { Key_flag[i].key_flag = KeyState_IDLE; } } else { Key_flag[i].key_cut--; } break; } case KeyState_PRESSED: //按下状态 { if ( Key_flag[i].level_state == User_Level ) //按键按下 { Key_flag[i].press_time++; //按下时间加1 } else //按键松开 { if ( Key_flag[i].press_time > (1000-1) ) //长按(按下持续时间 >= 1.5s) { Key_flag[i].key_flag = KeyState_IDLE; //恢复到空闲状态 Key_flag[i].key_last = KeyState_LONG_PRESSED; //长按 Key_flag[i].press_time = 0; printf("按键 %d 长按\n",i); Key_State = (i+1); }else if(Key_flag[i].press_time > (90-1)) //短按(持续时间>=90ms) { Key_flag[i].key_flag = KeyState_WAIT_DOUBLE_CLICK; //等待双击 Key_flag[i].press_time = 0; Key_flag[i].key_cut = KEY_SCAN_CNT; //释放消抖 } } break; } case KeyState_WAIT_DOUBLE_CLICK: //释放按键消抖,只在双击时释放消抖 { if ( Key_flag[i].key_cut == 0 ) { Key_flag[i].end_time++; //等待双击 if(Key_flag[i].end_time > (250-1)) //超出等待双击时间 { Key_flag[i].key_last = KeyState_PRESSED; //按键状态最终为短按 Key_flag[i].key_flag = KeyState_IDLE; //空闲 Key_flag[i].end_time = 0; printf("按键 %d 短按\n",i); Key_State = (i+1); } else { if(Key_flag[i].level_state == User_Level) //按键按下 { Key_flag[i].key_flag = KeyState_DOUBLE_CLICKED;//双击状态 Key_flag[i].end_time = 0; Key_flag[i].key_cut = KEY_SCAN_CNT; //按下消抖 } } } else { Key_flag[i].key_cut--; } break; } case KeyState_DOUBLE_CLICKED: { if ( Key_flag[i].key_cut == 0 ) //双击消抖 { if(Key_flag[i].level_state == User_Level) //按键按下 { Key_flag[i].press_time++; } else { Key_flag[i].key_last = KeyState_DOUBLE_CLICKED; //双击 Key_flag[i].key_flag = KeyState_IDLE; Key_flag[i].press_time = 0; Key_flag[i].end_time = 0; printf("按键 %d 双击\n",i); } } else { Key_flag[i].key_cut--; } break; } } } }
- 向“key.h”中添加代码
-
#ifndef __KEY_H__ #define __KEY_H__ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ /* USER CODE BEGIN Prototypes */ /* USER CODE END Prototypes */ #define KEY2_Pin GPIO_PIN_2 #define KEY2_GPIO_Port GPIOE #define KEY1_Pin GPIO_PIN_3 #define KEY1_GPIO_Port GPIOE #define KEY0_Pin GPIO_PIN_4 #define KEY0_GPIO_Port GPIOE #define KEY0_PRES 1 /* KEY0按下 下一曲*/ #define KEY1_PRES 2 /* KEY1按下 播放/暂停*/ #define KEY2_PRES 3 /* KEY2按下 上一曲*/ typedef enum { KeyState_IDLE, //空闲状态。 KeyState_CUT, //消抖状态。 KeyState_PRESSED, //按下状态。 KeyState_WAIT_DOUBLE_CLICK, //等待双击状态。 KeyState_DOUBLE_CLICKED, //双击状态。 KeyState_LONG_PRESSED //长按状态。 }KeyState; typedef struct key_state{ uint8_t key_flag; //按键标志 uint8_t level_state; //电平状态 uint16_t start_time; //按下时间 uint16_t end_time; //松开时间 uint8_t key_cut; //按键消抖 uint8_t key_last; //按键最终状态 uint32_t press_time; //按下时间 }key_state_t; #define User_Level GPIO_PIN_RESET void Key_Init(void); extern uint8_t Key_State; /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void Key_Scan(void); #endif /*__ GPIO_H__ */
- 删除main.h文件中关于按键的宏定义;
- 删除“gpio.c”文件“void MX_GPIO_Init(void)”函数中按键引脚初始化代码;
- stm32f4xx_it.c开头添加头文件:#include "key.h"
- stm32f4xx_it.c文件的SysTick_Handler函数最后添加以下代码:Key_Scan();
- main.c文件添加头文件:#include "key.h";
- main函数中在“MX_USART1_UART_Init();”后添加按键初始化函数:Key_Init();
修改完成后编译0错误0警告,烧录到开发板可以看到现象为开机有打印“Syetem Init success”、LEDD0在不停的闪,同时按键按下时串口会打印哪一个按键按下以及按下的状态。
4.3 增加SRAM驱动
- 打开“fsmc.c”和“fsmc.h”,删除所有和hsram4相关的内容;
- fsmc.h添加以下内容:
#define SRAM_FSMC_NEX 3
#define SRAM_BASE_ADDR (0X60000000 + (0X4000000 * (SRAM_FSMC_NEX - 1)))
- main函数按键驱动后增加以下代码:MX_FSMC_Init();;
修改完成后编译0错误0警告
4.4 增加内存管理代码
- 在“BSP”文件夹中新建MALLOC文件夹;
- 在MALLOC文件夹中新建“malloc.c” 和“malloc.h”两个文件;
- 在malloc.c中添加下列代码
-
#include "malloc.h" #include "fsmc.h" static __align(64) uint8_t mem1base[MEM1_MAX_SIZE]; /* 内部SRAM内存池 */ static __align(64) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(SRAM_BASE_ADDR))); /* 外部SRAM内存池 */ static MT_TYPE mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; /* 内部SRAM内存池MAP */ static MT_TYPE mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(SRAM_BASE_ADDR + MEM2_MAX_SIZE))); /* 外部SRAM内存池MAP */ /* 内存管理参数 */ const uint32_t memtblsize[SRAMBANK] = {MEM1_ALLOC_TABLE_SIZE, MEM2_ALLOC_TABLE_SIZE}; /* 内存表大小 */ const uint32_t memblksize[SRAMBANK] = {MEM1_BLOCK_SIZE, MEM2_BLOCK_SIZE}; /* 内存分块大小 */ const uint32_t memsize[SRAMBANK] = {MEM1_MAX_SIZE, MEM2_MAX_SIZE}; /* 内存总大小 */ /* 内存管理控制器 */ struct _m_mallco_dev mallco_dev = { my_mem_init, /* 内存初始化 */ my_mem_perused, /* 内存使用率 */ mem1base, mem2base, /* 内存池 */ mem1mapbase, mem2mapbase, /* 内存管理状态表 */ 0, 0, /* 内存管理未就绪 */ }; /** * @brief 复制内存 * @param *des : 目的地址 * @param *src : 源地址 * @param n : 需要复制的内存长度(字节为单位) * @retval 无 */ void my_mem_copy(void *des, void *src, uint32_t n) { uint8_t *xdes = des; uint8_t *xsrc = src; while (n--) *xdes++ = *xsrc++; } /** * @brief 设置内存值 * @param *s : 内存首地址 * @param c : 要设置的值 * @param count : 需要设置的内存大小(字节为单位) * @retval 无 */ void my_mem_set(void *s, uint8_t c, uint32_t count) { uint8_t *xs = s; while (count--) *xs++ = c; } /** * @brief 内存管理初始化 * @param memx : 所属内存块 * @retval 无 */ void my_mem_init(uint8_t memx) { uint8_t mttsize = sizeof(MT_TYPE); /* 获取memmap数组的类型长度(uint16_t /uint32_t)*/ my_mem_set(mallco_dev.memmap[memx], 0, memtblsize[memx] * mttsize); /* 内存状态表数据清零 */ mallco_dev.memrdy[memx] = 1; /* 内存管理初始化OK */ } /** * @brief 获取内存使用率 * @param memx : 所属内存块 * @retval 使用率(扩大了10倍,0~1000,代表0.0%~100.0%) */ uint16_t my_mem_perused(uint8_t memx) { uint32_t used = 0; uint32_t i; for (i = 0; i < memtblsize[memx]; i++) { if (mallco_dev.memmap[memx][i]) used++; } return (used * 1000) / (memtblsize[memx]); } /** * @brief 内存分配(内部调用) * @param memx : 所属内存块 * @param size : 要分配的内存大小(字节) * @retval 内存偏移地址 * @arg 0 ~ 0xFFFFFFFE : 有效的内存偏移地址 * @arg 0xFFFFFFFF : 无效的内存偏移地址 */ static uint32_t my_mem_malloc(uint8_t memx, uint32_t size) { signed long offset = 0; uint32_t nmemb; /* 需要的内存块数 */ uint32_t cmemb = 0; /* 连续空内存块数 */ uint32_t i; if (!mallco_dev.memrdy[memx]) { mallco_dev.init(memx); /* 未初始化,先执行初始化 */ } if (size == 0) return 0xFFFFFFFF; /* 不需要分配 */ nmemb = size / memblksize[memx]; /* 获取需要分配的连续内存块数 */ if (size % memblksize[memx]) nmemb++; for (offset = memtblsize[memx] - 1; offset >= 0; offset--) /* 搜索整个内存控制区 */ { if (!mallco_dev.memmap[memx][offset]) { cmemb++; /* 连续空内存块数增加 */ } else { cmemb = 0; /* 连续内存块清零 */ } if (cmemb == nmemb) /* 找到了连续nmemb个空内存块 */ { for (i = 0; i < nmemb; i++) /* 标注内存块非空 */ { mallco_dev.memmap[memx][offset + i] = nmemb; } return (offset * memblksize[memx]); /* 返回偏移地址 */ } } return 0xFFFFFFFF; /* 未找到符合分配条件的内存块 */ } /** * @brief 释放内存(内部调用) * @param memx : 所属内存块 * @param offset : 内存地址偏移 * @retval 释放结果 * @arg 0, 释放成功; * @arg 1, 释放失败; * @arg 2, 超区域了(失败); */ static uint8_t my_mem_free(uint8_t memx, uint32_t offset) { int i; if (!mallco_dev.memrdy[memx]) /* 未初始化,先执行初始化 */ { mallco_dev.init(memx); return 1; /* 未初始化 */ } if (offset < memsize[memx]) /* 偏移在内存池内. */ { int index = offset / memblksize[memx]; /* 偏移所在内存块号码 */ int nmemb = mallco_dev.memmap[memx][index]; /* 内存块数量 */ for (i = 0; i < nmemb; i++) /* 内存块清零 */ { mallco_dev.memmap[memx][index + i] = 0; } return 0; } else { return 2; /* 偏移超区了 */ } } /** * @brief 释放内存(外部调用) * @param memx : 所属内存块 * @param ptr : 内存首地址 * @retval 无 */ void myfree(uint8_t memx, void *ptr) { uint32_t offset; if (ptr == NULL) return; /* 地址为0. */ offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase[memx]; my_mem_free(memx, offset); /* 释放内存 */ } /** * @brief 分配内存(外部调用) * @param memx : 所属内存块 * @param size : 要分配的内存大小(字节) * @retval 分配到的内存首地址. */ void *mymalloc(uint8_t memx, uint32_t size) { uint32_t offset; offset = my_mem_malloc(memx, size); if (offset == 0xFFFFFFFF) /* 申请出错 */ { return NULL; /* 返回空(0) */ } else /* 申请没问题, 返回首地址 */ { return (void *)((uint32_t)mallco_dev.membase[memx] + offset); } } /** * @brief 重新分配内存(外部调用) * @param memx : 所属内存块 * @param *ptr : 旧内存首地址 * @param size : 要分配的内存大小(字节) * @retval 新分配到的内存首地址. */ void *myrealloc(uint8_t memx, void *ptr, uint32_t size) { uint32_t offset; offset = my_mem_malloc(memx, size); if (offset == 0xFFFFFFFF) /* 申请出错 */ { return NULL; /* 返回空(0) */ } else /* 申请没问题, 返回首地址 */ { my_mem_copy((void *)((uint32_t)mallco_dev.membase[memx] + offset), ptr, size); /* 拷贝旧内存内容到新内存 */ myfree(memx, ptr); /* 释放旧内存 */ return (void *)((uint32_t)mallco_dev.membase[memx] + offset); /* 返回新内存首地址 */ } }
- 在malloc.h中添加下列代码
-
#ifndef __MALLOC_H #define __MALLOC_H #include "main.h" /* 定义3个内存池 */ #define SRAMIN 0 /* 内部内存池 */ #define SRAMEX 1 /* 外部内存池 */ #define SRAMBANK 2 /* 定义支持的SRAM块数 */ /* 定义内存管理表类型,当外扩SDRAM的时候,必须使用uint32_t类型,否则可以定义成uint16_t,以节省内存占用 */ #define MT_TYPE uint16_t /* 单块内存,内存管理所占用的全部空间大小计算公式如下: * size = MEM1_MAX_SIZE + (MEM1_MAX_SIZE / MEM1_BLOCK_SIZE) * sizeof(MT_TYPE) * 以SRAMEX为例,size = 963 * 1024 + (963 * 1024 / 32) * 2 = 1047744 ≈ 1023KB * 已知总内存容量(size),最大内存池的计算公式如下: * MEM1_MAX_SIZE = (MEM1_BLOCK_SIZE * size) / (MEM1_BLOCK_SIZE + sizeof(MT_TYPE)) * 以CCM为例, MEM2_MAX_SIZE = (32 * 64) / (32 + 2) = 60.24KB ≈ 60KB */ /* mem1内存参数设定.mem1完全处于内部SRAM里面 */ #define MEM1_BLOCK_SIZE 32 /* 内存块大小为32字节 */ #define MEM1_MAX_SIZE 100 * 1024 /* 最大管理内存 100K */ #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE /* 内存表大小 */ /* mem3内存参数设定.mem3是外扩SRAM */ #define MEM2_BLOCK_SIZE 32 /* 内存块大小为32字节 */ #define MEM2_MAX_SIZE 963 * 1024 /* 最大管理内存963K */ #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE /* 内存表大小 */ /* 如果没有定义NULL, 定义NULL */ #ifndef NULL #define NULL 0 #endif /* 内存管理控制器 */ struct _m_mallco_dev { void (*init)(uint8_t); /* 初始化 */ uint16_t (*perused)(uint8_t); /* 内存使用率 */ uint8_t *membase[SRAMBANK]; /* 内存池 管理SRAMBANK个区域的内存 */ MT_TYPE *memmap[SRAMBANK]; /* 内存管理状态表 */ uint8_t memrdy[SRAMBANK]; /* 内存管理是否就绪 */ }; extern struct _m_mallco_dev mallco_dev; /* 在mallco.c里面定义 */ /* 函数声明 */ void my_mem_init(uint8_t memx); /* 内存管理初始化函数(外/内部调用) */ uint16_t my_mem_perused(uint8_t memx) ; /* 获得内存使用率(外/内部调用) */ void my_mem_set(void *s, uint8_t c, uint32_t count); /* 内存设置函数 */ void my_mem_copy(void *des, void *src, uint32_t n); /* 内存拷贝函数 */ void myfree(uint8_t memx, void *ptr); /* 内存释放(外部调用) */ void *mymalloc(uint8_t memx, uint32_t size); /* 内存分配(外部调用) */ void *myrealloc(uint8_t memx, void *ptr, uint32_t size); /* 重新分配内存(外部调用) */ #endif
- 将“malloc.c”添加进工程以及添加编译路径;
- main.c文件开头添加头文件:#include "malloc.h";
- 在main函数开头添加语句:char *str_buf = 0;
- 注销main函数中的“printf("Syetem Init success\n");”语句;
- 在main函数中按键初始化函数后添加以下代码:
my_mem_init(SRAMIN);
my_mem_init(SRAMEX);
str_buf = (char *)mymalloc(SRAMEX, 100);
if(str_buf)
{
memset(str_buf, 0, 110);
memset(str_buf, '1', 100);
printf("%s\n",str_buf);
myfree(SRAMIN, str_buf);
}
else printf("mymalloc failed\n");
修改完成后编译0错误0警告,烧录到开发板,可以看到串口接收到了100个字节的“1”,这就表明内存管理已经正常工作了(如果打印的是“mymalloc failed”请再仔细核对代码)。
4.5 增加SD卡驱动
- 将“sdio.c” 和“sdio.h”两个文件重命名为“sd_card.c” 和“sd_card.h”;
- 在“BSP”文件夹中新建sd_card文件夹;
- 将“sd_card.c” 和“sd_card.h”两个文件移至sd_card文件夹;
- 将“sd_card.c”添加进工程以及添加编译路径;
- 将“sd_card.c”开头的“#include "sdio.h"”改为“#include "sd_card.h"”;
- “sd_card.c”开头添加以下代码:HAL_SD_CardInfoTypeDef sd_card_info_handle; /* SD卡信息结构体 */;
- “sd_card.c”将“void MX_SDIO_SD_Init(void)”改为“uint8_t MX_SDIO_SD_Init(void)”;
- “sd_card.c”将两个“Error_Handler();”分别改为“return 1;”和“return 2;”;
- “sd_card.c”这MX_SDIO_SD_Init函数最后添加以下三行代码:Get_SD_Card_info();、show_sdcard_info();、return 0;
- “sd_card.c”最后添加“void Get_SD_Card_info(void)”函数和“void show_sdcard_info(void)”函数代码
-
void Get_SD_Card_info(void) { if( HAL_SD_GetCardInfo(&hsd, &sd_card_info_handle) != HAL_OK) /* 获取SD卡信息 */ { printf("Get_SD_Card_info failed\n"); } } void show_sdcard_info(void) { HAL_SD_CardCIDTypeDef sd_card_cid; HAL_SD_GetCardCID(&hsd, &sd_card_cid); /* 获取CID */ Get_SD_Card_info(); /* 获取SD卡信息 */ switch (sd_card_info_handle.CardType) { case CARD_SDSC: { if (sd_card_info_handle.CardVersion == CARD_V1_X) { printf("Card Type:SDSC V1\r\n"); } else if (sd_card_info_handle.CardVersion == CARD_V2_X) { printf("Card Type:SDSC V2\r\n"); } } break; case CARD_SDHC_SDXC: printf("Card Type:SDHC\r\n"); break; default: break; } printf("Card ManufacturerID:%d\r\n", sd_card_cid.ManufacturerID); /* 制造商ID */ printf("Card RCA:%d\r\n", sd_card_info_handle.RelCardAdd); /* 卡相对地址 */ printf("Card Capacity:%d MB\r\n", (uint32_t)SD_TOTAL_SIZE_MB(&hsd)); /* 显示容量 */ printf("Card BlockSize:%d\r\n\r\n", sd_card_info_handle.BlockSize); /* 显示块大小 */ }
- 将“sd_card.h”开头的“__SDIO_H__”改为“__SD_CARD_H__”;
- “sd_card.h”开头添加宏定义
-
#define SD_TIMEOUT ((uint32_t)0XFFFFFFFF) /* 超时时间 */ #define SD_TRANSFER_OK ((uint8_t)0x00) #define SD_TRANSFER_BUSY ((uint8_t)0x01) /* 根据 SD_HandleTypeDef 定义的宏,用于快速计算容量 */ #define SD_TOTAL_SIZE_BYTE(__Handle__) (((uint64_t)((__Handle__)->SdCard.LogBlockNbr)*((__Handle__)->SdCard.LogBlockSize))>>0) #define SD_TOTAL_SIZE_KB(__Handle__) (((uint64_t)((__Handle__)->SdCard.LogBlockNbr)*((__Handle__)->SdCard.LogBlockSize))>>10) #define SD_TOTAL_SIZE_MB(__Handle__) (((uint64_t)((__Handle__)->SdCard.LogBlockNbr)*((__Handle__)->SdCard.LogBlockSize))>>20) #define SD_TOTAL_SIZE_GB(__Handle__) (((uint64_t)((__Handle__)->SdCard.LogBlockNbr)*((__Handle__)->SdCard.LogBlockSize))>>30)
- “sd_card.h”开头添加外部声明:extern HAL_SD_CardInfoTypeDef sd_card_info_handle; /* SD卡信息结构体 */;
- 将“sd_card.h”中的“void MX_SDIO_SD_Init(void);”改为“uint8_t MX_SDIO_SD_Init(void);”
- 在“sd_card.h”最后添加:“void Get_SD_Card_info(void);”和“void show_sdcard_info(void);”
- main.c文件开头删除“#include "sdio.h"”并添加头文件:#include "sd_card.h";
- 删除main函数开头的“char *str_buf = 0;”语句;
- 删除main函数“my_mem_init(SRAMIN);”语句后“while(1)”语句前的内容;
- 在main函数“my_mem_init(SRAMIN);”语句后添加以下代码:
while(MX_SDIO_SD_Init())
{
printf("No SD card.....\n");
HAL_Delay(2000);
}
修改完成后编译0错误0警告,烧录到开发板后在插入SD卡时可以看到串口有打印SD卡的信息,在不插入SD卡时串口不停打印“No SD card.....”。
4.6 增加LCD驱动
- 在“BSP”文件夹中新建“lcd”文件夹;
- 在MALLOC文件夹中新建“lcd.c” 、“lcd.h”、“lcd_ex.c” 和“lcdfont.h”四个文件;
- 在lcd.c中添加下列代码
-
#include "lcd.h" #include "lcd_ex.c" #include "lcdfont.h" SRAM_HandleTypeDef hsram4; /* LCD的画笔颜色和背景色 */ uint32_t g_point_color = 0xFF000000; /* 画笔颜色 */ uint32_t g_back_color = 0xFFFFFFFF; /* 背景色 */ /* 管理LCD重要参数 */ _lcd_dev lcddev; static void MX_SRAM_NE4_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; FMC_NORSRAM_TimingTypeDef Timing = {0}; FMC_NORSRAM_TimingTypeDef ExtTiming = {0}; /* USER CODE BEGIN FMC_Init 1 */ /* USER CODE END FMC_Init 1 */ /*****************LCD IO Init*****************************************/ /* Peripheral clock enable */ __HAL_RCC_FSMC_CLK_ENABLE(); /** FSMC GPIO Configuration PF12 ------> FSMC_A6 PE7 ------> FSMC_D4 PE8 ------> FSMC_D5 PE9 ------> FSMC_D6 PE10 ------> FSMC_D7 PE11 ------> FSMC_D8 PE12 ------> FSMC_D9 PE13 ------> FSMC_D10 PE14 ------> FSMC_D11 PE15 ------> FSMC_D12 PD8 ------> FSMC_D13 PD9 ------> FSMC_D14 PD10 ------> FSMC_D15 PD14 ------> FSMC_D0 PD15 ------> FSMC_D1 PD0 ------> FSMC_D2 PD1 ------> FSMC_D3 PD4 ------> FSMC_NOE PD5 ------> FSMC_NWE PG12 ------> FSMC_NE4 */ /* GPIO_InitStruct */ GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); /* GPIO_InitStruct */ GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); /* GPIO_InitStruct */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4 |GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* GPIO_InitStruct */ GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FSMC; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /*****************LCD IO Init*****************************************/ /*****************SRAM Init*****************************************/ /** Perform the SRAM1 memory initialization sequence */ hsram4.Instance = FMC_NORSRAM_DEVICE; hsram4.Extended = FMC_NORSRAM_EXTENDED_DEVICE; /* hsram4.Init */ hsram4.Init.NSBank = FSMC_NORSRAM_BANK4; /* 使用NE4 */ hsram4.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; /* 地址/数据线不复用 */ hsram4.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; hsram4.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; /* 16位数据宽度 */ hsram4.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */ hsram4.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */ hsram4.Init.WrapMode = FSMC_WRAP_MODE_DISABLE; hsram4.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */ hsram4.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; /* 存储器写使能 */ hsram4.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; /* 等待使能位,此处未用到 */ hsram4.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE; /* 读写使用不同的时序 */ hsram4.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; /* 是否使能同步传输模式下的等待信号,此处未用到 */ hsram4.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* 禁止突发写 */ hsram4.Init.PageSize = FSMC_PAGE_SIZE_NONE; /* Timing */ Timing.AddressSetupTime = 15; Timing.AddressHoldTime = 0; Timing.DataSetupTime = 60; // Timing.BusTurnAroundDuration = 0; // Timing.CLKDivision = 16; // Timing.DataLatency = 17; Timing.AccessMode = FSMC_ACCESS_MODE_A; /* ExtTiming */ ExtTiming.AddressSetupTime = 9; ExtTiming.AddressHoldTime = 0; ExtTiming.DataSetupTime = 9; // ExtTiming.BusTurnAroundDuration = 0; // ExtTiming.CLKDivision = 16; // ExtTiming.DataLatency = 17; ExtTiming.AccessMode = FSMC_ACCESS_MODE_A; if (HAL_SRAM_Init(&hsram4, &Timing, &ExtTiming) != HAL_OK) { Error_Handler( ); } } /** * @brief LCD读数据 * @param 无 * @retval 读取到的数据 */ static uint16_t lcd_rd_data(void) { volatile uint16_t ram; /* 防止被优化 */ ram = LCD->LCD_RAM; return ram; } static void Get_LCD_IC_model(void) { /* 尝试9341 ID的读取 */ lcd_wr_regno(0xD3); lcddev.id = lcd_rd_data(); /* dummy read */ lcddev.id = lcd_rd_data(); /* 读到0x00 */ lcddev.id = lcd_rd_data(); /* 读取93 */ lcddev.id <<= 8; lcddev.id |= lcd_rd_data(); /* 读取41 */ 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(); /* 读回0x80 */ lcddev.id <<= 8; lcd_wr_regno(0xC501); /* 读取ID高八位 */ lcddev.id |= lcd_rd_data(); /* 读回0x00 */ HAL_Delay(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 */ } } } } } } } void LCD_Init(void) { FMC_NORSRAM_TimingTypeDef fmc_write_handle; MX_SRAM_NE4_Init();//初始化 Get_LCD_IC_model();//读ID /* 特别注意, 如果在main函数里面屏蔽串口1初始化, 则会卡死在printf * 里面(卡死在f_putc函数), 所以, 必须初始化串口1, 或者屏蔽掉下面 * 这行 printf 语句 !!!!!!! */ //printf("LCD ID:%x\r\n", lcddev.id); /* 打印LCD ID */ if (lcddev.id == 0x9341) { lcd_ex_ili9341_reginit(); /* 执行ILI9341初始化 */ } else if (lcddev.id == 0x7789) { lcd_ex_st7789_reginit(); /* 执行ST7789初始化 */ } 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初始化 */ } /* 由于不同屏幕的写时序不同,这里的时序可以根据自己的屏幕进行修改 (若插上长排线对时序也会有影响,需要自己根据情况修改) */ /* 初始化完成以后,提速 */ if (lcddev.id == 0x9341 || lcddev.id == 0x7789) { /* 重新配置写时序控制寄存器的时序 */ fmc_write_handle.AddressSetupTime = 4; fmc_write_handle.DataSetupTime = 4; FMC_NORSRAM_Extended_Timing_Init(hsram4.Extended, &fmc_write_handle, hsram4.Init.NSBank, hsram4.Init.ExtendedMode); } else if (lcddev.id == 0x5310 || lcddev.id == 0x9806 || lcddev.id == 0x7796) { /* 重新配置写时序控制寄存器的时序 */ fmc_write_handle.AddressSetupTime = 3; fmc_write_handle.DataSetupTime = 3; FMC_NORSRAM_Extended_Timing_Init(hsram4.Extended, &fmc_write_handle, hsram4.Init.NSBank, hsram4.Init.ExtendedMode); } else if (lcddev.id == 0x5510 || lcddev.id == 0x1963) { /* 重新配置写时序控制寄存器的时序 */ fmc_write_handle.AddressSetupTime = 2; fmc_write_handle.DataSetupTime = 2; FMC_NORSRAM_Extended_Timing_Init(hsram4.Extended, &fmc_write_handle, hsram4.Init.NSBank, hsram4.Init.ExtendedMode); } lcd_display_dir(0); /* 默认为竖屏 */ printf("lcd_size:width= %d px, height= %d px\n\n",lcddev.width, lcddev.height);//打印屏幕尺寸 LCD_BL(1); /* 点亮背光 */ lcd_clear(WHITE); } /** * @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 i : 延时的数值 * @retval 无 */ static void lcd_opt_delay(uint32_t i) { while (i--); /* 使用AC6时空循环可能被优化,可使用while(1) __asm volatile(""); */ } /** * @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直接读就可以 */ } lcd_opt_delay(2); r = lcd_rd_data(); /* 实际坐标颜色 */ if (lcddev.id == 0x7796) /* 7796 一次读取一个像素值 */ { return r; } /* 9341/5310/5510/7789/9806要分2次读出 */ lcd_opt_delay(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)); /* ILI9341/NT35310/NT35510/ST7789/ILI9806需要公式转换一下 */ } /** * @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不改变扫描方向!竖屏时1963改变方向(这里仅用于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 设置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; } } /* dir = 0 */ 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 准备写GRAM 清屏函数调用 * @param 无 * @retval 无 */ void lcd_write_ram_prepare(void) { LCD->LCD_REG = lcddev.wramcmd; } /** * @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 清屏函数 * @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; } } /*******************************************LCD应用代码*************************************************/ /** * @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 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 画线 * @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 x1,y1: 起点坐标 * @param x2,y2: 终点坐标 * @param color: 矩形的颜色 * @retval 无 */ void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) { lcd_draw_line(x1, y1, x2, y1, color); lcd_draw_line(x1, y1, x1, y2, color); lcd_draw_line(x1, y2, x2, y2, color); lcd_draw_line(x2, y1, x2, y2, color); } /** * @brief 画圆 * @param x0,y0 : 圆中心坐标 * @param r : 半径 * @param color : 圆的颜色 * @retval 无 */ void lcd_draw_circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color) { int a, b; int di; a = 0; b = r; di = 3 - (r << 1); /* 判断下个点位置的标志 */ while (a <= b) { lcd_draw_point(x0 + a, y0 - b, color); /* 5 */ lcd_draw_point(x0 + b, y0 - a, color); /* 0 */ lcd_draw_point(x0 + b, y0 + a, color); /* 4 */ lcd_draw_point(x0 + a, y0 + b, color); /* 6 */ lcd_draw_point(x0 - a, y0 + b, color); /* 1 */ lcd_draw_point(x0 - b, y0 + a, color); lcd_draw_point(x0 - a, y0 - b, color); /* 2 */ lcd_draw_point(x0 - b, y0 - a, color); /* 7 */ a++; /* 使用Bresenham算法画圆 */ if (di < 0) { di += 4 * a + 6; } else { di += 10 + 4 * (a - b); b--; } } } /** * @brief 填充实心圆 * @param x,y : 圆中心坐标 * @param r : 半径 * @param color: 圆的颜色 * @retval 无 */ void lcd_fill_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color) { uint32_t i; uint32_t imax = ((uint32_t)r * 707) / 1000 + 1; uint32_t sqmax = (uint32_t)r * (uint32_t)r + (uint32_t)r / 2; uint32_t xr = r; lcd_draw_hline(x - r, y, 2 * r, color); for (i = 1; i <= imax; i++) { if ((i * i + xr * xr) > sqmax) { /* draw lines from outside */ if (xr > imax) { lcd_draw_hline (x - i + 1, y + xr, 2 * (i - 1), color); lcd_draw_hline (x - i + 1, y - xr, 2 * (i - 1), color); } xr--; } /* draw lines from inside (center) */ lcd_draw_hline(x - xr, y + i, 2 * xr, color); lcd_draw_hline(x - xr, y - i, 2 * xr, color); } } /** * @brief 在指定位置显示一个字符 * @param x,y : 坐标 * @param chr : 要显示的字符:" "--->"~" * @param size : 字体大小 12/16/24/32 * @param mode : 叠加方式(1); 非叠加方式(0) * @param color: 字体颜色 * @retval 无 */ void lcd_show_char(uint16_t x, uint16_t y, char chr, uint8_t size, uint8_t mode, uint16_t color) { uint8_t temp, t1, t; uint16_t y0 = y; uint8_t csize = 0; uint8_t *pfont = 0; csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); /* 得到字体一个字符对应点阵集所占的字节数 */ chr = chr - ' '; /* 得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库) */ switch (size) { case 12: pfont = (uint8_t *)asc2_1206[chr]; /* 调用1206字体 */ break; case 16: pfont = (uint8_t *)asc2_1608[chr]; /* 调用1608字体 */ break; case 24: pfont = (uint8_t *)asc2_2412[chr]; /* 调用2412字体 */ break; case 32: pfont = (uint8_t *)asc2_3216[chr]; /* 调用3216字体 */ break; default: return ; } for (t = 0; t < csize; t++) { temp = pfont[t]; /* 获取字符的点阵数据 */ for (t1 = 0; t1 < 8; t1++) /* 一个字节8个点 */ { if (temp & 0x80) /* 有效点,需要显示 */ { lcd_draw_point(x, y, color); /* 画点出来,要显示这个点 */ } /*如果无效点的颜色要显示成背景色请做以下处理*/ //else if (mode == 0) /* 无效点,不显示 */ //{ // lcd_draw_point(x, y, g_back_color); /* 画背景色,相当于这个点不显示(注意背景色由全局变量控制) */ //} temp <<= 1; /* 移位, 以便获取下一个位的状态 */ y++; if (y >= lcddev.height)return; /* 超区域了 */ if ((y - y0) == size) /* 显示完一列了? */ { y = y0; /* y坐标复位 */ x++; /* x坐标递增 */ if (x >= lcddev.width) { return; /* x坐标超区域了 */ } break; } } } } /** * @brief 平方函数, m^n * @param m: 底数 * @param n: 指数 * @retval m的n次方 */ static uint32_t lcd_pow(uint8_t m, uint8_t n) { uint32_t result = 1; while (n--) { result *= m; } return result; } /** * @brief 显示len个数字 * @param x,y : 起始坐标 * @param num : 数值(0 ~ 2^32) * @param len : 显示数字的位数 * @param size: 选择字体 12/16/24/32 * @param color: 字体颜色 * @retval 无 */ void lcd_show_num(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint16_t color) { uint8_t t, temp; uint8_t enshow = 0; for (t = 0; t < len; t++) /* 按总显示位数循环 */ { temp = (num / lcd_pow(10, len - t - 1)) % 10; /* 获取对应位的数字 */ if (enshow == 0 && t < (len - 1)) /* 没有使能显示,且还有位要显示 */ { if (temp == 0) { lcd_show_char(x + (size / 2) * t, y, ' ', size, 0, color); /* 显示空格,占位 */ continue; /* 继续下个一位 */ } else { enshow = 1; /* 使能显示 */ } } lcd_show_char(x + (size / 2) * t, y, temp + '0', size, 0, color); /* 显示字符 */ } } /** * @brief 扩展显示len个数字(高位是0也显示) * @param x,y : 起始坐标 * @param num : 数值(0 ~ 2^32) * @param len : 显示数字的位数 * @param size: 选择字体 12/16/24/32 * @param mode: 显示模式 * [7]:0,不填充;1,填充0. * [6:1]:保留 * [0]:0,非叠加显示;1,叠加显示. * @param color: 字体颜色 * @retval 无 */ void lcd_show_xnum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode, uint16_t color) { uint8_t t, temp; uint8_t enshow = 0; for (t = 0; t < len; t++) /* 按总显示位数循环 */ { temp = (num / lcd_pow(10, len - t - 1)) % 10; /* 获取对应位的数字 */ if (enshow == 0 && t < (len - 1)) /* 没有使能显示,且还有位要显示 */ { if (temp == 0) { if (mode & 0x80) /* 高位需要填充0 */ { lcd_show_char(x + (size / 2) * t, y, '0', size, mode & 0x01, color); /* 用0占位 */ } else { lcd_show_char(x + (size / 2) * t, y, ' ', size, mode & 0x01, color); /* 用空格占位 */ } continue; } else { enshow = 1; /* 使能显示 */ } } lcd_show_char(x + (size / 2) * t, y, temp + '0', size, mode & 0x01, color); } } /** * @brief 显示字符串 * @param x,y : 起始坐标 * @param width,height: 区域大小 * @param size : 选择字体 12/16/24/32 * @param p : 字符串首地址 * @param color : 字体颜色 * @retval 无 */ void lcd_show_string(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, uint16_t color) { uint8_t x0 = x; width += x; height += y; while ((*p <= '~') && (*p >= ' ')) /* 判断是不是非法字符! */ { if (x >= width) { x = x0; y += size; } if (y >= height) { break; /* 退出 */ } lcd_show_char(x, y, *p, size, 0, color); x += size / 2; p++; } }
- 在lcd.h中添加下列代码
-
#ifndef __LCD_H #define __LCD_H #include "main.h" /* LCD背光控制 */ #define LCD_BL(x) do{ x ? \ HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_RESET); \ }while(0) /* LCD地址结构体 */ typedef struct { volatile uint16_t LCD_REG; volatile uint16_t LCD_RAM; } LCD_TypeDef; /* LCD_FMC_NEX:NE1至NE4 LCD_FMC_AX:RS脚接在了数据脚的哪一个,A0至A25 */ #define LCD_FMC_NEX 4 /* 使用FMC_NE1接LCD_CS,取值范围只能是: 1~4 */ #define LCD_FMC_AX 6 /* 使用FMC_A18接LCD_RS,取值范围是: 0 ~ 25 */ #define LCD_BASE (uint32_t)((0X60000000 + (0X4000000 * (LCD_FMC_NEX - 1))) | (((1 << LCD_FMC_AX) * 2) -2)) #define LCD ((LCD_TypeDef *) LCD_BASE) /* 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; /******************************************************************************************/ /* LCD扫描方向和颜色 定义 */ /* 扫描方向定义 */ #define L2R_U2D 0 /* 从左到右,从上到下 */ #define L2R_D2U 1 /* 从左到右,从下到上 */ #define R2L_U2D 2 /* 从右到左,从上到下 */ #define R2L_D2U 3 /* 从右到左,从下到上 */ #define U2D_L2R 4 /* 从上到下,从左到右 */ #define U2D_R2L 5 /* 从上到下,从右到左 */ #define D2U_L2R 6 /* 从下到上,从左到右 */ #define D2U_R2L 7 /* 从下到上,从右到左 */ #define DFT_SCAN_DIR L2R_U2D /* 默认的扫描方向 */ /* 常用画笔颜色 */ #define WHITE 0xFFFF /* 白色 */ #define BLACK 0x0000 /* 黑色 */ #define RED 0xF800 /* 红色 */ #define GREEN 0x07E0 /* 绿色 */ #define BLUE 0x001F /* 蓝色 */ #define MAGENTA 0xF81F /* 品红色/紫红色 = BLUE + RED */ #define YELLOW 0xFFE0 /* 黄色 = GREEN + RED */ #define CYAN 0x07FF /* 青色 = GREEN + BLUE */ /* 非常用颜色 */ #define BROWN 0xBC40 /* 棕色 */ #define BRRED 0xFC07 /* 棕红色 */ #define GRAY 0x8430 /* 灰色 */ #define DARKBLUE 0x01CF /* 深蓝色 */ #define LIGHTBLUE 0x7D7C /* 浅蓝色 */ #define GRAYBLUE 0x5458 /* 灰蓝色 */ #define LIGHTGREEN 0x841F /* 浅绿色 */ #define LGRAY 0xC618 /* 浅灰色(PANNEL),窗体背景色 */ #define LGRAYBLUE 0xA651 /* 浅灰蓝色(中间层颜色) */ #define LBBLUE 0x2B12 /* 浅棕蓝色(选择条目的反色) */ /******************************************************************************************/ /* SSD1963相关配置参数(一般不用改) */ /* LCD分辨率设置 */ #define SSD_HOR_RESOLUTION 800 /* LCD水平分辨率 */ #define SSD_VER_RESOLUTION 480 /* LCD垂直分辨率 */ /* LCD驱动参数设置 */ #define SSD_HOR_PULSE_WIDTH 1 /* 水平脉宽 */ #define SSD_HOR_BACK_PORCH 46 /* 水平前廊 */ #define SSD_HOR_FRONT_PORCH 210 /* 水平后廊 */ #define SSD_VER_PULSE_WIDTH 1 /* 垂直脉宽 */ #define SSD_VER_BACK_PORCH 23 /* 垂直前廊 */ #define SSD_VER_FRONT_PORCH 22 /* 垂直前廊 */ /* 如下几个参数,自动计算 */ #define SSD_HT (SSD_HOR_RESOLUTION + SSD_HOR_BACK_PORCH + SSD_HOR_FRONT_PORCH) #define SSD_HPS (SSD_HOR_BACK_PORCH) #define SSD_VT (SSD_VER_RESOLUTION + SSD_VER_BACK_PORCH + SSD_VER_FRONT_PORCH) #define SSD_VPS (SSD_VER_BACK_PORCH) /******************************************************************************************/ extern _lcd_dev lcddev; /* 管理LCD重要参数 */ extern uint32_t g_point_color; /* 画笔颜色 */ extern uint32_t g_back_color ; /* 背景色 */ /*******************************************LCD驱动代码*************************************************/ void LCD_Init(void); void lcd_wr_data(volatile uint16_t data);//LCD写数据 void lcd_wr_regno(volatile uint16_t regno);//LCD写寄存器编号/地址函数 void lcd_write_reg(uint16_t regno, uint16_t data);//LCD写寄存器 uint32_t lcd_read_point(uint16_t x, uint16_t y);//读取个某点的颜色值 void lcd_scan_dir(uint8_t dir);//设置LCD的自动扫描方向(对RGB屏无效) 设置LCD显示方向调用 void lcd_display_dir(uint8_t dir);//设置LCD显示方向 void lcd_write_ram_prepare(void);//准备写GRAM 清屏函数调用 void lcd_set_cursor(uint16_t x, uint16_t y);//设置光标位置(对RGB屏无效) 清屏函数调用 void lcd_clear(uint16_t color);//清屏 /*******************************************LCD应用代码*************************************************/ void lcd_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color);//在指定区域内填充单个颜色 void lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color);//在指定区域内填充指定颜色块 void lcd_draw_point(uint16_t x, uint16_t y, uint32_t color);//画点 void lcd_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);//画线 void lcd_draw_hline(uint16_t x, uint16_t y, uint16_t len, uint16_t color);//画水平线 void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);//画矩形 void lcd_draw_circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color);//画圆 void lcd_fill_circle(uint16_t x, uint16_t y, uint16_t r, uint16_t color);//填充实心圆 void lcd_show_char(uint16_t x, uint16_t y, char chr, uint8_t size, uint8_t mode, uint16_t color);//在指定位置显示一个字符 void lcd_show_num(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint16_t color);//显示len个数字 void lcd_show_xnum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode, uint16_t color);//扩展显示len个数字(高位是0也显示) void lcd_show_string(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, uint16_t color); //显示字符串 #endif
- 在lcd_ex.c中添加下列代码
-
#include "main.h" #include "lcd.h" /* * 屏幕类型测试顺序 *1、判断的芯片型号:ILI941 发送寄存器编号:0XD3 读取的芯片ID:0X9341 *2、判断的芯片型号:ST7789 发送寄存器编号:0X04 读取的芯片ID:0X8552 将芯片ID强制转换成:0X7789 *3、判断的芯片型号:NT35310 发送寄存器编号:0XD4 读取的芯片ID:0X5310 *4、判断的芯片型号:ST7796 发送寄存器编号:0XD3 读取的芯片ID:0X7796 *5、判断的芯片型号:NT35510 发送寄存器编号:发送密钥 读取的芯片ID:0X5510 *6、判断的芯片型号:ILI9806 发送寄存器编号:0XD3 读取的芯片ID:0X9806 *7、判断的芯片型号:SSD163 发送寄存器编号:0XA1 读取的芯片ID:0X5761 将芯片ID强制转换成:0X1963 */ /** * @brief ILI9341寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_ili9341_reginit(void) { lcd_wr_regno(0xCF); lcd_wr_data(0x00); lcd_wr_data(0xC1); lcd_wr_data(0x30); lcd_wr_regno(0xED); lcd_wr_data(0x64); lcd_wr_data(0x03); lcd_wr_data(0x12); lcd_wr_data(0x81); lcd_wr_regno(0xE8); lcd_wr_data(0x85); lcd_wr_data(0x10); lcd_wr_data(0x7A); lcd_wr_regno(0xCB); lcd_wr_data(0x39); lcd_wr_data(0x2C); lcd_wr_data(0x00); lcd_wr_data(0x34); lcd_wr_data(0x02); lcd_wr_regno(0xF7); lcd_wr_data(0x20); lcd_wr_regno(0xEA); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xC0); /* Power control */ lcd_wr_data(0x1B); /* VRH[5:0] */ lcd_wr_regno(0xC1); /* Power control */ lcd_wr_data(0x01); /* SAP[2:0];BT[3:0] */ lcd_wr_regno(0xC5); /* VCM control */ lcd_wr_data(0x30); /* 3F */ lcd_wr_data(0x30); /* 3C */ lcd_wr_regno(0xC7); /* VCM control2 */ lcd_wr_data(0xB7); lcd_wr_regno(0x36); /* Memory Access Control */ lcd_wr_data(0x48); lcd_wr_regno(0x3A); lcd_wr_data(0x55); lcd_wr_regno(0xB1); lcd_wr_data(0x00); lcd_wr_data(0x1A); lcd_wr_regno(0xB6); /* Display Function Control */ lcd_wr_data(0x0A); lcd_wr_data(0xA2); lcd_wr_regno(0xF2); /* 3Gamma Function Disable */ lcd_wr_data(0x00); lcd_wr_regno(0x26); /* Gamma curve selected */ lcd_wr_data(0x01); lcd_wr_regno(0xE0); /* Set Gamma */ lcd_wr_data(0x0F); lcd_wr_data(0x2A); lcd_wr_data(0x28); lcd_wr_data(0x08); lcd_wr_data(0x0E); lcd_wr_data(0x08); lcd_wr_data(0x54); lcd_wr_data(0xA9); lcd_wr_data(0x43); lcd_wr_data(0x0A); lcd_wr_data(0x0F); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xE1); /* Set Gamma */ lcd_wr_data(0x00); lcd_wr_data(0x15); lcd_wr_data(0x17); lcd_wr_data(0x07); lcd_wr_data(0x11); lcd_wr_data(0x06); lcd_wr_data(0x2B); lcd_wr_data(0x56); lcd_wr_data(0x3C); lcd_wr_data(0x05); lcd_wr_data(0x10); lcd_wr_data(0x0F); lcd_wr_data(0x3F); lcd_wr_data(0x3F); lcd_wr_data(0x0F); lcd_wr_regno(0x2B); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x3f); lcd_wr_regno(0x2A); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0xef); lcd_wr_regno(0x11); /* Exit Sleep */ HAL_Delay(120); lcd_wr_regno(0x29); /* display on */ } /** * @brief ST7789 寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_st7789_reginit(void) { lcd_wr_regno(0x11); HAL_Delay(120); lcd_wr_regno(0x36); lcd_wr_data(0x00); lcd_wr_regno(0x3A); lcd_wr_data(0x05); lcd_wr_regno(0xB2); lcd_wr_data(0x0C); lcd_wr_data(0x0C); lcd_wr_data(0x00); lcd_wr_data(0x33); lcd_wr_data(0x33); lcd_wr_regno(0xB7); lcd_wr_data(0x35); lcd_wr_regno(0xBB); /* vcom */ lcd_wr_data(0x32); /* 30 */ lcd_wr_regno(0xC0); lcd_wr_data(0x0C); lcd_wr_regno(0xC2); lcd_wr_data(0x01); lcd_wr_regno(0xC3); /* vrh */ lcd_wr_data(0x10); /* 17 0D */ lcd_wr_regno(0xC4); /* vdv */ lcd_wr_data(0x20); /* 20 */ lcd_wr_regno(0xC6); lcd_wr_data(0x0f); lcd_wr_regno(0xD0); lcd_wr_data(0xA4); lcd_wr_data(0xA1); lcd_wr_regno(0xE0); /* Set Gamma */ lcd_wr_data(0xd0); lcd_wr_data(0x00); lcd_wr_data(0x02); lcd_wr_data(0x07); lcd_wr_data(0x0a); lcd_wr_data(0x28); lcd_wr_data(0x32); lcd_wr_data(0x44); lcd_wr_data(0x42); lcd_wr_data(0x06); lcd_wr_data(0x0e); lcd_wr_data(0x12); lcd_wr_data(0x14); lcd_wr_data(0x17); lcd_wr_regno(0xE1); /* Set Gamma */ lcd_wr_data(0xd0); lcd_wr_data(0x00); lcd_wr_data(0x02); lcd_wr_data(0x07); lcd_wr_data(0x0a); lcd_wr_data(0x28); lcd_wr_data(0x31); lcd_wr_data(0x54); lcd_wr_data(0x47); lcd_wr_data(0x0e); lcd_wr_data(0x1c); lcd_wr_data(0x17); lcd_wr_data(0x1b); lcd_wr_data(0x1e); lcd_wr_regno(0x2A); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0xef); lcd_wr_regno(0x2B); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x3f); lcd_wr_regno(0x29); /* display on */ } /** * @brief NT35310寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_nt35310_reginit(void) { lcd_wr_regno(0xED); lcd_wr_data(0x01); lcd_wr_data(0xFE); lcd_wr_regno(0xEE); lcd_wr_data(0xDE); lcd_wr_data(0x21); lcd_wr_regno(0xF1); lcd_wr_data(0x01); lcd_wr_regno(0xDF); lcd_wr_data(0x10); /* VCOMvoltage */ lcd_wr_regno(0xC4); lcd_wr_data(0x8F); /* 5f */ lcd_wr_regno(0xC6); lcd_wr_data(0x00); lcd_wr_data(0xE2); lcd_wr_data(0xE2); lcd_wr_data(0xE2); lcd_wr_regno(0xBF); lcd_wr_data(0xAA); lcd_wr_regno(0xB0); lcd_wr_data(0x0D); lcd_wr_data(0x00); lcd_wr_data(0x0D); lcd_wr_data(0x00); lcd_wr_data(0x11); lcd_wr_data(0x00); lcd_wr_data(0x19); lcd_wr_data(0x00); lcd_wr_data(0x21); lcd_wr_data(0x00); lcd_wr_data(0x2D); lcd_wr_data(0x00); lcd_wr_data(0x3D); lcd_wr_data(0x00); lcd_wr_data(0x5D); lcd_wr_data(0x00); lcd_wr_data(0x5D); lcd_wr_data(0x00); lcd_wr_regno(0xB1); lcd_wr_data(0x80); lcd_wr_data(0x00); lcd_wr_data(0x8B); lcd_wr_data(0x00); lcd_wr_data(0x96); lcd_wr_data(0x00); lcd_wr_regno(0xB2); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x02); lcd_wr_data(0x00); lcd_wr_data(0x03); lcd_wr_data(0x00); lcd_wr_regno(0xB3); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xB4); lcd_wr_data(0x8B); lcd_wr_data(0x00); lcd_wr_data(0x96); lcd_wr_data(0x00); lcd_wr_data(0xA1); lcd_wr_data(0x00); lcd_wr_regno(0xB5); lcd_wr_data(0x02); lcd_wr_data(0x00); lcd_wr_data(0x03); lcd_wr_data(0x00); lcd_wr_data(0x04); lcd_wr_data(0x00); lcd_wr_regno(0xB6); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xB7); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x3F); lcd_wr_data(0x00); lcd_wr_data(0x5E); lcd_wr_data(0x00); lcd_wr_data(0x64); lcd_wr_data(0x00); lcd_wr_data(0x8C); lcd_wr_data(0x00); lcd_wr_data(0xAC); lcd_wr_data(0x00); lcd_wr_data(0xDC); lcd_wr_data(0x00); lcd_wr_data(0x70); lcd_wr_data(0x00); lcd_wr_data(0x90); lcd_wr_data(0x00); lcd_wr_data(0xEB); lcd_wr_data(0x00); lcd_wr_data(0xDC); lcd_wr_data(0x00); lcd_wr_regno(0xB8); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xBA); lcd_wr_data(0x24); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xC1); lcd_wr_data(0x20); lcd_wr_data(0x00); lcd_wr_data(0x54); lcd_wr_data(0x00); lcd_wr_data(0xFF); lcd_wr_data(0x00); lcd_wr_regno(0xC2); lcd_wr_data(0x0A); lcd_wr_data(0x00); lcd_wr_data(0x04); lcd_wr_data(0x00); lcd_wr_regno(0xC3); lcd_wr_data(0x3C); lcd_wr_data(0x00); lcd_wr_data(0x3A); lcd_wr_data(0x00); lcd_wr_data(0x39); lcd_wr_data(0x00); lcd_wr_data(0x37); lcd_wr_data(0x00); lcd_wr_data(0x3C); lcd_wr_data(0x00); lcd_wr_data(0x36); lcd_wr_data(0x00); lcd_wr_data(0x32); lcd_wr_data(0x00); lcd_wr_data(0x2F); lcd_wr_data(0x00); lcd_wr_data(0x2C); lcd_wr_data(0x00); lcd_wr_data(0x29); lcd_wr_data(0x00); lcd_wr_data(0x26); lcd_wr_data(0x00); lcd_wr_data(0x24); lcd_wr_data(0x00); lcd_wr_data(0x24); lcd_wr_data(0x00); lcd_wr_data(0x23); lcd_wr_data(0x00); lcd_wr_data(0x3C); lcd_wr_data(0x00); lcd_wr_data(0x36); lcd_wr_data(0x00); lcd_wr_data(0x32); lcd_wr_data(0x00); lcd_wr_data(0x2F); lcd_wr_data(0x00); lcd_wr_data(0x2C); lcd_wr_data(0x00); lcd_wr_data(0x29); lcd_wr_data(0x00); lcd_wr_data(0x26); lcd_wr_data(0x00); lcd_wr_data(0x24); lcd_wr_data(0x00); lcd_wr_data(0x24); lcd_wr_data(0x00); lcd_wr_data(0x23); lcd_wr_data(0x00); lcd_wr_regno(0xC4); lcd_wr_data(0x62); lcd_wr_data(0x00); lcd_wr_data(0x05); lcd_wr_data(0x00); lcd_wr_data(0x84); lcd_wr_data(0x00); lcd_wr_data(0xF0); lcd_wr_data(0x00); lcd_wr_data(0x18); lcd_wr_data(0x00); lcd_wr_data(0xA4); lcd_wr_data(0x00); lcd_wr_data(0x18); lcd_wr_data(0x00); lcd_wr_data(0x50); lcd_wr_data(0x00); lcd_wr_data(0x0C); lcd_wr_data(0x00); lcd_wr_data(0x17); lcd_wr_data(0x00); lcd_wr_data(0x95); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_data(0xE6); lcd_wr_data(0x00); lcd_wr_regno(0xC5); lcd_wr_data(0x32); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x65); lcd_wr_data(0x00); lcd_wr_data(0x76); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_regno(0xC6); lcd_wr_data(0x20); lcd_wr_data(0x00); lcd_wr_data(0x17); lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x00); lcd_wr_regno(0xC7); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xC8); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xC9); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xE0); lcd_wr_data(0x16); lcd_wr_data(0x00); lcd_wr_data(0x1C); lcd_wr_data(0x00); lcd_wr_data(0x21); lcd_wr_data(0x00); lcd_wr_data(0x36); lcd_wr_data(0x00); lcd_wr_data(0x46); lcd_wr_data(0x00); lcd_wr_data(0x52); lcd_wr_data(0x00); lcd_wr_data(0x64); lcd_wr_data(0x00); lcd_wr_data(0x7A); lcd_wr_data(0x00); lcd_wr_data(0x8B); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0xA8); lcd_wr_data(0x00); lcd_wr_data(0xB9); lcd_wr_data(0x00); lcd_wr_data(0xC4); lcd_wr_data(0x00); lcd_wr_data(0xCA); lcd_wr_data(0x00); lcd_wr_data(0xD2); lcd_wr_data(0x00); lcd_wr_data(0xD9); lcd_wr_data(0x00); lcd_wr_data(0xE0); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE1); lcd_wr_data(0x16); lcd_wr_data(0x00); lcd_wr_data(0x1C); lcd_wr_data(0x00); lcd_wr_data(0x22); lcd_wr_data(0x00); lcd_wr_data(0x36); lcd_wr_data(0x00); lcd_wr_data(0x45); lcd_wr_data(0x00); lcd_wr_data(0x52); lcd_wr_data(0x00); lcd_wr_data(0x64); lcd_wr_data(0x00); lcd_wr_data(0x7A); lcd_wr_data(0x00); lcd_wr_data(0x8B); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0xA8); lcd_wr_data(0x00); lcd_wr_data(0xB9); lcd_wr_data(0x00); lcd_wr_data(0xC4); lcd_wr_data(0x00); lcd_wr_data(0xCA); lcd_wr_data(0x00); lcd_wr_data(0xD2); lcd_wr_data(0x00); lcd_wr_data(0xD8); lcd_wr_data(0x00); lcd_wr_data(0xE0); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE2); lcd_wr_data(0x05); lcd_wr_data(0x00); lcd_wr_data(0x0B); lcd_wr_data(0x00); lcd_wr_data(0x1B); lcd_wr_data(0x00); lcd_wr_data(0x34); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x4F); lcd_wr_data(0x00); lcd_wr_data(0x61); lcd_wr_data(0x00); lcd_wr_data(0x79); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_data(0x97); lcd_wr_data(0x00); lcd_wr_data(0xA6); lcd_wr_data(0x00); lcd_wr_data(0xB7); lcd_wr_data(0x00); lcd_wr_data(0xC2); lcd_wr_data(0x00); lcd_wr_data(0xC7); lcd_wr_data(0x00); lcd_wr_data(0xD1); lcd_wr_data(0x00); lcd_wr_data(0xD6); lcd_wr_data(0x00); lcd_wr_data(0xDD); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE3); lcd_wr_data(0x05); lcd_wr_data(0x00); lcd_wr_data(0xA); lcd_wr_data(0x00); lcd_wr_data(0x1C); lcd_wr_data(0x00); lcd_wr_data(0x33); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x50); lcd_wr_data(0x00); lcd_wr_data(0x62); lcd_wr_data(0x00); lcd_wr_data(0x78); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_data(0x97); lcd_wr_data(0x00); lcd_wr_data(0xA6); lcd_wr_data(0x00); lcd_wr_data(0xB7); lcd_wr_data(0x00); lcd_wr_data(0xC2); lcd_wr_data(0x00); lcd_wr_data(0xC7); lcd_wr_data(0x00); lcd_wr_data(0xD1); lcd_wr_data(0x00); lcd_wr_data(0xD5); lcd_wr_data(0x00); lcd_wr_data(0xDD); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE4); lcd_wr_data(0x01); lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x00); lcd_wr_data(0x02); lcd_wr_data(0x00); lcd_wr_data(0x2A); lcd_wr_data(0x00); lcd_wr_data(0x3C); lcd_wr_data(0x00); lcd_wr_data(0x4B); lcd_wr_data(0x00); lcd_wr_data(0x5D); lcd_wr_data(0x00); lcd_wr_data(0x74); lcd_wr_data(0x00); lcd_wr_data(0x84); lcd_wr_data(0x00); lcd_wr_data(0x93); lcd_wr_data(0x00); lcd_wr_data(0xA2); lcd_wr_data(0x00); lcd_wr_data(0xB3); lcd_wr_data(0x00); lcd_wr_data(0xBE); lcd_wr_data(0x00); lcd_wr_data(0xC4); lcd_wr_data(0x00); lcd_wr_data(0xCD); lcd_wr_data(0x00); lcd_wr_data(0xD3); lcd_wr_data(0x00); lcd_wr_data(0xDD); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE5); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x02); lcd_wr_data(0x00); lcd_wr_data(0x29); lcd_wr_data(0x00); lcd_wr_data(0x3C); lcd_wr_data(0x00); lcd_wr_data(0x4B); lcd_wr_data(0x00); lcd_wr_data(0x5D); lcd_wr_data(0x00); lcd_wr_data(0x74); lcd_wr_data(0x00); lcd_wr_data(0x84); lcd_wr_data(0x00); lcd_wr_data(0x93); lcd_wr_data(0x00); lcd_wr_data(0xA2); lcd_wr_data(0x00); lcd_wr_data(0xB3); lcd_wr_data(0x00); lcd_wr_data(0xBE); lcd_wr_data(0x00); lcd_wr_data(0xC4); lcd_wr_data(0x00); lcd_wr_data(0xCD); lcd_wr_data(0x00); lcd_wr_data(0xD3); lcd_wr_data(0x00); lcd_wr_data(0xDC); lcd_wr_data(0x00); lcd_wr_data(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xE6); lcd_wr_data(0x11); lcd_wr_data(0x00); lcd_wr_data(0x34); lcd_wr_data(0x00); lcd_wr_data(0x56); lcd_wr_data(0x00); lcd_wr_data(0x76); lcd_wr_data(0x00); lcd_wr_data(0x77); lcd_wr_data(0x00); lcd_wr_data(0x66); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0xBB); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0x66); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_data(0x45); lcd_wr_data(0x00); lcd_wr_data(0x43); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_regno(0xE7); lcd_wr_data(0x32); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_data(0x76); lcd_wr_data(0x00); lcd_wr_data(0x66); lcd_wr_data(0x00); lcd_wr_data(0x67); lcd_wr_data(0x00); lcd_wr_data(0x67); lcd_wr_data(0x00); lcd_wr_data(0x87); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0xBB); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0x77); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x56); lcd_wr_data(0x00); lcd_wr_data(0x23); lcd_wr_data(0x00); lcd_wr_data(0x33); lcd_wr_data(0x00); lcd_wr_data(0x45); lcd_wr_data(0x00); lcd_wr_regno(0xE8); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0x87); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_data(0x77); lcd_wr_data(0x00); lcd_wr_data(0x66); lcd_wr_data(0x00); lcd_wr_data(0x88); lcd_wr_data(0x00); lcd_wr_data(0xAA); lcd_wr_data(0x00); lcd_wr_data(0xBB); lcd_wr_data(0x00); lcd_wr_data(0x99); lcd_wr_data(0x00); lcd_wr_data(0x66); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x44); lcd_wr_data(0x00); lcd_wr_data(0x55); lcd_wr_data(0x00); lcd_wr_regno(0xE9); lcd_wr_data(0xAA); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0x00); lcd_wr_data(0xAA); lcd_wr_regno(0xCF); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xF0); lcd_wr_data(0x00); lcd_wr_data(0x50); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xF3); lcd_wr_data(0x00); lcd_wr_regno(0xF9); lcd_wr_data(0x06); lcd_wr_data(0x10); lcd_wr_data(0x29); lcd_wr_data(0x00); lcd_wr_regno(0x3A); lcd_wr_data(0x55); /* 66 */ lcd_wr_regno(0x11); HAL_Delay(100); lcd_wr_regno(0x29); lcd_wr_regno(0x35); lcd_wr_data(0x00); lcd_wr_regno(0x51); lcd_wr_data(0xFF); lcd_wr_regno(0x53); lcd_wr_data(0x2C); lcd_wr_regno(0x55); lcd_wr_data(0x82); lcd_wr_regno(0x2c); } /** * @brief ST7796寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_st7796_reginit(void) { lcd_wr_regno(0x11); HAL_Delay(120); lcd_wr_regno(0x36); /* Memory Data Access Control MY,MX~~ */ lcd_wr_data(0x48); lcd_wr_regno(0x3A); lcd_wr_data(0x55); lcd_wr_regno(0xF0); lcd_wr_data(0xC3); lcd_wr_regno(0xF0); lcd_wr_data(0x96); lcd_wr_regno(0xB4); lcd_wr_data(0x01); lcd_wr_regno(0xB6); /* Display Function Control */ lcd_wr_data(0x0A); lcd_wr_data(0xA2); lcd_wr_regno(0xB7); lcd_wr_data(0xC6); lcd_wr_regno(0xB9); lcd_wr_data(0x02); lcd_wr_data(0xE0); lcd_wr_regno(0xC0); lcd_wr_data(0x80); lcd_wr_data(0x16); lcd_wr_regno(0xC1); lcd_wr_data(0x19); lcd_wr_regno(0xC2); lcd_wr_data(0xA7); lcd_wr_regno(0xC5); lcd_wr_data(0x16); lcd_wr_regno(0xE8); lcd_wr_data(0x40); lcd_wr_data(0x8A); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x29); lcd_wr_data(0x19); lcd_wr_data(0xA5); lcd_wr_data(0x33); lcd_wr_regno(0xE0); lcd_wr_data(0xF0); lcd_wr_data(0x07); lcd_wr_data(0x0D); lcd_wr_data(0x04); lcd_wr_data(0x05); lcd_wr_data(0x14); lcd_wr_data(0x36); lcd_wr_data(0x54); lcd_wr_data(0x4C); lcd_wr_data(0x38); lcd_wr_data(0x13); lcd_wr_data(0x14); lcd_wr_data(0x2E); lcd_wr_data(0x34); lcd_wr_regno(0xE1); lcd_wr_data(0xF0); lcd_wr_data(0x10); lcd_wr_data(0x14); lcd_wr_data(0x0E); lcd_wr_data(0x0C); lcd_wr_data(0x08); lcd_wr_data(0x35); lcd_wr_data(0x44); lcd_wr_data(0x4C); lcd_wr_data(0x26); lcd_wr_data(0x10); lcd_wr_data(0x12); lcd_wr_data(0x2C); lcd_wr_data(0x32); lcd_wr_regno(0xF0); lcd_wr_data(0x3C); lcd_wr_regno(0xF0); lcd_wr_data(0x69); HAL_Delay(120); lcd_wr_regno(0x21); lcd_wr_regno(0x29); } /** * @brief NT35510寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_nt35510_reginit(void) { lcd_write_reg(0xF000, 0x55); lcd_write_reg(0xF001, 0xAA); lcd_write_reg(0xF002, 0x52); lcd_write_reg(0xF003, 0x08); lcd_write_reg(0xF004, 0x01); /* AVDD Set AVDD 5.2V */ lcd_write_reg(0xB000, 0x0D); lcd_write_reg(0xB001, 0x0D); lcd_write_reg(0xB002, 0x0D); /* AVDD ratio */ lcd_write_reg(0xB600, 0x34); lcd_write_reg(0xB601, 0x34); lcd_write_reg(0xB602, 0x34); /* AVEE -5.2V */ lcd_write_reg(0xB100, 0x0D); lcd_write_reg(0xB101, 0x0D); lcd_write_reg(0xB102, 0x0D); /* AVEE ratio */ lcd_write_reg(0xB700, 0x34); lcd_write_reg(0xB701, 0x34); lcd_write_reg(0xB702, 0x34); /* VCL -2.5V */ lcd_write_reg(0xB200, 0x00); lcd_write_reg(0xB201, 0x00); lcd_write_reg(0xB202, 0x00); /* VCL ratio */ lcd_write_reg(0xB800, 0x24); lcd_write_reg(0xB801, 0x24); lcd_write_reg(0xB802, 0x24); /* VGH 15V (Free pump) */ lcd_write_reg(0xBF00, 0x01); lcd_write_reg(0xB300, 0x0F); lcd_write_reg(0xB301, 0x0F); lcd_write_reg(0xB302, 0x0F); /* VGH ratio */ lcd_write_reg(0xB900, 0x34); lcd_write_reg(0xB901, 0x34); lcd_write_reg(0xB902, 0x34); /* VGL_REG -10V */ lcd_write_reg(0xB500, 0x08); lcd_write_reg(0xB501, 0x08); lcd_write_reg(0xB502, 0x08); lcd_write_reg(0xC200, 0x03); /* VGLX ratio */ lcd_write_reg(0xBA00, 0x24); lcd_write_reg(0xBA01, 0x24); lcd_write_reg(0xBA02, 0x24); /* VGMP/VGSP 4.5V/0V */ lcd_write_reg(0xBC00, 0x00); lcd_write_reg(0xBC01, 0x78); lcd_write_reg(0xBC02, 0x00); /* VGMN/VGSN -4.5V/0V */ lcd_write_reg(0xBD00, 0x00); lcd_write_reg(0xBD01, 0x78); lcd_write_reg(0xBD02, 0x00); /* VCOM */ lcd_write_reg(0xBE00, 0x00); lcd_write_reg(0xBE01, 0x64); /* Gamma Setting */ lcd_write_reg(0xD100, 0x00); lcd_write_reg(0xD101, 0x33); lcd_write_reg(0xD102, 0x00); lcd_write_reg(0xD103, 0x34); lcd_write_reg(0xD104, 0x00); lcd_write_reg(0xD105, 0x3A); lcd_write_reg(0xD106, 0x00); lcd_write_reg(0xD107, 0x4A); lcd_write_reg(0xD108, 0x00); lcd_write_reg(0xD109, 0x5C); lcd_write_reg(0xD10A, 0x00); lcd_write_reg(0xD10B, 0x81); lcd_write_reg(0xD10C, 0x00); lcd_write_reg(0xD10D, 0xA6); lcd_write_reg(0xD10E, 0x00); lcd_write_reg(0xD10F, 0xE5); lcd_write_reg(0xD110, 0x01); lcd_write_reg(0xD111, 0x13); lcd_write_reg(0xD112, 0x01); lcd_write_reg(0xD113, 0x54); lcd_write_reg(0xD114, 0x01); lcd_write_reg(0xD115, 0x82); lcd_write_reg(0xD116, 0x01); lcd_write_reg(0xD117, 0xCA); lcd_write_reg(0xD118, 0x02); lcd_write_reg(0xD119, 0x00); lcd_write_reg(0xD11A, 0x02); lcd_write_reg(0xD11B, 0x01); lcd_write_reg(0xD11C, 0x02); lcd_write_reg(0xD11D, 0x34); lcd_write_reg(0xD11E, 0x02); lcd_write_reg(0xD11F, 0x67); lcd_write_reg(0xD120, 0x02); lcd_write_reg(0xD121, 0x84); lcd_write_reg(0xD122, 0x02); lcd_write_reg(0xD123, 0xA4); lcd_write_reg(0xD124, 0x02); lcd_write_reg(0xD125, 0xB7); lcd_write_reg(0xD126, 0x02); lcd_write_reg(0xD127, 0xCF); lcd_write_reg(0xD128, 0x02); lcd_write_reg(0xD129, 0xDE); lcd_write_reg(0xD12A, 0x02); lcd_write_reg(0xD12B, 0xF2); lcd_write_reg(0xD12C, 0x02); lcd_write_reg(0xD12D, 0xFE); lcd_write_reg(0xD12E, 0x03); lcd_write_reg(0xD12F, 0x10); lcd_write_reg(0xD130, 0x03); lcd_write_reg(0xD131, 0x33); lcd_write_reg(0xD132, 0x03); lcd_write_reg(0xD133, 0x6D); lcd_write_reg(0xD200, 0x00); lcd_write_reg(0xD201, 0x33); lcd_write_reg(0xD202, 0x00); lcd_write_reg(0xD203, 0x34); lcd_write_reg(0xD204, 0x00); lcd_write_reg(0xD205, 0x3A); lcd_write_reg(0xD206, 0x00); lcd_write_reg(0xD207, 0x4A); lcd_write_reg(0xD208, 0x00); lcd_write_reg(0xD209, 0x5C); lcd_write_reg(0xD20A, 0x00); lcd_write_reg(0xD20B, 0x81); lcd_write_reg(0xD20C, 0x00); lcd_write_reg(0xD20D, 0xA6); lcd_write_reg(0xD20E, 0x00); lcd_write_reg(0xD20F, 0xE5); lcd_write_reg(0xD210, 0x01); lcd_write_reg(0xD211, 0x13); lcd_write_reg(0xD212, 0x01); lcd_write_reg(0xD213, 0x54); lcd_write_reg(0xD214, 0x01); lcd_write_reg(0xD215, 0x82); lcd_write_reg(0xD216, 0x01); lcd_write_reg(0xD217, 0xCA); lcd_write_reg(0xD218, 0x02); lcd_write_reg(0xD219, 0x00); lcd_write_reg(0xD21A, 0x02); lcd_write_reg(0xD21B, 0x01); lcd_write_reg(0xD21C, 0x02); lcd_write_reg(0xD21D, 0x34); lcd_write_reg(0xD21E, 0x02); lcd_write_reg(0xD21F, 0x67); lcd_write_reg(0xD220, 0x02); lcd_write_reg(0xD221, 0x84); lcd_write_reg(0xD222, 0x02); lcd_write_reg(0xD223, 0xA4); lcd_write_reg(0xD224, 0x02); lcd_write_reg(0xD225, 0xB7); lcd_write_reg(0xD226, 0x02); lcd_write_reg(0xD227, 0xCF); lcd_write_reg(0xD228, 0x02); lcd_write_reg(0xD229, 0xDE); lcd_write_reg(0xD22A, 0x02); lcd_write_reg(0xD22B, 0xF2); lcd_write_reg(0xD22C, 0x02); lcd_write_reg(0xD22D, 0xFE); lcd_write_reg(0xD22E, 0x03); lcd_write_reg(0xD22F, 0x10); lcd_write_reg(0xD230, 0x03); lcd_write_reg(0xD231, 0x33); lcd_write_reg(0xD232, 0x03); lcd_write_reg(0xD233, 0x6D); lcd_write_reg(0xD300, 0x00); lcd_write_reg(0xD301, 0x33); lcd_write_reg(0xD302, 0x00); lcd_write_reg(0xD303, 0x34); lcd_write_reg(0xD304, 0x00); lcd_write_reg(0xD305, 0x3A); lcd_write_reg(0xD306, 0x00); lcd_write_reg(0xD307, 0x4A); lcd_write_reg(0xD308, 0x00); lcd_write_reg(0xD309, 0x5C); lcd_write_reg(0xD30A, 0x00); lcd_write_reg(0xD30B, 0x81); lcd_write_reg(0xD30C, 0x00); lcd_write_reg(0xD30D, 0xA6); lcd_write_reg(0xD30E, 0x00); lcd_write_reg(0xD30F, 0xE5); lcd_write_reg(0xD310, 0x01); lcd_write_reg(0xD311, 0x13); lcd_write_reg(0xD312, 0x01); lcd_write_reg(0xD313, 0x54); lcd_write_reg(0xD314, 0x01); lcd_write_reg(0xD315, 0x82); lcd_write_reg(0xD316, 0x01); lcd_write_reg(0xD317, 0xCA); lcd_write_reg(0xD318, 0x02); lcd_write_reg(0xD319, 0x00); lcd_write_reg(0xD31A, 0x02); lcd_write_reg(0xD31B, 0x01); lcd_write_reg(0xD31C, 0x02); lcd_write_reg(0xD31D, 0x34); lcd_write_reg(0xD31E, 0x02); lcd_write_reg(0xD31F, 0x67); lcd_write_reg(0xD320, 0x02); lcd_write_reg(0xD321, 0x84); lcd_write_reg(0xD322, 0x02); lcd_write_reg(0xD323, 0xA4); lcd_write_reg(0xD324, 0x02); lcd_write_reg(0xD325, 0xB7); lcd_write_reg(0xD326, 0x02); lcd_write_reg(0xD327, 0xCF); lcd_write_reg(0xD328, 0x02); lcd_write_reg(0xD329, 0xDE); lcd_write_reg(0xD32A, 0x02); lcd_write_reg(0xD32B, 0xF2); lcd_write_reg(0xD32C, 0x02); lcd_write_reg(0xD32D, 0xFE); lcd_write_reg(0xD32E, 0x03); lcd_write_reg(0xD32F, 0x10); lcd_write_reg(0xD330, 0x03); lcd_write_reg(0xD331, 0x33); lcd_write_reg(0xD332, 0x03); lcd_write_reg(0xD333, 0x6D); lcd_write_reg(0xD400, 0x00); lcd_write_reg(0xD401, 0x33); lcd_write_reg(0xD402, 0x00); lcd_write_reg(0xD403, 0x34); lcd_write_reg(0xD404, 0x00); lcd_write_reg(0xD405, 0x3A); lcd_write_reg(0xD406, 0x00); lcd_write_reg(0xD407, 0x4A); lcd_write_reg(0xD408, 0x00); lcd_write_reg(0xD409, 0x5C); lcd_write_reg(0xD40A, 0x00); lcd_write_reg(0xD40B, 0x81); lcd_write_reg(0xD40C, 0x00); lcd_write_reg(0xD40D, 0xA6); lcd_write_reg(0xD40E, 0x00); lcd_write_reg(0xD40F, 0xE5); lcd_write_reg(0xD410, 0x01); lcd_write_reg(0xD411, 0x13); lcd_write_reg(0xD412, 0x01); lcd_write_reg(0xD413, 0x54); lcd_write_reg(0xD414, 0x01); lcd_write_reg(0xD415, 0x82); lcd_write_reg(0xD416, 0x01); lcd_write_reg(0xD417, 0xCA); lcd_write_reg(0xD418, 0x02); lcd_write_reg(0xD419, 0x00); lcd_write_reg(0xD41A, 0x02); lcd_write_reg(0xD41B, 0x01); lcd_write_reg(0xD41C, 0x02); lcd_write_reg(0xD41D, 0x34); lcd_write_reg(0xD41E, 0x02); lcd_write_reg(0xD41F, 0x67); lcd_write_reg(0xD420, 0x02); lcd_write_reg(0xD421, 0x84); lcd_write_reg(0xD422, 0x02); lcd_write_reg(0xD423, 0xA4); lcd_write_reg(0xD424, 0x02); lcd_write_reg(0xD425, 0xB7); lcd_write_reg(0xD426, 0x02); lcd_write_reg(0xD427, 0xCF); lcd_write_reg(0xD428, 0x02); lcd_write_reg(0xD429, 0xDE); lcd_write_reg(0xD42A, 0x02); lcd_write_reg(0xD42B, 0xF2); lcd_write_reg(0xD42C, 0x02); lcd_write_reg(0xD42D, 0xFE); lcd_write_reg(0xD42E, 0x03); lcd_write_reg(0xD42F, 0x10); lcd_write_reg(0xD430, 0x03); lcd_write_reg(0xD431, 0x33); lcd_write_reg(0xD432, 0x03); lcd_write_reg(0xD433, 0x6D); lcd_write_reg(0xD500, 0x00); lcd_write_reg(0xD501, 0x33); lcd_write_reg(0xD502, 0x00); lcd_write_reg(0xD503, 0x34); lcd_write_reg(0xD504, 0x00); lcd_write_reg(0xD505, 0x3A); lcd_write_reg(0xD506, 0x00); lcd_write_reg(0xD507, 0x4A); lcd_write_reg(0xD508, 0x00); lcd_write_reg(0xD509, 0x5C); lcd_write_reg(0xD50A, 0x00); lcd_write_reg(0xD50B, 0x81); lcd_write_reg(0xD50C, 0x00); lcd_write_reg(0xD50D, 0xA6); lcd_write_reg(0xD50E, 0x00); lcd_write_reg(0xD50F, 0xE5); lcd_write_reg(0xD510, 0x01); lcd_write_reg(0xD511, 0x13); lcd_write_reg(0xD512, 0x01); lcd_write_reg(0xD513, 0x54); lcd_write_reg(0xD514, 0x01); lcd_write_reg(0xD515, 0x82); lcd_write_reg(0xD516, 0x01); lcd_write_reg(0xD517, 0xCA); lcd_write_reg(0xD518, 0x02); lcd_write_reg(0xD519, 0x00); lcd_write_reg(0xD51A, 0x02); lcd_write_reg(0xD51B, 0x01); lcd_write_reg(0xD51C, 0x02); lcd_write_reg(0xD51D, 0x34); lcd_write_reg(0xD51E, 0x02); lcd_write_reg(0xD51F, 0x67); lcd_write_reg(0xD520, 0x02); lcd_write_reg(0xD521, 0x84); lcd_write_reg(0xD522, 0x02); lcd_write_reg(0xD523, 0xA4); lcd_write_reg(0xD524, 0x02); lcd_write_reg(0xD525, 0xB7); lcd_write_reg(0xD526, 0x02); lcd_write_reg(0xD527, 0xCF); lcd_write_reg(0xD528, 0x02); lcd_write_reg(0xD529, 0xDE); lcd_write_reg(0xD52A, 0x02); lcd_write_reg(0xD52B, 0xF2); lcd_write_reg(0xD52C, 0x02); lcd_write_reg(0xD52D, 0xFE); lcd_write_reg(0xD52E, 0x03); lcd_write_reg(0xD52F, 0x10); lcd_write_reg(0xD530, 0x03); lcd_write_reg(0xD531, 0x33); lcd_write_reg(0xD532, 0x03); lcd_write_reg(0xD533, 0x6D); lcd_write_reg(0xD600, 0x00); lcd_write_reg(0xD601, 0x33); lcd_write_reg(0xD602, 0x00); lcd_write_reg(0xD603, 0x34); lcd_write_reg(0xD604, 0x00); lcd_write_reg(0xD605, 0x3A); lcd_write_reg(0xD606, 0x00); lcd_write_reg(0xD607, 0x4A); lcd_write_reg(0xD608, 0x00); lcd_write_reg(0xD609, 0x5C); lcd_write_reg(0xD60A, 0x00); lcd_write_reg(0xD60B, 0x81); lcd_write_reg(0xD60C, 0x00); lcd_write_reg(0xD60D, 0xA6); lcd_write_reg(0xD60E, 0x00); lcd_write_reg(0xD60F, 0xE5); lcd_write_reg(0xD610, 0x01); lcd_write_reg(0xD611, 0x13); lcd_write_reg(0xD612, 0x01); lcd_write_reg(0xD613, 0x54); lcd_write_reg(0xD614, 0x01); lcd_write_reg(0xD615, 0x82); lcd_write_reg(0xD616, 0x01); lcd_write_reg(0xD617, 0xCA); lcd_write_reg(0xD618, 0x02); lcd_write_reg(0xD619, 0x00); lcd_write_reg(0xD61A, 0x02); lcd_write_reg(0xD61B, 0x01); lcd_write_reg(0xD61C, 0x02); lcd_write_reg(0xD61D, 0x34); lcd_write_reg(0xD61E, 0x02); lcd_write_reg(0xD61F, 0x67); lcd_write_reg(0xD620, 0x02); lcd_write_reg(0xD621, 0x84); lcd_write_reg(0xD622, 0x02); lcd_write_reg(0xD623, 0xA4); lcd_write_reg(0xD624, 0x02); lcd_write_reg(0xD625, 0xB7); lcd_write_reg(0xD626, 0x02); lcd_write_reg(0xD627, 0xCF); lcd_write_reg(0xD628, 0x02); lcd_write_reg(0xD629, 0xDE); lcd_write_reg(0xD62A, 0x02); lcd_write_reg(0xD62B, 0xF2); lcd_write_reg(0xD62C, 0x02); lcd_write_reg(0xD62D, 0xFE); lcd_write_reg(0xD62E, 0x03); lcd_write_reg(0xD62F, 0x10); lcd_write_reg(0xD630, 0x03); lcd_write_reg(0xD631, 0x33); lcd_write_reg(0xD632, 0x03); lcd_write_reg(0xD633, 0x6D); /* LV2 Page 0 enable */ lcd_write_reg(0xF000, 0x55); lcd_write_reg(0xF001, 0xAA); lcd_write_reg(0xF002, 0x52); lcd_write_reg(0xF003, 0x08); lcd_write_reg(0xF004, 0x00); /* Display control */ lcd_write_reg(0xB100, 0xCC); lcd_write_reg(0xB101, 0x00); /* Source hold time */ lcd_write_reg(0xB600, 0x05); /* Gate EQ control */ lcd_write_reg(0xB700, 0x70); lcd_write_reg(0xB701, 0x70); /* Source EQ control (Mode 2) */ lcd_write_reg(0xB800, 0x01); lcd_write_reg(0xB801, 0x03); lcd_write_reg(0xB802, 0x03); lcd_write_reg(0xB803, 0x03); /* Inversion mode (2-dot) */ lcd_write_reg(0xBC00, 0x02); lcd_write_reg(0xBC01, 0x00); lcd_write_reg(0xBC02, 0x00); /* Timing control 4H w/ 4-delay */ lcd_write_reg(0xC900, 0xD0); lcd_write_reg(0xC901, 0x02); lcd_write_reg(0xC902, 0x50); lcd_write_reg(0xC903, 0x50); lcd_write_reg(0xC904, 0x50); lcd_write_reg(0x3500, 0x00); lcd_write_reg(0x3A00, 0x55); /* 16-bit/pixel */ lcd_wr_regno(0x1100); //delay_us(120); HAL_Delay(1); lcd_wr_regno(0x2900); } /** * @brief ILI9806寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_ili9806_reginit(void) { lcd_wr_regno(0xFF); /* EXTC Command Set enable register */ lcd_wr_data(0xFF); lcd_wr_data(0x98); lcd_wr_data(0x06); lcd_wr_regno(0xBC); /* GIP 1 */ lcd_wr_data(0x01); lcd_wr_data(0x0F); lcd_wr_data(0x61); lcd_wr_data(0xFF); lcd_wr_data(0x01); lcd_wr_data(0x01); lcd_wr_data(0x0B); lcd_wr_data(0x10); lcd_wr_data(0x37); lcd_wr_data(0x63); lcd_wr_data(0xFF); lcd_wr_data(0xFF); lcd_wr_data(0x01); lcd_wr_data(0x01); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0xFF); lcd_wr_data(0x52); lcd_wr_data(0x01); lcd_wr_data(0x00); lcd_wr_data(0x40); lcd_wr_regno(0xBD); /* GIP 2 */ lcd_wr_data(0x01); lcd_wr_data(0x23); lcd_wr_data(0x45); lcd_wr_data(0x67); lcd_wr_data(0x01); lcd_wr_data(0x23); lcd_wr_data(0x45); lcd_wr_data(0x67); lcd_wr_regno(0xBE); /* GIP 3 */ lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0xAB); lcd_wr_data(0x60); lcd_wr_data(0x22); lcd_wr_data(0x22); lcd_wr_data(0x22); lcd_wr_data(0x22); lcd_wr_data(0x22); lcd_wr_regno(0xC7); /* VCOM Control */ lcd_wr_data(0x36); lcd_wr_regno(0xED); /* EN_volt_reg VGMP / VGMN /VGSP / VGSN voltage to output */ lcd_wr_data(0x7F); lcd_wr_data(0x0F); lcd_wr_regno(0XC0); /* Power Control 1 Setting AVDD / AVEE / VGH / VGL */ lcd_wr_data(0x0F); lcd_wr_data(0x0B); lcd_wr_data(0x0A); /* VGH 15V,VGLO-10V */ lcd_wr_regno(0XFC); /* AVDD / AVEE generated by internal pumping. */ lcd_wr_data(0x08); lcd_wr_regno(0XDF); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x20); lcd_wr_regno(0XF3); /* DVDD Voltage Setting */ lcd_wr_data(0x74); lcd_wr_regno(0xB4); /* Inversion Type */ lcd_wr_data(0x00); /* 02 */ lcd_wr_data(0x00); /* 02 */ lcd_wr_data(0x00); /* 02 */ lcd_wr_regno(0xF7); /* Resolution Control */ lcd_wr_data(0x82); /* 480*800 */ lcd_wr_regno(0xB1); /* FRAME RATE Setting */ lcd_wr_data(0x00); lcd_wr_data(0x13); lcd_wr_data(0x13); lcd_wr_regno(0XF2); /* CR_EQ_PC_SDT #C0,06,40,28 */ lcd_wr_data(0x80); lcd_wr_data(0x04); lcd_wr_data(0x40); lcd_wr_data(0x28); lcd_wr_regno(0XC1); /* Power Control 2 SD OP Bias_VRH1_VRH2_EXT_CPCK_SEL */ lcd_wr_data(0x17); lcd_wr_data(0x88); /* VGMP */ lcd_wr_data(0x88); /* VGMN */ lcd_wr_data(0x20); lcd_wr_regno(0xE0); /* Positive Gamma Control */ lcd_wr_data(0x00); /* P1 */ lcd_wr_data(0x0A); /* P2 */ lcd_wr_data(0x12); /* P3 */ lcd_wr_data(0x10); /* P4 */ lcd_wr_data(0x0E); /* P5 */ lcd_wr_data(0x20); /* P6 */ lcd_wr_data(0xCC); /* P7 */ lcd_wr_data(0x07); /* P8 */ lcd_wr_data(0x06); /* P9 */ lcd_wr_data(0x0B); /* P10 */ lcd_wr_data(0x0E); /* P11 */ lcd_wr_data(0x0F); /* P12 */ lcd_wr_data(0x0D); /* P13 */ lcd_wr_data(0x15); /* P14 */ lcd_wr_data(0x10); /* P15 */ lcd_wr_data(0x00); /* P16 */ lcd_wr_regno(0xE1); /* Negative Gamma Correction */ lcd_wr_data(0x00); /* P1 */ lcd_wr_data(0x0B); /* P2 */ lcd_wr_data(0x13); /* P3 */ lcd_wr_data(0x0D); /* P4 */ lcd_wr_data(0x0E); /* P5 */ lcd_wr_data(0x1B); /* P6 */ lcd_wr_data(0x71); /* P7 */ lcd_wr_data(0x06); /* P8 */ lcd_wr_data(0x06); /* P9 */ lcd_wr_data(0x0A); /* P10 */ lcd_wr_data(0x0F); /* P11 */ lcd_wr_data(0x0E); /* P12 */ lcd_wr_data(0x0F); /* P13 */ lcd_wr_data(0x15); /* P14 */ lcd_wr_data(0x0C); /* P15 */ lcd_wr_data(0x00); /* P16 */ lcd_wr_regno(0x2a); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0xdf); lcd_wr_regno(0x2b); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x03); lcd_wr_data(0x1f); lcd_wr_regno(0x3A); /* Pixel Format */ lcd_wr_data(0x55); lcd_wr_regno(0x36); /* Memory Access Control */ lcd_wr_data(0x00); /* 02-180 */ lcd_wr_regno(0x11); HAL_Delay(120); lcd_wr_regno(0x29); HAL_Delay(20); lcd_wr_regno(0x2C); } /** * @brief SSD1963寄存器初始化代码 * @param 无 * @retval 无 */ void lcd_ex_ssd1963_reginit(void) { lcd_wr_regno(0xE2); /* Set PLL with OSC = 10MHz (hardware), Multiplier N = 35, 250MHz < VCO < 800MHz = OSC*(N+1), VCO = 300MHz */ lcd_wr_data(0x1D); /* 参数1 */ lcd_wr_data(0x02); /* 参数2 Divider M = 2, PLL = 300/(M+1) = 100MHz */ lcd_wr_data(0x04); /* 参数3 Validate M and N values */ //delay_us(100); HAL_Delay(1); lcd_wr_regno(0xE0); /* Start PLL command */ lcd_wr_data(0x01); /* enable PLL */ HAL_Delay(10); lcd_wr_regno(0xE0); /* Start PLL command again */ lcd_wr_data(0x03); /* now, use PLL output as system clock */ HAL_Delay(12); lcd_wr_regno(0x01); /* 软复位 */ HAL_Delay(10); lcd_wr_regno(0xE6); /* 设置像素频率,33Mhz */ lcd_wr_data(0x2F); lcd_wr_data(0xFF); lcd_wr_data(0xFF); lcd_wr_regno(0xB0); /* 设置LCD模式 */ lcd_wr_data(0x20); /* 24位模式 */ lcd_wr_data(0x00); /* TFT 模式 */ lcd_wr_data((SSD_HOR_RESOLUTION - 1) >> 8); /* 设置LCD水平像素 */ lcd_wr_data(SSD_HOR_RESOLUTION - 1); lcd_wr_data((SSD_VER_RESOLUTION - 1) >> 8); /* 设置LCD垂直像素 */ lcd_wr_data(SSD_VER_RESOLUTION - 1); lcd_wr_data(0x00); /* RGB序列 */ lcd_wr_regno(0xB4); /* Set horizontal period */ lcd_wr_data((SSD_HT - 1) >> 8); lcd_wr_data(SSD_HT - 1); lcd_wr_data(SSD_HPS >> 8); lcd_wr_data(SSD_HPS); lcd_wr_data(SSD_HOR_PULSE_WIDTH - 1); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xB6); /* Set vertical perio */ lcd_wr_data((SSD_VT - 1) >> 8); lcd_wr_data(SSD_VT - 1); lcd_wr_data(SSD_VPS >> 8); lcd_wr_data(SSD_VPS); lcd_wr_data(SSD_VER_FRONT_PORCH - 1); lcd_wr_data(0x00); lcd_wr_data(0x00); lcd_wr_regno(0xF0); /* 设置SSD1963与CPU接口为16bit */ lcd_wr_data(0x03); /* 16-bit(565 format) data for 16bpp */ lcd_wr_regno(0x29); /* 开启显示 */ /* 设置PWM输出 背光通过占空比可调 */ lcd_wr_regno(0xD0); /* 设置自动白平衡DBC */ lcd_wr_data(0x00); /* disable */ lcd_wr_regno(0xBE); /* 配置PWM输出 */ lcd_wr_data(0x05); /* 1设置PWM频率 */ lcd_wr_data(0xFE); /* 2设置PWM占空比 */ lcd_wr_data(0x01); /* 3设置C */ lcd_wr_data(0x00); /* 4设置D */ lcd_wr_data(0x00); /* 5设置E */ lcd_wr_data(0x00); /* 6设置F */ lcd_wr_regno(0xB8); /* 设置GPIO配置 */ lcd_wr_data(0x03); /* 2个IO口设置成输出 */ lcd_wr_data(0x01); /* GPIO使用正常的IO功能 */ lcd_wr_regno(0xBA); lcd_wr_data(0x01); /* GPIO[1:0]=01,控制LCD方向 */ /*设置背光亮度*/ uint8_t pwm = 100;//默认为最亮 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 */ }
- 在lcdfont.h中添加下列代码
-
#ifndef __LCDFONT_H #define __LCDFONT_H /* 常用ASCII表 * 偏移量32 * ASCII字符集: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ * PC2LCD2002取模方式设置:阴码+逐列式+顺向+C51格式 * 总共:4个字符集(12*12、16*16、24*24和32*32),用户可以自行新增其他分辨率的字符集。 * 每个字符所占用的字节数为:(size/8+((size%8)?1:0))*(size/2),其中size:是字库生成时的点阵大小(12/16/24/32...) */ /* 12*12 ASCII字符集点阵 */ const unsigned char asc2_1206[95][12]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ {0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ {0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/ {0x09,0x00,0x0B,0xC0,0x3D,0x00,0x0B,0xC0,0x3D,0x00,0x09,0x00},/*"#",3*/ {0x18,0xC0,0x24,0x40,0x7F,0xE0,0x22,0x40,0x31,0x80,0x00,0x00},/*"$",4*/ {0x18,0x00,0x24,0xC0,0x1B,0x00,0x0D,0x80,0x32,0x40,0x01,0x80},/*"%",5*/ {0x03,0x80,0x1C,0x40,0x27,0x40,0x1C,0x80,0x07,0x40,0x00,0x40},/*"&",6*/ {0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x20,0x40,0x40,0x20},/*"(",8*/ {0x00,0x00,0x40,0x20,0x20,0x40,0x1F,0x80,0x00,0x00,0x00,0x00},/*")",9*/ {0x09,0x00,0x06,0x00,0x1F,0x80,0x06,0x00,0x09,0x00,0x00,0x00},/*"*",10*/ {0x04,0x00,0x04,0x00,0x3F,0x80,0x04,0x00,0x04,0x00,0x00,0x00},/*"+",11*/ {0x00,0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ {0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x00,0x00},/*"-",13*/ {0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ {0x00,0x20,0x01,0xC0,0x06,0x00,0x38,0x00,0x40,0x00,0x00,0x00},/*"/",15*/ {0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"0",16*/ {0x00,0x00,0x10,0x40,0x3F,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"1",17*/ {0x18,0xC0,0x21,0x40,0x22,0x40,0x24,0x40,0x18,0x40,0x00,0x00},/*"2",18*/ {0x10,0x80,0x20,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"3",19*/ {0x02,0x00,0x0D,0x00,0x11,0x00,0x3F,0xC0,0x01,0x40,0x00,0x00},/*"4",20*/ {0x3C,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x23,0x80,0x00,0x00},/*"5",21*/ {0x1F,0x80,0x24,0x40,0x24,0x40,0x34,0x40,0x03,0x80,0x00,0x00},/*"6",22*/ {0x30,0x00,0x20,0x00,0x27,0xC0,0x38,0x00,0x20,0x00,0x00,0x00},/*"7",23*/ {0x1B,0x80,0x24,0x40,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"8",24*/ {0x1C,0x00,0x22,0xC0,0x22,0x40,0x22,0x40,0x1F,0x80,0x00,0x00},/*"9",25*/ {0x00,0x00,0x00,0x00,0x08,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ {0x00,0x00,0x00,0x00,0x04,0x60,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ {0x00,0x00,0x04,0x00,0x0A,0x00,0x11,0x00,0x20,0x80,0x40,0x40},/*"<",28*/ {0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x00,0x00},/*"=",29*/ {0x00,0x00,0x40,0x40,0x20,0x80,0x11,0x00,0x0A,0x00,0x04,0x00},/*">",30*/ {0x18,0x00,0x20,0x00,0x23,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"?",31*/ {0x1F,0x80,0x20,0x40,0x27,0x40,0x29,0x40,0x1F,0x40,0x00,0x00},/*"@",32*/ {0x00,0x40,0x07,0xC0,0x39,0x00,0x0F,0x00,0x01,0xC0,0x00,0x40},/*"A",33*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x40,0x1B,0x80,0x00,0x00},/*"B",34*/ {0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x30,0x80,0x00,0x00},/*"C",35*/ {0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"D",36*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x40,0x30,0xC0,0x00,0x00},/*"E",37*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x2E,0x00,0x30,0x00,0x00,0x00},/*"F",38*/ {0x0F,0x00,0x10,0x80,0x20,0x40,0x22,0x40,0x33,0x80,0x02,0x00},/*"G",39*/ {0x20,0x40,0x3F,0xC0,0x04,0x00,0x04,0x00,0x3F,0xC0,0x20,0x40},/*"H",40*/ {0x20,0x40,0x20,0x40,0x3F,0xC0,0x20,0x40,0x20,0x40,0x00,0x00},/*"I",41*/ {0x00,0x60,0x20,0x20,0x20,0x20,0x3F,0xC0,0x20,0x00,0x20,0x00},/*"J",42*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x0B,0x00,0x30,0xC0,0x20,0x40},/*"K",43*/ {0x20,0x40,0x3F,0xC0,0x20,0x40,0x00,0x40,0x00,0x40,0x00,0xC0},/*"L",44*/ {0x3F,0xC0,0x3C,0x00,0x03,0xC0,0x3C,0x00,0x3F,0xC0,0x00,0x00},/*"M",45*/ {0x20,0x40,0x3F,0xC0,0x0C,0x40,0x23,0x00,0x3F,0xC0,0x20,0x00},/*"N",46*/ {0x1F,0x80,0x20,0x40,0x20,0x40,0x20,0x40,0x1F,0x80,0x00,0x00},/*"O",47*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x24,0x00,0x18,0x00,0x00,0x00},/*"P",48*/ {0x1F,0x80,0x21,0x40,0x21,0x40,0x20,0xE0,0x1F,0xA0,0x00,0x00},/*"Q",49*/ {0x20,0x40,0x3F,0xC0,0x24,0x40,0x26,0x00,0x19,0xC0,0x00,0x40},/*"R",50*/ {0x18,0xC0,0x24,0x40,0x24,0x40,0x22,0x40,0x31,0x80,0x00,0x00},/*"S",51*/ {0x30,0x00,0x20,0x40,0x3F,0xC0,0x20,0x40,0x30,0x00,0x00,0x00},/*"T",52*/ {0x20,0x00,0x3F,0x80,0x00,0x40,0x00,0x40,0x3F,0x80,0x20,0x00},/*"U",53*/ {0x20,0x00,0x3E,0x00,0x01,0xC0,0x07,0x00,0x38,0x00,0x20,0x00},/*"V",54*/ {0x38,0x00,0x07,0xC0,0x3C,0x00,0x07,0xC0,0x38,0x00,0x00,0x00},/*"W",55*/ {0x20,0x40,0x39,0xC0,0x06,0x00,0x39,0xC0,0x20,0x40,0x00,0x00},/*"X",56*/ {0x20,0x00,0x38,0x40,0x07,0xC0,0x38,0x40,0x20,0x00,0x00,0x00},/*"Y",57*/ {0x30,0x40,0x21,0xC0,0x26,0x40,0x38,0x40,0x20,0xC0,0x00,0x00},/*"Z",58*/ {0x00,0x00,0x00,0x00,0x7F,0xE0,0x40,0x20,0x40,0x20,0x00,0x00},/*"[",59*/ {0x00,0x00,0x70,0x00,0x0C,0x00,0x03,0x80,0x00,0x40,0x00,0x00},/*"\",60*/ {0x00,0x00,0x40,0x20,0x40,0x20,0x7F,0xE0,0x00,0x00,0x00,0x00},/*"]",61*/ {0x00,0x00,0x20,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ {0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10},/*"_",63*/ {0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ {0x00,0x00,0x02,0x80,0x05,0x40,0x05,0x40,0x03,0xC0,0x00,0x40},/*"a",65*/ {0x20,0x00,0x3F,0xC0,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"b",66*/ {0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x06,0x40,0x00,0x00},/*"c",67*/ {0x00,0x00,0x03,0x80,0x04,0x40,0x24,0x40,0x3F,0xC0,0x00,0x40},/*"d",68*/ {0x00,0x00,0x03,0x80,0x05,0x40,0x05,0x40,0x03,0x40,0x00,0x00},/*"e",69*/ {0x00,0x00,0x04,0x40,0x1F,0xC0,0x24,0x40,0x24,0x40,0x20,0x00},/*"f",70*/ {0x00,0x00,0x02,0xE0,0x05,0x50,0x05,0x50,0x06,0x50,0x04,0x20},/*"g",71*/ {0x20,0x40,0x3F,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"h",72*/ {0x00,0x00,0x04,0x40,0x27,0xC0,0x00,0x40,0x00,0x00,0x00,0x00},/*"i",73*/ {0x00,0x10,0x00,0x10,0x04,0x10,0x27,0xE0,0x00,0x00,0x00,0x00},/*"j",74*/ {0x20,0x40,0x3F,0xC0,0x01,0x40,0x07,0x00,0x04,0xC0,0x04,0x40},/*"k",75*/ {0x20,0x40,0x20,0x40,0x3F,0xC0,0x00,0x40,0x00,0x40,0x00,0x00},/*"l",76*/ {0x07,0xC0,0x04,0x00,0x07,0xC0,0x04,0x00,0x03,0xC0,0x00,0x00},/*"m",77*/ {0x04,0x40,0x07,0xC0,0x04,0x40,0x04,0x00,0x03,0xC0,0x00,0x40},/*"n",78*/ {0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x40,0x03,0x80,0x00,0x00},/*"o",79*/ {0x04,0x10,0x07,0xF0,0x04,0x50,0x04,0x40,0x03,0x80,0x00,0x00},/*"p",80*/ {0x00,0x00,0x03,0x80,0x04,0x40,0x04,0x50,0x07,0xF0,0x00,0x10},/*"q",81*/ {0x04,0x40,0x07,0xC0,0x02,0x40,0x04,0x00,0x04,0x00,0x00,0x00},/*"r",82*/ {0x00,0x00,0x06,0x40,0x05,0x40,0x05,0x40,0x04,0xC0,0x00,0x00},/*"s",83*/ {0x00,0x00,0x04,0x00,0x1F,0x80,0x04,0x40,0x00,0x40,0x00,0x00},/*"t",84*/ {0x04,0x00,0x07,0x80,0x00,0x40,0x04,0x40,0x07,0xC0,0x00,0x40},/*"u",85*/ {0x04,0x00,0x07,0x00,0x04,0xC0,0x01,0x80,0x06,0x00,0x04,0x00},/*"v",86*/ {0x06,0x00,0x01,0xC0,0x07,0x00,0x01,0xC0,0x06,0x00,0x00,0x00},/*"w",87*/ {0x04,0x40,0x06,0xC0,0x01,0x00,0x06,0xC0,0x04,0x40,0x00,0x00},/*"x",88*/ {0x04,0x10,0x07,0x10,0x04,0xE0,0x01,0x80,0x06,0x00,0x04,0x00},/*"y",89*/ {0x00,0x00,0x04,0x40,0x05,0xC0,0x06,0x40,0x04,0x40,0x00,0x00},/*"z",90*/ {0x00,0x00,0x00,0x00,0x04,0x00,0x7B,0xE0,0x40,0x20,0x00,0x00},/*"{",91*/ {0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00},/*"|",92*/ {0x00,0x00,0x40,0x20,0x7B,0xE0,0x04,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ {0x40,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x20,0x00,0x40,0x00},/*"~",94*/ }; /* 16*16 ASCII字符集点阵 */ const unsigned char asc2_1608[95][16]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xCC,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ {0x00,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x00,0x00},/*""",2*/ {0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x00,0x00},/*"#",3*/ {0x00,0x00,0x0E,0x18,0x11,0x04,0x3F,0xFF,0x10,0x84,0x0C,0x78,0x00,0x00,0x00,0x00},/*"$",4*/ {0x0F,0x00,0x10,0x84,0x0F,0x38,0x00,0xC0,0x07,0x78,0x18,0x84,0x00,0x78,0x00,0x00},/*"%",5*/ {0x00,0x78,0x0F,0x84,0x10,0xC4,0x11,0x24,0x0E,0x98,0x00,0xE4,0x00,0x84,0x00,0x08},/*"&",6*/ {0x08,0x00,0x68,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x18,0x18,0x20,0x04,0x40,0x02,0x00,0x00},/*"(",8*/ {0x00,0x00,0x40,0x02,0x20,0x04,0x18,0x18,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ {0x02,0x40,0x02,0x40,0x01,0x80,0x0F,0xF0,0x01,0x80,0x02,0x40,0x02,0x40,0x00,0x00},/*"*",10*/ {0x00,0x80,0x00,0x80,0x00,0x80,0x0F,0xF8,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00},/*"+",11*/ {0x00,0x01,0x00,0x0D,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ {0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80},/*"-",13*/ {0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ {0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00},/*"/",15*/ {0x00,0x00,0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"0",16*/ {0x00,0x00,0x08,0x04,0x08,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"1",17*/ {0x00,0x00,0x0E,0x0C,0x10,0x14,0x10,0x24,0x10,0x44,0x11,0x84,0x0E,0x0C,0x00,0x00},/*"2",18*/ {0x00,0x00,0x0C,0x18,0x10,0x04,0x11,0x04,0x11,0x04,0x12,0x88,0x0C,0x70,0x00,0x00},/*"3",19*/ {0x00,0x00,0x00,0xE0,0x03,0x20,0x04,0x24,0x08,0x24,0x1F,0xFC,0x00,0x24,0x00,0x00},/*"4",20*/ {0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",21*/ {0x00,0x00,0x07,0xF0,0x08,0x88,0x11,0x04,0x11,0x04,0x18,0x88,0x00,0x70,0x00,0x00},/*"6",22*/ {0x00,0x00,0x1C,0x00,0x10,0x00,0x10,0xFC,0x13,0x00,0x1C,0x00,0x10,0x00,0x00,0x00},/*"7",23*/ {0x00,0x00,0x0E,0x38,0x11,0x44,0x10,0x84,0x10,0x84,0x11,0x44,0x0E,0x38,0x00,0x00},/*"8",24*/ {0x00,0x00,0x07,0x00,0x08,0x8C,0x10,0x44,0x10,0x44,0x08,0x88,0x07,0xF0,0x00,0x00},/*"9",25*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x03,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ {0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ {0x00,0x00,0x00,0x80,0x01,0x40,0x02,0x20,0x04,0x10,0x08,0x08,0x10,0x04,0x00,0x00},/*"<",28*/ {0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x00,0x00},/*"=",29*/ {0x00,0x00,0x10,0x04,0x08,0x08,0x04,0x10,0x02,0x20,0x01,0x40,0x00,0x80,0x00,0x00},/*">",30*/ {0x00,0x00,0x0E,0x00,0x12,0x00,0x10,0x0C,0x10,0x6C,0x10,0x80,0x0F,0x00,0x00,0x00},/*"?",31*/ {0x03,0xE0,0x0C,0x18,0x13,0xE4,0x14,0x24,0x17,0xC4,0x08,0x28,0x07,0xD0,0x00,0x00},/*"@",32*/ {0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04},/*"A",33*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x11,0x04,0x0E,0x88,0x00,0x70,0x00,0x00},/*"B",34*/ {0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x1C,0x10,0x00,0x00},/*"C",35*/ {0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"D",36*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x17,0xC4,0x10,0x04,0x08,0x18,0x00,0x00},/*"E",37*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x17,0xC0,0x10,0x00,0x08,0x00,0x00,0x00},/*"F",38*/ {0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x44,0x1C,0x78,0x00,0x40,0x00,0x00},/*"G",39*/ {0x10,0x04,0x1F,0xFC,0x10,0x84,0x00,0x80,0x00,0x80,0x10,0x84,0x1F,0xFC,0x10,0x04},/*"H",40*/ {0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00},/*"I",41*/ {0x00,0x03,0x00,0x01,0x10,0x01,0x10,0x01,0x1F,0xFE,0x10,0x00,0x10,0x00,0x00,0x00},/*"J",42*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x03,0x80,0x14,0x64,0x18,0x1C,0x10,0x04,0x00,0x00},/*"K",43*/ {0x10,0x04,0x1F,0xFC,0x10,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0C,0x00,0x00},/*"L",44*/ {0x10,0x04,0x1F,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x1F,0xFC,0x10,0x04,0x00,0x00},/*"M",45*/ {0x10,0x04,0x1F,0xFC,0x0C,0x04,0x03,0x00,0x00,0xE0,0x10,0x18,0x1F,0xFC,0x10,0x00},/*"N",46*/ {0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"O",47*/ {0x10,0x04,0x1F,0xFC,0x10,0x84,0x10,0x80,0x10,0x80,0x10,0x80,0x0F,0x00,0x00,0x00},/*"P",48*/ {0x07,0xF0,0x08,0x18,0x10,0x24,0x10,0x24,0x10,0x1C,0x08,0x0A,0x07,0xF2,0x00,0x00},/*"Q",49*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x11,0xC0,0x11,0x30,0x0E,0x0C,0x00,0x04},/*"R",50*/ {0x00,0x00,0x0E,0x1C,0x11,0x04,0x10,0x84,0x10,0x84,0x10,0x44,0x1C,0x38,0x00,0x00},/*"S",51*/ {0x18,0x00,0x10,0x00,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x00,0x18,0x00,0x00,0x00},/*"T",52*/ {0x10,0x00,0x1F,0xF8,0x10,0x04,0x00,0x04,0x00,0x04,0x10,0x04,0x1F,0xF8,0x10,0x00},/*"U",53*/ {0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",54*/ {0x1F,0xC0,0x10,0x3C,0x00,0xE0,0x1F,0x00,0x00,0xE0,0x10,0x3C,0x1F,0xC0,0x00,0x00},/*"W",55*/ {0x10,0x04,0x18,0x0C,0x16,0x34,0x01,0xC0,0x01,0xC0,0x16,0x34,0x18,0x0C,0x10,0x04},/*"X",56*/ {0x10,0x00,0x1C,0x00,0x13,0x04,0x00,0xFC,0x13,0x04,0x1C,0x00,0x10,0x00,0x00,0x00},/*"Y",57*/ {0x08,0x04,0x10,0x1C,0x10,0x64,0x10,0x84,0x13,0x04,0x1C,0x04,0x10,0x18,0x00,0x00},/*"Z",58*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x40,0x02,0x40,0x02,0x40,0x02,0x00,0x00},/*"[",59*/ {0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x80,0x00,0x60,0x00,0x1C,0x00,0x03,0x00,0x00},/*"\",60*/ {0x00,0x00,0x40,0x02,0x40,0x02,0x40,0x02,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00},/*"^",62*/ {0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"_",63*/ {0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ {0x00,0x00,0x00,0x98,0x01,0x24,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xFC,0x00,0x04},/*"a",65*/ {0x10,0x00,0x1F,0xFC,0x00,0x88,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"b",66*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x00},/*"c",67*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x11,0x08,0x1F,0xFC,0x00,0x04},/*"d",68*/ {0x00,0x00,0x00,0xF8,0x01,0x44,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xC8,0x00,0x00},/*"e",69*/ {0x00,0x00,0x01,0x04,0x01,0x04,0x0F,0xFC,0x11,0x04,0x11,0x04,0x11,0x00,0x18,0x00},/*"f",70*/ {0x00,0x00,0x00,0xD6,0x01,0x29,0x01,0x29,0x01,0x29,0x01,0xC9,0x01,0x06,0x00,0x00},/*"g",71*/ {0x10,0x04,0x1F,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"h",72*/ {0x00,0x00,0x01,0x04,0x19,0x04,0x19,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"i",73*/ {0x00,0x00,0x00,0x03,0x00,0x01,0x01,0x01,0x19,0x01,0x19,0xFE,0x00,0x00,0x00,0x00},/*"j",74*/ {0x10,0x04,0x1F,0xFC,0x00,0x24,0x00,0x40,0x01,0xB4,0x01,0x0C,0x01,0x04,0x00,0x00},/*"k",75*/ {0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"l",76*/ {0x01,0x04,0x01,0xFC,0x01,0x04,0x01,0x00,0x01,0xFC,0x01,0x04,0x01,0x00,0x00,0xFC},/*"m",77*/ {0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"n",78*/ {0x00,0x00,0x00,0xF8,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0xF8,0x00,0x00},/*"o",79*/ {0x01,0x01,0x01,0xFF,0x00,0x85,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"p",80*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0xFF,0x00,0x01},/*"q",81*/ {0x01,0x04,0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x04,0x01,0x00,0x01,0x80,0x00,0x00},/*"r",82*/ {0x00,0x00,0x00,0xCC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x98,0x00,0x00},/*"s",83*/ {0x00,0x00,0x01,0x00,0x01,0x00,0x07,0xF8,0x01,0x04,0x01,0x04,0x00,0x00,0x00,0x00},/*"t",84*/ {0x01,0x00,0x01,0xF8,0x00,0x04,0x00,0x04,0x00,0x04,0x01,0x08,0x01,0xFC,0x00,0x04},/*"u",85*/ {0x01,0x00,0x01,0x80,0x01,0x70,0x00,0x0C,0x00,0x10,0x01,0x60,0x01,0x80,0x01,0x00},/*"v",86*/ {0x01,0xF0,0x01,0x0C,0x00,0x30,0x01,0xC0,0x00,0x30,0x01,0x0C,0x01,0xF0,0x01,0x00},/*"w",87*/ {0x00,0x00,0x01,0x04,0x01,0x8C,0x00,0x74,0x01,0x70,0x01,0x8C,0x01,0x04,0x00,0x00},/*"x",88*/ {0x01,0x01,0x01,0x81,0x01,0x71,0x00,0x0E,0x00,0x18,0x01,0x60,0x01,0x80,0x01,0x00},/*"y",89*/ {0x00,0x00,0x01,0x84,0x01,0x0C,0x01,0x34,0x01,0x44,0x01,0x84,0x01,0x0C,0x00,0x00},/*"z",90*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3E,0xFC,0x40,0x02,0x40,0x02},/*"{",91*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ {0x00,0x00,0x40,0x02,0x40,0x02,0x3E,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ {0x00,0x00,0x60,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*"~",94*/ }; /* 24*24 ASICII字符集点阵 */ const unsigned char asc2_2412[95][36]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x38,0x0F,0xFE,0x38,0x0F,0x80,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0x00,0x38,0x00,0x00,0x31,0x00,0x00,0x06,0x00,0x00,0x0C,0x00,0x00,0x38,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*""",2*/ {0x00,0x00,0x00,0x00,0x61,0x80,0x00,0x67,0xF8,0x07,0xF9,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x61,0x80,0x00,0x67,0xF8,0x07,0xF9,0x80,0x00,0x61,0x80,0x00,0x00,0x00},/*"#",3*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xC0,0xE0,0x03,0xE0,0xF0,0x06,0x30,0x08,0x04,0x18,0x08,0x1F,0xFF,0xFE,0x04,0x0E,0x08,0x07,0x87,0xF0,0x03,0x81,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"$",4*/ {0x01,0xF0,0x00,0x06,0x0C,0x00,0x04,0x04,0x08,0x06,0x0C,0x70,0x01,0xF9,0xC0,0x00,0x0E,0x00,0x00,0x3B,0xE0,0x00,0xEC,0x18,0x07,0x08,0x08,0x04,0x0C,0x18,0x00,0x03,0xE0,0x00,0x00,0x00},/*"%",5*/ {0x00,0x01,0xE0,0x00,0x07,0xF0,0x03,0xF8,0x18,0x04,0x1C,0x08,0x04,0x17,0x08,0x07,0xE1,0xD0,0x03,0xC0,0xE0,0x00,0x23,0xB0,0x00,0x3C,0x08,0x00,0x20,0x08,0x00,0x00,0x10,0x00,0x00,0x00},/*"&",6*/ {0x00,0x00,0x00,0x01,0x00,0x00,0x31,0x00,0x00,0x32,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x01,0xFF,0xC0,0x07,0x80,0xF0,0x0C,0x00,0x18,0x10,0x00,0x04,0x20,0x00,0x02,0x00,0x00,0x00},/*"(",8*/ {0x00,0x00,0x00,0x20,0x00,0x02,0x10,0x00,0x04,0x0C,0x00,0x18,0x07,0x80,0xF0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ {0x00,0x00,0x00,0x00,0x42,0x00,0x00,0x66,0x00,0x00,0x66,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x03,0xFF,0xC0,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x66,0x00,0x00,0x66,0x00,0x00,0x42,0x00},/*"*",10*/ {0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x01,0xFF,0xC0,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00},/*"+",11*/ {0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x31,0x00,0x00,0x32,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ {0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00},/*"-",13*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ {0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x1C,0x00,0x00,0x70,0x00,0x01,0x80,0x00,0x0E,0x00,0x00,0x38,0x00,0x00,0xC0,0x00,0x07,0x00,0x00,0x1C,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*"/",15*/ {0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x03,0x80,0x70,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"0",16*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x08,0x01,0x00,0x08,0x01,0x00,0x08,0x03,0xFF,0xF8,0x07,0xFF,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ {0x00,0x00,0x00,0x01,0xC0,0x38,0x02,0xC0,0x58,0x04,0x00,0x98,0x04,0x01,0x18,0x04,0x02,0x18,0x04,0x04,0x18,0x06,0x1C,0x18,0x03,0xF8,0x18,0x01,0xE0,0xF8,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ {0x00,0x00,0x00,0x01,0xC0,0xE0,0x03,0xC0,0xF0,0x04,0x00,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x06,0x18,0x08,0x03,0xF4,0x18,0x01,0xE7,0xF0,0x00,0x01,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ {0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x0D,0x00,0x00,0x11,0x00,0x00,0x61,0x00,0x00,0x81,0x08,0x03,0x01,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x01,0x08,0x00,0x01,0x08,0x00,0x00,0x00},/*"4",20*/ {0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0xFC,0xD0,0x06,0x08,0x08,0x06,0x10,0x08,0x06,0x10,0x08,0x06,0x10,0x08,0x06,0x18,0x38,0x06,0x0F,0xF0,0x06,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ {0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x84,0x30,0x02,0x08,0x18,0x04,0x10,0x08,0x04,0x10,0x08,0x04,0x10,0x08,0x07,0x18,0x10,0x03,0x0F,0xF0,0x00,0x07,0xC0,0x00,0x00,0x00},/*"6",22*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x07,0x00,0x00,0x06,0x00,0x00,0x06,0x00,0xF8,0x06,0x07,0xF8,0x06,0x18,0x00,0x06,0xE0,0x00,0x07,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ {0x00,0x00,0x00,0x01,0xE1,0xE0,0x03,0xF7,0xF0,0x06,0x34,0x10,0x04,0x18,0x08,0x04,0x18,0x08,0x04,0x0C,0x08,0x04,0x0C,0x08,0x06,0x16,0x18,0x03,0xF3,0xF0,0x01,0xC1,0xE0,0x00,0x00,0x00},/*"8",24*/ {0x00,0x00,0x00,0x00,0xF8,0x00,0x03,0xFC,0x30,0x03,0x06,0x38,0x04,0x02,0x08,0x04,0x02,0x08,0x04,0x02,0x08,0x04,0x04,0x10,0x03,0x08,0xF0,0x01,0xFF,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00},/*"9",25*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x00,0x70,0x38,0x00,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x1A,0x00,0x30,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x14,0x00,0x00,0x22,0x00,0x00,0x41,0x00,0x00,0x80,0x80,0x01,0x00,0x40,0x02,0x00,0x20,0x04,0x00,0x10,0x08,0x00,0x08,0x00,0x00,0x00},/*"<",28*/ {0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x21,0x00,0x00,0x00,0x00},/*"=",29*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x08,0x04,0x00,0x10,0x02,0x00,0x20,0x01,0x00,0x40,0x00,0x80,0x80,0x00,0x41,0x00,0x00,0x22,0x00,0x00,0x14,0x00,0x00,0x08,0x00,0x00,0x00,0x00},/*">",30*/ {0x00,0x00,0x00,0x03,0xC0,0x00,0x04,0xC0,0x00,0x04,0x00,0x00,0x08,0x00,0x38,0x08,0x0F,0x38,0x08,0x08,0x38,0x08,0x10,0x00,0x0C,0x30,0x00,0x07,0xE0,0x00,0x03,0xC0,0x00,0x00,0x00,0x00},/*"?",31*/ {0x00,0x00,0x00,0x00,0x3F,0x80,0x00,0xFF,0xE0,0x03,0x80,0x70,0x02,0x0F,0x10,0x06,0x70,0x88,0x04,0xC0,0x88,0x04,0x83,0x08,0x04,0x7F,0x88,0x02,0xC0,0x90,0x03,0x01,0x20,0x00,0xFE,0x40},/*"@",32*/ {0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x01,0xF8,0x00,0x3E,0x08,0x01,0xC2,0x00,0x07,0x02,0x00,0x07,0xE2,0x00,0x00,0xFE,0x00,0x00,0x1F,0xC8,0x00,0x01,0xF8,0x00,0x00,0x38,0x00,0x00,0x08},/*"A",33*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x06,0x18,0x08,0x03,0xF4,0x18,0x01,0xE7,0xF0,0x00,0x01,0xE0,0x00,0x00,0x00},/*"B",34*/ {0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x02,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x10,0x06,0x00,0x20,0x07,0x80,0xC0,0x00,0x00,0x00},/*"C",35*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x18,0x02,0x00,0x10,0x03,0x80,0x70,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"D",36*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x08,0x08,0x04,0x3E,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x01,0x00,0x60,0x00,0x00,0x00},/*"E",37*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x00,0x04,0x08,0x00,0x04,0x08,0x00,0x04,0x3E,0x00,0x06,0x00,0x00,0x06,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00},/*"F",38*/ {0x00,0x00,0x00,0x00,0x3F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x02,0x08,0x04,0x02,0x08,0x02,0x03,0xF0,0x07,0x83,0xF0,0x00,0x02,0x00,0x00,0x02,0x00},/*"G",39*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x04,0x08,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08},/*"H",40*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ {0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x07,0x00,0x00,0x01,0x04,0x00,0x01,0x04,0x00,0x01,0x04,0x00,0x03,0x07,0xFF,0xFE,0x07,0xFF,0xFC,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00},/*"J",42*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x0C,0x08,0x00,0x18,0x00,0x00,0x3E,0x00,0x04,0xC7,0x80,0x05,0x03,0xC8,0x06,0x00,0xF8,0x04,0x00,0x38,0x04,0x00,0x18,0x00,0x00,0x08},/*"K",43*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x18,0x00,0x00,0x60,0x00,0x00,0x00},/*"L",44*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0x80,0x08,0x07,0xFC,0x00,0x00,0x7F,0xC0,0x00,0x03,0xF8,0x00,0x07,0xC0,0x00,0x78,0x00,0x07,0x80,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08},/*"M",45*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0x00,0x08,0x03,0xC0,0x00,0x00,0xE0,0x00,0x00,0x38,0x00,0x00,0x1E,0x00,0x00,0x07,0x00,0x00,0x01,0xC0,0x04,0x00,0xF0,0x07,0xFF,0xF8,0x04,0x00,0x00},/*"N",46*/ {0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x18,0x04,0x00,0x08,0x04,0x00,0x08,0x06,0x00,0x18,0x03,0x00,0x30,0x01,0xFF,0xE0,0x00,0x7F,0x80,0x00,0x00,0x00},/*"O",47*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x04,0x08,0x04,0x04,0x00,0x04,0x04,0x00,0x04,0x04,0x00,0x04,0x04,0x00,0x06,0x0C,0x00,0x03,0xF8,0x00,0x01,0xF0,0x00,0x00,0x00,0x00},/*"P",48*/ {0x00,0x00,0x00,0x00,0x7F,0x80,0x01,0xFF,0xE0,0x03,0x80,0x70,0x06,0x00,0x88,0x04,0x00,0x88,0x04,0x00,0xC8,0x06,0x00,0x3C,0x03,0x00,0x3E,0x01,0xFF,0xE6,0x00,0x7F,0x84,0x00,0x00,0x00},/*"Q",49*/ {0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x08,0x08,0x04,0x08,0x00,0x04,0x0C,0x00,0x04,0x0F,0x00,0x04,0x0B,0xC0,0x06,0x10,0xF0,0x03,0xF0,0x38,0x01,0xE0,0x08,0x00,0x00,0x08},/*"R",50*/ {0x00,0x00,0x00,0x01,0xE0,0xF8,0x03,0xF0,0x30,0x06,0x30,0x10,0x04,0x18,0x08,0x04,0x18,0x08,0x04,0x0C,0x08,0x04,0x0C,0x08,0x02,0x06,0x18,0x02,0x07,0xF0,0x07,0x81,0xE0,0x00,0x00,0x00},/*"S",51*/ {0x01,0x80,0x00,0x06,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x07,0xFF,0xF8,0x04,0x00,0x08,0x04,0x00,0x00,0x04,0x00,0x00,0x06,0x00,0x00,0x01,0x80,0x00},/*"T",52*/ {0x04,0x00,0x00,0x07,0xFF,0xE0,0x07,0xFF,0xF0,0x04,0x00,0x18,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x04,0x00,0x10,0x07,0xFF,0xE0,0x04,0x00,0x00},/*"U",53*/ {0x04,0x00,0x00,0x06,0x00,0x00,0x07,0xE0,0x00,0x07,0xFE,0x00,0x04,0x1F,0xE0,0x00,0x01,0xF8,0x00,0x00,0x38,0x00,0x01,0xE0,0x04,0x3E,0x00,0x07,0xC0,0x00,0x06,0x00,0x00,0x04,0x00,0x00},/*"V",54*/ {0x04,0x00,0x00,0x07,0xE0,0x00,0x07,0xFF,0xC0,0x04,0x1F,0xF8,0x00,0x07,0xC0,0x07,0xF8,0x00,0x07,0xFF,0x80,0x04,0x3F,0xF8,0x00,0x07,0xC0,0x04,0xF8,0x00,0x07,0x00,0x00,0x04,0x00,0x00},/*"W",55*/ {0x00,0x00,0x00,0x04,0x00,0x08,0x06,0x00,0x18,0x07,0xC0,0x78,0x05,0xF1,0xC8,0x00,0x3E,0x00,0x00,0x1F,0x80,0x04,0x63,0xE8,0x07,0x80,0xF8,0x06,0x00,0x18,0x04,0x00,0x08,0x00,0x00,0x00},/*"X",56*/ {0x04,0x00,0x00,0x06,0x00,0x00,0x07,0x80,0x00,0x07,0xE0,0x08,0x04,0x7C,0x08,0x00,0x1F,0xF8,0x00,0x07,0xF8,0x00,0x18,0x08,0x04,0xE0,0x08,0x07,0x00,0x00,0x06,0x00,0x00,0x04,0x00,0x00},/*"Y",57*/ {0x00,0x00,0x00,0x01,0x00,0x08,0x06,0x00,0x38,0x04,0x00,0xF8,0x04,0x03,0xE8,0x04,0x0F,0x08,0x04,0x7C,0x08,0x05,0xF0,0x08,0x07,0xC0,0x08,0x07,0x00,0x18,0x04,0x00,0x60,0x00,0x00,0x00},/*"Z",58*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFE,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x00,0x00,0x00},/*"[",59*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x07,0x00,0x00,0x00,0xC0,0x00,0x00,0x38,0x00,0x00,0x06,0x00,0x00,0x01,0xC0,0x00,0x00,0x30,0x00,0x00,0x0E,0x00,0x00,0x01,0x00,0x00,0x00},/*"\",60*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x20,0x00,0x02,0x3F,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x10,0x00,0x00,0x30,0x00,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ {0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01,0x00,0x00,0x01},/*"_",63*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ {0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x19,0xF8,0x00,0x1B,0x18,0x00,0x22,0x08,0x00,0x26,0x08,0x00,0x24,0x08,0x00,0x24,0x10,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x18},/*"a",65*/ {0x00,0x00,0x00,0x04,0x00,0x00,0x07,0xFF,0xF8,0x0F,0xFF,0xF0,0x00,0x18,0x18,0x00,0x10,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x18,0x00,0x1F,0xF0,0x00,0x0F,0xC0,0x00,0x00,0x00},/*"b",66*/ {0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x18,0x30,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x3C,0x08,0x00,0x1C,0x10,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ {0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x38,0x18,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x04,0x10,0x10,0x07,0xFF,0xF8,0x0F,0xFF,0xF0,0x00,0x00,0x10,0x00,0x00,0x00},/*"d",68*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x12,0x30,0x00,0x22,0x18,0x00,0x22,0x08,0x00,0x22,0x08,0x00,0x32,0x08,0x00,0x1E,0x10,0x00,0x0E,0x20,0x00,0x00,0x00},/*"e",69*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x01,0xFF,0xF8,0x03,0xFF,0xF8,0x06,0x20,0x08,0x04,0x20,0x08,0x04,0x20,0x08,0x07,0x20,0x00,0x03,0x00,0x00,0x00,0x00,0x00},/*"f",70*/ {0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x0E,0x6E,0x00,0x1F,0xF3,0x00,0x31,0xB1,0x00,0x20,0xB1,0x00,0x20,0xB1,0x00,0x31,0x91,0x00,0x1F,0x13,0x00,0x2E,0x1E,0x00,0x20,0x0E,0x00,0x30,0x00},/*"g",71*/ {0x00,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x00},/*"h",72*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x06,0x3F,0xF8,0x06,0x3F,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x03,0x00,0x20,0x01,0x00,0x20,0x01,0x00,0x20,0x03,0x06,0x3F,0xFE,0x06,0x3F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"j",74*/ {0x00,0x00,0x00,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x01,0x88,0x00,0x03,0x00,0x00,0x2F,0xC0,0x00,0x38,0xF8,0x00,0x20,0x38,0x00,0x20,0x08,0x00,0x00,0x08,0x00,0x00,0x00},/*"k",75*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x08,0x04,0x00,0x08,0x04,0x00,0x08,0x07,0xFF,0xF8,0x0F,0xFF,0xF8,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ {0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x20,0x00,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x00,0x08},/*"m",77*/ {0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x10,0x08,0x00,0x10,0x00,0x00,0x20,0x00,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x1F,0xF8,0x00,0x00,0x08,0x00,0x00,0x00},/*"n",78*/ {0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x0F,0xF0,0x00,0x18,0x30,0x00,0x30,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x08,0x00,0x18,0x30,0x00,0x0F,0xF0,0x00,0x07,0xC0,0x00,0x00,0x00},/*"o",79*/ {0x00,0x00,0x00,0x00,0x20,0x01,0x00,0x3F,0xFF,0x00,0x3F,0xFF,0x00,0x10,0x11,0x00,0x20,0x09,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x30,0x38,0x00,0x1F,0xF0,0x00,0x0F,0xC0,0x00,0x00,0x00},/*"p",80*/ {0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x1F,0xF0,0x00,0x38,0x18,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x09,0x00,0x10,0x11,0x00,0x1F,0xFF,0x00,0x3F,0xFF,0x00,0x00,0x01,0x00,0x00,0x00},/*"q",81*/ {0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x3F,0xF8,0x00,0x3F,0xF8,0x00,0x08,0x08,0x00,0x10,0x08,0x00,0x20,0x08,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x30,0x00,0x00,0x00,0x00},/*"r",82*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x78,0x00,0x1E,0x18,0x00,0x33,0x08,0x00,0x23,0x08,0x00,0x21,0x08,0x00,0x21,0x88,0x00,0x21,0x98,0x00,0x30,0xF0,0x00,0x38,0x60,0x00,0x00,0x00},/*"s",83*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0xFF,0xF0,0x03,0xFF,0xF8,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x3F,0xF0,0x00,0x7F,0xF8,0x00,0x00,0x18,0x00,0x00,0x08,0x00,0x00,0x08,0x00,0x20,0x10,0x00,0x3F,0xF8,0x00,0x7F,0xF0,0x00,0x00,0x10,0x00,0x00,0x00},/*"u",85*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x30,0x00,0x00,0x3C,0x00,0x00,0x3F,0x80,0x00,0x23,0xF0,0x00,0x00,0x78,0x00,0x00,0x70,0x00,0x23,0x80,0x00,0x3C,0x00,0x00,0x30,0x00,0x00,0x20,0x00},/*"v",86*/ {0x00,0x20,0x00,0x00,0x3C,0x00,0x00,0x3F,0xE0,0x00,0x23,0xF8,0x00,0x00,0xE0,0x00,0x27,0x00,0x00,0x3E,0x00,0x00,0x3F,0xE0,0x00,0x21,0xF8,0x00,0x01,0xE0,0x00,0x3E,0x00,0x00,0x20,0x00},/*"w",87*/ {0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x20,0x08,0x00,0x38,0x38,0x00,0x3E,0x68,0x00,0x27,0x80,0x00,0x03,0xC8,0x00,0x2C,0xF8,0x00,0x38,0x38,0x00,0x20,0x18,0x00,0x20,0x08,0x00,0x00,0x00},/*"x",88*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x30,0x03,0x00,0x3C,0x01,0x00,0x3F,0x83,0x00,0x23,0xEC,0x00,0x00,0x70,0x00,0x23,0x80,0x00,0x3C,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"y",89*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x08,0x00,0x20,0x38,0x00,0x20,0xF8,0x00,0x23,0xE8,0x00,0x2F,0x88,0x00,0x3E,0x08,0x00,0x38,0x08,0x00,0x20,0x18,0x00,0x00,0x70,0x00,0x00,0x00},/*"z",90*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x14,0x00,0x1F,0xF7,0xFC,0x30,0x00,0x06,0x20,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"{",91*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x02,0x30,0x00,0x06,0x1F,0xF7,0xFC,0x00,0x14,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ {0x00,0x00,0x00,0x18,0x00,0x00,0x60,0x00,0x00,0x40,0x00,0x00,0x40,0x00,0x00,0x20,0x00,0x00,0x10,0x00,0x00,0x08,0x00,0x00,0x04,0x00,0x00,0x04,0x00,0x00,0x0C,0x00,0x00,0x10,0x00,0x00},/*"~",94*/ }; /* 32*32 ASCII字符集点阵 */ const unsigned char asc2_3216[95][64]={ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x00,0xC0,0x07,0xFF,0xE1,0xE0,0x07,0xF0,0x01,0xE0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0xC0,0x00,0x00,0x07,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x1C,0x20,0x00,0x00,0x01,0xC0,0x00,0x00,0x07,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",2*/ {0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0F,0xE0,0x00,0x1F,0xFC,0x00,0x03,0xF8,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0F,0xE0,0x00,0x1F,0xFC,0x00,0x03,0xF8,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x18,0x0C,0x00,0x00,0x00,0x00,0x00},/*"#",3*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x78,0x07,0xC0,0x00,0xFC,0x06,0x40,0x01,0x0E,0x00,0x20,0x03,0x07,0x00,0x20,0x02,0x03,0x80,0x20,0x0F,0xFF,0xFF,0xFC,0x02,0x01,0xC0,0x20,0x02,0x00,0xE0,0x60,0x01,0x30,0x70,0x40,0x01,0xF0,0x3F,0x80,0x00,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"$",4*/ {0x00,0xFE,0x00,0x00,0x01,0xFF,0x00,0x00,0x03,0x01,0x80,0x00,0x02,0x00,0x80,0x60,0x03,0x01,0x81,0xC0,0x01,0xFF,0x07,0x00,0x00,0xFE,0x18,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0xBF,0x00,0x00,0x0C,0xFF,0xC0,0x00,0x71,0x80,0x60,0x01,0xC1,0x00,0x20,0x03,0x01,0x80,0x60,0x00,0x00,0xFF,0xC0,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00},/*"%",5*/ {0x00,0x00,0x1F,0x00,0x00,0x00,0x7F,0xC0,0x00,0xFC,0xC0,0xC0,0x01,0xFF,0x80,0x60,0x03,0x03,0xE0,0x20,0x02,0x02,0x78,0x20,0x02,0x06,0x1E,0x20,0x03,0xFC,0x07,0x40,0x01,0xF0,0x03,0x80,0x00,0x01,0x03,0xC0,0x00,0x01,0x1C,0x60,0x00,0x01,0xE0,0x20,0x00,0x01,0x00,0x20,0x00,0x01,0x00,0x40,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00},/*"&",6*/ {0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x1C,0x60,0x00,0x00,0x1C,0x40,0x00,0x00,0x1F,0x80,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFF,0x00,0x00,0x78,0x07,0xC0,0x01,0xC0,0x00,0xE0,0x03,0x00,0x00,0x30,0x04,0x00,0x00,0x08,0x08,0x00,0x00,0x04,0x10,0x00,0x00,0x02,0x00,0x00,0x00,0x00},/*"(",8*/ {0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0x08,0x00,0x00,0x04,0x04,0x00,0x00,0x08,0x03,0x00,0x00,0x30,0x01,0xC0,0x00,0xE0,0x00,0x78,0x07,0xC0,0x00,0x3F,0xFF,0x00,0x00,0x07,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x18,0x00,0x00,0x0E,0x38,0x00,0x00,0x0E,0x38,0x00,0x00,0x06,0x30,0x00,0x00,0x03,0x60,0x00,0x00,0x61,0x43,0x80,0x00,0xFF,0xFF,0x80,0x00,0x61,0x43,0x00,0x00,0x03,0x60,0x00,0x00,0x06,0x30,0x00,0x00,0x0E,0x38,0x00,0x00,0x0E,0x38,0x00,0x00,0x0C,0x18,0x00,0x00,0x00,0x00,0x00},/*"*",10*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x7F,0xFF,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},/*"+",11*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xE3,0x00,0x00,0x00,0xE2,0x00,0x00,0x00,0xFC,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00},/*"-",13*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x01,0xE0,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x0E,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"/",15*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x7F,0xFF,0x00,0x00,0xF0,0x07,0x80,0x01,0x80,0x00,0xC0,0x03,0x00,0x00,0x60,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x00,0x00,0x60,0x01,0x80,0x00,0xC0,0x00,0xE0,0x03,0x80,0x00,0x7F,0xFF,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"0",16*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x20,0x00,0x80,0x00,0x60,0x01,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"1",17*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0xE0,0x00,0x98,0x01,0x60,0x01,0x00,0x02,0x60,0x02,0x00,0x04,0x60,0x02,0x00,0x08,0x60,0x02,0x00,0x10,0x60,0x02,0x00,0x20,0x60,0x02,0x00,0x40,0x60,0x03,0x00,0x80,0x60,0x01,0x83,0x00,0x60,0x01,0xFE,0x00,0xE0,0x00,0x7C,0x07,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"2",18*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x07,0x80,0x01,0xF0,0x07,0xC0,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x03,0x03,0x80,0x20,0x01,0x86,0x80,0x40,0x01,0xFC,0xC0,0xC0,0x00,0x78,0x7F,0x80,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"3",19*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x48,0x00,0x00,0x01,0x88,0x00,0x00,0x06,0x08,0x00,0x00,0x0C,0x08,0x10,0x00,0x30,0x08,0x10,0x00,0x40,0x08,0x10,0x01,0xFF,0xFF,0xF0,0x03,0xFF,0xFF,0xF0,0x03,0xFF,0xFF,0xF0,0x00,0x00,0x08,0x10,0x00,0x00,0x08,0x10,0x00,0x00,0x08,0x10,0x00,0x00,0x00,0x00},/*"4",20*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0x1F,0x86,0x40,0x03,0xE1,0x00,0x20,0x03,0x02,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x03,0x06,0x00,0x40,0x03,0x03,0x01,0xC0,0x03,0x01,0xFF,0x80,0x03,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"5",21*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFC,0x00,0x00,0x3F,0xFF,0x00,0x00,0x70,0xC3,0x80,0x00,0x81,0x80,0xC0,0x01,0x01,0x00,0x60,0x03,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x02,0x00,0x20,0x02,0x03,0x00,0x40,0x01,0xC1,0x80,0xC0,0x00,0xC0,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"6",22*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x07,0xE0,0x03,0x00,0x3F,0xE0,0x03,0x01,0xC0,0x00,0x03,0x06,0x00,0x00,0x03,0x18,0x00,0x00,0x03,0x60,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"7",23*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x78,0x3F,0x80,0x00,0xFC,0x60,0xC0,0x01,0x8E,0xC0,0x40,0x03,0x07,0x80,0x20,0x02,0x03,0x00,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0xC0,0x20,0x03,0x01,0xE0,0x40,0x01,0x86,0x70,0xC0,0x00,0xFC,0x3F,0x80,0x00,0x78,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"8",24*/ {0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0xFF,0x81,0xC0,0x01,0xC0,0xC1,0xC0,0x01,0x00,0x60,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x20,0x02,0x00,0x20,0x60,0x02,0x00,0x40,0xC0,0x01,0x00,0xC1,0x80,0x00,0xC1,0x8F,0x00,0x00,0x7F,0xFE,0x00,0x00,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"9",25*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xC0,0x00,0x07,0x81,0xE0,0x00,0x07,0x81,0xE0,0x00,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x66,0x00,0x06,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x01,0xC0,0x00,0x00,0x03,0x60,0x00,0x00,0x06,0x30,0x00,0x00,0x0C,0x18,0x00,0x00,0x18,0x0C,0x00,0x00,0x30,0x06,0x00,0x00,0x60,0x03,0x00,0x00,0xC0,0x01,0x80,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"<",28*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x00,0x00,0x00},/*"=",29*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x10,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x00,0xC0,0x01,0x80,0x00,0x60,0x03,0x00,0x00,0x30,0x06,0x00,0x00,0x18,0x0C,0x00,0x00,0x0C,0x18,0x00,0x00,0x06,0x30,0x00,0x00,0x03,0x60,0x00,0x00,0x01,0xC0,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*">",30*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x01,0xF8,0x00,0x00,0x02,0x38,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0xC0,0x04,0x00,0x79,0xE0,0x04,0x00,0x81,0xE0,0x04,0x01,0x00,0xC0,0x04,0x03,0x00,0x00,0x02,0x02,0x00,0x00,0x03,0x06,0x00,0x00,0x01,0xFC,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00},/*"?",31*/ {0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0x70,0x07,0x80,0x00,0xC0,0x00,0xC0,0x01,0x01,0xF8,0x40,0x03,0x07,0xFC,0x20,0x02,0x1E,0x04,0x20,0x02,0x30,0x08,0x20,0x02,0x20,0x30,0x20,0x02,0x3F,0xFC,0x20,0x01,0x3F,0x04,0x40,0x01,0x80,0x0C,0xC0,0x00,0xE0,0x31,0x80,0x00,0x1F,0xC2,0x00,0x00,0x00,0x00,0x00},/*"@",32*/ {0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x03,0xE0,0x00,0x00,0x3E,0x20,0x00,0x03,0xE0,0x20,0x00,0x3E,0x20,0x00,0x03,0xE0,0x20,0x00,0x03,0x80,0x20,0x00,0x07,0xFC,0x20,0x00,0x00,0x3F,0xE0,0x00,0x00,0x03,0xFE,0x20,0x00,0x00,0x3F,0xE0,0x00,0x00,0x01,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"A",33*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x03,0x03,0x00,0x20,0x01,0x86,0x80,0x60,0x01,0xFC,0xC0,0xC0,0x00,0xF8,0x7F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00},/*"B",34*/ {0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFF,0x00,0x00,0x70,0x07,0x80,0x00,0xC0,0x00,0xC0,0x01,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x03,0xC0,0x01,0x80,0x00,0x30,0x06,0x00,0x00,0x00,0x00,0x00},/*"C",35*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x00,0x00,0x60,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x00,0xF0,0x07,0x80,0x00,0x7F,0xFE,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"D",36*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x03,0x80,0x20,0x02,0x0F,0xE0,0x20,0x03,0x00,0x00,0x60,0x03,0xC0,0x00,0xE0,0x00,0x60,0x03,0x00,0x00,0x00,0x00,0x00},/*"E",37*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x01,0x00,0x00,0x02,0x03,0x80,0x00,0x03,0x0F,0xE0,0x00,0x03,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x60,0x00,0x00},/*"F",38*/ {0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0x70,0x07,0x80,0x01,0xC0,0x01,0xC0,0x01,0x00,0x00,0x40,0x03,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x20,0x20,0x01,0x00,0x20,0x40,0x03,0xC0,0x3F,0x80,0x00,0x30,0x3F,0x80,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00},/*"G",39*/ {0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"H",40*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"I",41*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x01,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x01,0x02,0x00,0x00,0x03,0x02,0x00,0x00,0x06,0x03,0xFF,0xFF,0xFC,0x03,0xFF,0xFF,0xF8,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"J",42*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0xC0,0x20,0x02,0x01,0x00,0x20,0x00,0x07,0x80,0x00,0x00,0x0F,0xE0,0x00,0x00,0x30,0xF8,0x00,0x02,0x60,0x3E,0x20,0x03,0x80,0x0F,0x20,0x03,0x00,0x03,0xE0,0x02,0x00,0x00,0xE0,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"K",43*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0xE0,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00},/*"L",44*/ {0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xE0,0x00,0x20,0x03,0xFF,0x00,0x20,0x00,0x1F,0xF0,0x00,0x00,0x01,0xFF,0x80,0x00,0x00,0x0F,0xE0,0x00,0x00,0x1E,0x00,0x00,0x03,0xE0,0x00,0x00,0x3E,0x00,0x20,0x03,0xE0,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20},/*"M",45*/ {0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0x80,0x00,0x20,0x03,0xF0,0x00,0x20,0x00,0xFC,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x07,0xC0,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0x7C,0x00,0x02,0x00,0x1F,0x80,0x02,0x00,0x07,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"N",46*/ {0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x3F,0xFE,0x00,0x00,0xF0,0x07,0x80,0x01,0x80,0x00,0xC0,0x01,0x00,0x00,0x40,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x01,0x00,0x00,0x40,0x01,0x80,0x00,0xC0,0x00,0xF0,0x03,0x80,0x00,0x3F,0xFE,0x00,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00},/*"O",47*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x20,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x02,0x00,0x80,0x00,0x03,0x01,0x80,0x00,0x01,0x83,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00},/*"P",48*/ {0x00,0x00,0x00,0x00,0x00,0x0F,0xF8,0x00,0x00,0x7F,0xFF,0x00,0x00,0xF0,0x03,0x80,0x01,0x80,0x01,0xC0,0x01,0x00,0x06,0x40,0x02,0x00,0x04,0x20,0x02,0x00,0x04,0x20,0x02,0x00,0x06,0x20,0x02,0x00,0x03,0xE0,0x01,0x00,0x00,0xF8,0x01,0x80,0x00,0x5C,0x00,0xE0,0x03,0x8C,0x00,0x3F,0xFF,0x0C,0x00,0x0F,0xFC,0x18,0x00,0x00,0x00,0x00},/*"Q",49*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x01,0x00,0x20,0x02,0x01,0x00,0x20,0x02,0x01,0x80,0x00,0x02,0x01,0xE0,0x00,0x02,0x01,0xFC,0x00,0x03,0x03,0x3F,0x80,0x01,0x86,0x07,0xE0,0x01,0xFC,0x00,0xE0,0x00,0xF8,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"R",50*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x06,0x00,0x00,0xFE,0x01,0xE0,0x01,0x86,0x00,0xC0,0x03,0x03,0x00,0x40,0x02,0x03,0x00,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0x80,0x20,0x02,0x01,0xC0,0x20,0x02,0x00,0xC0,0x20,0x01,0x00,0xE0,0x60,0x01,0x80,0x70,0xC0,0x03,0xE0,0x3F,0x80,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00},/*"S",51*/ {0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x03,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x03,0xFF,0xFF,0xE0,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*"T",52*/ {0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x03,0xFF,0xFF,0xC0,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x02,0x00,0x00,0x40,0x02,0x00,0x00,0x80,0x03,0xFF,0xFF,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"U",53*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xFC,0x00,0x00,0x02,0x3F,0xC0,0x00,0x00,0x03,0xF8,0x00,0x00,0x00,0x7F,0x80,0x00,0x00,0x07,0xE0,0x00,0x00,0x07,0x80,0x00,0x00,0x78,0x00,0x02,0x03,0xC0,0x00,0x02,0x3C,0x00,0x00,0x03,0xC0,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00},/*"V",54*/ {0x02,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xFF,0x80,0x00,0x02,0x3F,0xFE,0x00,0x02,0x00,0x7F,0xE0,0x00,0x00,0x0F,0x00,0x02,0x00,0xF0,0x00,0x03,0xEF,0x00,0x00,0x03,0xFF,0x80,0x00,0x02,0x0F,0xFE,0x00,0x00,0x00,0x3F,0xE0,0x00,0x00,0x1F,0x00,0x02,0x07,0xE0,0x00,0x03,0xF8,0x00,0x00,0x03,0x00,0x00,0x00,0x02,0x00,0x00,0x00},/*"W",55*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0x80,0x00,0xE0,0x03,0xF0,0x03,0x20,0x02,0xFC,0x0C,0x20,0x02,0x1F,0x30,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xF0,0x00,0x02,0x18,0x7C,0x00,0x02,0x60,0x1F,0x20,0x03,0x80,0x03,0xE0,0x02,0x00,0x00,0xE0,0x02,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"X",56*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xF8,0x00,0x00,0x02,0x3E,0x00,0x20,0x02,0x0F,0xC0,0x20,0x00,0x01,0xFF,0xE0,0x00,0x00,0x7F,0xE0,0x00,0x03,0x80,0x20,0x02,0x1C,0x00,0x20,0x02,0x70,0x00,0x00,0x03,0x80,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Y",57*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x60,0x00,0xE0,0x03,0x80,0x03,0xE0,0x03,0x00,0x0F,0xA0,0x02,0x00,0x3E,0x20,0x02,0x00,0xF8,0x20,0x02,0x03,0xE0,0x20,0x02,0x0F,0x80,0x20,0x02,0x3E,0x00,0x20,0x02,0x78,0x00,0x20,0x03,0xE0,0x00,0x60,0x03,0x80,0x00,0xE0,0x02,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"Z",58*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFC,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"[",59*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"\",60*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x10,0x00,0x00,0x04,0x1F,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"^",62*/ {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01},/*"_",63*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x00,0x01,0x8F,0xC0,0x00,0x03,0x8C,0x60,0x00,0x06,0x18,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x20,0x20,0x00,0x04,0x20,0x40,0x00,0x06,0x20,0x40,0x00,0x03,0xFF,0xC0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00},/*"a",65*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xC0,0x00,0x01,0x80,0xC0,0x00,0x02,0x00,0x60,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x40,0x00,0x03,0x00,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00},/*"b",66*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x81,0xC0,0x00,0x02,0x00,0x40,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xC0,0x40,0x00,0x01,0xC0,0x80,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"c",67*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x80,0xC0,0x00,0x06,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x02,0x04,0x00,0x40,0x02,0x02,0x00,0x80,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00},/*"d",68*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x11,0xC0,0x00,0x02,0x10,0x40,0x00,0x04,0x10,0x60,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x04,0x10,0x20,0x00,0x06,0x10,0x20,0x00,0x03,0x10,0x40,0x00,0x01,0xF0,0xC0,0x00,0x00,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"e",69*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x7F,0xFF,0xE0,0x01,0xFF,0xFF,0xE0,0x01,0x04,0x00,0x20,0x03,0x04,0x00,0x20,0x02,0x04,0x00,0x20,0x02,0x04,0x00,0x20,0x02,0x04,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0xC0,0x00,0x00,0x01,0xC0,0x00,0x00},/*"f",70*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0xE3,0x3E,0x00,0x03,0xFF,0xC2,0x00,0x02,0x0C,0xC3,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x04,0x04,0xC1,0x00,0x06,0x0C,0xC1,0x00,0x03,0xF8,0xC3,0x00,0x05,0xF0,0x62,0x00,0x06,0x00,0x7E,0x00,0x06,0x00,0x3C,0x00,0x00,0x00,0x00},/*"g",71*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xFF,0xE0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"h",72*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x03,0x87,0xFF,0xE0,0x03,0x8F,0xFF,0xE0,0x03,0x80,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"i",73*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x03,0x00,0x04,0x00,0x06,0x03,0x87,0xFF,0xFC,0x03,0x8F,0xFF,0xF8,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"j",74*/ {0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x00,0x08,0x20,0x00,0x00,0x10,0x20,0x00,0x00,0x30,0x00,0x00,0x00,0xFC,0x00,0x00,0x05,0x8E,0x00,0x00,0x07,0x07,0xA0,0x00,0x06,0x01,0xE0,0x00,0x04,0x00,0xE0,0x00,0x04,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"k",75*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x02,0x00,0x00,0x20,0x03,0xFF,0xFF,0xE0,0x07,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"l",76*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x03,0xFF,0xE0,0x00,0x02,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x03,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"m",77*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x03,0xFF,0xE0,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20},/*"n",78*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0xFF,0x80,0x00,0x03,0x81,0xC0,0x00,0x02,0x00,0x40,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x02,0x00,0x40,0x00,0x03,0x81,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"o",79*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x07,0xFF,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x01,0x00,0xC1,0x00,0x02,0x00,0x41,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x06,0x00,0x40,0x00,0x03,0x01,0xC0,0x00,0x01,0xFF,0x80,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00},/*"p",80*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x01,0xFF,0x80,0x00,0x03,0x80,0xC0,0x00,0x02,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x02,0x00,0x41,0x00,0x03,0x00,0xC1,0x00,0x03,0xFF,0xFF,0x00,0x07,0xFF,0xFF,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01},/*"q",81*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x0F,0xFF,0xE0,0x00,0x0F,0xFF,0xE0,0x00,0x00,0xC0,0x20,0x00,0x01,0x00,0x20,0x00,0x02,0x00,0x20,0x00,0x06,0x00,0x20,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00},/*"r",82*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x00,0x01,0xC0,0xE0,0x00,0x03,0xE0,0x40,0x00,0x06,0x30,0x20,0x00,0x04,0x30,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x18,0x20,0x00,0x04,0x0C,0x20,0x00,0x02,0x0C,0x60,0x00,0x03,0x07,0xC0,0x00,0x07,0x83,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"s",83*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x1F,0xFF,0x80,0x00,0xFF,0xFF,0xC0,0x00,0x04,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x40,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"t",84*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0xFF,0x80,0x00,0x0F,0xFF,0xC0,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x40,0x00,0x04,0x00,0x80,0x00,0x07,0xFF,0xE0,0x00,0x0F,0xFF,0xC0,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40},/*"u",85*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x07,0xF0,0x00,0x00,0x04,0xFE,0x00,0x00,0x04,0x1F,0xC0,0x00,0x00,0x03,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x1C,0x00,0x00,0x04,0x60,0x00,0x00,0x07,0x80,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"v",86*/ {0x00,0x04,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x07,0xC0,0x00,0x00,0x07,0xFC,0x00,0x00,0x04,0x3F,0x80,0x00,0x00,0x03,0xE0,0x00,0x04,0x0F,0x80,0x00,0x06,0xF0,0x00,0x00,0x07,0xF0,0x00,0x00,0x07,0xFF,0x80,0x00,0x04,0x0F,0xE0,0x00,0x00,0x03,0x80,0x00,0x04,0x3C,0x00,0x00,0x07,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00},/*"w",87*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x20,0x00,0x04,0x00,0x60,0x00,0x07,0x00,0xE0,0x00,0x07,0x83,0x20,0x00,0x07,0xE6,0x00,0x00,0x04,0xF8,0x00,0x00,0x00,0x3C,0x00,0x00,0x04,0x5E,0x20,0x00,0x05,0x87,0xA0,0x00,0x06,0x01,0xE0,0x00,0x04,0x00,0x60,0x00,0x04,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00},/*"x",88*/ {0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x03,0x00,0x07,0x00,0x03,0x00,0x07,0xE0,0x01,0x00,0x04,0xF8,0x01,0x00,0x04,0x1F,0x02,0x00,0x00,0x07,0xFC,0x00,0x00,0x00,0xE0,0x00,0x00,0x07,0x00,0x00,0x04,0x38,0x00,0x00,0x07,0xC0,0x00,0x00,0x06,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00},/*"y",89*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x60,0x00,0x06,0x00,0xE0,0x00,0x04,0x03,0xE0,0x00,0x04,0x07,0xA0,0x00,0x04,0x0E,0x20,0x00,0x04,0x3C,0x20,0x00,0x04,0x70,0x20,0x00,0x05,0xE0,0x20,0x00,0x07,0x80,0x20,0x00,0x07,0x00,0x60,0x00,0x04,0x00,0xE0,0x00,0x00,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"z",90*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x01,0x40,0x00,0x07,0xFE,0x3F,0xF8,0x08,0x00,0x00,0x04,0x10,0x00,0x00,0x02,0x10,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"{",91*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0x10,0x00,0x00,0x02,0x08,0x00,0x00,0x04,0x07,0xFE,0x3F,0xF8,0x00,0x01,0x40,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ {0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",94*/ }; #endif
- 将“lcd.c”添加进工程以及添加编译路径;
- main.c文件开头添加头文件:#include "lcd.h";
- main函数SD卡驱动后添加:LCD_Init();
- main函数“while(1)”中添加:以下内容:
lcd_clear(WHITE);HAL_Delay(1000);
lcd_clear(RED);HAL_Delay(1000);
- 修改完成后编译0错误0警告,烧录到开发板后在插入SD卡时可以看到屏幕不断在红白刷新,在不插入SD卡时串口不停打印“No SD card.....”。
4.7 增加FSTFS
- 在工程根目录新建“Middlewares”,在“Middlewares”再创建“Third_Party”文件夹;
- 在“Third_Party”文件夹中新建“FATFS-R0.14”文件夹,并将FATFS源码(7个.c/.h文件)复制到文件夹中;
- 在FATFS-R0.14文件夹中新建“fatfs_function.c” 和“fatfs_function.h”两个文件;
- 在MDK中新建FATFS分组,将FATFS-R0.14文件夹的9个文件添加到FATFS分组并添加编译路径;
- 修改“ffcon.h”文件,修改完代码如下
-
/*---------------------------------------------------------------------------/ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ #define FFCONF_DEF 86606 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations /---------------------------------------------------------------------------*/ #define FF_FS_READONLY 0 /* 是否以只读的方式运行FATFS,如果读写都要用就将值设为0 */ /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) / Read-only configuration removes writing API functions, f_write(), f_sync(), / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / and optional writing functions as well. */ #define FF_FS_MINIMIZE 0 /* This option defines minimization level to remove some basic API functions. / / 0: Basic functions are fully enabled. / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() / are removed. / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 3: f_lseek() function is removed in addition to 2. */ #define FF_USE_STRFUNC 2 //#define FF_PRINT_LLI 0 //#define FF_PRINT_FLOAT 0 /* 这个用来设置是否支持字符串类操作,比如f_putc,f_puts等 0: Disable string functions.不启用字符串操作 1: Enable without LF-CRLF conversion.启用无低频-CRLF转换 2: Enable with LF-CRLF conversion. 启用带低频-CRLF转换 */ #define FF_USE_FIND 0 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ #define FF_USE_MKFS 1 /* 用来定义是否使能格式化 */ #define FF_USE_FASTSEEK 1 /* 用来使能快速搜索功能(0:Disable or 1:Enable) */ #define FF_USE_EXPAND 0 /* This option switches f_expand function. (0:Disable or 1:Enable) */ #define FF_USE_CHMOD 0 /* This option switches attribute manipulation functions, f_chmod() and f_utime(). / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ #define FF_USE_LABEL 1 /* 用来设置是否支持磁盘盘符(磁盘名字)读取与设置。 f_getlabel() and f_setlabel(). */ #define FF_USE_FORWARD 0 /* This option switches f_forward() function. (0:Disable or 1:Enable) */ /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ #define FF_CODE_PAGE 936 /* 个用于设置语言编码类型。This option specifies the OEM code page to be used on the target system. / Incorrect code page setting can cause a file open failure. / / 437 - U.S. / 720 - Arabic / 737 - Greek / 771 - KBL / 775 - Baltic / 850 - Latin 1 / 852 - Latin 2 / 855 - Cyrillic / 857 - Turkish / 860 - Portuguese / 861 - Icelandic / 862 - Hebrew / 863 - Canadian French / 864 - Arabic / 865 - Nordic / 866 - Russian / 869 - Greek 2 / 932 - Japanese (DBCS) / 936 - Simplified Chinese (DBCS) / 949 - Korean (DBCS) / 950 - Traditional Chinese (DBCS) / 0 - Include all code pages above and configured by f_setcp() */ #define FF_USE_LFN 2 #define FF_MAX_LFN 255 /* 用于设置是否支持长文件名,0:表示不支持长文件名,1~3 是支持长文件名,但是存储地方不一样. The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. / 2: Enable LFN with dynamic working buffer on the STACK. / 3: Enable LFN with dynamic working buffer on the HEAP. / / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN / specification. / When use stack for the working buffer, take care on stack overflow. When use heap / memory for the working buffer, memory management functions, ff_memalloc() and / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ #define FF_LFN_UNICODE 0 /* This option switches the character encoding on the API when LFN is enabled. / / 0: ANSI/OEM in current CP (TCHAR = char) / 1: Unicode in UTF-16 (TCHAR = WCHAR) / 2: Unicode in UTF-8 (TCHAR = char) / 3: Unicode in UTF-32 (TCHAR = DWORD) / / Also behavior of string I/O functions will be affected by this option. / When LFN is not enabled, this option has no effect. */ #define FF_LFN_BUF 255 #define FF_SFN_BUF 12 /* This set of options defines size of file name members in the FILINFO structure / which is used to read out directory items. These values should be suffcient for / the file names to read. The maximum possible length of the read file name depends / on character encoding. When LFN is not enabled, these options have no effect. */ #define FF_STRF_ENCODE 3 /* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(), / f_putc(), f_puts and f_printf() convert the character encoding in it. / This option selects assumption of character encoding ON THE FILE to be / read/written via those functions. / / 0: ANSI/OEM in current CP / 1: Unicode in UTF-16LE / 2: Unicode in UTF-16BE / 3: Unicode in UTF-8 */ #define FF_FS_RPATH 0 /* This option configures support for relative path. / / 0: Disable relative path and remove related functions. / 1: Enable relative path. f_chdir() and f_chdrive() are available. / 2: f_getcwd() function is available in addition to 1. */ /*---------------------------------------------------------------------------/ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ #define FF_VOLUMES 1 /* 用于设置 FATFS 支持的磁盘设备数目 (1-10) */ #define FF_STR_VOLUME_ID 0 #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / not defined, a user defined volume string table needs to be defined as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ #define FF_MULTI_PARTITION 0 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / funciton will be available. */ #define FF_MIN_SS 512 /*扇区缓冲的最小值,一般设置为 512*/ #define FF_MAX_SS 512 /*扇区缓冲的最大值,一般设置为 512*/ /* This set of options configures the range of sector size to be supported. (512, / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and / harddisk. But a larger value may be required for on-board flash memory and some / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured / for variable sector size mode and disk_ioctl() function needs to implement / GET_SECTOR_SIZE command. */ #define FF_LBA64 0 /* 这个选项用于设置是否支持64-bit LBA,如果要支持那FF_FS_EXFAT也必须使能; STM32F4的SDIO接口不支持超过32G的卡,FF_FS_EXFAT必须为0,所以此项必须为0 This option switches support for 64-bit LBA. (0:Disable or 1:Enable) / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ #define FF_MIN_GPT 0x100000000 /* 只有使能FF_LBA64才有效;STM32F4的SDIO接口不支持超过32G的卡,FF_FS_EXFAT和FF_LBA64必须为0,所以此项无意义 Minimum number of sectors to switch GPT format to create partition in f_mkfs and / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ #define FF_USE_TRIM 0 /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) / To enable Trim function, also CTRL_TRIM command should be implemented to the / disk_ioctl() function. */ /*---------------------------------------------------------------------------/ / System Configurations /---------------------------------------------------------------------------*/ #define FF_FS_TINY 0 /* 是否使用缩小版的FATFS */ /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. / Instead of private sector buffer eliminated from the file object, common sector / buffer in the filesystem object (FATFS) is used for the file data transfer. */ #define FF_FS_EXFAT 0 /* 用来设置是否使用exFAT文件系统,用于支持容量大于32G的SD卡。 STM32F4的SDIO接口不支持超过32G的卡,所以此项必须为0 This option switches support for exFAT filesystem. (0:Disable or 1:Enable) / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) / Note that enabling exFAT discards ANSI C (C89) compatibility. */ #define FF_FS_NORTC 0 #define FF_NORTC_MON 1 #define FF_NORTC_MDAY 1 #define FF_NORTC_YEAR 2019 /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / the timestamp function. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. / These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this / option, and f_getfree() function at first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. / bit0=1: Do not trust free cluster count in the FSINFO. / bit1=0: Use last allocated cluster number in the FSINFO if available. / bit1=1: Do not trust last allocated cluster number in the FSINFO. */ #define FF_FS_LOCK 0 /* The option FF_FS_LOCK switches file lock function to control duplicated file open / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY / is 1. / / 0: Disable file lock function. To avoid volume corruption, application program / should avoid illegal open, remove and rename to the open objects. / >0: Enable file lock function. The value defines how many files/sub-directories / can be opened simultaneously under file lock control. Note that the file / lock control is independent of re-entrancy. */ /* #include <somertos.h> // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 #define FF_SYNC_t NULL /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access / to the same volume is under control of this function. / / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / function, must be added to the project. Samples are available in / option/syscall.c. / / The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be / included somewhere in the scope of ff.h. */ /*--- End of configuration options ---*/
- 修改“diskio.c”文件,修改完代码如下
-
/*-----------------------------------------------------------------------*/ /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */ /*-----------------------------------------------------------------------*/ /* If a working storage control module is available, it should be */ /* attached to the FatFs via a glue function rather than modifying it. */ /* This is an example of glue functions to attach various exsisting */ /* storage control modules to the FatFs module with a defined API. */ /*-----------------------------------------------------------------------*/ #include "ff.h" /* Obtains integer types */ #include "diskio.h" /* Declarations of disk functions */ #include "sd_card.h" /* 驱动器宏定义 */ #define SD_Card 0 /* Example: Map Ramdisk to physical drive 0 */ /*-----------------------------------------------------------------------*/ /* 获取驱动器的状态 ,可以直接返回RES_OK */ /*-----------------------------------------------------------------------*/ DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { return RES_OK;; } /*-----------------------------------------------------------------------*/ /* 磁盘初始化 */ /*-----------------------------------------------------------------------*/ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { uint8_t ret = 0; switch (pdrv) { case SD_Card : ret = MX_SDIO_SD_Init();//SD卡初始化 break; } if(ret) return STA_NOINIT; else return 0; } /*-----------------------------------------------------------------------*/ /* Read Sector(s) * @brief 读扇区 * @param pdrv : 磁盘编号0~9 * @param buff : 数据接收缓冲首地址 * @param sector : 扇区地址 * @param count : 需要读取的扇区数 * @retval 无 */ /*-----------------------------------------------------------------------*/ DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to read */ ) { uint8_t ret = 0; if(!count) return RES_PARERR;//读取扇区的数量不能为0 switch (pdrv) { case SD_Card : { ret = sd_read_disk(buff, sector, count);//如果读取失败就将SD卡重新初始化 while(ret) { MX_SDIO_SD_Init();//SD卡初始化 ret = sd_read_disk(buff, sector, count); } break; } default : ret = 1; } if(ret == 0) return RES_OK; else return RES_ERROR; } /*-----------------------------------------------------------------------*/ /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ #if FF_FS_READONLY == 0 DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ LBA_t sector, /* Start sector in LBA */ UINT count /* Number of sectors to write */ ) { uint8_t ret = 0; if(!count) return RES_PARERR;//读取扇区的数量不能为0 switch (pdrv) { case SD_Card : { ret = sd_write_disk((uint8_t *)buff, sector, count);//如果读取失败就将SD卡重新初始化 while(ret) { MX_SDIO_SD_Init();//SD卡初始化 ret = sd_write_disk((uint8_t *)buff, sector, count); } break; } default : ret = 1; } if(ret == 0) return RES_OK; else return RES_ERROR; } #endif /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions * @brief 获取其他控制参数 * @param pdrv : 磁盘编号0~9 * @param ctrl : 控制代码 * @param buff : 发送/接收缓冲区指针 * @retval 无*/ /*-----------------------------------------------------------------------*/ DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { DRESULT res = RES_PARERR; if(pdrv == SD_Card) { switch (cmd) { case CTRL_SYNC: res = RES_OK; break; case GET_SECTOR_SIZE://获取扇区的大小 *(DWORD *)buff = 512; res = RES_OK; break; case GET_BLOCK_SIZE://获取块大小 *(WORD *)buff = sd_card_info_handle.LogBlockSize; res = RES_OK; break; case GET_SECTOR_COUNT://获取扇区的数量 *(DWORD *)buff = sd_card_info_handle.LogBlockNbr; res = RES_OK; break; default: res = RES_PARERR; break; } } return res; } /** * @brief 获得时间 * @param 无 * @retval 时间 * @note 时间编码规则如下: * User defined function to give a current time to fatfs module * 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) * 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */ DWORD get_fattime (void) { return 0; }
- 在fatfs_function.c中添加下列代码
-
#include "fatfs_function.h" #include "usart.h" #include "malloc.h" /* 文件类型列表 */ char *const FILE_TYPE_TBL[FILE_MAX_TYPE_NUM][FILE_MAX_SUBT_NUM] = { {"BIN"}, /* BIN文件 */ {"LRC"}, /* LRC文件 */ {"NES", "SMS"}, /* NES/SMS文件 */ {"TXT", "C", "H"}, /* 文本文件 */ {"WAV", "MP3", "OGG", "FLAC", "AAC", "WMA", "MID"}, /* 支持的音乐文件 */ {"BMP", "JPG", "JPEG", "GIF"}, /* 图片文件 */ {"AVI"}, /* 视频文件 */ }; /** * @brief 将小写字母转为大写字母,如果是数字,则保持不变. * @param c : 要转换的字母 * @retval 转换后的字母,大写 */ static uint8_t exfuns_char_upper(uint8_t c) { if (c < 'A')return c; /* 数字,保持不变. */ if (c >= 'a') { return c - 0x20; /* 变为大写. */ } else { return c; /* 大写,保持不变 */ } } /** * @brief 报告文件的类型 * @param fname : 文件名 * @retval 文件类型 * @arg 0XFF , 表示无法识别的文件类型编号. * @arg 其他 , 高四位表示所属大类, 低四位表示所属小类. */ unsigned char exfuns_file_type(char *fname) { unsigned char tbuf[5]; char *attr = 0; /* 后缀名 */ unsigned char i = 0, j; while (i < 250) { i++; if (*fname == '\0')break; /* 偏移到了最后了. */ fname++; } if (i == 250)return 0XFF; /* 错误的字符串. */ for (i = 0; i < 5; i++) /* 得到后缀名 */ { fname--; if (*fname == '.') { fname++; attr = fname; break; } } if (attr == 0)return 0XFF; strcpy((char *)tbuf, (const char *)attr); /* copy */ for (i = 0; i < 4; i++)tbuf[i] = exfuns_char_upper(tbuf[i]); /* 全部变为大写 */ for (i = 0; i < FILE_MAX_TYPE_NUM; i++) /* 大类对比 */ { for (j = 0; j < FILE_MAX_SUBT_NUM; j++) /* 子类对比 */ { if (*FILE_TYPE_TBL[i][j] == 0)break; /* 此组已经没有可对比的成员了. */ if (strcmp((const char *)FILE_TYPE_TBL[i][j], (const char *)tbuf) == 0) /* 找到了 */ { return (i << 4) | j; } } } return 0XFF; /* 没找到 */ } /** * @brief 得到path路径下,图片文件的总个数 * @param path : 路径 * @retval 总有效文件数 */ uint16_t pic_get_tnum(char *path) { uint8_t res; uint16_t rval = 0; DIR tdir; /* 临时目录 */ FILINFO *tfileinfo; /* 临时文件信息 */ tfileinfo = (FILINFO *)mymalloc(SRAMIN, sizeof(FILINFO)); /* 申请内存 */ res = f_opendir(&tdir, (const TCHAR *)path); /* 打开目录 */ if (res == FR_OK && tfileinfo) { while (1) /* 查询总的有效文件数 */ { res = f_readdir(&tdir, tfileinfo); /* 读取目录下的一个文件 */ if (res != FR_OK || tfileinfo->fname[0] == 0) { break; /* 错误了/到末尾了,退出 */ } res = exfuns_file_type(tfileinfo -> fname); if ((res & 0XF0) == 0X50) /* 取高四位,看看是不是图片文件 */ { rval++; /* 有效文件数增加1 */ } } } myfree(SRAMIN, tfileinfo); /* 释放内存 */ return rval; } /** * @brief 获取磁盘剩余容量 * @param pdrv : 磁盘编号("0:"~"9:") * @param total: 总容量 (KB) * @param free : 剩余容量 (KB) * @retval 0, 正常; 其他, 错误代码 */ uint8_t exfuns_get_free(uint8_t *pdrv, uint32_t *total, uint32_t *free) { FATFS *fs1; uint8_t res; uint32_t fre_clust = 0, fre_sect = 0, tot_sect = 0; /* 得到磁盘信息及空闲簇数量 */ res = (uint32_t)f_getfree((const TCHAR *)pdrv, (DWORD *)&fre_clust, &fs1); if (res == 0) { tot_sect = (fs1->n_fatent - 2) * fs1->csize; /* 得到总扇区数 */ fre_sect = fre_clust * fs1->csize; /* 得到空闲扇区数 */ #if FF_MAX_SS!=512 /* 扇区大小不是512字节,则转换为512字节 */ tot_sect *= fs1->ssize / 512; fre_sect *= fs1->ssize / 512; #endif *total = tot_sect >> 1; /* 单位为KB */ *free = fre_sect >> 1; /* 单位为KB */ } return res; } static Dir_list *dir_lists = { NULL };//文件夹列表 static uint8_t deep_count = 0;//记录当前的深度 /********************************************************************************************** 函数功能:按深度打印文件夹名称 入口参数: dir_name:文件夹名称 nDepth:文件夹的深度 返回值: 无 **********************************************************************************************/ void Print_Dir(TCHAR *dir_name, uint8_t nDepth) { for(int i=0; i<7*nDepth; i++){ printf(" "); } printf("|—<< %s >>\n", dir_name); } /********************************************************************************************** 函数功能:按深度打印文件名称 入口参数: file_name:文件名称 nDepth:文件的深度 返回值: 无 **********************************************************************************************/ void Printf_FileName(TCHAR *file_name, uint8_t nDepth) { char file_addr[100] = "", str[100] = "";//定义两个字符串 Dir_list *udir_list = { NULL };//文件夹列表 for(udir_list = dir_lists; udir_list != NULL; udir_list=udir_list->next) { sprintf(str, "%s/%s",udir_list->dir_name, file_addr); strcpy(file_addr, str); } if( (strncmp(".WAV",file_name+(strlen(file_name)-4),4) == 0)||(strncmp(".wav",file_name+(strlen(file_name)-4),4) == 0) || (strncmp(".MP3",file_name+(strlen(file_name)-4),4) == 0)||(strncmp(".mp3",file_name+(strlen(file_name)-4),4) == 0) ) { wav_list[file_num].file_addr=(char *)mymalloc(SRAMIN, strlen(file_addr)); if(wav_list[file_num].file_addr) { strcpy(wav_list[file_num].file_addr, file_addr); } else return; wav_list[file_num].file_name=(char *)mymalloc(SRAMIN, strlen(file_name)); if(wav_list[file_num].file_name) { strcpy(wav_list[file_num].file_name, file_name); } else { myfree(SRAMIN, wav_list[file_num].file_addr); return; } file_num ++; } // strcat(file_addr,file_name); // /*以设备树的格式打印*/ // for(int i=0; i<7*nDepth; i++){ // printf(" "); // } // printf("|***( %s )\n", file_addr);//file_name memset(file_addr, 0, sizeof(file_addr)); memset(str, 0, sizeof(str)); } /********************************************************************************************** 函数功能:以文件树的形式打印当前路径下指定深度的所有文件/文件夹名称 入口参数: Path:指定路径 nMaxDepth:最大深度 返回值: 0:成功; 1:失败; **********************************************************************************************/ uint8_t Scan_file(TCHAR *Path, uint8_t nMaxDepth) { FILINFO file_info = { NULL };//一个用于存储文件信息的结构体变量 DIR dir = { NULL }; FRESULT res = f_opendir(&dir, Path); uint8_t sta = 0; Dir_list *udir_list = mymalloc(SRAMIN, sizeof(Dir_list)); if(res == FR_OK) { /*新建节点*/ strcpy((char *)udir_list->dir_name, Path);//复制路径名称 udir_list->next = dir_lists; dir_lists = udir_list; udir_list = 0; // Print_Dir(Path, deep_count);//打印文件夹名称 deep_count++; do { res = f_readdir(&dir, &file_info); if(res == FR_OK) { if(file_info.fname[0]) { if((file_info.fattrib & AM_DIR) == 0) { /* 目标为文件,打印文件名 */ Printf_FileName(file_info.fname, deep_count); } else { /*目标为文件夹,打印文件夹名称,并执行递归 */ if(deep_count < nMaxDepth)/* 在寻址深度内,进行递归 */ { sta = Scan_file(file_info.fname, nMaxDepth); if(sta != 0) break; } } }else break; }else printf("f_readdir defeat, res=%d\n", res); }while(res == FR_OK); if(res == FR_OK && sta == 0 && deep_count > 0) { deep_count--; } /*删除节点*/ udir_list = dir_lists; dir_lists = dir_lists->next; memset(udir_list, 0, sizeof(Dir_list)); myfree(SRAMIN, udir_list); f_closedir(&dir); } else printf("f_opendir defeat, res=%d\n", res); return sta; }
- 在fatfs_function.h中添加下列代码
-
#ifndef __FATFS_FUNCTION_H #define __FATFS_FUNCTION_H #include "main.h" #include "ff.h" #define FILE_MAX_TYPE_NUM 7 /* 最多FILE_MAX_TYPE_NUM个大类 */ #define FILE_MAX_SUBT_NUM 7 /* 最多FILE_MAX_SUBT_NUM个小类 */ /* exfuns_file_type返回的类型定义 * 根据表FILE_TYPE_TBL获得.在exfuns.c里面定义 */ #define T_BIN 0X00 /* bin文件 */ #define T_LRC 0X10 /* lrc文件 */ #define T_NES 0X20 /* nes文件 */ #define T_SMS 0X21 /* sms文件 */ #define T_TEXT 0X30 /* .txt文件 */ #define T_C 0X31 /* .c文件 */ #define T_H 0X32 /* .h文件 */ #define T_WAV 0X40 /* WAV文件 */ #define T_MP3 0X41 /* MP3文件 */ #define T_OGG 0X42 /* OGG文件 */ #define T_FLAC 0X43 /* FLAC文件 */ #define T_AAC 0X44 /* AAC文件 */ #define T_WMA 0X45 /* WMA文件 */ #define T_MID 0X46 /* MID文件 */ #define T_BMP 0X50 /* bmp文件 */ #define T_JPG 0X51 /* jpg文件 */ #define T_JPEG 0X52 /* jpeg文件 */ #define T_GIF 0X53 /* gif文件 */ #define T_AVI 0X60 /* avi文件 */ /*目录深度链表,每打开一个目录就新建一个节点,每关闭一个目录就删除一个节点*/ typedef struct _dir_list_ { struct _dir_list_ *next; uint8_t dir_name[30];//文件夹名称 }Dir_list; unsigned char exfuns_file_type(char *fname);//报告文件的类型 uint16_t pic_get_tnum(char *path);//得到path路径下,图片文件的总个数 uint8_t exfuns_get_free(uint8_t *pdrv, uint32_t *total, uint32_t *free);//获取磁盘剩余容量 void Get_file_date(TCHAR *Path, uint8_t mode);//获取文件内容 uint8_t Scan_file(TCHAR *Path, uint8_t nMaxDepth); #endif
- 在“sd_card.c”最后添加以下三个函数
-
static uint8_t get_sd_card_state(void) { return ((HAL_SD_GetCardState(&hsd) == HAL_SD_CARD_TRANSFER) ? SD_TRANSFER_OK: SD_TRANSFER_BUSY); } /** * @brief 读SD卡(fatfs/usb调用) * @param pbuf : 数据缓存区 * @param saddr : 扇区地址 * @param cnt : 扇区个数 * @retval 0, 正常; 其他, 错误代码(详见SD_Error定义); */ uint8_t sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt) { uint8_t sta = HAL_OK; uint32_t timeout = SD_TIMEOUT; long long lsector = saddr; __disable_irq();/* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */ sta = HAL_SD_ReadBlocks(&hsd, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT); /* 多个sector的读操作 */ /* 等待SD卡读完 */ while (get_sd_card_state() != SD_TRANSFER_OK) { if (timeout-- == 0) { sta = SD_TRANSFER_BUSY; } } __enable_irq();/* 开启总中断 */ return sta; } /** * @brief 写SD卡(fatfs/usb调用) * @param pbuf : 数据缓存区 * @param saddr : 扇区地址 * @param cnt : 扇区个数 * @retval 0, 正常; 其他, 错误代码(详见SD_Error定义); */ uint8_t sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt) { uint8_t sta = HAL_OK; uint32_t timeout = SD_TIMEOUT; long long lsector = saddr; __disable_irq(); /* 关闭总中断(POLLING模式,严禁中断打断SDIO读写操作!!!) */ sta = HAL_SD_WriteBlocks(&hsd, (uint8_t *)pbuf, lsector, cnt, SD_TIMEOUT); /* 多个sector的写操作 */ /* 等待SD卡写完 */ while (get_sd_card_state() != SD_TRANSFER_OK) { if (timeout-- == 0) { sta = SD_TRANSFER_BUSY; } } __enable_irq(); return sta; }
- 在“sd_card.h”最后添加以下声明:
uint8_t sd_read_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt);
uint8_t sd_write_disk(uint8_t *pbuf, uint32_t saddr, uint32_t cnt);
- main.c文件开头添加以下语句:
#include "ff.h"
#include "fatfs_function.h"
FATFS fs[FF_VOLUMES]; //创建磁盘对象结构体,有几个磁盘就创建几个结构体
uint16_t file_num = 0;//统计wav文件个数
File_info wav_list[30] = { NULL };
- 在main.h添加以下语句:
typedef struct _file_nane_
{
char *file_addr;//文件路径
char *file_name;//文件名称
} File_info;
extern uint16_t file_num;//统计wav文件个数
extern File_info wav_list[30];
- 在main函数开头添加语句:uint8_t res = 0;uint16_t i = 0;
- 在main函数中“while(1)”前添加以下语句
-
res = f_mount(&fs[0], "0:", 1); /* 挂载SD卡 */ if (res == FR_NO_FILESYSTEM) /* FLASH磁盘,FAT文件系统错误,重新格式化FLASH */ { lcd_clear(WHITE); lcd_show_string(10, 40, lcddev.width, 32, 32, "SD Disk Formatting...", RED); printf("SD Disk Formatting...\n"); res = f_mkfs("0:", 0, 0, FF_MAX_SS); /* 格式化FLASH,1:,盘符;0,使用默认格式化参数 */ if (res == 0) { f_setlabel((const TCHAR *)"0:ALIENTEK"); /* 设置Flash磁盘的名字为:ALIENTEK */ lcd_clear(WHITE); lcd_show_string(10, 40, lcddev.width, 32, 32, "SD Disk Format Finish", RED); printf("SD Disk Format Finish\n"); } else { lcd_clear(WHITE); lcd_show_string(10, 40, lcddev.width, 32, 32, "SD Disk Format Error", RED); printf("SD Disk Format Error\n"); } HAL_Delay(1000); } Scan_file("0:", 8);//扫描全部文件 printf("\n\n"); for(i=0;i<file_num;i++) { printf("%s\n",wav_list[i].file_name); } printf("\n\n");
- 将音乐文件拷贝到SD卡中除“SYSTEM”外的任意目录
修改完成后编译0错误0警告,烧录到开发板后在插入SD卡时可以看到串口有打印SD卡的信息,之后会打印SD卡所有的音乐文件的名称,最后LCD再红白刷新。在不插入SD卡时串口不停打印“No SD card.....”。
4.8增加汉字显示部分代码
- 在“BSP”文件夹中新建chese_font文件夹;
- 在MALLOC文件夹中新建“chese_font.c” 和“chese_font.h”两个文件;
- 在chese_font.c中添加下列代码
-
#include "chese_font.h" #include "ff.h" #include "lcd.h" #include "malloc.h" uint8_t FONT_Check(void) { FIL files = { NULL };//一个用于指向文件的结构体 if(f_open(&files, FONT_PATH, FA_READ | FA_OPEN_EXISTING) != FR_OK)//打开文件失败 { return 1; } /*打开成功*/ if(f_size(&files) ==0)//获取文件长度 { return 1; } f_close(&files);//关闭文件 return 0; } /** * @brief 获取汉字点阵数据 * @param code : 当前汉字编码(GBK码) * @param mat : 当前汉字点阵数据存放地址 * @param size : 字体大小 * @note size大小的字体,其点阵数据大小为: (size / 8 + ((size % 8) ? 1 : 0)) * (size) 字节 * @retval 无 */ static void text_get_hz_mat(uint8_t *code, uint8_t *mat, uint8_t size) { uint8_t qh, ql; uint64_t foffset; uint8_t csize = 0;/* 得到字体一个字符对应点阵集所占的字节数 */ FIL files = { NULL };//一个用于指向文件的结构体 uint32_t br = 0;//读文件需使用 qh = *code; ql = *(++code); csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size); /* 得到字体一个字符对应点阵集所占的字节数 */ if (qh < 0x81 || ql < 0x40 || ql == 0xff || qh == 0xff) /* 非 常用汉字 */ { memset(mat, 0, csize); return; /* 结束访问 */ } if (ql < 0x7f) ql -= 0x40; /* 注意! */ else ql -= 0x41; qh -= 0x81; foffset = ((uint64_t)190 * qh + ql) * csize; /* 得到字库中的字节偏移量 */ if(f_open(&files, FONT_PATH, FA_READ | FA_OPEN_EXISTING) == FR_OK) { if(f_lseek(&files, foffset) == FR_OK) { if( f_read(&files, mat, csize, &br) == FR_OK) return;//读取成功,正常退出 } } /*读取不成功,给0*/ memset(mat, 0, csize); } /** * @brief 显示一个指定大小的汉字 * @param x,y : 汉字的坐标 * @param font : 汉字GBK码 * @param size : 字体大小 * @param mode : 显示模式 * @note 0, 正常显示(不需要显示的点,用LCD背景色填充,即g_back_color) * @note 1, 叠加显示(仅显示需要显示的点, 不需要显示的点, 不做处理) * @param color : 字体颜色 * @retval 无 */ static void text_show_font(uint16_t x, uint16_t y, uint8_t *font, uint8_t size, uint8_t mode, uint16_t color) { uint8_t temp, t, t1; uint16_t y0 = y; uint8_t *dzk; uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size); /* 得到字体一个字符对应点阵集所占的字节数 */ if (size != 12 && size != 16 && size != 24 && size != 32) { return; /* 不支持的size */ } dzk = mymalloc(SRAMIN, csize); /* 申请内存 */ if (dzk == 0) return; /* 内存不够了 */ text_get_hz_mat(font, dzk, size); /* 得到相应大小的点阵数据 */ for (t = 0; t < csize; t++) { temp = dzk[t]; /* 得到点阵数据 */ for (t1 = 0; t1 < 8; t1++) { if (temp & 0x80) { lcd_draw_point(x, y, color); /* 画需要显示的点 */ } else if (mode == 0) /* 如果非叠加模式, 不需要显示的点,用背景色填充 */ { lcd_draw_point(x, y, g_back_color); /* 填充背景色 */ } temp <<= 1; y++; if ((y - y0) == size) { y = y0; x++; break; } } } myfree(SRAMIN, dzk); /* 释放内存 */ } void LCD_show_chinese(uint16_t x, uint16_t y, uint16_t width, uint16_t height, char *str, uint8_t size, uint8_t mode, uint16_t color) { uint16_t x0 = x; uint16_t y0 = y; uint8_t *pstr = (uint8_t *)str; /* 指向char*型字符串首地址 */ while (*pstr != 0) /* 数据未结束 */ { if (*pstr > 0x80) /* 中文 */ { if (x > (x0 + width - size)) /* 换行 */ { y += size; x = x0; } if (y > (y0 + height - size)) { break; /* 越界返回 */ } text_show_font(x, y, pstr, size, mode, color); /* 显示这个汉字,空心显示 */ pstr += 2; x += size; /* 下一个汉字偏移 */ } else /* 字符 */ { if (x > (x0 + width - size / 2)) /* 换行 */ { y += size; x = x0; } if (y > (y0 + height - size)) { break; /* 越界返回 */ } if (*pstr == 13) /* 换行符号 */ { y += size; x = x0; pstr++; } else { lcd_show_char(x, y, *pstr, size, mode, color); /* 有效部分写入 */ } pstr++; x += size / 2; /* 英文字符宽度, 为中文汉字宽度的一半 */ } } }
- 在chese_font.h中添加下列代码
#ifndef __CHINESE_FONT_H #define __CHINESE_FONT_H #include "main.h" uint8_t FONT_Check(void); void LCD_show_chinese(uint16_t x, uint16_t y, uint16_t width, uint16_t height, char *str, uint8_t size, uint8_t mode, uint16_t color); #endif
- 将“chese_font.c”添加进工程以及添加编译路径;
- 在main.h添加字库大小和路径声明:
#define FONT_SIZE 24
#define FONT_PATH "0:/SYSTEM/FONT/GBK24.bin"
- main.c文件开头添加头文件:#include "chese_font.h"
- 删除main函数while(1)里的内容;
- 在main函数while(1)前增加以下语句:
while(FONT_Check())//确认字库文件是否存在
{
lcd_clear(WHITE);//清屏
lcd_show_string(10, 40, lcddev.width, 32, 32, "Read font files failed", RED);
HAL_Delay(5000);
}
LCD_show_chinese(0,0,lcddev.width,FONT_SIZE, “汉字显示”, FONT_SIZE, 0, g_point_color);
- 将前面准备好的字库文件复制到SD卡的“SYSTEM/FONT/GBK24.bin”路径中。
修改完成后编译0错误0警告,烧录后可以看到屏幕上显示“汉字显示”。
4.9 增加I2S接口驱动
- 删除“dma.c” 和“dma.h”两个文件;
- 将i2s.c替换为如下内容
-
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file i2s.c * @brief This file provides code for the configuration * of the I2S instances. ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "i2s.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ I2S_HandleTypeDef hi2s2; DMA_HandleTypeDef hdma_spi2_tx; /* I2S2 init function */ void MX_I2S2_Init(uint32_t I2S_DataFormat) { /* USER CODE BEGIN I2S2_Init 0 */ /* USER CODE END I2S2_Init 0 */ /* USER CODE BEGIN I2S2_Init 1 */ /* USER CODE END I2S2_Init 1 */ hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_TX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DataFormat;//I2S_DATAFORMAT_16B_EXTENDED; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_DEFAULT;//I2S_AUDIOFREQ_96K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2S2_Init 2 */ SPI2->CR2|=1<<1; //SPI2 TX DMA请求使能. __HAL_I2S_ENABLE(&hi2s2); //使能I2S2 /* USER CODE END I2S2_Init 2 */ } void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(i2sHandle->Instance==SPI2) { /* USER CODE BEGIN SPI2_MspInit 0 */ /* USER CODE END SPI2_MspInit 0 */ /* I2S2 clock enable */ __HAL_RCC_SPI2_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2S2 GPIO Configuration PC2 ------> I2S2_ext_SD PC3 ------> I2S2_SD PB12 ------> I2S2_WS PB13 ------> I2S2_CK PC6 ------> I2S2_MCK */ GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USER CODE BEGIN SPI2_MspInit 1 */ /* USER CODE END SPI2_MspInit 1 */ } } void HAL_I2S_MspDeInit(I2S_HandleTypeDef* i2sHandle) { if(i2sHandle->Instance==SPI2) { /* USER CODE BEGIN SPI2_MspDeInit 0 */ /* USER CODE END SPI2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_SPI2_CLK_DISABLE(); /**I2S2 GPIO Configuration PC2 ------> I2S2_ext_SD PC3 ------> I2S2_SD PB12 ------> I2S2_WS PB13 ------> I2S2_CK PC6 ------> I2S2_MCK */ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_6); HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_13); /* I2S2 DMA DeInit */ HAL_DMA_DeInit(i2sHandle->hdmatx); /* USER CODE BEGIN SPI2_MspDeInit 1 */ /* USER CODE END SPI2_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ //I2S2 TX DMA配置 //设置为双缓冲模式,并开启DMA传输完成中断 //buf0:M0AR地址. //buf1:M1AR地址. //num:每次传输数据量 void I2S2_TX_DMA_Init(uint8_t* buf0,uint8_t *buf1,uint16_t num) { __HAL_RCC_DMA1_CLK_ENABLE(); //使能DMA1时钟 __HAL_LINKDMA(&hi2s2,hdmatx,hdma_spi2_tx); //将DMA与I2S联系起来 /* I2S2 DMA Init */ /* SPI2_TX Init */ hdma_spi2_tx.Instance=DMA1_Stream4; //DMA1数据流4 hdma_spi2_tx.Init.Channel=DMA_CHANNEL_0; //通道0 hdma_spi2_tx.Init.Direction=DMA_MEMORY_TO_PERIPH; //存储器到外设模式 hdma_spi2_tx.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式 hdma_spi2_tx.Init.MemInc=DMA_MINC_ENABLE; //存储器增量模式 hdma_spi2_tx.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设数据长度:16位 hdma_spi2_tx.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位 hdma_spi2_tx.Init.Mode=DMA_CIRCULAR; //使用循环模式 hdma_spi2_tx.Init.Priority=DMA_PRIORITY_HIGH; //高优先级 hdma_spi2_tx.Init.FIFOMode=DMA_FIFOMODE_DISABLE; //不使用FIFO HAL_DMA_DeInit(&hdma_spi2_tx); //先清除以前的设置 if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK) //初始化DMA { Error_Handler(); } HAL_DMAEx_MultiBufferStart(&hdma_spi2_tx,(uint32_t)buf0,(uint32_t)&SPI2->DR,(uint32_t)buf1,num);//开启双缓冲 __HAL_DMA_DISABLE(&hdma_spi2_tx); //先关闭DMA HAL_Delay(1); //10us延时,防止-O2优化出问题 __HAL_DMA_ENABLE_IT(&hdma_spi2_tx,DMA_IT_TC); //开启传输完成中断 __HAL_DMA_CLEAR_FLAG(&hdma_spi2_tx,DMA_FLAG_TCIF0_4); //清除DMA传输完成中断标志位 HAL_NVIC_SetPriority(DMA1_Stream4_IRQn,0,0); //DMA中断优先级 HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); } //采样率计算公式:Fs=I2SxCLK/[256*(2*I2SDIV+ODD)] //I2SxCLK=(HSE/pllm)*PLLI2SN/PLLI2SR //一般HSE=8Mhz //pllm:在Sys_Clock_Set设置的时候确定,一般是8 //PLLI2SN:一般是192~432 //PLLI2SR:2~7 //I2SDIV:2~255 //ODD:0/1 //I2S分频系数表@pllm=8,HSE=8Mhz,即vco输入频率为1Mhz //表格式:采样率/10,PLLI2SN,PLLI2SR,I2SDIV,ODD const uint16_t I2S_PSC_TBL[][5]= { {800 ,256,5,12,1}, //8Khz采样率 {1102,429,4,19,0}, //11.025Khz采样率 {1600,213,2,13,0}, //16Khz采样率 {2205,429,4, 9,1}, //22.05Khz采样率 {3200,213,2, 6,1}, //32Khz采样率 {4410,271,2, 6,0}, //44.1Khz采样率 {4800,258,3, 3,1}, //48Khz采样率 {8820,316,2, 3,1}, //88.2Khz采样率 {9600,344,2, 3,1}, //96Khz采样率 {17640,361,2,2,0}, //176.4Khz采样率 {19200,393,2,2,0}, //192Khz采样率 }; //开启I2S的DMA功能,HAL库没有提供此函数 //因此我们需要自己操作寄存器编写一个 void I2S_DMA_Enable(void) { uint32_t tempreg=0; tempreg=SPI2->CR2; //先读出以前的设置 tempreg|=1<<1; //使能DMA SPI2->CR2=tempreg; //写入CR1寄存器中 } //设置SAIA的采样率(@MCKEN) //samplerate:采样率,单位:Hz //返回值:0,设置成功;1,无法设置. uint8_t I2S2_SampleRate_Set(uint32_t samplerate) { uint8_t i=0; uint32_t tempreg=0; RCC_PeriphCLKInitTypeDef RCCI2S2_ClkInitSture; for(i=0;i<(sizeof(I2S_PSC_TBL)/10);i++)//看看改采样率是否可以支持 { if((samplerate/10)==I2S_PSC_TBL[i][0])break; } if(i==(sizeof(I2S_PSC_TBL)/10))return 1;//搜遍了也找不到 RCCI2S2_ClkInitSture.PeriphClockSelection=RCC_PERIPHCLK_I2S; //外设时钟源选择 RCCI2S2_ClkInitSture.PLLI2S.PLLI2SN=(uint32_t)I2S_PSC_TBL[i][1]; //设置PLLI2SN RCCI2S2_ClkInitSture.PLLI2S.PLLI2SR=(uint32_t)I2S_PSC_TBL[i][2]; //设置PLLI2SR HAL_RCCEx_PeriphCLKConfig(&RCCI2S2_ClkInitSture); //设置时钟 RCC->CR|=1<<26; //开启I2S时钟 while((RCC->CR&1<<27)==0); //等待I2S时钟开启成功. tempreg=I2S_PSC_TBL[i][3]<<0; //设置I2SDIV tempreg|=I2S_PSC_TBL[i][4]<<8; //设置ODD位 tempreg|=1<<9; //使能MCKOE位,输出MCK SPI2->I2SPR=tempreg; //设置I2SPR寄存器 return 0; } //I2S DMA回调函数指针 void (*i2s_tx_callback)(void); //TX回调函数 /** * @brief This function handles DMA1 stream4 global interrupt. */ void DMA1_Stream4_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream4_IRQn 0 */ /* USER CODE END DMA1_Stream4_IRQn 0 */ // HAL_DMA_IRQHandler(&hdma_spi2_tx); /* USER CODE BEGIN DMA1_Stream4_IRQn 1 */ if(__HAL_DMA_GET_FLAG(&hdma_spi2_tx,DMA_FLAG_TCIF0_4)!=RESET) //DMA传输完成 { __HAL_DMA_CLEAR_FLAG(&hdma_spi2_tx,DMA_FLAG_TCIF0_4); //清除DMA传输完成中断标志位 i2s_tx_callback(); //执行回调函数,读取数据等操作在这里面处理 } /* USER CODE END DMA1_Stream4_IRQn 1 */ } //I2S开始播放 void I2S_Play_Start(void) { __HAL_DMA_ENABLE(&hdma_spi2_tx);//开启DMA TX传输 } //关闭I2S播放 void I2S_Play_Stop(void) { __HAL_DMA_DISABLE(&hdma_spi2_tx);//结束播放; } /* USER CODE END 1 */
- 将i2s.h替换为如下内容
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file i2s.h * @brief This file contains all the function prototypes for * the i2s.c file ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __I2S_H__ #define __I2S_H__ #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ extern I2S_HandleTypeDef hi2s2; /* USER CODE BEGIN Private defines */ extern void (*i2s_tx_callback)(void); //IIS TX回调函数指针 /* USER CODE END Private defines */ void MX_I2S2_Init(uint32_t I2S_DataFormat); /* USER CODE BEGIN Prototypes */ void I2S2_TX_DMA_Init(uint8_t* buf0,uint8_t *buf1,uint16_t num); uint8_t I2S2_SampleRate_Set(uint32_t samplerate); void I2S_Play_Start(void); void I2S_Play_Stop(void); /* USER CODE END Prototypes */ #ifdef __cplusplus } #endif #endif /* __I2S_H__ */
- 删除“stm32f4xx_it.c”和“stm32f4xx_it.h”文件中关于DMA中断的全部内容;
4.10 增加音频解码芯片驱动
- 在main.h添加以下宏定义:
#define ES8388 1
#define WM8978 2
#define music_phy WM8978
- 将“i2c,c”中MX_I2C1_Init函数的“hi2c1.Init.OwnAddress1 = 52;”替换成以下内容:
#if(music_phy == ES8388)
hi2c1.Init.OwnAddress1 = 32;
#elif(music_phy == WM8978)
hi2c1.Init.OwnAddress1 = 52;
#endif
- 在MX_I2C1_Init函数最后添加:
while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {};
- 在“i2c.c”最后添加以下内容
#if(music_phy == ES8388) /******************************ES8388驱动*********************************/ /** * @brief ES8388写寄存器 * @param reg : 寄存器地址 * @param val : 要写入寄存器的值 * @retval 0,成功 * 其他,错误代码 */ uint8_t es8388_write_reg(uint8_t reg, uint8_t val) { while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } while(HAL_I2C_Mem_Write(&hi2c1, ES8388_ADDR<<1, (uint16_t)reg, I2C_MEMADD_SIZE_8BIT, &val, 1, 100) != HAL_OK) { } return 0; } /** * @brief ES8388初始化 * @param 无 * @retval 0,初始化正常 * 其他,错误代码 */ uint8_t es8388_init(void) { MX_I2C1_Init(); /* 初始化IIC接口 */ es8388_write_reg(0, 0x80); /* 软复位ES8388 */ es8388_write_reg(0, 0x00); HAL_Delay(100); /* 等待复位 */ es8388_write_reg(0x01, 0x58); es8388_write_reg(0x01, 0x50); es8388_write_reg(0x02, 0xF3); es8388_write_reg(0x02, 0xF0); es8388_write_reg(0x03, 0x09); /* 麦克风偏置电源关闭 */ es8388_write_reg(0x00, 0x06); /* 使能参考 500K驱动使能 */ es8388_write_reg(0x04, 0x00); /* DAC电源管理,不打开任何通道 */ es8388_write_reg(0x08, 0x00); /* MCLK不分频 */ es8388_write_reg(0x2B, 0x80); /* DAC控制 DACLRC与ADCLRC相同 */ es8388_write_reg(0x09, 0x88); /* ADC L/R PGA增益配置为+24dB */ es8388_write_reg(0x0C, 0x4C); /* ADC 数据选择为left data = left ADC, right data = left ADC 音频数据为16bit */ es8388_write_reg(0x0D, 0x02); /* ADC配置 MCLK/采样率=256 */ es8388_write_reg(0x10, 0x00); /* ADC数字音量控制将信号衰减 L 设置为最小!!! */ es8388_write_reg(0x11, 0x00); /* ADC数字音量控制将信号衰减 R 设置为最小!!! */ es8388_write_reg(0x17, 0x18); /* DAC 音频数据为16bit */ es8388_write_reg(0x18, 0x02); /* DAC 配置 MCLK/采样率=256 */ es8388_write_reg(0x1A, 0x00); /* DAC数字音量控制将信号衰减 L 设置为最小!!! */ es8388_write_reg(0x1B, 0x00); /* DAC数字音量控制将信号衰减 R 设置为最小!!! */ es8388_write_reg(0x27, 0xB8); /* L混频器 */ es8388_write_reg(0x2A, 0xB8); /* R混频器 */ HAL_Delay(100); return 0; } ///** // * @brief ES8388读寄存器 // * @param reg : 寄存器地址 // * @retval 读取到的数据 // */ //uint8_t es8388_read_reg(uint8_t reg) //{ // uint8_t temp = 0; // // if(HAL_I2C_Master_Transmit(&hi2c1, ES8388_ADDR, ®, 1, 10) != HAL_OK)/* 写寄存器地址 */ // { // return 1; // } // // // if( HAL_I2C_Master_Receive(&hi2c1, ES8388_ADDR, &temp, 1, 1000) != HAL_OK)/*读数据*/ // { // return 1; // } // // return temp; //} /** * @brief 设置ES8388工作模式 * @param fmt : 工作模式 * @arg 0, 飞利浦标准I2S; * @arg 1, MSB(左对齐); * @arg 2, LSB(右对齐); * @arg 3, PCM/DSP * @param len : 数据长度 * @arg 0, 24bit * @arg 1, 20bit * @arg 2, 18bit * @arg 3, 16bit * @arg 4, 32bit * @retval 无 */ void es8388_sai_cfg(uint8_t fmt, uint8_t len) { fmt &= 0x03; len &= 0x07; /* 限定范围 */ es8388_write_reg(23, (fmt << 1) | (len << 3)); /* R23,ES8388工作模式设置 */ } /** * @brief 设置耳机音量 * @param volume : 音量大小(0 ~ 33) * @retval 无 */ void es8388_hpvol_set(uint8_t volume) { if (volume > 33) { volume = 33; } es8388_write_reg(0x2E, volume); es8388_write_reg(0x2F, volume); } /** * @brief 设置喇叭音量 * @param volume : 音量大小(0 ~ 33) * @retval 无 */ void es8388_spkvol_set(uint8_t volume) { if (volume > 33) { volume = 33; } es8388_write_reg(0x30, volume); es8388_write_reg(0x31, volume); } /** * @brief 设置3D环绕声 * @param depth : 0 ~ 7(3D强度,0关闭,7最强) * @retval 无 */ void es8388_3d_set(uint8_t depth) { depth &= 0x7; /* 限定范围 */ es8388_write_reg(0x1D, depth << 2); /* R7,3D环绕设置 */ } /** * @brief ES8388 DAC/ADC配置 * @param dacen : dac使能(1)/关闭(0) * @param adcen : adc使能(1)/关闭(0) * @retval 无 */ void es8388_adda_cfg(uint8_t dacen, uint8_t adcen) { uint8_t tempreg = 0; tempreg |= ((!dacen) << 0); tempreg |= ((!adcen) << 1); tempreg |= ((!dacen) << 2); tempreg |= ((!adcen) << 3); es8388_write_reg(0x02, tempreg); } /** * @brief ES8388 DAC输出通道配置 * @param o1en : 通道1使能(1)/禁止(0) * @param o2en : 通道2使能(1)/禁止(0) * @retval 无 */ void es8388_output_cfg(uint8_t o1en, uint8_t o2en) { uint8_t tempreg = 0; tempreg |= o1en * (3 << 4); tempreg |= o2en * (3 << 2); es8388_write_reg(0x04, tempreg); } /** * @brief ES8388 MIC增益设置(MIC PGA增益) * @param gain : 0~8, 对应0~24dB 3dB/Step * @retval 无 */ void es8388_mic_gain(uint8_t gain) { gain &= 0x0F; gain |= gain << 4; es8388_write_reg(0x09, gain); /* R9,左右通道PGA增益设置 */ } /** * @brief ES8388 ALC设置 * @param sel * @arg 0,关闭ALC * @arg 1,右通道ALC * @arg 2,左通道ALC * @arg 3,立体声ALC * @param maxgain : 0~7,对应-6.5~+35.5dB * @param mingain : 0~7,对应-12~+30dB 6dB/STEP * @retval 无 */ void es8388_alc_ctrl(uint8_t sel, uint8_t maxgain, uint8_t mingain) { uint8_t tempreg = 0; tempreg = sel << 6; tempreg |= (maxgain & 0x07) << 3; tempreg |= mingain & 0x07; es8388_write_reg(0x12, tempreg); /* R18,ALC设置 */ } /** * @brief ES8388 ADC输出通道配置 * @param in : 输入通道 * @arg 0, 通道1输入 * @arg 1, 通道2输入 * @retval 无 */ void es8388_input_cfg(uint8_t in) { es8388_write_reg(0x0A, (5 * in) << 4); /* ADC1 输入通道选择L/R INPUT1 */ } #elif(music_phy == WM8978) /******************************WM8978驱动*********************************/ //WM8978寄存器值缓存区(总共58个寄存器,0~57),占用116字节内存 //因为WM8978的IIC操作不支持读操作,所以在本地保存所有寄存器值 //写WM8978寄存器时,同步更新到本地寄存器值,读寄存器时,直接返回本地保存的寄存器值. //注意:WM8978的寄存器值是9位的,所以要用uint16_t来存储. static uint16_t WM8978_REGVAL_TBL[58]= { 0X0000,0X0000,0X0000,0X0000,0X0050,0X0000,0X0140,0X0000, 0X0000,0X0000,0X0000,0X00FF,0X00FF,0X0000,0X0100,0X00FF, 0X00FF,0X0000,0X012C,0X002C,0X002C,0X002C,0X002C,0X0000, 0X0032,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000,0X0000, 0X0038,0X000B,0X0032,0X0000,0X0008,0X000C,0X0093,0X00E9, 0X0000,0X0000,0X0000,0X0000,0X0003,0X0010,0X0010,0X0100, 0X0100,0X0002,0X0001,0X0001,0X0039,0X0039,0X0039,0X0039, 0X0001,0X0001 }; //WM8978初始化 //返回值:0,初始化正常 // 其他,错误代码 uint8_t WM8978_Init(void) { uint8_t res; MX_I2C1_Init();//初始化IIC接口 res=WM8978_Write_Reg(0,0); //软复位WM8978 if(res)return 1; //发送指令失败,WM8978异常 //以下为通用设置 WM8978_Write_Reg(1,0X1B); //R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K) WM8978_Write_Reg(2,0X1B0); //R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能 WM8978_Write_Reg(3,0X6C); //R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能 WM8978_Write_Reg(6,0); //R6,MCLK由外部提供 WM8978_Write_Reg(43,1<<4); //R43,INVROUT2反向,驱动喇叭 WM8978_Write_Reg(47,1<<8); //R47设置,PGABOOSTL,左通道MIC获得20倍增益 WM8978_Write_Reg(48,1<<8); //R48设置,PGABOOSTR,右通道MIC获得20倍增益 WM8978_Write_Reg(49,1<<1); //R49,TSDEN,开启过热保护 WM8978_Write_Reg(10,1<<3); //R10,SOFTMUTE关闭,128x采样,最佳SNR WM8978_Write_Reg(14,1<<3); //R14,ADC 128x采样率 return 0; } //WM8978写寄存器 //reg:寄存器地址 //val:要写入寄存器的值 //返回值:0,成功; // 其他,错误代码 uint8_t WM8978_Write_Reg(uint8_t reg,uint16_t val) { uint8_t tmp[2]; tmp[0] = ((reg << 1) & 0xFE) | ((val >> 8) & 0x1); tmp[1] = val & 0xFF; while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) { } while(HAL_I2C_Master_Transmit(&hi2c1, WM8978_ADDR<<1, tmp, 2, 0XFFFFFFFF) != HAL_OK) { } WM8978_REGVAL_TBL[reg]=val; //保存寄存器值到本地 return 0; } //WM8978读寄存器 //就是读取本地寄存器值缓冲区内的对应值 //reg:寄存器地址 //返回值:寄存器值 uint16_t WM8978_Read_Reg(uint8_t reg) { return WM8978_REGVAL_TBL[reg]; } //WM8978 DAC/ADC配置 //adcen:adc使能(1)/关闭(0) //dacen:dac使能(1)/关闭(0) void WM8978_ADDA_Cfg(uint8_t dacen,uint8_t adcen) { uint16_t regval; regval=WM8978_Read_Reg(3); //读取R3 if(dacen)regval|=3<<0; //R3最低2个位设置为1,开启DACR&DACL else regval&=~(3<<0); //R3最低2个位清零,关闭DACR&DACL. WM8978_Write_Reg(3,regval); //设置R3 regval=WM8978_Read_Reg(2); //读取R2 if(adcen)regval|=3<<0; //R2最低2个位设置为1,开启ADCR&ADCL else regval&=~(3<<0); //R2最低2个位清零,关闭ADCR&ADCL. WM8978_Write_Reg(2,regval); //设置R2 } //WM8978 输入通道配置 //micen:MIC开启(1)/关闭(0) //lineinen:Line In开启(1)/关闭(0) //auxen:aux开启(1)/关闭(0) void WM8978_Input_Cfg(uint8_t micen,uint8_t lineinen,uint8_t auxen) { uint16_t regval; regval=WM8978_Read_Reg(2); //读取R2 if(micen)regval|=3<<2; //开启INPPGAENR,INPPGAENL(MIC的PGA放大) else regval&=~(3<<2); //关闭INPPGAENR,INPPGAENL. WM8978_Write_Reg(2,regval); //设置R2 regval=WM8978_Read_Reg(44); //读取R44 if(micen)regval|=3<<4|3<<0; //开启LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA. else regval&=~(3<<4|3<<0); //关闭LIN2INPPGA,LIP2INPGA,RIN2INPPGA,RIP2INPGA. WM8978_Write_Reg(44,regval);//设置R44 if(lineinen)WM8978_LINEIN_Gain(5);//LINE IN 0dB增益 else WM8978_LINEIN_Gain(0); //关闭LINE IN if(auxen)WM8978_AUX_Gain(7);//AUX 6dB增益 else WM8978_AUX_Gain(0); //关闭AUX输入 } //WM8978 输出配置 //dacen:DAC输出(放音)开启(1)/关闭(0) //bpsen:Bypass输出(录音,包括MIC,LINE IN,AUX等)开启(1)/关闭(0) void WM8978_Output_Cfg(uint8_t dacen,uint8_t bpsen) { uint16_t regval=0; if(dacen)regval|=1<<0; //DAC输出使能 if(bpsen) { regval|=1<<1; //BYPASS使能 regval|=5<<2; //0dB增益 } WM8978_Write_Reg(50,regval);//R50设置 WM8978_Write_Reg(51,regval);//R51设置 } //WM8978 MIC增益设置(不包括BOOST的20dB,MIC-->ADC输入部分的增益) //gain:0~63,对应-12dB~35.25dB,0.75dB/Step void WM8978_MIC_Gain(uint8_t gain) { gain&=0X3F; WM8978_Write_Reg(45,gain); //R45,左通道PGA设置 WM8978_Write_Reg(46,gain|1<<8); //R46,右通道PGA设置 } //WM8978 L2/R2(也就是Line In)增益设置(L2/R2-->ADC输入部分的增益) //gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step void WM8978_LINEIN_Gain(uint8_t gain) { uint16_t regval; gain&=0X07; regval=WM8978_Read_Reg(47); //读取R47 regval&=~(7<<4); //清除原来的设置 WM8978_Write_Reg(47,regval|gain<<4);//设置R47 regval=WM8978_Read_Reg(48); //读取R48 regval&=~(7<<4); //清除原来的设置 WM8978_Write_Reg(48,regval|gain<<4);//设置R48 } //WM8978 AUXR,AUXL(PWM音频部分)增益设置(AUXR/L-->ADC输入部分的增益) //gain:0~7,0表示通道禁止,1~7,对应-12dB~6dB,3dB/Step void WM8978_AUX_Gain(uint8_t gain) { uint16_t regval; gain&=0X07; regval=WM8978_Read_Reg(47); //读取R47 regval&=~(7<<0); //清除原来的设置 WM8978_Write_Reg(47,regval|gain<<0);//设置R47 regval=WM8978_Read_Reg(48); //读取R48 regval&=~(7<<0); //清除原来的设置 WM8978_Write_Reg(48,regval|gain<<0);//设置R48 } //设置I2S工作模式 //fmt:0,LSB(右对齐);1,MSB(左对齐);2,飞利浦标准I2S;3,PCM/DSP; //len:0,16位;1,20位;2,24位;3,32位; void WM8978_I2S_Cfg(uint8_t fmt,uint8_t len) { fmt&=0X03; len&=0X03;//限定范围 WM8978_Write_Reg(4,(fmt<<3)|(len<<5)); //R4,WM8978工作模式设置 } //设置耳机左右声道音量 //voll:左声道音量(0~63) //volr:右声道音量(0~63) void WM8978_HPvol_Set(uint8_t voll,uint8_t volr) { voll&=0X3F; volr&=0X3F;//限定范围 if(voll==0)voll|=1<<6;//音量为0时,直接mute if(volr==0)volr|=1<<6;//音量为0时,直接mute WM8978_Write_Reg(52,voll); //R52,耳机左声道音量设置 WM8978_Write_Reg(53,volr|(1<<8)); //R53,耳机右声道音量设置,同步更新(HPVU=1) } //设置喇叭音量 //voll:左声道音量(0~63) void WM8978_SPKvol_Set(uint8_t volx) { volx&=0X3F;//限定范围 if(volx==0)volx|=1<<6;//音量为0时,直接mute WM8978_Write_Reg(54,volx); //R54,喇叭左声道音量设置 WM8978_Write_Reg(55,volx|(1<<8)); //R55,喇叭右声道音量设置,同步更新(SPKVU=1) } //设置3D环绕声 //depth:0~15(3D强度,0最弱,15最强) void WM8978_3D_Set(uint8_t depth) { depth&=0XF;//限定范围 WM8978_Write_Reg(41,depth); //R41,3D环绕设置 } //设置EQ/3D作用方向 //dir:0,在ADC起作用 // 1,在DAC起作用(默认) void WM8978_EQ_3D_Dir(uint8_t dir) { uint16_t regval; regval=WM8978_Read_Reg(0X12); if(dir)regval|=1<<8; else regval&=~(1<<8); WM8978_Write_Reg(18,regval);//R18,EQ1的第9位控制EQ/3D方向 } //设置EQ1 //cfreq:截止频率,0~3,分别对应:80/105/135/175Hz //gain:增益,0~24,对应-12~+12dB void WM8978_EQ1_Set(uint8_t cfreq,uint8_t gain) { uint16_t regval; cfreq&=0X3;//限定范围 if(gain>24)gain=24; gain=24-gain; regval=WM8978_Read_Reg(18); regval&=0X100; regval|=cfreq<<5; //设置截止频率 regval|=gain; //设置增益 WM8978_Write_Reg(18,regval);//R18,EQ1设置 } //设置EQ2 //cfreq:中心频率,0~3,分别对应:230/300/385/500Hz //gain:增益,0~24,对应-12~+12dB void WM8978_EQ2_Set(uint8_t cfreq,uint8_t gain) { uint16_t regval=0; cfreq&=0X3;//限定范围 if(gain>24)gain=24; gain=24-gain; regval|=cfreq<<5; //设置截止频率 regval|=gain; //设置增益 WM8978_Write_Reg(19,regval);//R19,EQ2设置 } //设置EQ3 //cfreq:中心频率,0~3,分别对应:650/850/1100/1400Hz //gain:增益,0~24,对应-12~+12dB void WM8978_EQ3_Set(uint8_t cfreq,uint8_t gain) { uint16_t regval=0; cfreq&=0X3;//限定范围 if(gain>24)gain=24; gain=24-gain; regval|=cfreq<<5; //设置截止频率 regval|=gain; //设置增益 WM8978_Write_Reg(20,regval);//R20,EQ3设置 } //设置EQ4 //cfreq:中心频率,0~3,分别对应:1800/2400/3200/4100Hz //gain:增益,0~24,对应-12~+12dB void WM8978_EQ4_Set(uint8_t cfreq,uint8_t gain) { uint16_t regval=0; cfreq&=0X3;//限定范围 if(gain>24)gain=24; gain=24-gain; regval|=cfreq<<5; //设置截止频率 regval|=gain; //设置增益 WM8978_Write_Reg(21,regval);//R21,EQ4设置 } //设置EQ5 //cfreq:中心频率,0~3,分别对应:5300/6900/9000/11700Hz //gain:增益,0~24,对应-12~+12dB void WM8978_EQ5_Set(uint8_t cfreq,uint8_t gain) { uint16_t regval=0; cfreq&=0X3;//限定范围 if(gain>24)gain=24; gain=24-gain; regval|=cfreq<<5; //设置截止频率 regval|=gain; //设置增益 WM8978_Write_Reg(22,regval);//R22,EQ5设置 } #endif
- 修改“i2c.h”文件,替换为如下内容
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file i2c.h * @brief This file contains all the function prototypes for * the i2c.c file ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __I2C_H__ #define __I2C_H__ #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "main.h" /******************************************************************************************/ #if(music_phy == ES8388) #define ES8388_ADDR 0x10 /* ES8388的器件地址,固定为0x10 */ uint8_t es8388_init(void); /* ES8388初始化 */ uint8_t es8388_write_reg(uint8_t reg, uint8_t val); /* ES8388写寄存器 */ //uint8_t es8388_read_reg(uint8_t reg); /* ES8388读寄存器 */ void es8388_sai_cfg(uint8_t fmt, uint8_t len); /* 设置I2S工作模式 */ void es8388_hpvol_set(uint8_t volume); /* 设置耳机音量 */ void es8388_spkvol_set(uint8_t volume); /* 设置喇叭音量 */ void es8388_3d_set(uint8_t depth); /* 设置3D环绕声 */ void es8388_adda_cfg(uint8_t dacen, uint8_t adcen); /* ES8388 DAC/ADC配置 */ void es8388_output_cfg(uint8_t o1en, uint8_t o2en); /* ES8388 DAC输出通道配置 */ void es8388_mic_gain(uint8_t gain); /* ES8388 MIC增益设置(MIC PGA增益) */ void es8388_alc_ctrl(uint8_t sel, uint8_t maxgain, uint8_t mingain); /* ES8388 ALC设置 */ void es8388_input_cfg(uint8_t in); /* ES8388 ADC输出通道配置 */ #elif(music_phy == WM8978) #define WM8978_ADDR 0X1A //WM8978的器件地址,固定为0X1A #define EQ1_80Hz 0X00 #define EQ1_105Hz 0X01 #define EQ1_135Hz 0X02 #define EQ1_175Hz 0X03 #define EQ2_230Hz 0X00 #define EQ2_300Hz 0X01 #define EQ2_385Hz 0X02 #define EQ2_500Hz 0X03 #define EQ3_650Hz 0X00 #define EQ3_850Hz 0X01 #define EQ3_1100Hz 0X02 #define EQ3_14000Hz 0X03 #define EQ4_1800Hz 0X00 #define EQ4_2400Hz 0X01 #define EQ4_3200Hz 0X02 #define EQ4_4100Hz 0X03 #define EQ5_5300Hz 0X00 #define EQ5_6900Hz 0X01 #define EQ5_9000Hz 0X02 #define EQ5_11700Hz 0X03 uint8_t WM8978_Init(void); void WM8978_ADDA_Cfg(uint8_t dacen,uint8_t adcen); void WM8978_Input_Cfg(uint8_t micen,uint8_t lineinen,uint8_t auxen); void WM8978_Output_Cfg(uint8_t dacen,uint8_t bpsen); void WM8978_MIC_Gain(uint8_t gain); void WM8978_LINEIN_Gain(uint8_t gain); void WM8978_AUX_Gain(uint8_t gain); uint8_t WM8978_Write_Reg(uint8_t reg,uint16_t val); uint16_t WM8978_Read_Reg(uint8_t reg); void WM8978_HPvol_Set(uint8_t voll,uint8_t volr); void WM8978_SPKvol_Set(uint8_t volx); void WM8978_I2S_Cfg(uint8_t fmt,uint8_t len); void WM8978_3D_Set(uint8_t depth); void WM8978_EQ_3D_Dir(uint8_t dir); void WM8978_EQ1_Set(uint8_t cfreq,uint8_t gain); void WM8978_EQ2_Set(uint8_t cfreq,uint8_t gain); void WM8978_EQ3_Set(uint8_t cfreq,uint8_t gain); void WM8978_EQ4_Set(uint8_t cfreq,uint8_t gain); void WM8978_EQ5_Set(uint8_t cfreq,uint8_t gain); #endif #ifdef __cplusplus } #endif #endif /* __I2C_H__ */
- main函数while(1)前添加以下内容
#if(music_phy == ES8388)
es8388_init(); /* ES8388初始化 */
es8388_adda_cfg(1, 0); /* 开启DAC关闭ADC */
es8388_output_cfg(1, 1); /* DAC选择通道输出 */
es8388_hpvol_set(20); /* 设置耳机音量 */
es8388_spkvol_set(20); /* 设置喇叭音量 */
es8388_adda_cfg(1, 0); /* 开启DAC关闭ADC */
es8388_output_cfg(1, 1); /* DAC选择通道1输出 */
#elif(music_phy == WM8978)
WM8978_Init(); //初始化WM8978
WM8978_SPKvol_Set(20); //喇叭音量设置
WM8978_ADDA_Cfg(1,0); //开启DAC
WM8978_Input_Cfg(0,0,0);//关闭输入通道
WM8978_Output_Cfg(1,0); //开启DAC输出
- #endif
修改完成后编译0错误0警告。
4.11 添加音频解码部分代码
- 从程序源码中的“Third_Party”文件夹复制“audio”文件夹到当前工程;
- MDK新建分组audio,将audio文件夹全部内容添加到MDK的audio分组。
- main.c开头添加以下头文件:
#include "audioplay.h"
#include "wavplay.h"
#include "mp3play.h"
- main函数开头添加以下内容:uint8_t key = 0;char *hotel_file_addr = 0;
- main函数while(1)前添加以下内容
i = 0;
while(!hotel_file_addr)
{
hotel_file_addr = (char *)mymalloc(SRAMIN, FF_MAX_LFN * 2 + 1);//最长文件名
}
- main函数while(1)中添加以下内容
audio_index_show((uint8_t *)wav_list[i].file_name, i + 1, file_num);//显示歌曲名 memset(hotel_file_addr, 0, (FF_MAX_LFN * 2 + 1));//清空存放路径的数组 sprintf(hotel_file_addr,"%s%s",wav_list[i].file_addr,wav_list[i].file_name);//拼接歌曲路径 if( (strncmp(".WAV",wav_list[i].file_name+(strlen(wav_list[i].file_name)-4),4) == 0)||(strncmp(".wav",wav_list[i].file_name+(strlen(wav_list[i].file_name)-4),4) == 0) ) { key = wav_play_song((uint8_t *)hotel_file_addr); } else if( (strncmp(".MP3",wav_list[i].file_name+(strlen(wav_list[i].file_name)-4),4) == 0)||(strncmp(".mp3",wav_list[i].file_name+(strlen(wav_list[i].file_name)-4),4) == 0) ) { key = mp3_play_song((uint8_t *)hotel_file_addr); } else { key = KEY0_PRES; } if (key == KEY2_PRES) /* 上一曲 */ { if (i) i--; else i = file_num - 1; } else if (key == KEY0_PRES) /* 下一曲 */ { i++; if (i >= file_num) i = 0; /* 到末尾的时候,自动从头开始 */ }
- 将音乐文件拷贝到SD卡中初“SYSTEM”外的任意目录。
修改完成后编译0错误0警告,烧录后插入SD卡(SD卡里要有字库和音乐文件)后音乐开始播放,同时可以看到屏幕上显示出音乐的名称、当前播放的进度,三个按键分别可以切歌和暂停。不插SD卡串口一只打印“No SD card.....”
本次实验的源代码见以下链接:https://download.csdn.net/download/qq_44712722/90842243