业务请联系elautoctrl@qq.com
野火LCD控制器之前采用的是ili9325,但是LCD控制器这东西更新换代比较快,ili9325现在缺货了,所以新购的这批货控制器换成了HX8347。对于一块新的控制器,其实我们比较关注的是以下几个部分:
1 初始化函数(即使俩控制器是请兄弟,我想初始化函数多少也是要改改的,O(∩_∩)O哈!)
2 设置GRAM指针函数(比如SetCursor(u16 x,u16 y))
3 开窗函数 (比如:SetWindows(u16 StartX,u16 StartY,u16 EndX,u16 EndY))
4 清屏函数(其实清屏函数和开窗函数差不了多少)
5获取指定位置的像素信息函数 (比如u16 GetPoint(u16 x,u16 y))
6 在指定位置描写指定颜色的点 SetPoint(u16 x,u16 y,u16 point)
7其它
在野火例程中,为了保持对ili9325的兼容性,我们采用“选择性编译”来选择不同的控制器(用户大可不必担心^^)。打开lcd.h文件,我们可以看到有个宏定义“#define HX8347”,如果我们手上的LCD采用的是HX8347控制器,我们则需要保留这个宏定义;如果我们手上的LCD采用的是ili9325控制器,我们则将这个宏定义去掉或注释掉即可。当让接下来的开发板都是采用HX8347咯~~
在这里就说说HX8347,一次只把该控制器的驱动部分抽出来,至于ili9325部分,大家可看野火资料例程。
首先是LCD初始化函数。
/*
- * 函数名:LCD_Init
- * 描述 :LCD 控制 I/O 初始化
- * LCD FSMC 初始化
- * LCD 控制器 ILI9325C 初始化
- * 输入 :NONE
- * 输出 :NONE
- * 调用 :外部调用
- */
void LCD_Init(void) - {
- unsigned long i;
- LCD_GPIO_Config(); //管脚初始化
- LCD_FSMC_Config(); //FSMC配置
- LCD_Rst(); //复位
- //Driving ability Setting
- LCD_WR_CMD(0xEA,0×00); //PTBA[15:8]
- LCD_WR_CMD(0xEB,0×20); //PTBA[7:0]
- LCD_WR_CMD(0xEC,0x3C); //STBA[15:8]
- LCD_WR_CMD(0xED,0xC4); //STBA[7:0]
- LCD_WR_CMD(0xE8,0×48); //OPON[7:0]
- LCD_WR_CMD(0xE9,0×38); //OPON1[7:0]
- LCD_WR_CMD(0xF1,0×01); //OTPS1B
- LCD_WR_CMD(0xF2,0×08); //GEN
- //Gamma 2.2 Setting
- LCD_WR_CMD(0×40,0×01); //
- LCD_WR_CMD(0×41,0×07); //
- LCD_WR_CMD(0×42,0×09); //
- LCD_WR_CMD(0×43,0×19); //
- LCD_WR_CMD(0×44,0×17); //
- LCD_WR_CMD(0×45,0×20); //
- LCD_WR_CMD(0×46,0×18); //
- LCD_WR_CMD(0×47,0×61); //
- LCD_WR_CMD(0×48,0×00); //
- LCD_WR_CMD(0×49,0×10); //
- LCD_WR_CMD(0x4A,0×17); //
- LCD_WR_CMD(0x4B,0×19); //
- LCD_WR_CMD(0x4C,0×14); //
- LCD_WR_CMD(0×50,0x1F); //
- LCD_WR_CMD(0×51,0×28); //
- LCD_WR_CMD(0×52,0×26); //
- LCD_WR_CMD(0×53,0×36); //
- LCD_WR_CMD(0×54,0×38); //
- LCD_WR_CMD(0×55,0x3E); //
- LCD_WR_CMD(0×56,0x1E); //
- LCD_WR_CMD(0×57,0×67); //
- LCD_WR_CMD(0×58,0x0B); //
- LCD_WR_CMD(0×59,0×06); //
- LCD_WR_CMD(0x5A,0×08); //
- LCD_WR_CMD(0x5B,0x0F); //
- LCD_WR_CMD(0x5C,0x1F); //
- LCD_WR_CMD(0x5D,0xCC); //
- //Power Voltage Setting
- LCD_WR_CMD(0x1B,0x1B); //VRH=4.65V
- LCD_WR_CMD(0x1A,0×01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)
- LCD_WR_CMD(0×24,0×70); //VMH(VCOM High voltage ~4.2V)
- LCD_WR_CMD(0×25,0×58); //VML(VCOM Low voltage -1.2V)
//****VCOM offset**/// - LCD_WR_CMD(0×23,0x6E); //for Flicker adjust //can reload from OTP
- //Power on Setting
- LCD_WR_CMD(0×18,0×36); //I/P_RADJ,N/P_RADJ, Normal mode 70Hz
- LCD_WR_CMD(0×19,0×01); //OSC_EN=’1′, start Osc
- LCD_WR_CMD(0×01,0×00); //DP_STB=’0′, out deep sleep
- LCD_WR_CMD(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
- LCD_WR_CMD(0×17,0×05); //default 0×06 262k color // 0×05 65k color
- //SET PANEL
- LCD_WR_CMD(0×36,0×09); //SS_P, GS_P,REV_P,BGR_P
- LCD_WR_CMD(0×28,0x3F); //GON=1, DTE=1, D=1100
- LCD_WR_CMD(0×16,0×50); //左上到右下 竖屏
- //LCD_WR_CMD(0×16,0X70); //
- LCD_WR_CMD(0×02,0×00);
- LCD_WR_CMD(0×03,0×00); //Column Start
- LCD_WR_CMD(0×04,0×00);
- LCD_WR_CMD(0×05,0xEF); //Column End
- LCD_WR_CMD(0×06,0×00);
- LCD_WR_CMD(0×07,0×00); //Row Start
- LCD_WR_CMD(0×08,0×01);
- LCD_WR_CMD(0×09,0x3F); //Row End
- LCD_WR_REG(0×22);
- for(i=0; i<(320*240); i++)
- {
- LCD_WR_Data(RED); //清屏
- }
- }
初始化函数中,大家比较熟悉的是LCD_Rst();这个函数可要注意了,要留意一下datasheet,是高电平复位还是低电平复位,决不能机械地凭经验断定,datasheet是这么说的
“NRESET Reset pin.Setting either pin low initializes the LSI. Must be reset after power is supplied.”。看了这句话,心里也就踏实了,复位函数如下:
- /*
- * 函数名:LCD_Rst
- * 描述 :LCD 软件复位
- * 输入 :无
- * 输出 :无
- * 调用 :内部调用
- */
static void LCD_Rst(void) - {
- GPIO_ResetBits(GPIOE, GPIO_Pin_1); //低电平复位
- Delay(0xAFFFFf);
- GPIO_SetBits(GPIOE, GPIO_Pin_1 ); //拉高进入工作状态
- Delay(0xAFFFFf);
- }
另外一个我觉得比较重要的就是屏的扫描方向和开窗位置设置这两个部分。我们来看一下扫描方向的设置:
对应的是0×16寄存器
开窗起点终点位置的设置
对应0×02 0×03 0x040x050x06 0×07 0×08寄存器
该LCD例程实现的功能如下:
- /*
- * 函数名:main
- * 描述 :主函数
- * 输入 :无
- * 输出 :无
- */
int main(void) - {
- SystemInit(); /*配置系统时钟*/
- SysTick_Init(); /* 配置SysTick*/
- USART1_Config(); /* 串口初始化*/
- LED_GPIO_Config(); /* LED初始化 */
- LCD_Init(); /* LCD 初始化*/
- sd_fs_init(); /*文件系统初始化*/
- /*显示图片*/
- Lcd_show_bmp(0, 0,”/pic3.bmp”);
- Lcd_show_bmp(200, 40,”/pic2.bmp”);
- Lcd_show_bmp(100, 100,”/pic1.bmp”);
- /*水平方向显示字符串*/
- Put_ascii_chinese_string(10,20,”欢迎您使用野火Stm32开发板^_^”,0xffe0,1);
- Put_ascii_chinese_string(10,280,”http://firestm32.taobao.com”,0,1);
- LCD_Show_8x16_String(50, 30, 1, “8X16 ASCII LCD DEMO”);
- PutChinese_strings21(50,50,”液晶例程”,0,1);
- PutChinese_strings11(50,70,”液晶例程”,0,0xffff);
/*竖直方向显示字符串*/ - LCD_Show_8x16_String2(80,220, 1, “8X16 ASCII”);
- PutChinese_strings22(80,200,”液晶例程”,0,1);
- PutChinese_strings12(80,180,”液晶例程”,0,0xffff);
- /*截图保存*/
- Screen_shot(0, 0, 320, 240, “/myScreen”);
- PutChinese_strings11(50,150,”截图完成”,0,0xffff);
while (1) - {
- }
- }
而对于LCD驱动的整体框架,相信大家在ili9325的基础上也应该动了不少,下面就将一下比较关键的部分吧:
1 开窗函数
- /*
- * 函数名:LCD_open_windows
- * 描述 :开窗(以x,y为坐标起点,长为len,高为wid)
- * 输入 :-x -y -len -wid -rgb565
- * 输出 :无
- */
void LCD_open_windows(u16 x,u16 y,u8 len,u16 wid) - {
- LCD_WR_CMD(0×02, x>>8); //高八位
- LCD_WR_CMD(0×03, x-((x>>8)<<8)); //低八位
//LCD_WR_CMD(0×03, x&0x00ff); //低八位—另一种写法 - LCD_WR_CMD(0×04, (x+len-1)>>8);
- LCD_WR_CMD(0×05, (x+len-1)-(((x+len-1)>>8)<<8));
- LCD_WR_CMD(0×06, y>>8);
- LCD_WR_CMD(0×07, y-((y>>8)<<8));
- LCD_WR_CMD(0×08, (y+wid-1)>>8);
- LCD_WR_CMD(0×09, (y+wid-1)-(((y+wid-1)>>8)<<8));
- LCD_WR_REG(0X22); / /为传输数据做准备
- }
2 清屏函数
- *
- * 函数名:LCD_CLEAR
- * 描述 :以x,y为坐标起点,在长len,高wid的范围内清屏
- * 输入 :-x -y -len -wid
- * 输出 :无
- */
void LCD_CLEAR(u8 x,u16 y,u8 len,u16 wid) - {
- u32 n, temp;
- LCD_WR_CMD(0×06, 0);
- LCD_WR_CMD(0×07, x);
- LCD_WR_CMD(0×08, 0);
- LCD_WR_CMD(0×09, x+len-1);
- LCD_WR_CMD(0×02, y>>8);
- LCD_WR_CMD(0×03, y-((y>>8)<<8));
- LCD_WR_CMD(0×04, (y+wid-1)>>8);
- LCD_WR_CMD(0×05, (y+wid-1)-(((y+wid-1)>>8)<<8));
- LCD_WR_REG(0X22);
- temp = (u32)len*wid;
- for(n=0; n<temp; n++)
- LCD_WR_Data( RGB(20,20,20) ); //写入数据
- }
3 在指定位置描写指定颜色的点(其实本质上还是清屏函数)
- /*
- * 函数名:LCD_DrawPoint
- * 描述 :在坐标(x,y)处画一个指定颜色的点
- * 输入 :-x 0~239
- -y 0~319
- * 输出 :无
- */
- void LCD_Draw_ColorPoint(u16 x,u16 y, u16 rgb565)
- {
- LCD_WR_CMD(0×06, 0);
- LCD_WR_CMD(0×07, x);
- LCD_WR_CMD(0×08, 0);
- LCD_WR_CMD(0×09, x);
- LCD_WR_CMD(0×02, y>>8);
- LCD_WR_CMD(0×03, y-((y>>8)<<8));
- LCD_WR_CMD(0×04, (y)>>8);
- LCD_WR_CMD(0×05, (y)-(((y)>>8)<<8));
- LCD_WR_REG(0X22);
- LCD_WR_Data(rgb565);
- }
4 获取指定位置的像素信息函数
LCD_open_windows(x,y,1,1);
LCD_WR_REG(0X22);
之后调用下面这个函数— LCD_RD_data返回RGB565格式的数据
- /*
- * 函数名:LCD_WR_REG
- * 描述 :读 ILI9325 RAM 数据
- * 输出 :读取的数据,16bit *
- */
- static __inline u16 LCD_RD_data(void)
- {
- u16 tmp_color = 0;
- u8 Green = 0,Red=0,Black=0;
- Green = *((__IO u8 *)(Bank1_LCD_D)); //Dummy
- Green = *((__IO u8 *)(Bank1_LCD_D)); //—8位为基本读单位
- Red = *((__IO u8 *)(Bank1_LCD_D));
- Black = *((__IO u8 *)(Bank1_LCD_D));
- tmp_color = (u16)((((u16)Red>>3)<<11)|(((u16)Green>>2)<<5)|((u16)Black>>3));
- return(tmp_color);
- }
大伙需要注意了,HX8347在此读的基本单位是8位,和ili9325差别挺远的咯。
ili9325读GRAM数据写法如下:
- static __inline u16 LCD_RD_data(void)
- {
- u16 a = 0;
- a = *((__IO u16 *) (Bank1_LCD_D)); //Dummy
- a = *((__IO u16 *) (Bank1_LCD_D)); //16位为基本基本单位
- return(a);
- }
关键的部分也就是以上这几个函数了,其它函数变通一下即可,大伙可以对照一下野火开发板当前使用的HX8347控制器驱动和之前使用的ili9325区别,对比之下相信大家一下子也就能够明白,其实也没变化什么东西O(∩_∩)O哈!