当前位置: 首页 > news >正文

基于正点原子探索者开发板的简易音乐播放器

1、概述

本次实验的名称叫做“基于正点原子探索者开发板的简易音乐播放器”。本实验的功能框图如下:

从图上我们可以清晰的看到本实验所需的实现的功能、以及每个功能需要怎么实现。

这次实验使用的是正点原子的探索者开发板,此开发板采用的MCU是STM32F407ZGT6,其资源如下:

正点原子的探索者开发板硬件资源丰富,分布图如下:

本次实验使用的外设有:LCD、SRAM、TF卡接口、音频解码、按键、LED。对于不同版本的板子对本次实验有一定的影响:

  1. V2版本的开发板SD卡接口是SD卡接口(大卡),音频解码芯片采用的是WM8978。
  2. 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规范:

  1. 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总线的拓扑结构如下:

接口说明如下:

  1. CLK:时钟线,由 SDIO 主机产生,即由 STM32 控制器输出,通信时 CLK 时钟线的上升沿时数据才有效有效;
  2. CMD:命令控制线,SDIO 主机通过该线发送命令控制SD卡,如果命令要求SD卡提供应答 (响应),SD 卡也是通过该线传输应答信息;
  3. D0-3:数据线,传输读写数据;SD 卡可将 D0 拉低表示忙状态;
  4. VDD、VSS1、VSS2:电源和地信号。

SD 总线通信是基于命令和数据传输的。SD 通信一般是主机通过 CMD 线(数据线不参与)发送一个命令 (Command),从设备在接收到命令后作出响应 (Response),如有需要会有数据 (Data) 传输参与。注意:SD命令发送时的顺序是从最高位到最低位

SD 卡的命令固定为48位长,由6个字节组成,格式如下:

  1. 最高字节的最高2位固定为01(0是起始位,1是传输标志表示主机发送给从机),低6位为命令号 (代号:CMD0~CMD63);
  2. 字节 2~5为命令地址或者参数,有些命令是没有参数的。
  3. 最低字节的高七位为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接口特性

  1. 数据传输方向固定为MSB在前;
  2. I2S数据寄存器为16位,每次发送的数据是16的倍数,数据长度不够时自动补0;
  3. 支持主时钟(MCLK)输出,固定为256倍的fs;
  4. 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页面

  1. 首先进入Project选项
  • 设置工程名称以及保存地址,我这里就设为MUSIC_Player,保存在桌面的MUSIC_Player文件夹;
  • 设置生成代码的IDE,这里选择MDK-ARM;
  • 修改堆栈空间:将Min Stack 修改为0X800;
  • 修改F4驱动包的版本:去除使用最新版本的勾,手动修改为V1.26.0版本;
  1. 然后进入Code Generator选项,勾选“Generate peripheral initialization as a pair of ".c/h' fles per periphera”,其含义是生成的外设初始化代码是否要拆分成.c和.h文件。
  2. 点击最上面的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_RESETvoid 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 ConfigurationPF12   ------> FSMC_A6PE7   ------> FSMC_D4PE8   ------> FSMC_D5PE9   ------> FSMC_D6PE10   ------> FSMC_D7PE11   ------> FSMC_D8PE12   ------> FSMC_D9PE13   ------> FSMC_D10PE14   ------> FSMC_D11PE15   ------> FSMC_D12PD8   ------> FSMC_D13PD9   ------> FSMC_D14PD10   ------> FSMC_D15PD14   ------> FSMC_D0PD15   ------> FSMC_D1PD0   ------> FSMC_D2PD1   ------> FSMC_D3PD4   ------> FSMC_NOEPD5   ------> FSMC_NWEPG12   ------> 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至NE4LCD_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;//读取扇区的数量不能为0switch (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 == 0DRESULT 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;//读取扇区的数量不能为0switch (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_namememset(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 ConfigurationPC2     ------> I2S2_ext_SDPC3     ------> I2S2_SDPB12     ------> I2S2_WSPB13     ------> I2S2_CKPC6     ------> 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 ConfigurationPC2     ------> I2S2_ext_SDPC3     ------> I2S2_SDPB12     ------> I2S2_WSPB13     ------> I2S2_CKPC6     ------> 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;                  		//通道0hdma_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;          		//不使用FIFOHAL_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;			//使能DMASPI2->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];    	//设置PLLI2SNRCCI2S2_ClkInitSture.PLLI2S.PLLI2SR=(uint32_t)I2S_PSC_TBL[i][2];    	//设置PLLI2SRHAL_RCCEx_PeriphCLKConfig(&RCCI2S2_ClkInitSture);             	//设置时钟RCC->CR|=1<<26;					//开启I2S时钟while((RCC->CR&1<<27)==0);		//等待I2S时钟开启成功. tempreg=I2S_PSC_TBL[i][3]<<0;	//设置I2SDIVtempreg|=I2S_PSC_TBL[i][4]<<8;	//设置ODD位tempreg|=1<<9;					//使能MCKOE位,输出MCKSPI2->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, &reg, 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);	//软复位WM8978if(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);	//读取R3if(dacen)regval|=3<<0;		//R3最低2个位设置为1,开启DACR&DACLelse regval&=~(3<<0);		//R3最低2个位清零,关闭DACR&DACL.WM8978_Write_Reg(3,regval);	//设置R3regval=WM8978_Read_Reg(2);	//读取R2if(adcen)regval|=3<<0;		//R2最低2个位设置为1,开启ADCR&ADCLelse 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);	//读取R2if(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);	//读取R44if(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);//设置R44if(lineinen)WM8978_LINEIN_Gain(5);//LINE IN 0dB增益else WM8978_LINEIN_Gain(0);	//关闭LINE INif(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);	//读取R47regval&=~(7<<4);			//清除原来的设置 WM8978_Write_Reg(47,regval|gain<<4);//设置R47regval=WM8978_Read_Reg(48);	//读取R48regval&=~(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);	//读取R47regval&=~(7<<0);			//清除原来的设置 WM8978_Write_Reg(47,regval|gain<<0);//设置R47regval=WM8978_Read_Reg(48);	//读取R48regval&=~(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时,直接muteif(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		0X03uint8_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

