stm32——lcd液晶显示

一.液晶屏介绍

        液晶显示屏是由液晶显示面板,电容触摸屏,pcb底板构成。在液晶显示屏里我们有带控制芯片的还有不带控制芯片的。对于低端的微控制器它不能直接控制液晶面板,所以需要给液晶控制面板而外增加一个液晶控制芯片。对于单片机stm32f429系列的芯片就不需要额外的液晶控制器,该芯片将液晶控制的功能集成到该芯片的内部了,对于f1系列就需要液晶屏带液晶控制芯片。

二.液晶面板的信号控制 

        液晶面板的控制信号线(不带液晶控制器):

· RGB信号线 :RGB信号线各有8根,分别用于表示液晶屏一个像素点的红、绿、蓝颜色分量。

· 同步时钟信号CLK:液晶屏与外部使用同步通讯方式,以CLK信号作为同步时钟,在同步时钟的驱动下,每个时钟传输一个像素点数据。

· 水平同步信号HSYNC:水平同步信号HSYNC(Horizontal Sync)用于表示液晶屏一行像素数据的传输结束,每传输完成液晶屏的一行像素数据时,HSYNC会发生电平跳变,如分辨率为800x480的显示屏(800列,480行),传输一帧的图像HSYNC的电平会跳变480次。

· 垂直同步信号VSYNC: 垂直同步信号VSYNC(Vertical Sync)用于表示液晶屏一帧像素数据的传输结束,每传输完成一帧像素数据时,VSYNC会发生电平跳变。其中“帧”是图像的单位,一幅图像称为一帧,在液晶屏中,一帧指一个完整屏液晶像素点。人们常常用“帧/秒”来表示液晶屏的刷新特性,即液晶屏每秒可以显示多少帧图像,如液晶屏以60帧/秒的速率运行时,VSYNC每秒钟电平会跳变60次。

· 数据使能信号DE: 数据使能信号DE(Data Enable)用于表示数据的有效性,当DE信号线为高电平时,RGB信号线表示的数据有效。

传输一帧图像数据的时序:


        液晶屏显示的图像可看作一个矩形,液晶屏有一个显示指针,它指向将要显示的像素。显示指针的扫描方向方向从左到右、从上到下,一个像素点一个像素点地描绘图形。这些像素点的数据通过RGB数据线传输至液晶屏,它们在同步时钟CLK的驱动下一个一个地传输到液晶屏中,交给显示指针,传输完成一行时,水平同步信号HSYNC电平跳变一次,而传输完一帧时VSYNC电平跳变一次。 

液晶显示指针在行与行之间,帧与帧之间切换时需要延时,而且HSYNC及VSYNC信号本身也有宽度,这些时间参数说明见下表:

 在这些时间参数控制的区域,数据使能信号线“DE”都为低电平,RGB数据线的信号无效,当“DE”为高电平时,表示的数据有效,传输的数据会直接影响液晶屏的显示区域。


显存

        液晶屏中的每个像素点都是数据,在实际应用中需要把每个像素点的数据缓存起来,再传输给液晶屏,这种存储显示数据的存储器被称为显存。显存一般至少要能存储液晶屏的一帧显示数据,如分辨率为800x480的液晶屏,使用RGB888格式显示,它的一帧显示数据大小为:3x800x480=1152000字节;若使用RGB565格式显示,一帧显示数据大小为:2x800x480=768000字节。

三.液晶控制原理

        在这里我们要讲解的是LCD电阻屏,在这个屏幕里面集成了ili9341液晶控制芯片,该控制器芯片中存在显存。使用的是8080接口与单片机通讯,液晶面板引出的FPC信号线即8080接口(RGB接口已在内部直接与ILI9341相连)。PCB底板,它主要包含了一个电阻触摸屏的控制器XPT2046,电阻触摸屏控制器实质上是一个ADC芯片,通过检测电压值来计算触摸坐标。PCB底板与液晶触摸面板通过FPC排线座连接,然后引出到排针,方便与实验板的排母连接。

 四.ili9341液晶显示控制器

ili9341内部结构图:

液晶显示屏原理图:


液晶屏的信号线及8080时序:

        LI9341控制器根据自身的IM[3:0]信号线电平决定它与MCU的通讯方式,其支持SPI及8080通讯方式,本示例中液晶屏被配置为8080接口通讯,用16根数据线的RGB565格式。内部硬件电路连接完,剩下的其它信号线被引出到FPC排线,最后该排线由PCB底板引出到排针,排针再与实验板上的STM32芯片连接,引出的排针信号线如下图:

        这些引出的信号线即8080通讯接口,带X的表示低电平有效。通讯的内容主要包括命令和显存数据,显存数据即各个像素点的RGB565内容;命令是指对ILI9341的控制指令,MCU可通过8080接口发送命令编码控制ILI9341的工作方式,例如复位指令、设置光标指令、睡眠模式指令等等,具体的指令在《ILI9341.pdf》数据手册均有详细说明。 


向ILI9341写命令的时序图: 

    写命令时序由片选信号CSX拉低开始,对数据/命令选择信号线D/CX也置低电平表示写入的是命令地址(可理解为命令编码,如软件复位命令:0x01),以写信号WRX为低,读信号RDX为高表示数据传输方向为写入,同时,在数据线D[17:0](或D[15:0])输出命令地址,在第二个传输阶段传送的是命令的参数,所以D/CX要置高电平,表示写入的是命令数据,命令数据是某些指令带有的参数,如复位指令编码为0x01,它后面可以带一个参数,该参数表示多少秒后复位(实际的复位命令不含参数,此处只是为了讲解指令编码与参数的区别)。 当需要把像素数据写入GRAM时,过程很类似,把片选信号CSX拉低后,再把数据/命令选择信号线D/CX置为高电平,这时由D[17:0]传输的数据则会被ILI9341保存至它的GRAM中。 

五.FSMC模拟8080时序

        8080时序可以用i/o口翻转电平进行通讯模拟实现,但是这种方法的效率太低。在stm32中我们有FSMC功能我们可以用这个外设实现8080时序。(FSMC外设可以用于控制扩展的外部存储器)


FSMC功能框图

控制LCD时,适合使用FSMC的NOR\PSRAM模式,它与前面使用FSMC控制SRAM的稍有不同,控制SRAM时使用的是模式A,而控制LCD时使用的是与NOR FLASH一样的模式B,所以我们重点分析框图中NOR FLASH控制信号线部分。

在控制LCD时,使用的是类似异步、地址与数据线独立的NOR FLASH控制方式,所以实际上CLK、NWAIT、NADV引脚并没有使用到。 


