STM32F103 TFTLCD显示实验(二)

您所在的位置:网站首页 0x00和0x0000有什么区别 STM32F103 TFTLCD显示实验(二)

STM32F103 TFTLCD显示实验(二)

2024-05-26 22:22| 来源: 网络整理| 查看: 265

文章内容

在上一章的基础上,将讲解部分代码。

STM32F103 TFTLCD显示实验(一) https://blog.csdn.net/qq_40318498/article/details/97111069

相关代码

我们知道 TFTLCD 的 RS 接在 FSMC 的 A10 上面,CS 接在 FSMC_NE4 上,并且是 16 位数据总线。即我们使用的是 FSMC 存储器 1 的第 4 区。

//LCD地址结构体 typedef struct { vu16 LCD_REG; vu16 LCD_RAM; } LCD_TypeDef; #define LCD_BASE ((u32)(0x6C000000 | 0x000007FE)) #define LCD ((LCD_TypeDef *) LCD_BASE)

bank1.sector4的地址就是从0X6C000000开始,而0x000007FE,则是A10的偏移量,将这个地址强制转换成LCD_TypeDef结构体地址,那么可以得到 LCD->LCD_REG 的地址就是 0X6C00,07FE,对应 A10 的状态为 0(即 RS=0),而 LCD-> LCD_RAM 的地址就是 0X6C00,0800(结构体地址自增),对应 A10 的状态为 1(即 RS=1)。

写寄存器值函数 //写寄存器函数 //regval:寄存器值 void LCD_WR_REG(u16 regval) { LCD->LCD_REG=regval;//写入要写的寄存器序号 //FSMC自动控制片选信号等等,如果没有FSMC的话,比如,先拉低片选cs,在WR的上升沿写入数据等,比较麻烦。 //这里指对应没有FSMC的,比如mini版的和OLED这种 } 写数据函数 //写LCD数据 //data:要写入的值 void LCD_WR_DATA(u16 data) { LCD->LCD_RAM=data; //跟写寄存器值函数类似 } 读数据函数 //读LCD数据 //返回值:读到的值 u16 LCD_RD_DATA(void) { vu16 ram; //防止被优化 ram=LCD->LCD_RAM; return ram; //return LCD->LCD_RAM } 写寄存器内容函数 //写寄存器 //LCD_Reg:寄存器地址 //LCD_RegValue:要写入的数据 void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue) { LCD->LCD_REG = LCD_Reg; //写入要写的寄存器序号 LCD->LCD_RAM = LCD_RegValue;//写入数据 } 读寄存器内容函数 //读寄存器 //LCD_Reg:寄存器地址 //返回值:读到的数据 u16 LCD_ReadReg(u16 LCD_Reg) { LCD_WR_REG(LCD_Reg); //写入要读的寄存器序号 delay_us(5); return LCD_RD_DATA(); //返回读到的值 } 开始写GRAM函数 //开始写GRAM void LCD_WriteRAM_Prepare(void) { LCD->LCD_REG=lcddev.wramcmd; } 写GRAM函数 //LCD写GRAM //RGB_Code:颜色值 void LCD_WriteRAM(u16 RGB_Code) { LCD->LCD_RAM = RGB_Code;//写十六位GRAM }

上面7个函数是比较简单也比较基础的,下面介绍一下坐标设置函数