相关文章:

基于正点原子探索者开发板的简易音乐播放器

1、概述 本次实验的名称叫做“基于正点原子探索者开发板的简易音乐播放器”。本实验的功能框图如下&#xff1a; 从图上我们可以清晰的看到本实验所需的实现的功能、以及每个功能需要怎么实现。 这次实验使用的是正点原子的探索者开发板&#xff0c;此开发板采用的MCU是STM32F4…...

【CF】Day59——Codeforces Round 914 (Div. 2) D

D. Set To Max 题目&#xff1a; Easy 思路&#xff1a; 简单题 由于题目的数据给的很小&#xff0c;所以我们可以用 n 的复杂度过&#xff0c;那我们来观察一下我们应该怎么操作 显然&#xff0c;如果 a[i] > b[i] 时是无法构造的&#xff0c;同时 a[i] b[i] 时就不用管…...

【Linux专栏】Linux进程间关系和守护进程

文章目录 1、进程间关系1.1 进程组1.2 组长进程 2、会话&#xff1f;2.1 查看会话2.2 创建会话 3、控制终端4、作业控制4.1 前台/后台进程 5、守护进程5.1 如何创建守护进程&#xff1f;5.2 杀掉守护进程 1、进程间关系 主要描述两个名称概念&#xff1a;即进程组和组长进程。…...

AutoVACUUM (PostgreSQL) 与 DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC (Oracle) 对比