FSMC NOR 中的模式B的时序图:

用FSMC模拟8080时序:

 对比FSMC NOR/PSRAM中的模式B时序与ILI9341液晶控制器芯片使用的8080时序可发现,这两个时序是十分相似的(除了FSMC的地址线A和8080的D/CX线,可以说是完全一样)


FSMC时序结构体介绍

        与控制SRAM时一样,控制FSMC使用NOR FLASH存储器时主要是配置时序寄存器以及控制寄存器,利用ST标准库的时序结构体以及初始化结构体可以很方便地写入参数。

· FSMC_AddressSetupTime   本成员设置地址建立时间,它可以被设置为0-0xF个HCLK周期数,按STM32标准库的默认配置,HCLK的时钟频率为72MHz,即一个HCLK周期为1/72微秒。

· FSMC_AddressHoldTime    本成员设置地址保持时间,它可以被设置为0-0xF个HCLK周期数。

· FSMC_DataSetupTime   本成员设置数据建立时间,它可以被设置为0-0xF个HCLK周期数。 

· FSMC_BusTurnAroundDuration 本成员设置总线转换周期,在NOR FLASH存储器中,地址线与数据线可以分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其它存储器时这个参数无效,配置为0即可。 

· FSMC_CLKDivision 本成员用于设置时钟分频,它以HCLK时钟作为输入,经过FSMC_CLKDivision分频后输出到FSMC_CLK引脚作为通讯使用的同步时钟。控制其它异步通讯的存储器时这个参数无效,配置为0即可。

· FSMC_DataLatency 本成员设置数据保持时间,它表示在读取第一个数据之前要等待的周期数,该周期指同步时钟的周期,本参数仅用于同步NOR FLASH类型的存储器,控制其它类型的存储器时,本参数无效。

· FSMC_AccessMode 本成员设置存储器访问模式,不同的模式下FSMC访问存储器地址时引脚输出的时序不一样,可选FSMC_AccessMode_A/B/C/D模式。一般来说控制异步NOR FLASH时使用B模式。


FSMC的NOR FLASH初始化结构体介绍

· FSMC_Bank 本成员用于选择FSMC映射的存储区域,它的可选参数以及相应的内核地址映射范围见上面的表格。

· FSMC_DataAddressMux     本成员用于设置地址总线与数据总线是否复用。(FSMC_DataAddressMux_Enable /Disable),在控制NOR FLASH时,可以地址总线与数据总线可以分时复用,以减少使用STM32信号线的数量。

· FSMC_MemoryType     本成员用于设置要控制的存储器类型,它支持控制的存储器类型为SRAM、PSRAM以及NOR FLASH(FSMC_MemoryType_SRAM/PSRAM/NOR)。

· FSMC_MemoryDataWidth     本成员用于设置要控制的存储器的数据宽度,可选择设置成8或16位(FSMC_MemoryDataWidth_8b /16b)。

· FSMC_BurstAccessMode     本成员用于设置是否使用突发访问模式。(FSMC_BurstAccessMode_Enable/Disable),突发访问模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地址,仅在控制同步类型的存储器时才能使用突发模式。

· FSMC_AsynchronousWait     本成员用于设置是否使能在同步传输时使用的等待信号。(FSMC_AsynchronousWait_Enable/Disable),在控制同步类型的NOR或PSRAM时,存储器可以使用FSMC_NWAIT引脚通知STM32需要等待。

· FSMC_WaitSignalPolarity     本成员用于设置等待信号的有效极性,即要求等待时,使用高电平还是低电平(FSMC_WaitSignalPolarity_High/Low)。

· FSMC_WrapMode     本成员用于设置是否支持把非对齐的AHB突发操作分割成2次线性操作(FSMC_WrapMode_Enable/Disable),该配置仅在突发模式下有效。

· FSMC_WaitSignalActive     本成员用于配置在突发传输模式时,决定存储器是在等待状态之前的一个数据周期有效还是在等待状态期间有效(FSMC_WaitSignalActive_BeforeWaitState/DuringWaitState)。

· FSMC_WriteOperation     这个成员用于设置是否写使能(FSMC_WriteOperation_ Enable /Disable),禁止写使能的话FSMC只能从存储器中读取数据,不能写入。

· FSMC_WaitSignal     本成员用于设置当存储器牌突发传输模式时,是否允许通过NWAIT信号插入等待状态(FSMC_WaitSignal_Enable/Disable)。

· FSMC_ExtendedMode     本成员用于设置是否使用扩展模式(FSMC_ExtendedMode_Enable/Disable),在非扩展模式下,对存储器读写的时序都只使用FSMC_BCR寄存器中的配置,即下面的FSMC_ReadWriteTimingStruct结构体成员;在扩展模式下,对存储器的读写时序可以分开配置,读时序使用FSMC_BCR寄存器,写时序使用FSMC_BWTR寄存器的配置,即下面的FSMC_WriteTimingStruct结构体。

· FSMC_ReadWriteTimingStruct     本成员是一个指针,赋值时使用上一小节中讲解的时序结构体FSMC_NORSRAMInitTypeDef设置,当不使用扩展模式时,读写时序都使用本成员的参数配置。

· FSMC_WriteTimingStruct     同样地,本成员也是一个时序结构体的指针,只有当使用扩展模式时,本配置才有效,它是写操作使用的时序。 

六.LCD液晶显示屏的驱动程序

液晶屏硬件原理图


对引脚进行宏定义

