STM32开发--- F429IG+3.5寸显示屏( ILI9486) +汉字驱动

本文未完,更新中........2020.04.05

先上图,有图有真相:


文章结构:

实验平台

3.5寸ILI9486的特点

编写初始化代码

编写点读、写函数

英文字符显示代码

汉字显示代码

汉字字库的使用


一、实验平台搭建

屏幕:

  • 材料器件:信泰微 3.5寸TFT_ILI9486驱动
  • 选择理由:1:接口兼容正点原子的TFT34针;  2:够便宜,才43元入手的, 但买的时候没留意是不带触摸, 可惜 

板子:

  • 材料器件:魔女的开发板 STM32F429IGT6
  • 选择理由:1:内置CMSIS-DAP下载器、虚拟串口,接线方便; 2:价钱实,这是硬道理

软件:

  • Keil 5.27,  近来Keil又升级了,进入界面漂亮了,
  • 没用库函数,没用HAL,全寄存器,并详细注释 ;用寄存器操作,查错除BUG就是速度

二、3.5寸驱动ILI9486的特点

这货最大的特点: 省钱!  所以3.5寸就它最大存量了. 比原子哥的3.5寸便宜一半以上, 但原子哥的代码中没它影子. 咱造一个呗!

参数上的特点 , 懒得百度了, 你也别管了, 做开发用啥的不是用, 来来去去就是写寄存器, 读寄存器。最直接的就是提取厂商的代码再根据项目优化,  别造轮子.

 


编写初始化代码

共需要初始化3个小部份

1:GPIO的初始化,因为板子、屏幕接口都和正点原子的一样,没必要造轮子,将在正点原子的代码基础上修改完善。

  • 引脚有两种: 背光引脚推挽输出、FMS引脚使用复用功能
  • 使用了魔女开发板团队提供的函数GPIOSet()对GPIO的初始化,比较简洁,函数会使能引脚时钟,并可设置引脚复用功能,就如下面只用了3行代码,就完成了屏幕所需21个引脚的初始化,和指定了引脚复用FMC功能。
// 控制背光引脚,推挽输出  		
GPIOSet(GPIOB, PIN5, G_MODE_OUT , G_OTYPE_PP , G_OSPEED_50M , G_PUPD_UP , 0);  
  
// GPIOD中需要的引脚, 使用FMC复用功能
GPIOSet(GPIOD, PIN0|PIN1|PIN4|PIN5|PIN7|PIN8|PIN9|PIN10|PIN13|PIN14|PIN15, G_MODE_AF , G_OTYPE_PP , G_OSPEED_100M , G_PUPD_UP , G_AF_FMC);
// GPIOE中需要的引脚, 使用FMC复用功能
GPIOSet (GPIOE, PIN7|PIN8|PIN9|PIN10|PIN11|PIN12|PIN13|PIN14|PIN15, G_MODE_AF , G_OTYPE_PP , G_OSPEED_100M , G_PUPD_UP , G_AF_FMC );