AutoVACUUM (PostgreSQL) 与 DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC (Oracle) 对比 核心功能对比 特性PostgreSQL AutoVACUUMOracle GATHER_DATABASE_STATS_JOB_PROC主要目的空间回收 统计信息更新仅优化器统计信息收集底层机制MVCC(多版本并发控制)维护CBO(基于成本的…...

go依赖查询工具之godepgraph(分析main.go的依赖树)

文章目录 go依赖查询工具之godepgraph&#xff08;分析main.go的依赖树&#xff09;什么是服务间的隐式耦合&#xff1f;分析main.go的依赖树方法1. godepgraph (配合 Graphviz 可视化) - 最直观【推荐】方法2. go list go依赖查询工具之godepgraph&#xff08;分析main.go的依…...

市场差分探头信号输出形式的一些因素考量

在5G/6G通信、新能源汽车电控等高频测量场景中&#xff0c;差分探头的信号输出架构直接影响测试系统的信噪比与可靠性。根据IEEE仪器与测量协会2024年度报告&#xff0c;单端输出方案的市场渗透率较2020年提升42%&#xff0c;这一趋势背后蕴含着深刻的技术变革逻辑。 一、核心…...

SQL练习——day01

力扣——SQL练习总结 DENSE_RANK()窗口函数 这是排名函数的一种&#xff0c;它在处理相同值时&#xff0c;会给相同的值分配相同的排名&#xff0c;并且后续的排名不会跳过。比如有三个分数并列第一&#xff0c;那么它们的排名都是 1&#xff0c;接下来的分数排名就是 2&#…...

断点续传使用场景,完整前后端实现示例,包括上传,下载,验证

断点续传在多个场景中非常有用&#xff0c;包括但不限于大文件上传、跨国或跨区域文件传输、移动设备文件传输、备份和同步以及软件更新等。接下来&#xff0c;我将为你提供一个基于Java的后端实现示例&#xff0c;结合前端逻辑来完成整个断点续传的功能&#xff0c;包括上传、…...

Xinference推理框架

概述 GitHub&#xff0c;官方文档。 核心优势 性能优化&#xff1a;通过vLLM、SGLang等引擎实现低延迟推理&#xff0c;吞吐量提升2-3倍&#xff1b;企业级支持&#xff1a;支持分布式部署、国产硬件适配及模型全生命周期管理&#xff1b;生态兼容&#xff1a;无缝对接LangC…...

技术更新频繁,团队如何适应变化

构建持续学习机制、引入技术雷达与预研机制、通过敏捷方法快速响应变化、推动跨团队知识协作与传承 是应对技术更新频繁、团队保持适应力的核心策略。其中&#xff0c;构建持续学习机制尤为关键。通过制度化、场景化的学习安排&#xff0c;团队可以主动追踪新技术趋势&#xff…...

解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs-MCP大模型上下文解析

解密企业级大模型智能体Agentic AI 关键技术&#xff1a;MCP、A2A、Reasoning LLMs-MCP大模型上下文解析 我们首先来看一下 整个MCP的一个基本的一个流程&#xff0c;他解决的一个问题。我们回到这里&#xff0c;他解决的一个问题是什么呢&#xff1f;他解决这个问题就是你的大…...

游戏代码混淆的作用与应用分析

1. 防止逆向工程 核心保护对象&#xff1a;游戏引擎、算法&#xff08;如物理模拟、AI行为树&#xff09;、加密逻辑等。实例&#xff1a;Unity游戏使用 ConfuserEx 混淆C#代码&#xff0c;使反编译工具&#xff08;如dnSpy&#xff09;只能显示杂乱命名&#xff0c;难以理解逻…...

信息系统运行管理员:临阵磨枪版

信息系统运行管理员考试 - 全覆盖详细背诵大纲 (根据考情分析和原始材料&#xff0c;力求完整覆盖考点细节) 第一部分&#xff1a;基础知识与运维概览 Chapter 1: 信息系统运维概述 (上午题 5分) 信息&#xff1a; 含义&#xff1a;香农 - 减少随机不确定性的东西&#xff1b…...

PWM(脉宽调制)的配置参数[预分频器\自动重载值]的自动计算

文章目录 前言一、数据结构二、二分法搜索最佳预分频器和自动重载值三、示例 前言 pwm是嵌入式开发过程中很常见的一个模块&#xff0c;而配置pwm的过程中就少不了频率参数的计算&#xff0c;大多数32位机的pwm频率都由时钟、预分频器&#xff08;prescaler&#xff09;、自动…...

manuskript开源程序是面向作家的开源工具

一、软件介绍 文末提供程序和源码下载 manuskript开源程序是面向作家的开源工具&#xff0c;Manuskript 可在 GNU/Linux、Mac OS X 和 Windows 上运行。 二、Features 特征 Manuskript provides a rich environment to help writers create their first draft and then furt…...

antd 主题色定制

定制方案&#xff1a; 1. 全局定制 整个应用范围内的组件都生效 全局文件 theme.css :root:root {--adm-color-primary: #a062d4; } antd-mobile 中的主题变量也是在 :root 下声明的&#xff0c;所以在有些情况会由于优先级的问题无法覆盖。通过 :root:root 显式地让你所…...

召回11:地理位置召回、作者召回、缓存召回

GeoHash 召回 属于地理位置召回&#xff0c;用户可能对附近发生的事情感兴趣。GeoHash 是一种对经纬度的编码&#xff0c;地图上每个单位矩形的 GeoHash 的前几位是相同的&#xff0c;GeoHash 编码截取前几位后&#xff0c;将相同编码发布的内容按时间顺序&#xff08;先是时间…...

leetcode0767. 重构字符串-medium

1 题目&#xff1a;重构字符串 官方标定难度&#xff1a;中 给定一个字符串 s &#xff0c;检查是否能重新排布其中的字母&#xff0c;使得两相邻的字符不同。 返回 s 的任意可能的重新排列。若不可行&#xff0c;返回空字符串 “” 。 示例 1: 输入: s “aab” 输出: “…...

vue基本介绍

Vue是一款流行的JavaScript前端框架&#xff0c;以下是其基本介绍&#xff1a; 发展历程 - 2014年&#xff0c;尤雨溪发布了Vue的第一个版本。 - 此后&#xff0c;Vue不断发展和完善&#xff0c;陆续发布了多个版本&#xff0c;功能逐渐强大&#xff0c;社区也日益活跃。 …...

【vue】【环境配置】项目无法npm run serve,显示node版本过低

解决方案&#xff1a;安装高版本node&#xff0c;并且启用高版本node 步骤&#xff1a; 1、查看当前版本 node -v2、配置nvm下载镜像源 1&#xff09;查看配置文件位置 npm root2&#xff09;找到settings.txt文件 修改镜像源为&#xff1a; node_mirror: https://npmmirro…...

第35周Zookkeeper+Dubbo JDK不同版本介绍

一、JDK 新特性全解析 JDK9 - 模块化&#xff1a;化繁为简的魔法 模块化特性&#xff1a;JDK9 给 Java 程序带来模块化特性&#xff0c;就像把一个大公司划分成多个部门&#xff0c;每个部门&#xff08;模块&#xff09;各司其职。模块比包更大&#xff0c;一个模块包含多个…...

【ORB-SLAM3】CreateNewKeyFrame()函数阅读

void Tracking::CreateNewKeyFrame() void Tracking::CreateNewKeyFrame() {// 如果局部建图线程正在初始化且没做完或关闭了,就无法插入关键帧if(mpLocalMapper->IsInitializing() && !mpAtlas->isImuInitialized())return;if(!mpLocalMapper->SetNotStop(t…...

腾讯开源实时语音大模型VITA-audio,92mstoken极速响应,支持多语言~

简介 VITA-Audio 是一个由腾讯优图实验室&#xff08;Tencent Youtu Lab&#xff09;、南京大学和厦门大学的研究人员共同开发的项目&#xff0c;旨在解决现有语音模型在流式生成&#xff08;streaming&#xff09;场景下生成第一个音频令牌&#xff08;token&#xff09;时的高…...

使用 TypeScript + dhtmlx-gantt 在 Next.js 中实现

1. 安装依赖&#xff08;确保已安装&#xff09; npm install dhtmlx-gantt2. 创建 pages/gantt.tsx use clientimport { useRef, useEffect } from react import { gantt } from dhtmlx-gantt import dhtmlx-gantt/codebase/dhtmlxgantt.cssinterface Task {id: number | st…...

web第四次课后作业--页面操作实现数据库的增删查改

一、环境配置 1. 创建一个java web&#xff08;maven构建&#xff09;的项目2. 配置tomcat3. 连接数据库二、页面呈现 登录页面 详细信息 删除一条信息后 更新 更新后的信息 三、目录结构 四、代码实现 4.1 denglu.jsp <% page language"java" cont…...

DeepSearch:字节新一代 DeerFlow 框架

项目地址&#xff1a;https://github.com/bytedance/deer-flow/ 【全新的 Multi-Agent 架构设计】独家设计的 Research Team 机制&#xff0c;支持多轮对话、多轮决策和多轮任务执行。与 LangChain 原版 Supervisor 相比&#xff0c;显著减少 Tokens 消耗和 API 调用次数&#…...

uniapp中vue3和pinia安装依赖npm install失败

目录 一、问题描述 二、问题原因 三、问题解析及解决方案 一、问题描述 用uni-app开发小程序的时候&#xff0c;使用了vue3pinia,安装依赖的时候发现vue和pinia的版本问题&#xff0c;安装失败&#xff0c; npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve np…...

【java】synchronized关键字详解

目录 一、线程同步与线程安全问题线程不安全Demo线程不安全的原因 二、synchronized关键字关键字锁粒度修饰对象修饰代码块修饰方法修饰静态方法修饰类 synchronized 锁总结 synchronized加锁原理MarkWordsynchronized锁升级synchronized锁原理synchronized关键字总结 其他同步…...

使用 `perf` 和火焰图(Flame Graph)进行性能分析

在现代软件开发中&#xff0c;性能优化是提升应用程序响应速度和资源利用率的关键步骤。当一个进程的 CPU 占用率异常高时&#xff0c;识别并优化性能瓶颈显得尤为重要。本文将详细介绍如何使用 Linux 下强大的性能分析工具 perf 以及火焰图&#xff08;Flame Graph&#xff09…...

Cocos Creator 3.8.5 构建依赖环境配置文档

Cocos Creator 3.8.5 构建依赖环境配置文档 文章目录 Cocos Creator 3.8.5 构建依赖环境配置文档✅ 构建依赖汇总表✅ 构建平台配置说明&#x1f449; Windows 构建&#x1f449; Android 构建 ✅ 推荐构建环境组合&#xff08;稳定&#xff09;✅ 常见问题提示 适用于打包 An…...

# FlyEnv 环境下 MySQL 操作全攻略:从基础到字段修改

在使用 FlyEnv 搭建开发环境时&#xff0c;MySQL 数据库的操作是开发过程中不可或缺的一环。无论是修改字段结构&#xff0c;还是执行其他常见操作&#xff0c;都需要熟练掌握相关技能。下面将为你详细介绍 FlyEnv 环境下 MySQL 的操作&#xff0c;以及修改字段的多种方法。 一…...

C语言_自动义类型:联合和枚举

1. 联合体 1.1 联合体类型的声明 与结构体相似&#xff0c;联合体也是有一个或多个成员&#xff08;可以是不同类型&#xff09;构成&#xff1b;但是编译器只为最大的成员分配足够的内存空间 联合体的特点是所有成员共用同一块内存空间&#xff0c;所以联合体也叫&#xff…...

Golang基础知识—cond

cond 通常指 sync.Cond&#xff0c;它是标准库 sync 包中用于实现 条件变量 的同步原语。条件变量在多 goroutine 协作场景中非常有用&#xff0c;尤其在需要根据特定条件协调多个 goroutine 的执行顺序时。 sync.Cond 的核心作用 条件变量用于 等待某个条件满足 或 通知其他等…...

深入探索向量数据库:构建智能应用的新基础

&#x1f4cc; 友情提示&#xff1a; 本文内容由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;创作平台的gpt-4-turbo模型辅助生成&#xff0c;旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证&#xff0c;建议读者通过官方文档或实践进一步确认…...

实验5 DNS协议分析与测量

实验5 DNS协议分析与测量 1、实验目的 了解互联网的域名结构、域名系统DNS及其域名服务器的基本概念 熟悉DNS协议及其报文基本组成、DNS域名解析原理 掌握常用DNS测量工具dig使用方法和DNS测量的基本技术 2、实验环境 硬件要求&#xff1a;阿里云云主机ECS 一台。 软件要…...

1200/1500 PID 学习笔记

一 准备 1. 仿真库文件&#xff0c;下载链接放在最后 2.PID仿真&#xff0c;不支持1200.所以组CPU需要1500. 3.PID必须在循环中断里面调用。 二 试水 1. 拉一个PID指令 2. 库文件拉入 3 仿真试水&#xff0c;可以看到已经开始调节了。 、 三 组态设置 1. Input: 输入值&a…...

深度学习中--模型调试与可视化

第一部分&#xff1a;损失函数与准确率的监控&#xff08;Loss / Accuracy Curve&#xff09; 1. 为什么要监控 Loss 与 Accuracy&#xff1f; Loss 是模型优化的依据&#xff0c;但它可能下降了 Accuracy 反而没变&#xff08;过拟合信号&#xff09; Accuracy 才是评估效果的…...

tomcat项目重构踩坑易错点

是的&#xff0c;没错&#xff0c;弄了一个特别老的项目。重构真是头疼啊。其实好吧&#xff0c;还是用的太少。 前提条件&#xff1a;用idea工具非社区版。注意是非社区版。点击设置- project Structure 1.配置Modules 点击import module 添加好模块后。 重点来了&#xff0…...

如何安全擦除 SSD 上的可用空间

无论您是要处理旧 SSD 还是只是想确保敏感信息的私密性&#xff0c;擦除可用空间都是至关重要的一步。那么&#xff0c;您可以擦除 SSD 上的可用空间吗&#xff1f;是的&#xff0c;可以擦除 SSD 上的可用空间&#xff0c;我们在本指南中提供了两种有效的方法。是的&#xff0c…...

增强 HTNN 服务网格功能:基于 Istio 的BasicAuth 与 ACL 插件开发实战

目录 1.引言 什么是HTNN&#xff1f; 为什么开发 BasicAuth 和 ACL 插件&#xff1f; 2.技术背景 技术栈概览 Istio 与服务网格简述 HTNN 框架与插件机制概览 3.插件开发详解&#xff1a;BasicAuth 与 ACL 3.1 BasicAuth插件 功能点 实现细节 3.2 ACL插件 功能点 …...

从概念到可工程化智能体的转变路径——以“知识奇点工程师”为例

产品部门定义了一个如下概念性的“知识奇点工程师”&#xff0c;他们构建的不仅仅是一个数据库或知识图谱&#xff0c;而是一个活的、能自我进化的知识生态系统&#xff0c;是整个“Neuralink for Education”宏伟蓝图的基石。他们的工作难度和重要性&#xff0c;不亚于为AI引擎…...

docker(四)使用篇一:docker 镜像仓库

前文我们已经介绍了 docker 并安装了 docker&#xff0c;下面我们将正式步入使用环节&#xff0c;本章是第一个使用教学&#xff1a;docker 镜像仓库。 一、什么是镜像仓库 所谓镜像仓库&#xff0c;其实就是负责存储、管理和分发镜像的仓库&#xff0c;并且建立了仓库的索引…...

S7-1500 与 IM60 进行 PROFINET 通信

S7-1500 与 IM60 进行 PROFINET 通信 本文档介绍使用 S7-1500 CPU 与 IM 60 进行 PROFINET 通信&#xff0c;实现对 IM60 及 AM03 的控制。 使用软件及硬件 软件&#xff1a;工控人加入PLC工业自动化精英社群 TIA Portal V19 ET 200 SMART IM60 GSD 文件下载链接&#xff…...

车载诊断架构 ---车载总线对于功能寻址的处理策略

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...

观QFramework框架底层逻辑有感

拿QFramework&#xff08;以下简称QF&#xff09;第一个案例简单理解框架底层代码逻辑。 使用QF框架重构后的代码&#xff0c;给我这种小白一种很抽象的感觉&#xff0c;但好的代码就是抽象的&#xff0c;这是不可否认的。于是想掌握一下这个框架的基础部分&#xff0c;至少能…...

ExecutorService详解:Java 17线程池管理从零到一

简介 在现代高并发应用中,线程池管理已成为提升系统性能与稳定性的关键核心技术。ExecutorService作为Java并发编程的核心接口,提供了对线程池的强大抽象与管理能力,相比直接管理线程,它能显著降低资源消耗、提高响应速度并增强系统可维护性。随着Java 17的发布,线程池管…...

Go 中闭包的常见使用场景

在 Go 中&#xff0c;闭包&#xff08;Closure&#xff09; 是一个函数值&#xff0c;它引用了其定义时所在作用域中的变量。也就是说&#xff0c;闭包可以访问并修改外部作用域中的变量。 Go 中闭包的常见使用场景 ✅ 1. 封装状态&#xff08;无须结构体&#xff09; 闭包可…...

养生:打造健康生活的四大支柱

饮食养生&#xff1a;吃对食物&#xff0c;滋养生命根基 饮食是健康的物质基础&#xff0c;需遵循 “均衡、天然、顺应时节” 原则&#xff1a; 三餐科学搭配&#xff1a; 早餐以高蛋白 膳食纤维为主&#xff0c;如燕麦粥配水煮蛋、蓝莓&#xff0c;快速激活代谢&#xff1b;…...

OpenCV 图像直方图:从原理剖析到实战应用

在数字图像处理领域&#xff0c;图像直方图是一种强大而基础的工具&#xff0c;它以直观的方式展示了图像中像素值的分布情况。OpenCV 作为广泛应用的计算机视觉库&#xff0c;提供了丰富的函数来处理图像直方图。本文将深入讲解图像直方图的原理、OpenCV 中的实现方法&#xf…...

springboot+vue实现在线书店(图书商城)系统

今天教大家如何设计一个图书商城 , 基于目前主流的技术&#xff1a;前端vue&#xff0c;后端springboot。 同时还带来的项目的部署教程。 视频演示 在线书城 图片演示 一. 系统概述 商城是一款比较庞大的系统&#xff0c;需要有商品中心&#xff0c;库存中心&#xff0c;订单…...