/*LCD控制信号****************************/
#ifdef USE_ZNZ#define     FSMC_BANK_NORSRAMx				FSMC_Bank1_NORSRAM1#define 		ILI9341_CMD_ADDR  		(__IO uint16_t*)(0x60000000)#define 		ILI9341_DATA_ADDR  		(__IO uint16_t*)(0x60020000)#define      ILI9341_CS_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_CS_PORT          GPIOD#define      ILI9341_CS_PIN           GPIO_Pin_7#define      ILI9341_RST_CLK           RCC_APB2Periph_GPIOE#define      ILI9341_RST_PORT          GPIOE#define      ILI9341_RST_PIN           GPIO_Pin_1#define      ILI9341_BK_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_BK_PORT          GPIOD#define      ILI9341_BK_PIN           GPIO_Pin_12#define      ILI9341_RD_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_RD_PORT          GPIOD#define      ILI9341_RD_PIN           GPIO_Pin_4#define      ILI9341_WR_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_WR_PORT          GPIOD#define      ILI9341_WR_PIN           GPIO_Pin_5#define      ILI9341_DC_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_DC_PORT          GPIOD#define      ILI9341_DC_PIN           GPIO_Pin_11#else#define     FSMC_BANK_NORSRAMx				FSMC_Bank1_NORSRAM4#define 		ILI9341_CMD_ADDR  		(__IO uint16_t*)(0x6c000000)#define 		ILI9341_DATA_ADDR  		(__IO uint16_t*)(0x6d000000)#define      ILI9341_CS_CLK           RCC_APB2Periph_GPIOG#define      ILI9341_CS_PORT          GPIOG#define      ILI9341_CS_PIN           GPIO_Pin_12#define      ILI9341_RST_CLK           RCC_APB2Periph_GPIOG#define      ILI9341_RST_PORT          GPIOG#define      ILI9341_RST_PIN           GPIO_Pin_11#define      ILI9341_BK_CLK           RCC_APB2Periph_GPIOG#define      ILI9341_BK_PORT          GPIOG#define      ILI9341_BK_PIN           GPIO_Pin_6#define      ILI9341_RD_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_RD_PORT          GPIOD#define      ILI9341_RD_PIN           GPIO_Pin_4#define      ILI9341_WR_CLK           RCC_APB2Periph_GPIOD#define      ILI9341_WR_PORT          GPIOD#define      ILI9341_WR_PIN           GPIO_Pin_5#define      ILI9341_DC_CLK           RCC_APB2Periph_GPIOE#define      ILI9341_DC_PORT          GPIOE#define      ILI9341_DC_PIN           GPIO_Pin_2#endif#define      ILI9341_D0_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D0_PORT               GPIOD
#define      ILI9341_D0_PIN                GPIO_Pin_14#define      ILI9341_D1_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D1_PORT               GPIOD
#define      ILI9341_D1_PIN                GPIO_Pin_15#define      ILI9341_D2_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D2_PORT               GPIOD
#define      ILI9341_D2_PIN                GPIO_Pin_0#define      ILI9341_D3_CLK                RCC_APB2Periph_GPIOD  
#define      ILI9341_D3_PORT               GPIOD
#define      ILI9341_D3_PIN                GPIO_Pin_1#define      ILI9341_D4_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D4_PORT               GPIOE
#define      ILI9341_D4_PIN                GPIO_Pin_7#define      ILI9341_D5_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D5_PORT               GPIOE
#define      ILI9341_D5_PIN                GPIO_Pin_8#define      ILI9341_D6_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D6_PORT               GPIOE
#define      ILI9341_D6_PIN                GPIO_Pin_9#define      ILI9341_D7_CLK                RCC_APB2Periph_GPIOE  
#define      ILI9341_D7_PORT               GPIOE
#define      ILI9341_D7_PIN                GPIO_Pin_10#define      ILI9341_D8_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D8_PORT               GPIOE
#define      ILI9341_D8_PIN                GPIO_Pin_11#define      ILI9341_D9_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D9_PORT               GPIOE
#define      ILI9341_D9_PIN                GPIO_Pin_12#define      ILI9341_D10_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D10_PORT               GPIOE
#define      ILI9341_D10_PIN                GPIO_Pin_13#define      ILI9341_D11_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D11_PORT               GPIOE
#define      ILI9341_D11_PIN                GPIO_Pin_14#define      ILI9341_D12_CLK                RCC_APB2Periph_GPIOE   
#define      ILI9341_D12_PORT               GPIOE
#define      ILI9341_D12_PIN                GPIO_Pin_15#define      ILI9341_D13_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D13_PORT               GPIOD
#define      ILI9341_D13_PIN                GPIO_Pin_8#define      ILI9341_D14_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D14_PORT               GPIOD
#define      ILI9341_D14_PIN                GPIO_Pin_9#define      ILI9341_D15_CLK                RCC_APB2Periph_GPIOD   
#define      ILI9341_D15_PORT               GPIOD
#define      ILI9341_D15_PIN                GPIO_Pin_10

注意:

就是让编译器不要优化代码。 


引脚初始化配置(数据引脚和FSMC外设)