2:FMS的初始化,这个没啥好说的,如果想要理解FMC的原理,可以翻翻正点原子和野火的书,会比PDF详尽很多。

    //bank1有NE1~4,每一个有一个BCR+TCR,所以总共八个寄存器。
    //这里我们使用NE1 ,也就对应BTCR[0],[1]。				    
	FMC_Bank1->BTCR[0]=0X00000000;
	FMC_Bank1->BTCR[1]=0X00000000;
	FMC_Bank1E->BWTR[0]=0X00000000;

    //操作BCR寄存器	使用异步模式
	FMC_Bank1->BTCR[0]|=1<<12;		//存储器写使能
	FMC_Bank1->BTCR[0]|=1<<14;		//读写使用不同的时序
	FMC_Bank1->BTCR[0]|=1<<4; 		//存储器数据宽度为16bit 	
    
    //操作BTR寄存器	
    //读时序控制寄存器 							    
	FMC_Bank1->BTCR[1]|=0<<28;		//模式A 	 						  	 
	FMC_Bank1->BTCR[1]|=0XF<<0; 	//地址建立时间(ADDSET)为15个HCLK 1/192M=5.2ns*15=78ns	
	
    //因为液晶驱动IC的读数据的时候,速度不能太快,尤其是个别奇葩芯片。
	FMC_Bank1->BTCR[1]|=70<<8;  	//数据保存时间(DATAST)为60个HCLK	=5.2*70=360ns
	
    //写时序控制寄存器  
	FMC_Bank1E->BWTR[0]|=0<<28; 	//模式A 	 							    
	FMC_Bank1E->BWTR[0]|=15<<0;		//地址建立时间(ADDSET)为15个HCLK=78ns
	
    //10个HCLK(HCLK=180M),某些液晶驱动IC的写信号脉宽,最少也得50ns。  	 
	FMC_Bank1E->BWTR[0]|=15<<8; 	//数据保存时间(DATAST)为5.2ns*15个HCLK=78ns
	
    //使能BANK1,区域1
	FMC_Bank1->BTCR[0]|=1<<0;		//使能BANK1,区域1	    

初始化了GPIO和FMC,不着急初始化屏幕芯片ILI9486, 先测试一下能否读取屏幕型号,以判断连接和之前的初始化是否正确。

    //判断LCD TFT 9486是否连通:尝试ILI9486 ID的读取   
        delay_ms(10);        // delay 50 ms     
        LCD_REG   = 0XD3 ;				   
	xLCD.ID = LCD_RAM;	 // dummy read 	
	xLCD.ID = LCD_RAM;	 // 读到0X00
	xLCD.ID = LCD_RAM;   // 读取93								   
	xLCD.ID <<=8;
	xLCD.ID |=LCD_RAM;   // 读取41     
        if(xLCD.ID!=0x9486)  // 判断是否连通
        {
            printf("错误: 没检测到TFT_3.5寸; 型号值读取:0x%X; 将放弃本屏幕的使用!\r", xLCD.ID);
            xLCD.InitOK = 0;        
            return;
    }    

其中:LCD_REG是在h文件中的宏定义, 使用指针直接读写内存中的值,这个内存段是FMC使用的区域,可理解显存区域。

#define LCD_REG         (*(u16 *)(0x6007FFFE))   // (*(u16 *)(0x60000000 | 0x0007FFFE))  
#define LCD_RAM         (*(u16 *)(0x6008000E))   // (*(u16 *)((0x60000000 | 0x0007FFFE)+16)))

还有一个xLCD,是一个结构体,习惯了每个外设的c文件都初始化一个独立的结构体,存放设备自己数据

//LCD重要参数集
    struct  
    {		 
        u8  InitOK;    
	u16 width;			//LCD 宽度
	u16 height;			//LCD 高度
    
	u16 ID;				//LCD ID
	u8  dir;			//横屏还是竖屏控制:0,竖屏;1,横屏。	
	u16	wramcmd;		//开始写gram指令
	u16 setxcmd;		//设置x坐标指令
	u16 setycmd;		//设置y坐标指令 
    }xLCD; 	

回到判断连接的思路上,语句if(xLCD.ID!=0x9486)进行判断,如果读取的值不是0x9486, 就退出,不再继续9486芯片的配置。

3:屏幕芯片ILI9486的初始化、配置 

这部分按照厂家的步骤进行,几乎都是复制+粘贴了。

