本文主要是介绍GD32F303开发之EXMC与LCD显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 前言
- 一、实验内容
- 二、实验原理
- 1.LCD显示模块
- 2.NT35510的显存
- 3.NT35510常用指令
- 4.EXMC简介
- 5.LCD驱动流程
- 三、实验代码解析
- 1.EXMC文件对
- 2.LCD文件对
- 3.Main.c文件
- 4.实验结果
- 总结
前言
LCD是一种支持全彩显示的显示设备,GD32F3苹果派开发板上的LCD显示模块尺寸为4.3寸,相比于0.96寸的OLED显示模块,能够显示更加丰富的内容,比如可以显示彩色文本、图片,波形及GUI界面等。LCD显示模块上还集成了触摸屏,支持多点触控,基于LCD显示模块可以呈现出更为直观的实验结果,设计更加丰富的实验。本文将介绍LCD显示模块的显示原理和使用方法。
一、实验内容
本文主要介绍GD32F3苹果派开发板上的LCD显示模块,包括LCD显示控制芯片NT35510和驱动NT35510芯片的EXMC外设的工作原理。掌握驱动LCD显示模块显示的原理和方法后,基于GD32F3苹果派开发板设计一个EXMC与LCD显示实验,在LCD显示模块上绘制出DAC实验的正弦波。
二、实验原理
1.LCD显示模块
LCD是Liquid Crystal Display的缩写,即液晶显示器。LCD按工作原理不同可分为主动矩阵式和被动矩阵式,被动矩阵式常见的有TN-LCD、STN-LCD和DSTN-LCD,主动矩阵式通常为TFT-LCD。GD32F3苹果派开发板上使用的LCD即为TFT-LCD,在液晶显示屏的每个像素上都设置了一个薄膜晶体管(TFT),可有效克服非选通时的串扰,使液晶屏的静态特性与扫描线数无关,极大地提高了图像质量。
GD32F3苹果派开发板上使用的LCD显示模块是一款集NT35510驱动芯片、4.3寸480×800ppi分辨率显示屏、电容触摸屏及驱动电路为一体的集成显示屏,可以通过GD32F303ZET6微控制器上的外部存储器控制器EXMC控制LCD显示屏。
开发板上的LCD显示模块接口电路原理图如下图所示,LCD显示模块的EXMC_D[0:15]引脚分别与GD32F303ZET6微控制器的PD[14:15]、PD[0:1]、PE[7:15]和PD[8:10]引脚相连,LCD_CS引脚连接到PG9引脚,LCD_RD引脚连接到PD4引脚,LCD_WR引脚连接到PD5引脚,LCD_RS引脚连接到PF0引脚,LCD_BL引脚连接到PB0引脚,LCD_IO4引脚连接到NRST引脚。
GD32F3苹果派开发板配套的LCD显示模块采用16位的8080并行接口来传输数据,8080接口方式用到4条控制线(LCD_CS、LCD_WR、LCD_RD和LCD_RS)和16条双向数据线,LCD显示模块接口定义如下表所示。
LCD显示模块通过8080并行接口传输的数据有两种,分别为NT35510芯片的控制指令和LCD像素点显示的RGB颜色数据。这两种数据都涉及写入和读取,LCD读/写指令和RGB数据的时序图请查阅相关手册。
2.NT35510的显存
液晶控制器NT35510芯片自带显存,NT35510的显存大小为1152000字节(480×800×24/8字节),即24位模式下的显存量。在16位模式下,NT35510采用RGB565格式存储颜色数据,此时NT35510的24位数据线、GD32F30x系列微控制器的16位数据线和LCD GRAM的对应关系如下表所示。
NT35510在16位模式下,使用到的数据线为D17~D13和D11~D1,D0和D12未使用,NT35510的D17~D13和D11~D1分别对应GD32F303ZET6微控制器上的16个GPIO。RGB的16位颜色数据,最低5位代表蓝色,中间6位为绿色,最高5位为红色。数值越大,表示该颜色越深。注意,NT35510的所有指令均为16位,且读/写GRAM时也是16位。
3.NT35510常用指令
微控制器通过向NT35510芯片发送指令来设置LCD的显示参数,NT35510提供了一系列指令供用户开发,关于这些指令具体的定义和描述请参考NT35510的数据手册《NT35510 data sheet》(位于本书配套资料包“09.参考资料\01.EXMC与LCD显示实验参考资料”文件夹下)的第255~257页。设置NT35510的过程如下:先向NT35510发送某项设置对应的指令,目的是告知NT35510接下来将进行该项设置,然后再发送此项设置的参数完成设置。如设置LCD的扫描方向为从左到右、从下到上,应先向NT35510发送对应设置读/写方向的指令(0x3600),然后发送从左到右、从下到上读写方向对应的参数(0x0080),即可完成设置。
NT35510的常用指令包括:0xDA00~0xDC00、0x3600、0x2A00~0x2A03、0x2B00~0x2B03、0x2C00和0x2E00。通过以上指令,即可用NT35510控制LCD进行简单的显示。
4.EXMC简介
LCD显示可以通过GPIO模拟8080接口时序来控制,但由于使用GPIO模拟时序较慢,且对CPU的占用率较高,因此本实验使用GD32F303ZET6微控制器的EXMC接口来驱动LCD显示模块。下面介绍EXMC的基本原理。
(1)EXMC功能框图
EXMC是外部存储器控制器,主要用于访问各种外部存储器,通过配置寄存器,EXMC可以把AMBA协议转换为专用的片外存储器通信协议。GD32F30x系列微控制器的EXMC可访问的存储器包括SRAM、ROM、NOR Flash、NAND Flash和PC卡等。用户还可以调整配置寄存器中的时间参数来提高通信效率。EXMC的访问空间被划分为多个块(Bank),每个块支持特定的存储器类型,用户可以通过配置Bank的控制寄存器来控制外部存储器。
GD32F30x系列微控制器的EXMC由5部分组成:AHB总线接口、EXMC配置寄存器、NOR Flash/PSRAM控制器、NAND Flash/PC Card控制器和外部设备接口,如下图所示。
(2)AHB总线接口
EXMC是AHB总线至外部设备协议的转换接口。如下图所示,EXMC由AHB总线控制,AHB总线同时也由微控制器控制,如果需要对芯片内某个地址进行读/写操作,则通过上图中的通用共享引脚EXMC_A[25:0]即可完成对外部存储器的寻址。
AHB总线的宽度为32位,32位的AHB读/写操作可以转化为几个连续的8位或16位读写操作。但在数据传输的过程中,AHB数据宽度和存储器数据宽度可能不相同。为了保证数据传输的一致性,EXMC读/写访问需要遵循以下规范:①AHB访问宽度等于存储器宽度,则正常传输;②AHB访问宽度大于存储器宽度,则自动将AHB访问分割成几个连续的存储器数据宽度来传输,即32位的AHB读/写操作可以转化为几个连续的8位或16位读/写操作;③AHB访问宽度小于存储器宽度,如果外部存储设备有字节选择功能(如SRAM、ROM和PSRAM),则可通过它的字节通道EXMC_NBL[1:0]来访问对应的高低字节。否则禁止写操作,只允许读操作。
(3)NOR Flash/PSRAM控制器
EXMC将外部存储器分成4个Bank:Bank0~Bank3,每个Bank占256MB,其中Bank0又分为4个Region,每个Region占64MB,如下图所示。每个Bank或Region都有独立的片选控制信号,也都能进行独立的配置。
Bank0用于访问NOR Flash和PSRAM设备;Bank1和Bank2用于连接NAND Flash,且每个Bank连接一个NAND Flash;Bank3用于连接PC Card。
本实验通过EXMC来驱动LCD显示模块,具体使用的存储区域范围为Bank0的region1区(即0x6400 0000~0x67FF FFFF),如下图所示。
每个区都有独立的寄存器,用于对所连接的存储器进行配置。Bank0的256MB空间由28条地址线(HADDR[27:0])寻址。
这里的HADDR为内部AHB地址总线,其中,HADDR[25:0]来自外部存储器地址EXMC_A[25:0],而HADDR[27:26]对4个Region区进行寻址。如下表所示:
(4)外部设备接口
EXMC驱动外部SRAM时,外部SRAM的控制信号线一般有:地址线(如EXMC_A[0:25])、数据线(如EXMC_D[0:15])、写信号(EXMC_WE)、读信号(EXMC_OE)和片选信号(EXMC_NEx),如果SRAM支持字节控制,那么还有UB/LB信号。
LCD涉及的信号包括LCD_RS、EXMC_D[0:15]、LCD_WR、LCD_RD、LCD_CS、NRST和LCD_BL等,其中,真正在操作LCD时需要用到的仅有LCD_RS、EXMC_D[0:15]、LCD_WR、LCD_RD和LCD_CS。操作LCD时序与SRAM的控制类似,惟一不同的是LCD有LCD_RS信号,没有地址信号。
LCD通过LCD_RS信号来决定传输的是数据还是指令,本质上可以将LCD_RS理解为一个地址信号,例如把LCD_RS视为A[0],LCD_RS为0或1时分别对应两块地址,假设为地址0x64000000和地址0x64000001,当EXMC控制器写地址0x64000000时,LCD_RS输出为0,对于LCD而言,就是写指令;当EXMC控制器写地址0x64000001时,LCD_RS输出为1,对于LCD而言,则是写数据。这样,即可将数据区和指令区分开。上述操作本质上即是对应读写SRAM时的两个连续地址。因此,在编写驱动程序时,可以将LCD当作SRAM来看待,只是该“SRAM”有2个地址,这就是EXMC可以用于驱动LCD的原理。
(5)EXMC寄存器
对于NOR Flash/PSRAM控制器(Bank0),可以通过EXMC_SNCTLx、EXMC_SNTCFGx和EXMC_SNWTCFGx这3个寄存器进行配置(其中x=0~3,对应4个Region),包括设置EXMC访问外部存储器的时序参数等,拓宽了可选用的外部存储器的速度范围。
关于上述寄存器的定义以及各个位的介绍可以参见GD32F30x系列微控制器中文版用户手册《GD32F30x用户手册(中文版)》(配套资料包“07.数据手册”文件夹下)的第602~606页。
(6)EXMC部分固件库函数
本实验涉及的EXMC固件库函数包括exmc_norsram_deinit、exmc_norsram_struct_para_init、exmc_norsram_init、exmc_norsram_enable和exmc_norsram_disable。这些函数在gd32f30x_exmc.h文件中声明,在gd32f30x_exmc.c文件中实现。关于EXMC部分的固件库函数请参见GD32F30x系列微控制器的固件库使用指南《GD32F30x固件库使用指南》(配套资料包“07.数据手册”文件夹下)的第290~315页。
5.LCD驱动流程
LCD显示模块的驱动流程如下图所示。其中,硬件复位即初始化LCD模块,初始化序列的代码由LCD厂家提供,不同厂家不同型号都不相同,硬件复位和初始化序列只需要执行一次即可。下面以画点和读点的流程为例进行介绍,画点流程如下:设置坐标→写GRAM指令→写入颜色数据,完成上述操作后,即可在LCD上的指定坐标显示对应的颜色。读点流程如下:设置坐标→读GRAM指令→读取颜色数据,这样即可获取到对应点的颜色数据,最后由微控制器进行处理。
三、实验代码解析
1.EXMC文件对
(1)EXMC.h文件
在EXMC.h文件的“API函数声明”区,声明了1个API函数,如下程序清单所示。InitEXMC函数用于初始化外部存储控制模块。
void InitEXMC(void); //初始化外部存储控制模块
(2)EXMC.c文件
在EXMC.c文件的“内部函数声明”区,声明了内部函数ConfigEXMCGPIO和ConfigBank0Region1,如下程序清单所示。ConfigEXMCGPIO函数用于配置EXMC的相关GPIO,ConfigBank0Region1函数用于配置外部存储Bank0的Region1。
static void ConfigEXMCGPIO(void); //配置EXMC的相关GPIO
static void ConfigBank0Region1(void); //配置外部存储Bank0的Region1
在“内部函数实现”区,实现了ConfigEXMCGPIO函数,如下程序清单所示。在ConfigEXMCGPIO函数中,使能了相关GPIO的时钟并且配置地址总线、数据总线和控制信号线的GPIO,所有GPIO采用复用推挽输出模式和最大的高于50MHz的输出速度。其中PD4对应EXMC_NOE,即读信号,PD5对应EXMC_NEW,即写信号。
1.static void ConfigEXMCGPIO(void)
2.{
3. //使能RCU相关时钟
4. rcu_periph_clock_enable(RCU_GPIOD); //使能GPIOD的时钟
5. …
6. //地址总线
7. gpio_init(GPIOF, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0 ); //A0
8. …
9. //数据总线
10. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_14); //A0
11. …
12. //控制信号线
13. gpio_init(GPIOG, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_9 ); //EXMC_NE1
14. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4 ); //EXMC_NOE
15. gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_5 ); //EXMC_NWE
16.}
在ConfigEXMCGPIO函数实现区后为ConfigBank0Region1函数的实现代码,如下程序清单所示。
1.static void ConfigBank0Region1(void)
2.{
3. exmc_norsram_parameter_struct sram_init_struct;
4. exmc_norsram_timing_parameter_struct lcd_readwrite_timing_init_struct;
5. exmc_norsram_timing_parameter_struct lcd_write_timing_init_struct;
6.
7. //使能EXMC的时钟
8. rcu_periph_clock_enable(RCU_EXMC);
9.
10. //读时序配置
11. lcd_readwrite_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A; //模式A,异步访问SRAM
12. lcd_readwrite_timing_init_struct.asyn_address_setuptime = 0; //异步访问地址建立时间
13. lcd_readwrite_timing_init_struct.asyn_address_holdtime = 0; //异步访问地址保持时间
14. lcd_readwrite_timing_init_struct.asyn_data_setuptime = 15; //异步访问数据建立时间
15. lcd_readwrite_timing_init_struct.bus_latency = 0; //同步/异步访问总线延时时间
16. lcd_readwrite_timing_init_struct.syn_clk_division = 0; //同步访问时钟分频系数(从HCLK中分频)
17. lcd_readwrite_timing_init_struct.syn_data_latency = 0; //同步访问中获得第1个数据所需要的等待延迟
18.
19. //写时序配置
20. lcd_write_timing_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A; //模式A,异步访问SRAM
21. lcd_write_timing_init_struct.asyn_address_setuptime = 0; //异步访问地址建立时间
22. lcd_write_timing_init_struct.asyn_address_holdtime = 0; //异步访问地址保持时间
23. lcd_write_timing_init_struct.asyn_data_setuptime = 2; //异步访问数据建立时间
24. lcd_write_timing_init_struct.bus_latency = 0; //同步/异步访问总线延时时间
25. lcd_write_timing_init_struct.syn_clk_division = 0; //同步访问时钟分频系数(从HCLK中分频)
26. lcd_write_timing_init_struct.syn_data_latency = 0; //同步访问中获得第1个数据所需要的等待延迟
27.
28. //Region1配置
29. sram_init_struct.norsram_region = EXMC_BANK0_NORSRAM_REGION1; //Region1
30. sram_init_struct.address_data_mux = DISABLE; //禁用地址、数据总线多路复用
31. sram_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM; //储存器类型为SRAM
32. sram_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B; //数据宽度16位
33. sram_init_struct.burst_mode = DISABLE; //禁用突发访问
34. sram_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE; //等待输入配置
35. sram_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW; //等待输入信号低电平有效
36. sram_init_struct.wrap_burst_mode = DISABLE; //禁用包突发访问
37. sram_init_struct.asyn_wait = DISABLE; //禁用异步等待
38. sram_init_struct.extended_mode = ENABLE; //使能扩展模式
39. sram_init_struct.memory_write = ENABLE; //使能写入外部存储器
40. sram_init_struct.nwait_signal = DISABLE; //禁用等待输入信号
41. sram_init_struct.write_mode = EXMC_ASYN_WRITE; //写入模式为异步写入
42. sram_init_struct.read_write_timing = &lcd_readwrite_timing_init_struct; //读时序配置
43. sram_init_struct.write_timing = &lcd_write_timing_init_struct; //写时序配置
44.
45. //初始化Region1
46. exmc_norsram_init(&sram_init_struct);
47.
48. //使能Region1
49. exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION1);
50.}
在“API函数实现”区,实现了InitEXMC函数,如下程序清单所示。InitEXMC函数通过调用ConfigEXMCGPIO函数和ConfigBank0Region1函数对EXMC进行初始化。
void InitEXMC(void)
{ConfigEXMCGPIO(); //配置EXMC的GPIOConfigBank0Region1(); //配置外部存储Bank0的Region1(LCD)
}
2.LCD文件对
(1)LCD.h文件
在LCD.h文件的“宏定义”区,进行了如下程序清单所示的变量定义。第13行代码中的宏定义LCD_BASE必须根据外部电路的连接来确定,本实验使用Bank0的region1即是从地址0x6400 0000开始的。将这个地址强制转换为StructLCDBase结构体地址,可以得到LCD->cmd的地址为0x6400 0000,对应A[0]的状态为0(即LCD_RS=0),而LCD->data的地址为0x6400 0001(结构体地址自增),对应A[0]的状态为1(即LCD_RS=1)。
1.//-----------------LCD端口定义----------------
2.#define LCD_LED_HIGH gpio_bit_set(GPIOB, GPIO_PIN_0) //LCD背光 PB0
3.#define LCD_LED_LOW gpio_bit_reset(GPIOB, GPIO_PIN_0)
4.
5.//LCD地址结构体
6.typedef struct
7.{
8. volatile u16 cmd; //读写指令
9. volatile u16 data; //读写数据
10.}StructLCDBase;
11.//使用NOR/PSRAM的 Bank0 Region1,地址位HADDR[27,26]=01 A0作为数据指令区分线
12.//注意设置时GD32内部会右移一位对齐
13.#define LCD_BASE ((u32)(0x60000000 | 0x04000000))
14.#define LCD ((StructLCDBase *)LCD_BASE)
15.
16.//扫描方向定义
17.#define L2R_U2D 0 //从左到右,从上到下
18.……
19.
20.#define DFT_SCAN_DIR L2R_U2D //默认的扫描方向
21.
22.//画笔颜色
23.#define WHITE 0xFFFF //白色
24.……
25.
26.//LCD分辨率设置
27.#define SSD_HOR_RESOLUTION 800 //LCD水平分辨率
28.#define SSD_VER_RESOLUTION 480 //LCD垂直分辨率
29.
30.//LCD驱动参数设置
31.#define SSD_HOR_PULSE_WIDTH 1 //水平脉宽
32.……
在“枚举结构体”区中,声明了如下程序清单所示的结构体。该结构体用于保存一些LCD重要参数信息,如LCD的长宽、LCD ID(驱动IC型号)和LCD横竖屏状态等,其中的width、height、dir、wramcmd、setxcmd和setycmd等指令或参数都在LCDDisplayDir中进行初始化。
1.//LCD重要参数信息
2.typedef struct
3.{
4. u16 width; //LCD宽度
5. u16 height; //LCD高度
6. u16 id; //LCD ID
7. u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
8. u16 wramcmd; //开始写GRAM指令
9. u16 setxcmd; //设置x坐标指令
10. u16 setycmd; //设置y坐标指令
11.}StructLCDDev;
12.
13.//LCD参数
14.extern StructLCDDev s_structLCDDev; //管理LCD重要参数
在“API函数声明”区,声明了如下程序清单所示的API函数。InitLCD函数用于初始化LCD显示模块,LCDWriteCMD函数用于向LCD写指令,LCDWriteData函数用于向LCD写数据,LCDReadData函数用于从LCD读数据,LCDSendWriteGramCMD函数用于发送开始写GRAM指令,LCDWriteRAM函数用于向LCD写GRAM,LCDSetCursor函数用于设置光标,LCDShowChar和LCDShowNum函数分别用于在指定位置显示一个字符或数字。
1.void InitLCD(void); //初始化
2.void LCDWriteCMD(u16 cmd); //向LCD写指令
3.void LCDWriteData(u16 data); //向LCD写数据
4.u16 LCDReadData(void); //从LCD读数据
5.……
6.void LCDSendWriteGramCMD(void); //发送开始写GRAM指令
7.void LCDWriteRAM(u16 rgb); //写GRAM
8.……
9.void LCDSetCursor(u16 x, u16 y); //设置光标
10.……
11.void LCDShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode); //显示一个字符
12.……
13.void LCDShowNum(u16 x,u16 y,u32 num,u8 len,u8 size); //显示一个数字
……
(2)LCD.c文件
在LCD.c文件的“内部函数实现”区,首先实现了LCDWriteCMD函数,如下程序清单所示。LCDWriteCMD函数的功能是向LCD写指令,LCD->cmd的地址为0x6400 0000,对应A[0]的状态为0(即LCD_RS=0),即给LCD读/写指令。函数输入参数cmd为对NT35510输入的指令。
void LCDWriteCMD(u16 cmd)
{LCD->cmd = cmd;//
}
在LCDWriteCMD函数实现区后为LCDWriteData函数的实现代码,如下程序清单所示。LCDWriteData函数的功能是向LCD写数据,LCD->data的地址为0x6400 0001,对应A[0]的状态为1(即LCD_RS=1),即给LCD读/写数据。函数输入参数data为写进NT35510的数据。
void LCDWriteData(u16 data)
{LCD->data = data;
}
在LCDWriteData函数实现区后为LCDReadData函数的实现代码,如下程序清单所示。LCDReadData函数的功能是从LCD读数据,LCD->data的地址为0x6400 0001,对应A[0]的状态为1(即LCD_RS=1),即给LCD读/写数据。ram为读取的数据,使用volatile关键字定义ram是为了防止编译器优化。
u16 LCDReadData(void)
{volatile u16 ram;ram = LCD->data;return ram;
}
在LCDReadData函数实现区后为LCDWriteReg和LCDReadReg函数的实现代码,这两个函数分别用于写和读寄存器,寄存器地址由函数的输入参数指定。
在LCDReadReg函数实现区后为LCDSendWriteGramCMD和LCDWriteRAM函数的实现代码,如下程序清单所示。LCDWriteRAM函数的功能是向LCD写GRAM,GRAM的值即为RGB565值。若直接向LCD写入GRAM值,LCD无法识别写入的为RGB565值,所以在向LCD写GRAM值之前,必须先向LCD发送写GRAM的指令,即通过调用LCDSendWriteGramCMD函数来实现。
void LCDSendWriteGramCMD(void)
{LCD->cmd = s_structLCDDev.wramcmd;
}void LCDWriteRAM(u16 rgb)
{LCD->data = rgb; //写16位GRAM
}
在LCDWriteRAM函数实现区后为LCDBGRToRGB、LCDReadPoint、LCDDisplayOn、LCDDisplayOff、LCDSetCursor和LCDScanDir函数的实现代码,这些函数的功能分别为将BGR格式数据转化为RGB格式、读取某个点的颜色值、LCD开启显示、LCD关闭显示、设置光标位置和设置自动扫描方向。
在LCDScanDir函数实现区后为LCDDrawPoint函数的实现代码,如下程序清单所示。LCDDrawPoint函数的功能是向LCD上特定的位置写入GRAM值,以实现在该位置的像素点上显示指定的颜色。
void LCDDrawPoint(u16 x,u16 y)
{LCDSetCursor(x, y); //设置光标位置LCDSendWriteGramCMD(); //发送写GRAM指令LCD->data = s_iLCDPointColor; //写GRAM
}
在LCDDrawPoint函数实现区后为LCDFastDrawPoint、LCDSSDBackLightSet、LCDDisplayDir和LCDSetWindow函数的实现代码,这些函数的功能分别是快速画点、进行SSD1963背光设置、设置LCD显示方向和设置窗口。
在LCDSetWindow函数实现区后为InitLCD函数的实现代码,如下程序清单所示。InitLCD函数的功能是初始化LCD。
1.void InitLCD(void)
2.{
3. //GPIOB时钟使能
4. rcu_periph_clock_enable(RCU_GPIOB);
5.
6. //配置背光控制GPIO
7. gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);
8.
9. //延时50ms
10. DelayNms(50);
11.
12. //校验ID
13. LCDWriteCMD(0xDA00);
14. s_structLCDDev.id = LCDReadData(); //读回0x00
15. LCDWriteCMD(0xDB00);
16. s_structLCDDev.id = LCDReadData(); //读回0x80
17. s_structLCDDev.id <<= 8;
18. LCDWriteCMD(0xDC00);
19. s_structLCDDev.id |= LCDReadData(); //读回0x00
20.
21. if(s_structLCDDev.id==0x8000)
22. {
23. //NT35510读回的ID是8000H,为方便区分,强制设置为5510
24. s_structLCDDev.id=0x5510;
25. }
26.
27. printf("LCD ID:%x\r\n", s_structLCDDev.id); //打印LCD ID
28.
29.if(s_structLCDDev.id == 0x5510)
30. {
31. LCDWriteReg(0xF000, 0x55);
32. LCDWriteReg(0xF001, 0x55);
33. …//此处省略LCD设置寄存器代码
34.
35. DelayNus(120);
36. LCDWriteCMD(0x2900);
37. }
38. LCDDisplayDir(0); //默认为竖屏
39. LCD_LED_HIGH; //点亮背光
40. LCDClear(WHITE); //清屏
41.}
在InitLCD函数实现区后为LCDClear、LCDFill、LCDColorFill、LCDDrawLine、LCDDrawRectangle和LCDDrawCircle函数的实现代码,这些函数的功能分别是清屏、在指定区域内填充单个颜色、在指定区域内填充颜色块、画线、画矩形和画圆。
在LCDDrawCircle函数实现区后为LCDShowChar函数的实现代码,如下程序清单所示。
1.void LCDShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode)
2.{
3. u8 temp, t1, t;
4. u16 y0 = y;
5. u8 csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); //得到字体一个字符对应点阵集所占的字节数
6. num = num - ' '; //得到偏移后的值(ASCII字库是从空格开始取模的,所以-' '就是对应字符的字库)
7.
8. for(t = 0; t < csize; t++)
9. {
10. //调用1206字体
11. if(size == 12)
12. {
13. temp = asc2_1206[num][t];
14. }
15.
16. //调用1608字体
17. else if(size == 16)
18. {
19. temp = asc2_1608[num][t];
20. }
21.
22. //调用2412字体
23. else if(size == 24)
24. {
25. temp = asc2_2412[num][t];
26. }
27.
28. //没有的字库
29. else
30. {
31. return;
32. }
33.
34. for(t1 = 0; t1 < 8; t1++)
35. {
36. if(temp & 0x80)
37. {
38. LCDFastDrawPoint(x, y, s_iLCDPointColor);
39. }
40. else if(mode == 0)
41. {
42. LCDFastDrawPoint(x, y, s_iLCDBackColor);
43. }
44.
45. temp <<= 1;
46. y++;
47.
48. //超区域了
49. if(y >= s_structLCDDev.height)
50. {
51. return;
52. }
53. if((y - y0) == size)
54. {
55. y = y0;
56. x++;
57.
58. //超区域了
59. if(x >= s_structLCDDev.width)
60. {
61. return;
62. }
63. break;
64. }
65. }
66. }
67.}
在LCDShowChar函数的实现区后为LCDPow和LCDShowNum函数的实现代码,这两个函数的功能分别是进行幂运算和显示数字。
在LCDShowNum函数实现区后为LCDShowString函数的实现代码,如下程序清单所示。LCDShowString函数的功能是在指定位置显示字符串。该函数调用了LCDShowChar实现字符串的显示。
1.void LCDShowString(u16 x, u16 y, u16 width, u16 height, u8 size, u8 *p)
2.{
3. u8 x0 = x;
4. width += x;
5. height += y;
6. while((*p <= '~') && (*p >= ' '))//判断是不是非法字符
7. {
8. if(x >= width)
9. {
10. x = x0;
11. y += size;
12. }
13. if(y >= height)
14. {
15. break;//退出
16. }
17. LCDShowChar(x, y, *p, size, 0);
18. x += size / 2;
19. p++;
20. }
}
3.Main.c文件
main函数的实现代码如下程序清单所示,先调用LCDDisplayDir函数将LCD设置为横屏显示,然后调用DisPlayBackgroudJPEG函数将LCD背景设置为预先解码好的图片,最后调用InitGraphWidgetStruct和CreateGraphWidget函数创建波形控件。
1.int main(void)
2.{
3. InitHardware(); //初始化硬件相关函数
4. InitSoftware(); //初始化软件相关函数
5.
6. //LCD测试
7. LCDDisplayDir(1);
8. LCDClear(GBLUE);
9. s_iLCDPointColor = GREEN;
10. LCDShowString(30,40,210,24,24,"Hello! GD32 ^_^");
11.
12. //显示背景图片
13. DisPlayBackgroudJPEG();
14.
15. //创建波形控件
16. InitGraphWidgetStruct(&s_structGraph);
17. CreateGraphWidget(10, 150, 780, 200, &s_structGraph);
18. s_structGraph.startDraw = 1;
19.
20. while(1)
21. {
22. Proc1msTask(); //1ms处理任务
23. Proc2msTask(); //2ms处理任务
24. Proc1SecTask(); //1s处理任务
25. }
26.}
Proc1msTask函数的实现代码如下程序清单所示,第11、12行代码用于从PA1引脚获取从PA4引脚发送的正弦波信号并进行数据处理,再由波形控件将正弦波信号显示到LCD指定区域。
1.static void Proc1msTask(void)
2.{
3. static u8 s_iCnt = 0;
4. int wave;
5. if(Get1msFlag())
6. {
7. s_iCnt++;
8. if(s_iCnt >= 5)
9. {
10. s_iCnt = 0;
11. wave = GetADC() * (s_structGraph.y1 - s_structGraph.y0) / 4095;
12. GraphWidgetAddData(&s_structGraph, wave);
13. }
14. Clr1msFlag();
15. }
16.}
4.实验结果
用杜邦线将GD32F3苹果派开发板上的PA4引脚与PA1引脚连接,然后通过Keil μVision5软件将.axf文件下载到开发板,下载完成后,可以观察到LCD屏上显示如下图所示的正弦波曲线,表示实验成功。
总结
以上就是今天要讲的内容,本文介绍了LCD显示控制芯片NT35510和驱动NT35510芯片的EXMC外设的工作原理,基于GD32F3苹果派开发板设计一个EXMC与LCD显示实验,在LCD显示模块上绘制出DAC实验的正弦波。
这篇关于GD32F303开发之EXMC与LCD显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!