void ILI9341_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 打开GPIO的时钟RCC_APB2PeriphClockCmd(ILI9341_CS_CLK|ILI9341_RST_CLK|ILI9341_BK_CLK|ILI9341_RD_CLK|ILI9341_WR_CLK|ILI9341_DC_CLK|ILI9341_D0_CLK|ILI9341_D1_CLK|ILI9341_D2_CLK|ILI9341_D3_CLK|ILI9341_D4_CLK|ILI9341_D5_CLK|ILI9341_D6_CLK|ILI9341_D7_CLK|ILI9341_D8_CLK|ILI9341_D9_CLK|ILI9341_D10_CLK|ILI9341_D11_CLK|ILI9341_D12_CLK|ILI9341_D13_CLK|ILI9341_D14_CLK|ILI9341_D15_CLK	, ENABLE);// 将的GPIO配置为推挽模式GPIO_InitStructure.GPIO_Pin = ILI9341_BK_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(ILI9341_BK_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = ILI9341_RST_PIN;GPIO_Init(ILI9341_RST_PORT, &GPIO_InitStructure);// 将的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = ILI9341_CS_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(ILI9341_CS_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = ILI9341_RD_PIN;GPIO_Init(ILI9341_RD_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = ILI9341_WR_PIN;GPIO_Init(ILI9341_WR_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = ILI9341_DC_PIN;GPIO_Init(ILI9341_DC_PORT, &GPIO_InitStructure);/* 配置FSMC相对应的数据线,FSMC-D0~D15 */	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = ILI9341_D0_PIN;GPIO_Init ( ILI9341_D0_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D1_PIN;GPIO_Init ( ILI9341_D1_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D2_PIN;GPIO_Init ( ILI9341_D2_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D3_PIN;GPIO_Init ( ILI9341_D3_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D4_PIN;GPIO_Init ( ILI9341_D4_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D5_PIN;GPIO_Init ( ILI9341_D5_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D6_PIN;GPIO_Init ( ILI9341_D6_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D7_PIN;GPIO_Init ( ILI9341_D7_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D8_PIN;GPIO_Init ( ILI9341_D8_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D9_PIN;GPIO_Init ( ILI9341_D9_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D10_PIN;GPIO_Init ( ILI9341_D10_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D11_PIN;GPIO_Init ( ILI9341_D11_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D12_PIN;GPIO_Init ( ILI9341_D12_PORT, & GPIO_InitStructure );	GPIO_InitStructure.GPIO_Pin = ILI9341_D13_PIN;GPIO_Init ( ILI9341_D13_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D14_PIN;GPIO_Init ( ILI9341_D14_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D15_PIN;GPIO_Init ( ILI9341_D15_PORT, & GPIO_InitStructure );
}
void ILI9341_FSMC_Config(void)
{FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;FSMC_NORSRAMTimingInitTypeDef  readWriteTiming;/*使能FSMC外设时钟*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);//地址建立时间(ADDSET)readWriteTiming.FSMC_AddressSetupTime = 0x01;	//数据保持时间(DATAST)readWriteTiming.FSMC_DataSetupTime = 0x04;		 //地址保持时间(ADDHLD)模式B未用到readWriteTiming.FSMC_AddressHoldTime = 0x00;	 //设置总线转换周期,仅用于复用模式的NOR操作readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;//设置时钟分频,仅用于同步类型的存储器readWriteTiming.FSMC_CLKDivision = 0x00;	//数据保持时间,仅用于NORreadWriteTiming.FSMC_DataLatency = 0x00;		//选择匹配SRAM的模式readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_B;	 // 选择FSMC映射的存储区域: Bank1 NORSRAMxFSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_BANK_NORSRAMx; //设置地址总线与数据总线是否复用,仅用于NORFSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; //设置要控制的存储器类型:NOR类型FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_NOR;   //存储器数据宽度:16位FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; //设置是否使用突发访问模式,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;//设置是否使能等待信号,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;//设置等待信号的有效极性,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;//设置是否支持把非对齐的突发操作,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; //设置等待信号插入的时间,仅用于同步类型的存储器FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive =         FSMC_WaitSignalActive_BeforeWaitState;//存储器写使能 FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;//不使用等待信号FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;  		// 不使用扩展模式,读写使用相同的时序FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; //突发写操作FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;  //读写时序配置FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;//读写同样时序,使用扩展模式时这个配置才有效FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  //初始化FSMC配置FSMC_NORSRAMCmd(FSMC_BANK_NORSRAMx, ENABLE);  // 使能BANK										  }

向液晶屏读写及命令操作

/*** @brief  向ILI9341写入命令* @param  usCmd :要写入的命令(表寄存器地址)* @retval 无*/	
__inline void ILI9341_Write_Cmd ( uint16_t usCmd )
{*ILI9341_CMD_ADDR = usCmd;	
}/*** @brief  向ILI9341写入数据* @param  usData :要写入的数据* @retval 无*/	
__inline void ILI9341_Write_Data ( uint16_t usData )
{* ILI9341_DATA_ADDR = usData;}/*** @brief  从ILI9341读取数据* @param  无* @retval 读取到的数据*/	
__inline uint16_t ILI9341_Read_Data ( void )
{return ( *ILI9341_DATA_ADDR );}uint16_t Read_Pixel_Format(void)
{ILI9341_Write_Cmd(0x0C);ILI9341_Read_Data();return ILI9341_Read_Data();}

背光控制函数

/*** @brief  ILI9341背光LED控制* @param  enumState :决定是否使能背光LED*   该参数为以下值之一:*     @arg ENABLE :使能背光LED*     @arg DISABLE :禁用背光LED* @retval 无*/
void ILI9341_BackLed_Control ( FunctionalState enumState )
{if ( enumState )GPIO_ResetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );	elseGPIO_SetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );}

初始化ili9341寄存器

/*** @brief  初始化ILI9341寄存器* @param  无* @retval 无*/
static void ILI9341_REG_Config ( void )
{/*  Power control B (CFh)  */DEBUG_DELAY  ();ILI9341_Write_Cmd ( 0xCF  );ILI9341_Write_Data ( 0x00  );ILI9341_Write_Data ( 0x81  );ILI9341_Write_Data ( 0x30  );/*  Power on sequence control (EDh) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xED );ILI9341_Write_Data ( 0x64 );ILI9341_Write_Data ( 0x03 );ILI9341_Write_Data ( 0x12 );ILI9341_Write_Data ( 0x81 );/*  Driver timing control A (E8h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xE8 );ILI9341_Write_Data ( 0x85 );ILI9341_Write_Data ( 0x10 );ILI9341_Write_Data ( 0x78 );/*  Power control A (CBh) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xCB );ILI9341_Write_Data ( 0x39 );ILI9341_Write_Data ( 0x2C );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x34 );ILI9341_Write_Data ( 0x02 );/* Pump ratio control (F7h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xF7 );ILI9341_Write_Data ( 0x20 );/* Driver timing control B */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xEA );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xB1 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x1B );/*  Display Function Control (B6h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xB6 );ILI9341_Write_Data ( 0x0A );ILI9341_Write_Data ( 0xA2 );/* Power Control 1 (C0h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xC0 );ILI9341_Write_Data ( 0x35 );/* Power Control 2 (C1h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xC1 );ILI9341_Write_Data ( 0x11 );/* VCOM Control 1 (C5h) */ILI9341_Write_Cmd ( 0xC5 );ILI9341_Write_Data ( 0x45 );ILI9341_Write_Data ( 0x45 );/*  VCOM Control 2 (C7h)  */ILI9341_Write_Cmd ( 0xC7 );ILI9341_Write_Data ( 0xA2 );/* Enable 3G (F2h) */ILI9341_Write_Cmd ( 0xF2 );ILI9341_Write_Data ( 0x00 );/* Gamma Set (26h) */ILI9341_Write_Cmd ( 0x26 );ILI9341_Write_Data ( 0x01 );DEBUG_DELAY ();/* Positive Gamma Correction */ILI9341_Write_Cmd ( 0xE0 ); //Set GammaILI9341_Write_Data ( 0x0F );ILI9341_Write_Data ( 0x26 );ILI9341_Write_Data ( 0x24 );ILI9341_Write_Data ( 0x0B );ILI9341_Write_Data ( 0x0E );ILI9341_Write_Data ( 0x09 );ILI9341_Write_Data ( 0x54 );ILI9341_Write_Data ( 0xA8 );ILI9341_Write_Data ( 0x46 );ILI9341_Write_Data ( 0x0C );ILI9341_Write_Data ( 0x17 );ILI9341_Write_Data ( 0x09 );ILI9341_Write_Data ( 0x0F );ILI9341_Write_Data ( 0x07 );ILI9341_Write_Data ( 0x00 );/* Negative Gamma Correction (E1h) */ILI9341_Write_Cmd ( 0XE1 ); //Set GammaILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x19 );ILI9341_Write_Data ( 0x1B );ILI9341_Write_Data ( 0x04 );ILI9341_Write_Data ( 0x10 );ILI9341_Write_Data ( 0x07 );ILI9341_Write_Data ( 0x2A );ILI9341_Write_Data ( 0x47 );ILI9341_Write_Data ( 0x39 );ILI9341_Write_Data ( 0x03 );ILI9341_Write_Data ( 0x06 );ILI9341_Write_Data ( 0x06 );ILI9341_Write_Data ( 0x30 );ILI9341_Write_Data ( 0x38 );ILI9341_Write_Data ( 0x0F );/* memory access control set */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0x36 ); 	ILI9341_Write_Data ( 0xC8 );    /*竖屏  左上角到 (起点)到右下角 (终点)扫描方式*/DEBUG_DELAY ();/* column address control set */ILI9341_Write_Cmd ( CMD_SetCoordinateX );  ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0xEF );/* page address control set */DEBUG_DELAY ();ILI9341_Write_Cmd ( CMD_SetCoordinateY ); ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x01 );ILI9341_Write_Data ( 0x3F );/*  Pixel Format Set (3Ah)  */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0x3a ); ILI9341_Write_Data ( 0x55 );/* Sleep Out (11h)  */ILI9341_Write_Cmd ( 0x11 );	ILI9341_Delay ( 0xAFFf<<2 );DEBUG_DELAY ();/* Display ON (29h) */ILI9341_Write_Cmd ( 0x29 ); }

 在这里我们要特别注意这个设置窗口坐标的函数。