//************* Start Initial Sequence **********//		
	LCD_REG = 0XF9;
	LCD_RAM = 0x00;
	LCD_RAM = 0x08;
	
	LCD_REG = 0xC0;
	LCD_RAM = 0x19;//VREG1OUT POSITIVE
	LCD_RAM = 0x1a;//VREG2OUT NEGATIVE
	
	LCD_REG = 0xC1;
	LCD_RAM = 0x45;//VGH,VGL    VGH>=14V.
	LCD_RAM = 0x00;
	
	LCD_REG = 0xC2;
	LCD_RAM = 0x33;
	
	LCD_REG = 0XC5;
	LCD_RAM = 0x00;
	LCD_RAM = 0x28;//VCM_REG[7:0]. <=0X80.
	
	LCD_REG = 0xB1;
	LCD_RAM = 0xA0;//0XB0 =70HZ, <=0XB0.0xA0=62HZ
	LCD_RAM = 0x11;
	
	LCD_REG = 0xB4;
	LCD_RAM = 0x02; //2 DOT FRAME MODE,F<=70HZ.
	
	LCD_REG = 0xB6;
	LCD_RAM = 0x00;
	LCD_RAM = 0x42;//0 GS SS SM ISC[3:0];
	LCD_RAM = 0x3B;	
	
	LCD_REG = 0xB7;
	LCD_RAM = 0x07;
	
	LCD_REG = 0xE0;
	LCD_RAM = 0x1F;
	LCD_RAM = 0x25;
	LCD_RAM = 0x22;
	LCD_RAM = 0x0B;
	LCD_RAM = 0x06;
	LCD_RAM = 0x0A;
	LCD_RAM = 0x4E;
	LCD_RAM = 0xC6;
	LCD_RAM = 0x39;
	LCD_RAM = 0x00;
	LCD_RAM = 0x00;
	LCD_RAM = 0x00;
	LCD_RAM = 0x00;
	LCD_RAM = 0x00;
	LCD_RAM = 0x00;
	
	LCD_REG = 0XE1;
	LCD_RAM = 0x1F;
	LCD_RAM = 0x3F;
	LCD_RAM = 0x3F;
	LCD_RAM = 0x0F;
	LCD_RAM = 0x1F;
	LCD_RAM = 0x0F;
	LCD_RAM = 0x46;
	LCD_RAM = 0x49;
	LCD_RAM = 0x31;
	LCD_RAM = 0x05;
	LCD_RAM = 0x09;
	LCD_RAM = 0x03;
	LCD_RAM = 0x1C;
	LCD_RAM = 0x1A;
	LCD_RAM = 0x00;
	
	LCD_REG = 0XF1;
	LCD_RAM = 0x36;
	LCD_RAM = 0x04;
	LCD_RAM = 0x00;
	LCD_RAM = 0x3C;
	LCD_RAM = 0x0F;
	LCD_RAM = 0x0F;
	LCD_RAM = 0xA4;
	LCD_RAM = 0x02;
	
	LCD_REG = 0XF2;
	LCD_RAM = 0x18;
	LCD_RAM = 0xA3;
	LCD_RAM = 0x12;
	LCD_RAM = 0x02;
	LCD_RAM = 0x32;
	LCD_RAM = 0x12;
	LCD_RAM = 0xFF;
	LCD_RAM = 0x32;
	LCD_RAM = 0x00;
	
	LCD_REG = 0XF4;
	LCD_RAM = 0x40;
	LCD_RAM = 0x00;
	LCD_RAM = 0x08;
	LCD_RAM = 0x91;
	LCD_RAM = 0x04;
	
	LCD_REG = 0XF8;
	LCD_RAM = 0x21;
	LCD_RAM = 0x04;
	
	LCD_REG = 0x36;
	LCD_RAM = 0x48;
	
	LCD_REG = 0x3A;
	LCD_RAM = 0x55;
	
	LCD_REG = 0x11;
	delay_ms(20);
	LCD_REG = 0x29;  

    //重新配置写时序控制寄存器的时序   	 							    
    FMC_Bank1E->BWTR[0]&=~(0XF<<0);	// 地址建立时间(ADDSET)清零 	 
    FMC_Bank1E->BWTR[0]&=~(0XF<<8);	// 数据保存时间清零
    FMC_Bank1E->BWTR[0]|=4<<0;	 	// 地址建立时间(ADDSET)为4个HCLK =21ns  	 
    FMC_Bank1E->BWTR[0]|=4<<8; 		// 数据保存时间(DATAST)为5.2ns*4个HCLK=21ns

    SetDir(1);                      // 横屏 1,3  竖屏0,3
    ScanDir(3);	                    // 默认扫描方向 
    LCD_On();    