坐标设置函数 //LCD重要参数集 typedef struct { u16 width; //LCD 宽度 u16 height; //LCD 高度 u16 id; //LCD ID u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。 u16 wramcmd; //开始写gram指令 u16 setxcmd; //设置x坐标指令 u16 setycmd; //设置y坐标指令 }_lcd_dev; //管理LCD重要参数 //默认为竖屏 _lcd_dev lcddev; //设置光标位置 //Xpos:横坐标 //Ypos:纵坐标 lcddev.dir=0; //竖屏 lcddev.width=240; lcddev.height=320; lcddev.wramcmd=0X2C; //写GRAM,写入函数数据 lcddev.setxcmd=0X2A; //列地址 lcddev.setycmd=0X2B; //页地址 void LCD_SetCursor(u16 Xpos, u16 Ypos) { LCD_WR_REG(lcddev.setxcmd); //向寄存器写入指令 LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF); //因为坐标是16为的,先传高8位,后传低8位 LCD_WR_REG(lcddev.setycmd); LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF); } 画点函数 //画点 //x,y:坐标 //POINT_COLOR:此点的颜色 void LCD_DrawPoint(u16 x,u16 y) { LCD_SetCursor(x,y); //设置光标位置,这不是窗口,而是一个点 LCD_WriteRAM_Prepare(); //开始写入GRAM LCD->LCD_RAM=POINT_COLOR; } //快速画点 //x,y:坐标 //color:颜色 void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color){ LCD_WR_REG(lcddev.setxcmd); //写控制x命令. LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF); //写入数据 LCD_WR_REG(lcddev.setycmd); //写入y命令 LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF); LCD->LCD_REG=lcddev.wramcmd; //写GRAM LCD->LCD_RAM=color; //写颜色 //相对于上面,应该省去了调用函数的时间,本质是一样的。 }

该函数实现比较简单,就是先设置坐标,然后往坐标写颜色。其中 POINT_COLOR 是我们 定义的一个全局变量,用于存放画笔颜色。

画直线矩形 //画线 //x1,y1:起点坐标 //x2,y2:终点坐标 void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2) { //比如x1=10,y1=10,x2=10,y2=20,也就是竖直线,dalta_x=0,delta_y=10. //incx=0,incy=1,distance=delta_y(这么多的距离,也就是点) u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=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 xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } } //画矩形 //(x1,y1),(x2,y2):矩形的对角坐标 void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2) { LCD_DrawLine(x1,y1,x2,y1); LCD_DrawLine(x1,y1,x1,y2); LCD_DrawLine(x1,y2,x2,y2); LCD_DrawLine(x2,y1,x2,y2); }

有了画点,当然还需要有读点的函数,那就还有读点函数,用于读取 LCD 的 GRAM,这里说明一下,为什么 OLED 模块没做读 GRAM 的函数,而这里做了。因为 OLED 模块是单色的,所需要全部 GRAM 也就 1K 个字节,而 TFTLCD 模块为彩色的,点数也比 OLED 模块多很多,以 16 位色计算,一款 320×240 的液晶,需要 320×240×2 个字节来存储颜色值, 也就是也需要 150K 字节,这对任何一款单片机来说,都不是一个小数目了。而且我们在图形 叠加的时候,可以先读回原来的值,然后写入新的值,在完成叠加后,我们又恢复原来的值。 这样在做一些简单菜单的时候,是很有用的。这里我们读取 TFTLCD 模块数据的函数为 LCD_ReadPoint,该函数直接返回读到的 GRAM 值。该函数使用之前要先设置读取的 GRAM 地址,通过 LCD_SetCursor 函数来实现。LCD_ReadPoint 的代码如下:

读点函数 u16 LCD_ReadPoint(u16 x,u16 y) { u16 r=0,g=0,b=0; if(x>=lcddev.width||y>=lcddev.height)return 0; //超过了范围,直接返回 LCD_SetCursor(x,y); //设置点的坐标 LCD_WR_REG(0X2E); //9341/6804/3510/1963 发送读GRAM指令 r=LCD_RD_DATA(); //dummy Read,假读,参考显示实验一的指令0x2e opt_delay(2); r=LCD_RD_DATA(); //实际坐标颜色 opt_delay(2); b=LCD_RD_DATA(); g=r&0XFF; //对于9341/5310/5510,第一次读取的是RG的值,R在前,G在后,各占8位 g11)10)11)); //ILI9341/NT35310/NT35510需要公式转换一下 //r是高5位,这里右移11位,也就是将低11位全部置0,不是相当于没移。 //g=r&0xFF,也就是相当于取低8位,只有高6位是颜色,若r = 1111 1000 1111 1100,g = r&0XFF=0000 0000 1111 1100 //g10 = 0000 0000 0011 1111 if(size==12)temp=asc2_1206[num][t]; //调用1206字体 else if(size==16)temp=asc2_1608[num][t]; //调用1608字体 else if(size==24)temp=asc2_2412[num][t]; //调用2412字体 else return; //没有的字库 for(t1=0;t1 y=y0; x++; if(x>=lcddev.width)return; //超区域了 break; } } } } 初始化函数 GPIO_InitTypeDef GPIO_InitStructure; FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef readWriteTiming; FSMC_NORSRAMTimingInitTypeDef writeTiming; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE); //使能FSMC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOG,ENABLE);//使能PORTB,D,E,G以及AFIO复用功能时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PB0 推挽输出 背光 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //PORTD复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15; // //PORTD复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); //PORTE复用推挽输出 GPIO_InitStructure.GPIO_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; // //PORTD复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); // //PORTG12复用推挽输出 A0 ,LCD_CS ->PG12,LCD_RS->PG0 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_12; // //PORTD复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOG, &GPIO_InitStructure); readWriteTiming.FSMC_AddressSetupTime = 0x01; //地址建立时间(ADDSET)为2个HCLK 1/36M=27ns readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间(ADDHLD)模式A未用到 readWriteTiming.FSMC_DataSetupTime = 0x0f; // 数据保存时间为16个HCLK,因为液晶驱动IC的读数据的时候,速度不能太快,尤其对1289这个IC。 readWriteTiming.FSMC_BusTurnAroundDuration = 0x00; readWriteTiming.FSMC_CLKDivision = 0x00; readWriteTiming.FSMC_DataLatency = 0x00; readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A writeTiming.FSMC_AddressSetupTime = 0x00; //地址建立时间(ADDSET)为1个HCLK writeTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间(A writeTiming.FSMC_DataSetupTime = 0x03; 数据保存时间为4个HCLK writeTiming.FSMC_BusTurnAroundDuration = 0x00; writeTiming.FSMC_CLKDivision = 0x00; writeTiming.FSMC_DataLatency = 0x00; writeTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;// 这里我们使用NE4 ,也就对应BTCR[6],[7]。 FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; // 不复用数据地址 FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM; //SRAM FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存储器数据宽度为16bit FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable; 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_Enable; // 读写使用不同的时序 FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming; //读写时序 FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &writeTiming; //写时序 FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置 FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE); // 使能BANK1 delay_ms(50); // delay 50 ms lcddev.id=LCD_ReadReg(0x0000); //读ID(9320/9325/9328/4531/4535等IC) LCD_WR_REG(0XD3); lcddev.id=LCD_RD_DATA(); //dummy read lcddev.id=LCD_RD_DATA(); //读到0X00 lcddev.id=LCD_RD_DATA(); //读取93 lcddev.id switch(x) { case 0:LCD_Clear(WHITE);break; case 1:LCD_Clear(BLACK);break; case 2:LCD_Clear(BLUE);break; case 3:LCD_Clear(RED);break; case 4:LCD_Clear(MAGENTA);break; case 5:LCD_Clear(GREEN);break; case 6:LCD_Clear(CYAN);break; case 7:LCD_Clear(YELLOW);break; case 8:LCD_Clear(BRRED);break; case 9:LCD_Clear(GRAY);break; case 10:LCD_Clear(LGRAY);break; case 11:LCD_Clear(BROWN);break; } POINT_COLOR=RED; LCD_ShowString(30,40,210,24,24,"Elite STM32F1 ^_^"); LCD_ShowString(30,70,200,16,16,"TFTLCD TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,lcd_id); //显示LCD ID LCD_ShowString(30,130,200,12,12,"2015/1/14"); x++; if(x==12)x=0; LED0=!LED0; delay_ms(1000); } } void LCD_Clear(u16 color) { u32 index=0; u32 totalpoint=lcddev.width; totalpoint*=lcddev.height; //得到总点数 LCD_SetCursor(0x00,0x0000); //设置光标位置 LCD_WriteRAM_Prepare(); //开始写入GRAM for(index=0;index


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3