/******************************* 定义 ILI934 常用命令 ********************************/
#define      CMD_SetCoordinateX		 		    0x2A	     //设置X坐标
#define      CMD_SetCoordinateY		 		    0x2B	     //设置Y坐标
#define      CMD_SetPixel		 		          0x2C	     //填充像素

由这两个命令我们就可以在液晶屏上面确认像素的显示区域。


总的初始化函数

void ILI9341_Init(void)
{ILI9341_GPIO_Config();				// FSMC_GPIO的配置ILI9341_FSMC_Config();				// FSMC相关配置ILI9341_BackLed_Control(ENABLE);	// 点亮LCD背光灯ILI9341_Rst();						// 复位ILI9341_REG_Config();				// 初始化ILI9341寄存器// 其中0、3、5、6 模式适合从左至右显示文字,// 不推荐使用其它模式显示文字	其它模式显示文字会有镜像效果// 其中 6 模式为大部分液晶例程的默认显示方向ILI9341_GramScan(LCD_SCAN_MODE);
}

设置液晶显示窗口和光标位置

/*** @brief  在ILI9341显示器上开辟一个窗口* @param  usX :在特定扫描方向下窗口的起点X坐标* @param  usY :在特定扫描方向下窗口的起点Y坐标* @param  usWidth :窗口的宽度* @param  usHeight :窗口的高度* @retval 无*/
void ILI9341_OpenWindow(uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight)
{/* 设置X坐标,设置起始点和结束点 */ILI9341_Write_Cmd(CMD_SetCoordinateX); 				ILI9341_Write_Data(usX >> 8);ILI9341_Write_Data(usX & 0xff);ILI9341_Write_Data((usX + usWidth - 1) >> 8);ILI9341_Write_Data((usX + usWidth - 1) & 0xff);/* 设置Y坐标,设置起始点和结束点 */ILI9341_Write_Cmd(CMD_SetCoordinateY);ILI9341_Write_Data(usY >> 8);ILI9341_Write_Data(usY & 0xff);ILI9341_Write_Data((usY + usHeight - 1) >> 8);ILI9341_Write_Data((usY + usHeight - 1) & 0xff);
}/*** @brief  设定ILI9341的光标坐标* @param  usX :在特定扫描方向下光标的X坐标* @param  usY :在特定扫描方向下光标的Y坐标* @retval 无*/
static void ILI9341_SetCursor(uint16_t usX, uint16_t usY)
{ILI9341_OpenWindow(usX, usY, 1, 1);
}

填充像素点和清窗口屏

/*** @brief  在ILI9341显示器上以某一颜色填充像素点* @param  ulAmout_Point :要填充颜色的像素点的总数目* @param  usColor :颜色* @retval 无*/
static __inline void ILI9341_FillColor(uint32_t ulAmout_Point, uint16_t usColor)
{uint32_t i = 0;/* memory write */ILI9341_Write_Cmd(CMD_SetPixel);for (i = 0; i < ulAmout_Point; i ++){ILI9341_Write_Data(usColor);}
}static uint16_t CurrentTextColor = BLACK;	// 前景色
static uint16_t CurrentBackColor = WHITE;	// 背景色/*** @brief  对ILI9341显示器的某一窗口以某种颜色进行清屏* @param  usX :在特定扫描方向下窗口的起点X坐标* @param  usY :在特定扫描方向下窗口的起点Y坐标* @param  usWidth :窗口的宽度* @param  usHeight :窗口的高度* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_Clear(uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight)
{ILI9341_OpenWindow(usX, usY, usWidth, usHeight);ILI9341_FillColor(usWidth * usHeight, CurrentBackColor);
}/*** @brief  对ILI9341显示器的某一点以某种颜色进行填充* @param  usX :在特定扫描方向下该点的X坐标* @param  usY :在特定扫描方向下该点的Y坐标* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_SetPointPixel(uint16_t usX, uint16_t usY)
{if ((usX < LCD_X_LENGTH) && (usY < LCD_Y_LENGTH)){ILI9341_SetCursor(usX, usY);ILI9341_FillColor(1, CurrentTextColor);}
}

获取某一个坐标点的像素数据

/*** @brief  读取 GRAM 的一个像素数据* @param  无* @retval 像素数据*/
static uint16_t ILI9341_Read_PixelData(void)
{uint16_t usRG = 0, usB = 0 ;ILI9341_Write_Cmd(0x2E); /* 读数据 */// 去掉前一次读取结果ILI9341_Read_Data(); 	 /* FIRST READ OUT DUMMY DATA */// 获取红色通道与绿色通道的值usRG = ILI9341_Read_Data();  	/*READ OUT RED AND GREEN DATA  */usB = ILI9341_Read_Data();  	/*READ OUT BLUE DATA*/return ((usRG & 0xF800) | ((usRG << 3) & 0x7E0) | (usB >> 11));
}/*** @brief  获取 ILI9341 显示器上某一个坐标点的像素数据* @param  usX :在特定扫描方向下该点的X坐标* @param  usY :在特定扫描方向下该点的Y坐标* @retval 像素数据*/
uint16_t ILI9341_GetPointPixel(uint16_t usX, uint16_t usY)
{uint16_t usPixelData;ILI9341_SetCursor(usX, usY);usPixelData = ILI9341_Read_PixelData();return usPixelData;
}