上面代码的最后,有两处要注意:重新配置FMC的一些时序, 设置了屏幕的显示方向,其中的3个小函数,可以完整代码中查看。

 

未完,待续.....

 

 

读写操作已优化,文件、函数结构也已优化,直接调用即可。

c文件可不用修改,主要是按h文件的函数声明调用。

注意字库的使用,本代码使用的是w25q128, GBK字库起始地址:0x00200000

 

字库

 

显示ASCII字符

显示汉字

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
驱动TFT-LCD显示屏,您需要一个TFT-LCD控制器驱动芯片。STM32F103C8T6并没有内置这样的控制器,因此您需要使用外部控制器,例如ILI9341。 以下是使用STM32F103C8T6和ILI9341驱动TFT-LCD显示屏的示例代码: 首先,您需要在STM32F103C8T6上配置SPI接口,并使用以下库函数进行初始化: ```c SPI_InitTypeDef SPI_InitStructure; /* Enable SPI1 clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* SPI1 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); /* Enable SPI1 */ SPI_Cmd(SPI1, ENABLE); ``` 接下来,您需要编写ILI9341的驱动程序。这里需要注意的是,ILI9341与TFT-LCD显示屏的连接方式可能不同,因此您需要根据您使用的具体显示屏和芯片进行修改。 以下是一个简单的ILI9341驱动程序,用于在TFT-LCD显示屏上显示颜色块: ```c #include "ili9341.h" /* ILI9341 initialization */ void ili9341_init(void) { /* Reset */ GPIO_ResetBits(GPIOA, GPIO_Pin_1); delay_ms(100); GPIO_SetBits(GPIOA, GPIO_Pin_1); delay_ms(100); /* Software reset */ ili9341_write_command(ILI9341_SWRESET); delay_ms(100); /* Power control A */ ili9341_write_command(ILI9341_POWERA); ili9341_write_data(0x39); ili9341_write_data(0x2C); ili9341_write_data(0x00); ili9341_write_data(0x34); ili9341_write_data(0x02); ili9341_write_command(ILI9341_POWERB); ili9341_write_data(0x00); ili9341_write_data(0xC1); ili9341_write_data(0x30); /* Driver timing control A */ ili9341_write_command(ILI9341_DTCA); ili9341_write_data(0x85); ili9341_write_data(0x00); ili9341_write_data(0x78); /* Driver timing control B */ ili9341_write_command(ILI9341_DTCB); ili9341_write_data(0x00); ili9341_write_data(0x00); /* Power on sequence control */ ili9341_write_command(ILI9341_POWER_SEQ); ili9341_write_data(0x64); ili9341_write_data(0x03); ili9341_write_data(0x12); ili9341_write_data(0x81); /* Pump ratio control */ ili9341_write_command(ILI9341_PRC); ili9341_write_data(0x20); /* Power control 1 */ ili9341_write_command(ILI9341_POWER1); ili9341_write_data(0x23); /* Power control 2 */ ili9341_write_command(ILI9341_POWER2); ili9341_write_data(0x10); /* VCOM control 1 */ ili9341_write_command(ILI9341_VCOM1); ili9341_write_data(0x3E); ili9341_write_data(0x28); /* VCOM control 2 */ ili9341_write_command(ILI9341_VCOM2); ili9341_write_data(0x86); /* Memory access control */ ili9341_write_command(ILI9341_MAC); ili9341_write_data(0x48); /* Pixel format */ ili9341_write_command(ILI9341_PIXEL_FORMAT); ili9341_write_data(0x55); /* Frame rate control */ ili9341_write_command(ILI9341_FRC); ili9341_write_data(0x00); ili9341_write_data(0x18); /* Display function control */ ili9341_write_command(ILI9341_DFC); ili9341_write_data(0x08); ili9341_write_data(0x82); ili9341_write_data(0x27); /* 3GAMMA function disable */ ili9341_write_command(ILI9341_3GAMMA_EN); ili9341_write_data(0x00); /* Gamma curve selected */ ili9341_write_command(ILI9341_GAMMA); ili9341_write_data(0x01); /* Set gamma */ ili9341_write_command(ILI9341_PGAMMA); ili9341_write_data(0x0F); ili9341_write_data(0x31); ili9341_write_data(0x2B); ili9341_write_data(0x0C); ili9341_write_data(0x0E); ili9341_write_data(0x08); ili9341_write_data(0x4E); ili9341_write_data(0xF1); ili9341_write_data(0x37); ili9341_write_data(0x07); ili9341_write_data(0x10); ili9341_write_data(0x03); ili9341_write_data(0x0E); ili9341_write_data(0x09); ili9341_write_data(0x00); /* Set gamma */ ili9341_write_command(ILI9341_NGAMMA); ili9341_write_data(0x00); ili9341_write_data(0x0E); ili9341_write_data(0x14); ili9341_write_data(0x03); ili9341_write_data(0x11); ili9341_write_data(0x07); ili9341_write_data(0x31); ili9341_write_data(0xC1); ili9341_write_data(0x48); ili9341_write_data(0x08); ili9341_write_data(0x0F); ili9341_write_data(0x0C); ili9341_write_data(0x31); ili9341_write_data(0x36); ili9341_write_data(0x0F); /* Sleep out */ ili9341_write_command(ILI9341_SLPOUT); delay_ms(120); /* Display on */ ili9341_write_command(ILI9341_DISPON); } /* ILI9341 write command */ void ili9341_write_command(uint8_t command) { GPIO_ResetBits(GPIOA, GPIO_Pin_3); SPI_I2S_SendData(SPI1, command); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); } /* ILI9341 write data */ void ili9341_write_data(uint8_t data) { GPIO_SetBits(GPIOA, GPIO_Pin_3); SPI_I2S_SendData(SPI1, data); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); } /* ILI9341 set address */ void ili9341_set_address(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { ili9341_write_command(ILI9341_CASET); ili9341_write_data(x1 >> 8); ili9341_write_data(x1 & 0xFF); ili9341_write_data(x2 >> 8); ili9341_write_data(x2 & 0xFF); ili9341_write_command(ILI9341_PASET); ili9341_write_data(y1 >> 8); ili9341_write_data(y1 & 0xFF); ili9341_write_data(y2 >> 8); ili9341_write_data(y2 & 0xFF); ili9341_write_command(ILI9341_RAMWR); } /* ILI9341 draw pixel */ void ili9341_draw_pixel(uint16_t x, uint16_t y, uint16_t color) { ili9341_set_address(x, y, x, y); ili9341_write_data(color >> 8); ili9341_write_data(color & 0xFF); } /* ILI9341 fill screen */ void ili9341_fill_screen(uint16_t color) { uint32_t i; ili9341_set_address(0, 0, TFT_WIDTH - 1, TFT_HEIGHT - 1); for (i = 0; i < TFT_WIDTH * TFT_HEIGHT; i++) { ili9341_write_data(color >> 8); ili9341_write_data(color & 0xFF); } } ``` 最后,您可以使用以下代码在TFT-LCD显示屏上显示颜色块: ```c #define TFT_WIDTH 240 #define TFT_HEIGHT 320 int main(void) { /* TFT-LCD initialization */ ili9341_init(); /* Fill screen with red color */ ili9341_fill_screen(0xF800); /* Fill half screen with green color */ ili9341_set_address(0, 0, TFT_WIDTH - 1, TFT_HEIGHT / 2 - 1); ili9341_fill_screen(0x07E0); /* Fill half screen with blue color */ ili9341_set_address(0, TFT_HEIGHT / 2, TFT_WIDTH - 1, TFT_HEIGHT - 1); ili9341_fill_screen(0x001F); while (1); return 0; } ``` 这就是一个简单的使用STM32F103C8T6和ILI9341驱动TFT-LCD显示屏的示例代码,您可以根据您使用的具体显示屏和芯片进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值