画线

/*** @brief  在 ILI9341 显示器上使用 Bresenham 算法画线段* @param  usX1 :在特定扫描方向下线段的一个端点X坐标* @param  usY1 :在特定扫描方向下线段的一个端点Y坐标* @param  usX2 :在特定扫描方向下线段的另一个端点X坐标* @param  usY2 :在特定扫描方向下线段的另一个端点Y坐标* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DrawLine(uint16_t usX1, uint16_t usY1, uint16_t usX2, uint16_t usY2)
{uint16_t us;uint16_t usX_Current, usY_Current;int32_t lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance;int32_t lIncrease_X, lIncrease_Y;//计算坐标增量lDelta_X = usX2 - usX1;lDelta_Y = usY2 - usY1;usX_Current = usX1;usY_Current = usY1;if (lDelta_X > 0){lIncrease_X = 1;    //设置单步方向}else if (lDelta_X == 0){lIncrease_X = 0;    //垂直线}else{lIncrease_X = -1;lDelta_X = - lDelta_X;}if (lDelta_Y > 0){lIncrease_Y = 1;}else if (lDelta_Y == 0){lIncrease_Y = 0;    //水平线}else{lIncrease_Y = -1;lDelta_Y = - lDelta_Y;}if (lDelta_X > lDelta_Y){lDistance = lDelta_X;    //选取基本增量坐标轴}else{lDistance = lDelta_Y;}for (us = 0; us <= lDistance + 1; us ++)  //画线输出{ILI9341_SetPointPixel(usX_Current, usY_Current);   //画点lError_X += lDelta_X ;lError_Y += lDelta_Y ;if (lError_X > lDistance){lError_X -= lDistance;usX_Current += lIncrease_X;}if (lError_Y > lDistance){lError_Y -= lDistance;usY_Current += lIncrease_Y;}}
}

画矩形

/*** @brief  在 ILI9341 显示器上画一个矩形* @param  usX_Start :在特定扫描方向下矩形的起始点X坐标* @param  usY_Start :在特定扫描方向下矩形的起始点Y坐标* @param  usWidth:矩形的宽度(单位:像素)* @param  usHeight:矩形的高度(单位:像素)* @param  ucFilled :选择是否填充该矩形*   该参数为以下值之一:*     @arg 0 :空心矩形*     @arg 1 :实心矩形* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DrawRectangle(uint16_t usX_Start, uint16_t usY_Start, uint16_t usWidth, uint16_t usHeight,uint8_t ucFilled)
{if (ucFilled){ILI9341_OpenWindow(usX_Start, usY_Start, usWidth, usHeight);ILI9341_FillColor(usWidth * usHeight, CurrentTextColor);}else{ILI9341_DrawLine(usX_Start, usY_Start, usX_Start + usWidth - 1, usY_Start);ILI9341_DrawLine(usX_Start, usY_Start + usHeight - 1, usX_Start + usWidth - 1, usY_Start + usHeight - 1);ILI9341_DrawLine(usX_Start, usY_Start, usX_Start, usY_Start + usHeight - 1);ILI9341_DrawLine(usX_Start + usWidth - 1, usY_Start, usX_Start + usWidth - 1, usY_Start + usHeight - 1);}
}

画圆形

/*** @brief  在 ILI9341 显示器上使用 Bresenham 算法画圆* @param  usX_Center :在特定扫描方向下圆心的X坐标* @param  usY_Center :在特定扫描方向下圆心的Y坐标* @param  usRadius:圆的半径(单位:像素)* @param  ucFilled :选择是否填充该圆*   该参数为以下值之一:*     @arg 0 :空心圆*     @arg 1 :实心圆* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DrawCircle(uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint8_t ucFilled)
{int16_t sCurrentX, sCurrentY;int16_t sError;sCurrentX = 0;sCurrentY = usRadius;sError = 3 - (usRadius << 1);       //判断下个点位置的标志while (sCurrentX <= sCurrentY){int16_t sCountY;if (ucFilled){for (sCountY = sCurrentX; sCountY <= sCurrentY; sCountY ++){ILI9341_SetPointPixel(usX_Center + sCurrentX, usY_Center + sCountY);              //1,研究对象ILI9341_SetPointPixel(usX_Center - sCurrentX, usY_Center + sCountY);              //2ILI9341_SetPointPixel(usX_Center - sCountY,   usY_Center + sCurrentX);            //3ILI9341_SetPointPixel(usX_Center - sCountY,   usY_Center - sCurrentX);            //4ILI9341_SetPointPixel(usX_Center - sCurrentX, usY_Center - sCountY);              //5ILI9341_SetPointPixel(usX_Center + sCurrentX, usY_Center - sCountY);              //6ILI9341_SetPointPixel(usX_Center + sCountY,   usY_Center - sCurrentX);            //7ILI9341_SetPointPixel(usX_Center + sCountY,   usY_Center + sCurrentX);            //0}}else{ILI9341_SetPointPixel(usX_Center + sCurrentX, usY_Center + sCurrentY);                //1,研究对象ILI9341_SetPointPixel(usX_Center - sCurrentX, usY_Center + sCurrentY);                //2ILI9341_SetPointPixel(usX_Center - sCurrentY, usY_Center + sCurrentX);                //3ILI9341_SetPointPixel(usX_Center - sCurrentY, usY_Center - sCurrentX);                //4ILI9341_SetPointPixel(usX_Center - sCurrentX, usY_Center - sCurrentY);                //5ILI9341_SetPointPixel(usX_Center + sCurrentX, usY_Center - sCurrentY);                //6ILI9341_SetPointPixel(usX_Center + sCurrentY, usY_Center - sCurrentX);                //7ILI9341_SetPointPixel(usX_Center + sCurrentY, usY_Center + sCurrentX);                //0}sCurrentX ++;if (sError < 0){sError += 4 * sCurrentX + 6;}else{sError += 10 + 4 * (sCurrentX - sCurrentY);sCurrentY --;}}
}

显示字符和字符串

/*** @brief  在 ILI9341 显示器上显示一个英文字符* @param  usX :在特定扫描方向下字符的起始X坐标* @param  usY :在特定扫描方向下该点的起始Y坐标* @param  cChar :要显示的英文字符* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DispChar_EN(uint16_t usX, uint16_t usY, const char cChar)
{uint8_t  byteCount, bitCount, fontLength;uint16_t ucRelativePositon;uint8_t *Pfont;//对ascii码表偏移(字模表不包含ASCII表的前32个非图形符号)ucRelativePositon = cChar - ' ';//每个字模的字节数fontLength = (LCD_Currentfonts->Width * LCD_Currentfonts->Height) / 8;//字模首地址/*ascii码表偏移值乘以每个字模的字节数,求出字模的偏移位置*/Pfont = (uint8_t *)&LCD_Currentfonts->table[ucRelativePositon * fontLength];//设置显示窗口ILI9341_OpenWindow(usX, usY, LCD_Currentfonts->Width, LCD_Currentfonts->Height);ILI9341_Write_Cmd(CMD_SetPixel);//按字节读取字模数据//由于前面直接设置了显示窗口,显示数据会自动换行for (byteCount = 0; byteCount < fontLength; byteCount++){//一位一位处理要显示的颜色for (bitCount = 0; bitCount < 8; bitCount++){if (Pfont[byteCount] & (0x80 >> bitCount)){ILI9341_Write_Data(CurrentTextColor);}else{ILI9341_Write_Data(CurrentBackColor);}}}
}/*** @brief  在 ILI9341 显示器上显示英文字符串* @param  line :在特定扫描方向下字符串的起始Y坐标*   本参数可使用宏LINE(0)、LINE(1)等方式指定文字坐标,*   宏LINE(x)会根据当前选择的字体来计算Y坐标值。*		显示中文且使用LINE宏时,需要把英文字体设置成Font8x16* @param  pStr :要显示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DispStringLine_EN(uint16_t line,  char *pStr)
{uint16_t usX = 0;while (* pStr != '\0'){if ((usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width) > LCD_X_LENGTH){usX = ILI9341_DispWindow_X_Star;line += LCD_Currentfonts->Height;}if ((line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height) > LCD_Y_LENGTH){usX = ILI9341_DispWindow_X_Star;line = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN(usX, line, * pStr);pStr ++;usX += LCD_Currentfonts->Width;}
}/*** @brief  在 ILI9341 显示器上显示英文字符串* @param  usX :在特定扫描方向下字符的起始X坐标* @param  usY :在特定扫描方向下字符的起始Y坐标* @param  pStr :要显示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DispString_EN(uint16_t usX, uint16_t usY,  char *pStr)
{while (* pStr != '\0'){if ((usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width) > LCD_X_LENGTH){usX = ILI9341_DispWindow_X_Star;usY += LCD_Currentfonts->Height;}if ((usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height) > LCD_Y_LENGTH){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN(usX, usY, * pStr);pStr ++;usX += LCD_Currentfonts->Width;}
}/*** @brief  在 ILI9341 显示器上显示英文字符串(沿Y轴方向)* @param  usX :在特定扫描方向下字符的起始X坐标* @param  usY :在特定扫描方向下字符的起始Y坐标* @param  pStr :要显示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色* @retval 无*/
void ILI9341_DispString_EN_YDir(uint16_t usX, uint16_t usY,  char *pStr)
{while (* pStr != '\0'){if ((usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height) > LCD_Y_LENGTH){usY = ILI9341_DispWindow_Y_Star;usX += LCD_Currentfonts->Width;}if ((usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width) >  LCD_X_LENGTH){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN(usX, usY, * pStr);pStr ++;usY += LCD_Currentfonts->Height;}
}

设置或获取当前字体类型

/*** @brief  设置英文字体类型* @param  fonts: 指定要选择的字体*		参数为以下值之一* 	@arg:Font24x32;* 	@arg:Font16x24;* 	@arg:Font8x16;* @retval None*/
void LCD_SetFont(sFONT *fonts)
{LCD_Currentfonts = fonts;
}/*** @brief  获取当前字体类型* @param  None.* @retval 返回当前字体类型*/
sFONT *LCD_GetFont(void)
{return LCD_Currentfonts;
}

设置或获取LCD前景和背景颜色

/*** @brief  设置LCD的前景(字体)及背景颜色,RGB565* @param  TextColor: 指定前景(字体)颜色* @param  BackColor: 指定背景颜色* @retval None*/
void LCD_SetColors(uint16_t TextColor, uint16_t BackColor)
{CurrentTextColor = TextColor;CurrentBackColor = BackColor;
}/*** @brief  获取LCD的前景(字体)及背景颜色,RGB565* @param  TextColor: 用来存储前景(字体)颜色的指针变量* @param  BackColor: 用来存储背景颜色的指针变量* @retval None*/
void LCD_GetColors(uint16_t *TextColor, uint16_t *BackColor)
{*TextColor = CurrentTextColor;*BackColor = CurrentBackColor;
}/*** @brief  设置LCD的前景(字体)颜色,RGB565* @param  Color: 指定前景(字体)颜色* @retval None*/
void LCD_SetTextColor(uint16_t Color)
{CurrentTextColor = Color;
}/*** @brief  设置LCD的背景颜色,RGB565* @param  Color: 指定背景颜色* @retval None*/
void LCD_SetBackColor(uint16_t Color)
{CurrentBackColor = Color;
}

清除某行文字

/*** @brief  清除某行文字* @param  Line: 指定要删除的行*   本参数可使用宏LINE(0)、LINE(1)等方式指定要删除的行,*   宏LINE(x)会根据当前选择的字体来计算Y坐标值,并删除当前字体高度的第x行。* @retval None*/
void LCD_ClearLine(uint16_t Line)
{ILI9341_Clear(0, Line, LCD_X_LENGTH, ((sFONT *)LCD_GetFont())->Height);	/* 清屏,显示全黑 */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/49726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

销售分析,奥威BI,销售好帮手

【销售分析&#xff0c;奥威BI&#xff0c;销售好帮手】 在商海浮沉中&#xff0c;销售数据是企业最宝贵的资产之一&#xff0c;它不仅反映了市场的反馈&#xff0c;更是指引企业未来战略方向的灯塔。奥威BI&#xff08;Business Intelligence&#xff09;&#xff0c;作为数据…

硅纪元视角 | Stability AI推出Stable Video 4D,40秒生成8角度动态视频!

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

SpringBoot集成Tomcat、DispatcherServlet

通过 SpringBoot 自动配置机制&#xff0c;导入配置类 利用 SpringBoot 自动配置机制&#xff0c;SpringBoot 会导入一个类型为 ServletWebServerFactoryAutoConfiguration 的配置类 ServletWebServerFactoryAutoConfiguration ServletWebServerFactoryAutoConfigurations 类上…

C# VS2019 Form 图标的修改

一、 窗口的左上角图标 1、Form的属性中找到Icon项直接选择图标&#xff08;.ico&#xff09;路径,窗口左上角会自动更新选择更新的图标。 Form属性 2.发布后的exe图标

谷粒商城实战笔记-48~49-商品服务-API-三级分类-查询-树形展示三级分类数据-前端优化

文章目录 一&#xff0c;48-商品服务-API-三级分类-查询-树形展示三级分类数据1&#xff0c;创建商品服务命名空间2&#xff0c;商品服务增加配置3&#xff0c;网关增加商品服务的路由配置4&#xff0c;前端树形展示5&#xff0c;测试 二&#xff0c;49-商品服务-API-三级分类-…

Python酷库之旅-第三方库Pandas(044)

目录 一、用法精讲 151、pandas.Series.any方法 151-1、语法 151-2、参数 151-3、功能 151-4、返回值 151-5、说明 151-6、用法 151-6-1、数据准备 151-6-2、代码示例 151-6-3、结果输出 152、pandas.Series.autocorr方法 152-1、语法 152-2、参数 152-3、功能 …

线上语音交友平台成熟案例源码出售本地找搭子交友app软件线下陪玩系统开发服务

1、上麦相亲互动:直播间内除了红娘外&#xff0c;还有男女用户两个视频麦位&#xff0c;直播间符合要求的用户可以申请上麦, 2、公屏聊天:为上麦用户可以通过在公屏发言的方式参与直播间内的话题互动。 3、私信异性用户之间可以发送私信消息&#xff0c;通过付要或开通会员可解…

无线领夹麦克风哪个牌子好?几十块和几百块的领夹麦克风推荐

现如今视频自媒体行业还在蓬勃发展&#xff0c;麦克风对于自媒体行业可以说是必不可少的装备了&#xff0c;在互联网“内卷”的时代&#xff0c;各大视频博主、Up主、主播大多都会使用无线麦克风来辅助视频和直播内容输出。无线领夹麦克风作为视频行业中的麦克风新宠&#xff0…

深入理解TCP:互联网通信的基石

深入理解TCP&#xff1a;互联网通信的基石 引言TCP的普遍应用TCP连接的建立与维护三次握手&#xff08;Three-Way Handshake&#xff09;连接的可靠性与超时重传数据传输与流量控制连接的终止状态转换 TCP与UDP的对比TCP协议栈的层级结构应用层&#xff08;Application Layer&a…

DevExpress WPF中文教程:如何完成GridControl的列和编辑器配置?

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

【C++BFS算法】2192. 有向无环图中一个节点的所有祖先

本文涉及知识点 CBFS算法 LeetCode2192. 有向无环图中一个节点的所有祖先 给你一个正整数 n &#xff0c;它表示一个 有向无环图 中节点的数目&#xff0c;节点编号为 0 到 n - 1 &#xff08;包括两者&#xff09;。 给你一个二维整数数组 edges &#xff0c;其中 edges[i]…

springcloud rocketmq 新增的消费者组从哪里开始消费

如果新建一个新的消费者组&#xff0c;是否会消费历史消息&#xff0c;导致重复消费&#xff1f; 直接在 console 界面新增消费者组&#xff0c;但是没有办法绑定订阅关系&#xff0c;没有找到入口&#xff0c;在 控制台项目源码 rocketmq-externals 也没有找到可以确定订阅关系…

Android 常用调试工具/方法解析

一、内存相关 参考Android内存分析命令_dumpsys meminfo 算出rss-CSDN博客 1、基本概念 1&#xff09;PSS & RSS & USS & VSS a、PSS 概念&#xff1a;全称Proportional Set Size&#xff0c;根据进程实际使用的内存量按照共享比例分配给进程的一种内存度量方…

SpringBoot 项目配置文件注释乱码的问题解决方案

一、问题描述 在项目的配置文件中&#xff0c;我们写了一些注释&#xff0c;如下所示&#xff1a; 但是再次打开注释会变成乱码&#xff0c;如下所示&#xff1a; 那么如何解决呢&#xff1f; 二、解决方案 1. 点击” File→Setting" 2. 搜索“File Encodings”, 将框…

Wonder3D 论文学习

论文链接&#xff1a;https://arxiv.org/abs/2310.15008 代码链接&#xff1a;https://github.com/xxlong0/Wonder3D 解决了什么问题&#xff1f; 随着扩散模型的提出&#xff0c;3D 生成领域取得了长足进步。从单张图片重建出 3D 几何是计算机图形学和 3D 视觉的基础任务&am…

World of Warcraft [CLASSIC] Timebadge

游戏币【每个服务器实时金价不一样&#xff0c;本例子是5000-6000金】 1枚【魔兽世界时光徽章】 30天游戏时间。 5760金币游戏币&#xff0c;策划如何消耗游戏里面的金币总量&#xff0c;以及如何留住那些非人民币玩家呢 30天加上去了 World of Warcraft [CLASSIC] [魔兽世界…

搜索与下载Stable Diffusion 模型

我只是一个刚开始学习SD没多久小白&#xff0c;拿到别人的工作流想要运行时&#xff0c;很多时候还要下载对应的模型才能正常运行&#xff0c;虽然也可以通过comfyui-manager下载&#xff0c;不过有时候好像会下载失败&#xff0c;而单独下载所需模型&#xff0c;我自己试过&am…

英语科技写作 希拉里·格拉斯曼-蒂(英文版)pdf下载

下载链接&#xff1a; 链接1&#xff1a;https://pan.baidu.com 链接2&#xff1a;/s/1fxRUGnlJrKEzQVF6k1GmBA 提取码&#xff1a;b69t 由于是英文版&#xff0c;可能有些看着不太方便&#xff0c;可以在网页版使用以下软件中英文对照着看&#xff0c;看着更舒服&#xff0c;…

图书管理系统设计

设计一个图书管理系统时&#xff0c;我们需要考虑系统的基本功能、用户需求、技术选型以及数据的安全性和完整性。下面是一个基本的图书管理系统的设计概览&#xff1a; 1. 系统目标 管理图书信息&#xff1a;添加、删除、修改图书信息。借阅管理&#xff1a;处理借书、还书流…

Python 教程(二):语法与数据结构

目录 前言专栏列表语法特点实例代码基本数据类型变量命名规则赋值动态类型作用域示例代码 运算符list、set和dict 数据结构 区别1. list&#xff08;列表&#xff09;2. set&#xff08;集合&#xff09;3. dict&#xff08;字典&#xff09; 总结 前言 Python 是一种计算机编…