STM32H7系列芯片不像F4系列,其通过FMC来驱动TFTLCD需要先配置MPU,这个步骤是必要的,然后是配置FMC的相关设置,最后生成对应代码,同时将自己的LCD代码嵌入其中,就可以实现对TFTLCD的显示控制!!
第一步:在如下的配置框中对MPU进行配置!!
图上为什么基地址是0X60000000?请看下图,
上面两个图可以看到,块1才是用于设置FMC的,根据你自己的LCD的引脚配置选择基地址,我这边选择的是FSMC_NE1,所以我的基地址是0X60000000,其他的可以按照上面CUBEMX的相关配置!!
第二步:对FMC的配置:
基本的CUBEMX配置就完成了!!
最后主函数就是这样,将自己的LCD代码嵌入其中!!
主函数的头文件:
下面是LCD.c的代码块:
#include "lCD.h"
#include "stdlib.h"
#include "font.h"
#include "stdio.h"
#include "fmc.h"
/*************************************************************************/
SRAM_HandleTypeDef TFTSRAM_Handler; //SRAM句柄(用于控制LCD)
//LCD的画笔颜色和背景色
uint32_t POINT_COLOR=0xFF000000; //画笔颜色
uint32_t BACK_COLOR =0xFFFFFFFF; //背景色
//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;
/*************************************************************************/
/*************************************************************************/
//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(__IO uint16_t regval)
{
regval=regval; //使用-O2优化的时候,必须插入的延时
LCD->LCD_REG=regval;//写入要写的寄存器序号
}
/*************************************************************************/
/*************************************************************************/
//写LCD数据
//data:要写入的值
void LCD_WR_DATA(__IO uint16_t data)
{
data=data; //使用-O2优化的时候,必须插入的延时
LCD->LCD_RAM=data;
}
/*************************************************************************/
/*************************************************************************/
//读LCD数据
//返回值:读到的值
uint16_t LCD_RD_DATA(void)
{
__IO uint16_t ram; //防止被优化
ram=LCD->LCD_RAM;
return ram;
}
/*************************************************************************/
/*************************************************************************/
//写寄存器
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)
{
LCD->LCD_REG = LCD_Reg; //写入要写的寄存器序号
LCD->LCD_RAM = LCD_RegValue;//写入数据
}
/*************************************************************************/
/*************************************************************************/
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
uint16_t LCD_ReadReg(uint16_t LCD_Reg)
{
LCD_WR_REG(LCD_Reg); //写入要读的寄存器序号
return LCD_RD_DATA(); //返回读到的值
}
/*************************************************************************/
/*************************************************************************/
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
LCD->LCD_REG=lcddev.wramcmd;
}
/*************************************************************************/
/*************************************************************************/
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(uint16_t RGB_Code)
{
LCD->LCD_RAM = RGB_Code;//写十六位GRAM
}
/*************************************************************************/
/*************************************************************************/
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
uint16_t LCD_BGR2RGB(uint16_t c)
{
uint16_t r,g,b,rgb;
b=(c>>0)&0x1f;
g=(c>>5)&0x3f;
r=(c>>11)&0x1f;
rgb=(b<<11)+(g<<5)+(r<<0);
return(rgb);
}
/*************************************************************************/
/*************************************************************************/
//当mdk -O1时间优化时需要设置
//延时i
void opt_delay(uint8_t i)
{
while(i--);
}
/*************************************************************************/
/*************************************************************************/
//设置光标位置(对RGB屏无效)
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0XFF);
LCD_WR_DATA((lcddev.width-1)>>8);
LCD_WR_DATA((lcddev.width-1)&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0XFF);
LCD_WR_DATA((lcddev.length-1)>>8);
LCD_WR_DATA((lcddev.length-1)&0XFF);
}
/*************************************************************************/
/*************************************************************************/
//设置LCD的自动扫描方向(对RGB屏无效)
//注意:其他函数可能会受到此函数设置的影响(尤其是9341),
//所以,一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
//dir:0~7,代表8个方向(具体定义见lcd.h)
//9341/5310/5510/1963等IC已经实际测试
void LCD_Scan_Dir(uint8_t dir)
{
uint16_t regval=0;
uint16_t dirreg=0;
uint16_t temp;
switch(dir)
{
case L2R_U2D://从左到右,从上到下0x00
regval|=(0<<7)|(0<<6)|(0<<5);
break;
case L2R_D2U://从左到右,从下到上0x80
regval|=(1<<7)|(0<<6)|(0<<5);
break;
case R2L_U2D://从右到左,从上到下0x40
regval|=(0<<7)|(1<<6)|(0<<5);
break;
case R2L_D2U://从右到左,从下到上0xc0
regval|=(1<<7)|(1<<6)|(0<<5);
break;
case U2D_L2R://从上到下,从左到右0x20
regval|=(0<<7)|(0<<6)|(1<<5);
break;
case U2D_R2L://从上到下,从右到左0x60
regval|=(0<<7)|(1<<6)|(1<<5);
break;
case D2U_L2R://从下到上,从左到右0xa0
regval|=(1<<7)|(0<<6)|(1<<5);
break;
case D2U_R2L://从下到上,从右到左0xe0
regval|=(1<<7)|(1<<6)|(1<<5);
break;
}
dirreg=0X36;
LCD_WriteReg(dirreg,regval);
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA((lcddev.width-1)>>8);LCD_WR_DATA((lcddev.width-1)&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA((lcddev.length-1)>>8);LCD_WR_DATA((lcddev.length-1)&0XFF);
}
/*************************************************************************/
/*************************************************************************/
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(uint16_t x, uint16_t y)//单纯的画点函数,颜色不可选,默认为青色
{
LCD_SetCursor(x,y); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
LCD->LCD_RAM=POINT_COLOR;
}
/*************************************************************************/
/*************************************************************************/
void LCD_DrawPoint_color(uint16_t x, uint16_t y, uint32_t color)//画点函数,颜色可选,可以自我判断是否为默认青色,不是则更替其他颜色
{
LCD_SetCursor(x,y); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
LCD->LCD_RAM=color;
}
/*************************************************************************/
/*************************************************************************/
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(uint16_t x, uint16_t y, uint32_t color)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);
LCD_WR_DATA(x&0XFF);
LCD_WR_DATA((lcddev.width-1)>>8);
LCD_WR_DATA((lcddev.width-1)&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);
LCD_WR_DATA(y&0XFF);
LCD_WR_DATA((lcddev.length-1)>>8);
LCD_WR_DATA((lcddev.length-1)&0XFF);
LCD->LCD_REG=lcddev.wramcmd;
LCD->LCD_RAM=color;
}
/*************************************************************************/
/*************************************************************************/
//SSD1963 背光设置
//pwm:背光等级,0~100.越大越亮.
void LCD_SSD_BackLightSet(uint8_t pwm)
{
LCD_WR_REG(0xBE); //配置PWM输出
LCD_WR_DATA(0x05); //1设置PWM频率
LCD_WR_DATA(pwm*2.55);//2设置PWM占空比
LCD_WR_DATA(0x01); //3设置C
LCD_WR_DATA(0xFF); //4设置D
LCD_WR_DATA(0x00); //5设置E
LCD_WR_DATA(0x00); //6设置F
}
/*************************************************************************/
/*************************************************************************/
//设置LCD显示方向
//dir:0,竖屏;1,横屏
void LCD_Display_Dir(uint8_t Dir, uint8_t Scan_Dir )//横屏还是竖屏,看个人需要
{
lcddev.dir=Dir; //竖屏/横屏
lcddev.wramcmd=0X2C;
lcddev.setxcmd=0X2A;
lcddev.setycmd=0X2B;
if(Dir==0) //竖屏
{
lcddev.width=320;//竖屏时屏幕的宽为320像素
lcddev.length=480;//竖屏时屏幕的长为480像素
}
else //横屏
{
lcddev.width=480;//横屏以后,原来的宽就要变成现在的长了,即480
lcddev.length=320;//横屏以后,原来的长就要变成现在的宽了,即320
}
LCD_Scan_Dir(Scan_Dir);
}
/*************************************************************************/
/*************************************************************************/
//设置窗口(对RGB屏无效),并自动设置画点坐标到窗口左上角(sx,sy).
//sx,sy:窗口起始坐标(左上角)
//width,length:窗口宽度和高度,必须大于0!!
//窗体大小:width*length.
void LCD_Set_Window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t length)//一般我们公用的代码都是坐标原点(0,0)在左上角,当然自己也是可以设置到其他的地方
{
uint16_t twidth,tlength;
twidth=sx+width-1;
tlength=sy+length-1;
}
/*************************************************************************/
/*************************************************************************/
//连续多点填充(适应touchgfx硬件接口)
//uint16_t* ptr
//numBytes:填充点数
void LCD_DrawSerialPoint(uint16_t* ptr, int16_t numBytes)
{
uint32_t index=0;
for(index=0;index<numBytes;numBytes++)
{
LCD->LCD_RAM=*ptr;
}
}
/*************************************************************************/
/*************************************************************************/
/**
* @brief SSD1963背光亮度设置函数
* @param pwm: 背光等级,0~100.越大越亮.
* @retval 无
*/
void lcd_ssd_backlight_set(uint8_t pwm)
{
LCD_WR_REG(0xBE); /* 配置PWM输出 */
LCD_WR_DATA(0x05); /* 1设置PWM频率 */
LCD_WR_DATA(pwm * 2.55); /* 2设置PWM占空比 */
LCD_WR_DATA(0x01); /* 3设置C */
LCD_WR_DATA(0xFF); /* 4设置D */
LCD_WR_DATA(0x00); /* 5设置E */
LCD_WR_DATA(0x00); /* 6设置F */
}
/*************************************************************************/
/*************************************************************************/
/*read id*/
uint16_t Read_ID(void)
{
uint16_t id;
uint16_t id1,id2;
LCD_WR_REG(0xBF);
id= *(__IO uint16_t *) (Bank1_LCD_D);
id = *(__IO uint16_t *) (Bank1_LCD_D);
id = *(__IO uint16_t *) (Bank1_LCD_D);
id = *(__IO uint16_t *) (Bank1_LCD_D);
id1=*(__IO uint16_t *) (Bank1_LCD_D);
id2 = *(__IO uint16_t *) (Bank1_LCD_D);
id=(id1<<8)+id2;
return id;
}
/*************************************************************************/
/********************************下面这些代码是处理MPU的,对于使用FMC驱动LCD是必要的!!*********************************************/
//下面的代码先不要删!!
LCD MPU保护参数
//#define LCD_REGION_NUMBER MPU_REGION_NUMBER0 //LCD使用region0
//#define LCD_ADDRESS_START (0X60000000) //LCD区的首地址
//#define LCD_REGION_SIZE MPU_REGION_SIZE_256MB //LCD区大小
配置MPU的region(SRAM区域为透写模式)
//void LCD_MPU_Config(void)
//{
// MPU_Region_InitTypeDef MPU_Initure;
// HAL_MPU_Disable(); //配置MPU之前先关闭MPU,配置完成以后在使能MPU
// //外部SRAM为region0,大小为2MB,此区域可读写
// MPU_Initure.Enable=MPU_REGION_ENABLE; //使能region
// MPU_Initure.Number=LCD_REGION_NUMBER; //设置region,外部SRAM使用的region0
// MPU_Initure.BaseAddress=LCD_ADDRESS_START; //region基地址
// MPU_Initure.Size=LCD_REGION_SIZE; //region大小
// MPU_Initure.SubRegionDisable=0X00;
// MPU_Initure.TypeExtField=MPU_TEX_LEVEL0;
// MPU_Initure.AccessPermission=MPU_REGION_FULL_ACCESS; //此region可读写
// MPU_Initure.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE; //允许读取此区域中的指令
// MPU_Initure.IsShareable=MPU_ACCESS_NOT_SHAREABLE;
// MPU_Initure.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;
// MPU_Initure.IsBufferable=MPU_ACCESS_BUFFERABLE;
// HAL_MPU_ConfigRegion(&MPU_Initure);
// HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); //开启MPU
//}
/*****************************************************************************/
/*************************************************************************/
//初始化lcd
//该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
void LCD_Init(uint8_t dir, uint8_t Scan_Dir, uint32_t back_color)
{
uint16_t id;
HAL_Delay(50);
LCD_WR_REG(0XB0);
LCD_WR_DATA(0X04);
id=Read_ID(); //读id
printf(" The LCD'ID is: 0X%04X rn",id);//这里是读取屏幕ID用的,不同的屏幕,不同的FMC协议,得到的ID不一定完全相同,总而言之,能用就行!!!
LCD_WR_REG (0x3A);
LCD_WR_DATA(0x55);
LCD_WR_REG(0xB3);
LCD_WR_DATA(0x02);
LCD_WR_REG(0xB4); //Frequence
LCD_WR_DATA(0x00);
LCD_WR_REG (0xC0);
LCD_WR_DATA(0x03); //0013
LCD_WR_DATA(0xDF); //480
LCD_WR_DATA(0x40);
LCD_WR_DATA(0x12);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x43);
LCD_WR_REG (0xC1);//frame frequency
LCD_WR_DATA(0x05);//BCn,DIVn[1:0
LCD_WR_DATA(0x2f);//RTNn[4:0]
LCD_WR_DATA(0x08);// BPn[7:0]
LCD_WR_DATA(0x08);// FPn[7:0]
LCD_WR_DATA(0x00);
LCD_WR_REG (0xC4);
LCD_WR_DATA(0x63);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x08);
LCD_WR_REG (0xC8);//Gamma
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);//26
LCD_WR_DATA(0x30);//32
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);
LCD_WR_DATA(0x30);
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_REG (0xC9);//Gamma
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);//26
LCD_WR_DATA(0x30);//32
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);
LCD_WR_DATA(0x30);
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_REG (0xB6);
LCD_WR_DATA(0x00);
LCD_WR_REG (0xCA);//Gamma
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);//26
LCD_WR_DATA(0x30);//32
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x16);
LCD_WR_DATA(0x24);
LCD_WR_DATA(0x30);
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x3d);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x0c);
LCD_WR_DATA(0x04);
LCD_WR_REG (0xD0);
LCD_WR_DATA(0x95);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x3f);
LCD_WR_REG (0xD1);
LCD_WR_DATA(0x02);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x40);
LCD_WR_REG (0xE1);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xE2);
LCD_WR_DATA(0x80);
LCD_WR_REG (0x2A);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x3F);
LCD_WR_REG (0x2B);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0xDF);
LCD_WR_REG(0x11);
LCD_WR_REG(0x29);
LCD_WR_REG (0xC1);//frame frequency
LCD_WR_DATA(0x05);//BCn,DIVn[1:0]
LCD_WR_DATA(0x2f);//RTNn[4:0]
LCD_WR_DATA(0x08);//BPn[7:0]
LCD_WR_DATA(0x08);//FPn[7:0]
LCD_WR_DATA(0x00);
HAL_Delay(50);
LCD_Display_Dir(dir,Scan_Dir); //默认为竖屏
HAL_Delay(50);
LCD_Clear(back_color);
printf("The LCD_Init is done!!! rn");
}
/*************************************************************************/
/*************************************************************************/
//清屏函数
//color:要清屏的填充色
void LCD_Clear(uint32_t color)
{
uint32_t index=0;
uint32_t totalpoint=lcddev.width;
totalpoint*=lcddev.length; //得到总点数
LCD_SetCursor(0x0000,0x0000); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(index=0;index<totalpoint;index++)
{
LCD->LCD_RAM=color;
}
}
/*************************************************************************/
/*************************************************************************/
//在显示器上面以某一颜色填充像素点
//ulAmout_Point:要填充的像素点的总数目
//Color:像素颜色
//没有坐标可设
void LCD_Fill_1(uint32_t ulAmout_Point, uint16_t Color)
{
uint16_t i=0;
LCD_WR_REG(0x2C);
for (i=0;i<ulAmout_Point;i++) LCD_WR_DATA(Color);
}
/*************************************************************************/
/*************************************************************************/
void LCD_DrawCircle ( uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint16_t Color, 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 ++ )
{
LCD_DrawPoint_color ( usX_Center + sCurrentX, usY_Center + sCountY ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentX, usY_Center + sCountY ,Color);
LCD_DrawPoint_color ( usX_Center - sCountY, usY_Center + sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center - sCountY, usY_Center - sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentX, usY_Center - sCountY ,Color);
LCD_DrawPoint_color ( usX_Center + sCurrentX, usY_Center - sCountY ,Color);
LCD_DrawPoint_color ( usX_Center + sCountY, usY_Center - sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center + sCountY, usY_Center + sCurrentX ,Color);
}
else
{
LCD_DrawPoint_color ( usX_Center + sCurrentX, usY_Center + sCurrentY ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentX, usY_Center + sCurrentY ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentY, usY_Center + sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentY, usY_Center - sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center - sCurrentX, usY_Center - sCurrentY ,Color);
LCD_DrawPoint_color ( usX_Center + sCurrentX, usY_Center - sCurrentY ,Color);
LCD_DrawPoint_color ( usX_Center + sCurrentY, usY_Center - sCurrentX ,Color);
LCD_DrawPoint_color ( usX_Center + sCurrentY, usY_Center + sCurrentX ,Color);
}
sCurrentX ++;
if ( sError < 0 )
sError += 4 * sCurrentX + 6;
else
{
sError += 10 + 4 * ( sCurrentX - sCurrentY );
sCurrentY --;
}
}
}
/*************************************************************************/
/*************************************************************************/
//在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color)//与下面的这个函数功能是一样的!
{
uint16_t i,j;
uint16_t xlen=0;
xlen=ex-sx+1;
for(i=sy;i<=ey;i++)
{
LCD_SetCursor(sx,i); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(j=0;j<xlen;j++)LCD->LCD_RAM=color; //显示颜色
}
}
/*************************************************************************/
/*************************************************************************/
//在指定区域内填充指定颜色块
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)//与上面的这个函数功能是一样的!
{
uint16_t length,width;
uint16_t i,j;
width=ex-sx+1; //得到填充的宽度
length=ey-sy+1; //高度
for(i=0;i<length;i++)
{
LCD_SetCursor(sx,sy+i); //设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(j=0;j<width;j++)LCD->LCD_RAM=color[i*width+j];//写入数据
}
}
/*************************************************************************/
/*************************************************************************/
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
//color:画笔的颜色
void LCD_DrawLine_color(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint32_t color)//画有颜色的线的函数,给线的起点坐标(x1,y1)以及线的终点坐标(x2.y2)还有就是线的颜色color
{
uint16_t 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<=distance+1;t++ )//画线输出
{
LCD_DrawPoint_color(uRow,uCol,color);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
/*************************************************************************/
/*************************************************************************/
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)//画线函数,给线的起点坐标(x1,y1)以及线的终点坐标(x2.y2)
{
uint16_t 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<=distance+1;t++ )//画线输出
{
LCD_DrawPoint(uRow,uCol);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
/*************************************************************************/
/*************************************************************************/
//画矩形
//(x1,y1),(x2,y2):矩形的对角坐标
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t 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);
}
/*************************************************************************/
/*************************************************************************/
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r)
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0+a,y0-b); //5
LCD_DrawPoint(x0+b,y0-a); //0
LCD_DrawPoint(x0+b,y0+a); //4
LCD_DrawPoint(x0+a,y0+b); //6
LCD_DrawPoint(x0-a,y0+b); //1
LCD_DrawPoint(x0-b,y0+a);
LCD_DrawPoint(x0-a,y0-b); //2
LCD_DrawPoint(x0-b,y0-a); //7
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
}
}
/*************************************************************************/
/*************************************************************************/
//在指定位置画一个指定大小的空心的圆
//(x0,y0):中心点
//r :半径
//Color:圆的颜色
void LCD_Draw_Circle_Color(uint16_t x0, uint16_t y0, uint8_t r, uint16_t Color)//这是一个画空心圆的函数代码
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint_color(x0+a,y0-b,Color); //5
LCD_DrawPoint_color(x0+b,y0-a,Color); //0
LCD_DrawPoint_color(x0+b,y0+a,Color); //4
LCD_DrawPoint_color(x0+a,y0+b,Color); //6
LCD_DrawPoint_color(x0-a,y0+b,Color); //1
LCD_DrawPoint_color(x0-b,y0+a,Color);
LCD_DrawPoint_color(x0-a,y0-b,Color); //2
LCD_DrawPoint_color(x0-b,y0-a,Color); //7
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
}
}
/*************************************************************************/
/*************************************************************************/
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24/32
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode)
{
uint8_t temp,t1,t;
uint16_t y0=y;
uint8_t csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
for(t=0;t<csize;t++)
{
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 if(size==32)temp=asc2_3216[num][t]; //调用3216字体
else return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);
temp<<=1;
y++;
if(y>=lcddev.length)return; //超区域了
if((y-y0)==size)
{
y=y0;
x++;
if(x>=lcddev.width)return; //超区域了
break;
}
}
}
}
/*************************************************************************/
/*************************************************************************/
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24/32
//mode:叠加方式(1)还是非叠加方式(0)
//Color_Paint:字体的颜色
//Color_Background:要显示的字体的背景颜色
void LCD_ShowChar_Color(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode, uint16_t Color_Paint, uint16_t Color_Background)
{
uint8_t temp,t1,t;
uint16_t y0=y;
uint8_t csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
for(t=0;t<csize;t++)
{
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 if(size==32)temp=asc2_3216[num][t]; //调用3216字体
else return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)LCD_Fast_DrawPoint(x,y,Color_Paint);
else if(mode==0)LCD_Fast_DrawPoint(x,y,Color_Background);
temp<<=1;
y++;
if(y>=lcddev.length)return; //超区域了
if((y-y0)==size)
{
y=y0;
x++;
if(x>=lcddev.width)return; //超区域了
break;
}
}
}
}
/*************************************************************************/
/*************************************************************************/
//m^n函数
//返回值:m^n次方.
uint32_t LCD_Pow(uint8_t m, uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
/*************************************************************************/
/*************************************************************************/
//显示数字,高位为0,则不显示
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//color:颜色
//num:数值(0~4294967295);
void LCD_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/LCD_Pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+(size/2)*t,y,' ',size,0);
continue;
}else enshow=1;
}
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);
}
}
/*************************************************************************/
/*************************************************************************/
//显示数字,高位为0,还是显示
//x,y:起点坐标
//num:数值(0~999999999);
//len:长度(即要显示的位数)
//size:字体大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非叠加显示;1,叠加显示.
void LCD_ShowxNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0;t<len;t++)
{
temp=(num/LCD_Pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);
else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);
continue;
}else enshow=1;
}
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01);
}
}
/*************************************************************************/
/*************************************************************************/
//显示字符串
//x,y:起点坐标
//width,length:区域大小
//size:字体大小
//*p:字符串起始地址
uint16_t LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t length, uint8_t size, char *p)
{
uint8_t x0=x;
width+=x;
length+=y;
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{
if(x>=width){x=x0;y+=size;}
if(y>=length)break;//退出
LCD_ShowChar(x,y,*p,size,0);
x+=size/2;
p++;
}
return x;
}
/*************************************************************************/
/*************************************************************************/
//显示字符串
//x,y:起点坐标
//width,height:区域大小
//size:字体大小
//*p:字符串起始地址
//Color_Paint:字体的颜色
//Color_Background:要显示的字体的背景颜色
uint16_t LCD_ShowString_Background(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, char *p, uint16_t Color_Paint, uint16_t Color_Background)
{
uint8_t x0=x;
width+=x;
height+=y;
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{
if(x>=width){x=x0;y+=size;}//字体大小选择:12x12 16x16 24x24 32x32
if(y>=height)break;//退出
LCD_ShowChar_Color(x,y,*p,size,0,Color_Paint,Color_Background);
x+=size/2;
p++;
}
return x;
}
/*************************************************************************/
/*************************************************************************/
/**********************************************
函数名:Lcd块选函数
功能:选定Lcd上指定的矩形区域
注意:xStart、yStart、Xend、Yend随着屏幕的旋转而改变,位置是矩形框的四个角
入口参数:xStart x方向的起始点
ySrart y方向的起始点
Xend y方向的终止点
Yend y方向的终止点
返回值:无
***********************************************/
void BlockWrite(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend)
{
LCD_WR_REG(0x2a);
LCD_WR_DATA(Xstart>>8);
LCD_WR_DATA(Xstart&0xff);
LCD_WR_DATA(Xend>>8);
LCD_WR_DATA(Xend&0xff);
LCD_WR_REG(0x2b);
LCD_WR_DATA(Ystart>>8);
LCD_WR_DATA(Ystart&0xff);
LCD_WR_DATA(Yend>>8);
LCD_WR_DATA(Yend&0xff);
LCD_WR_REG(0x2c);
}
/*************************************************************************/
/*************************************************************************/
/**********************************************
函数名:Lcd块选函数
功能:选定Lcd上指定的矩形区域
注意:xStart和 yStart随着屏幕的旋转而改变,位置是矩形框的四个角
入口参数:xStart x方向的起始点
ySrart y方向的终止点
xLong 要选定矩形的x方向长度
yLong 要选定矩形的y方向长度
返回值:无
***********************************************/
void Lcd_ColorBox(uint16_t xStart, uint16_t yStart, uint16_t xLong, uint16_t yLong, uint16_t Color)
{
uint32_t temp;
BlockWrite(xStart,xStart+xLong-1,yStart,yStart+yLong-1);
for (temp=0; temp<xLong*yLong; temp++)
{
*(__IO uint16_t *) (Bank1_LCD_D) = Color;
}
}
/*************************************************************************/
/*************************************************************************/
/**
* @brief Displays picture.
* @param pData: picture address. 照片的数组地址
* @param Xpos: Image X position in the LCD 要显示的照片的初始位置的x轴坐标
* @param Ypos: Image Y position in the LCD 要显示的照片的初始位置的y轴坐标
* @param Xsize: Image X size in the LCD 要显示的照片的大小尺寸-x轴长度
* @param Ysize: Image Y size in the LCD 要显示的照片的大小尺寸-y轴长度
* @retval None
*/
void DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pData)//显示一张图片的函数,要配合一个图片转换工具完成
{
uint32_t index;
uint32_t ImageSize = 0;
uint16_t data;
ImageSize = (Xsize * Ysize);
BlockWrite(Xpos,Xpos+Xsize-1,Ypos,Ypos+Ysize-1);
for(index = 0; index < ImageSize; index++)
{
data=(*pData);
data+=(*(pData+1))<<8;
LCD_WR_DATA((uint16_t)data);
pData += 2;
}
}
/*************************************************************************/
下面是lcd.h的代码块:
#include "main.h"
#define lcd_width 320
#define lcd_heigth 480
//LCD重要参数集
typedef struct
{
uint16_t width; //LCD 宽度
uint16_t length; //LCD 高度
uint16_t id; //LCD ID
uint8_t dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
uint16_t wramcmd; //开始写gram指令
uint16_t setxcmd; //设置x坐标指令
uint16_t setycmd; //设置y坐标指令
}_lcd_dev;
#define LCD_DIR_VER 0 //竖屏
#define LCD_DIR_HOR 1 //横屏
//扫描方向定义
#define L2R_U2D 0 //从左到右,从上到下
#define L2R_D2U 1 //从左到右,从下到上
#define R2L_U2D 2 //从右到左,从上到下
#define R2L_D2U 3 //从右到左,从下到上
#define U2D_L2R 4 //从上到下,从左到右
#define U2D_R2L 5 //从上到下,从右到左
#define D2U_L2R 6 //从下到上,从左到右
#define D2U_R2L 7 //从下到上,从右到左
#define WHITE 0xFFFF//白色
#define BLACK 0x0000//黑色
#define BLUE 0x001F//蓝色
#define BRED 0XF81F//
#define GRED 0XFFE0//
#define GBLUE 0X07FF//
#define RED 0xF800//红色
#define MAGENTA 0xF81F//
#define GREEN 0x07E0//绿色
#define CYAN 0x7FFF//
#define YELLOW 0xFFE0//黄色
#define BROWN 0XBC40//棕色
#define BRRED 0XFC07//棕红色
#define GRAY 0X8430//灰色
#define DARKBLUE 0X01CF//深蓝色
#define LIGHTBLUE 0X7D7C//浅蓝色
#define GRAYBLUE 0X5458//灰蓝色
#define LIGHTGREEN 0X841F//浅绿色
#define LIGHTGRAY 0XEF5B//浅灰色(PANNEL)
#define LGRAY 0XC618//浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651//浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12//浅棕蓝色(选择条目的反色)
//LCD地址结构体
typedef struct
{
__IO uint16_t LCD_REG;
__IO uint16_t LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线
//注意设置时STM32内部会右移一位对其! 111 1110=0X7E
#define LCD_BASE ((uint32_t)(0x60000000 | 0x0001fffe))
/* 选择BANK1-BORSRAM1 连接 TFT,地址范围为0X60000000~0X63FFFFFF
* FSMC_A16 接LCD的DC(寄存器/数据选择)脚
* 16 bit => FSMC[24:0]对应HADDR[25:1]
* 寄存器基地址 = 0X60000000
* RAM基地址 = 0X60020000 = 0X60000000+2^16*2 = 0X60000000 + 0X20000 = 0X60020000
* 当选择不同的地址线时,地址要重新计算。
*/
#define Bank1_LCD_D ((uint32_t)0x60020000) //Disp Data ADDR
#define Bank1_LCD_C ((uint32_t)0x60000000) //Disp Reg ADDR
#define LCD ((LCD_TypeDef *) LCD_BASE)
/******************************************************************************/
void LCD_Init(uint8_t dir, uint8_t Scan_Dir, uint32_t back_color); //初始化
void LCD_Clear(uint32_t Color); //清屏
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos); //设置光标
void LCD_DrawPoint(uint16_t x, uint16_t y);
void LCD_DrawPoint_color(uint16_t x, uint16_t y, uint32_t color);
void LCD_Fast_DrawPoint(uint16_t x, uint16_t y, uint32_t color); //快速画点
void LCD_DrawSerialPoint(uint16_t* ptr, int16_t numBytes);//连续多点填充(适应touchgfx硬件接口)
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r); //画圆
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); //画线
void LCD_DrawLine_color(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color);//画有颜色的线
//void LCD_MPU_Config(void);//初始化MPU函数
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); //画矩形
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint32_t color); //填充单色
void LCD_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color); //填充指定颜色
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode); //显示一个字符
void LCD_ShowChar_Color(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode, uint16_t Color_Paint, uint16_t Color_Background);
void LCD_ShowNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size); //显示一个数字
void LCD_ShowxNum(uint16_t x, uint16_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode); //显示 数字
uint16_t LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t length, uint8_t size,char *p); //显示一个字符串,12/16字体
uint16_t LCD_ShowString_Background(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size,char *p, uint16_t Color_Paint, uint16_t Color_Background);
void DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pData);
void Lcd_ColorBox(uint16_t xStart, uint16_t yStart, uint16_t xLong, uint16_t yLong, uint16_t Color);
void BlockWrite(unsigned int Xstart, unsigned int Xend, unsigned int Ystart, unsigned int Yend);
void LCD_Draw_Circle_Color(uint16_t x0, uint16_t y0, uint8_t r, uint16_t Color);
void LCD_DrawCircle( uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint16_t Color, uint8_t ucFilled);
void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);
uint16_t LCD_ReadReg(uint16_t LCD_Reg);
uint16_t Read_ID(void);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(uint16_t RGB_Code);
void LCD_SSD_BackLightSet(uint8_t pwm); //SSD1963 背光控制
void LCD_Scan_Dir(uint8_t dir); //设置屏扫描方向
void LCD_Display_Dir(uint8_t Dir , uint8_t Scan_Dir ); //设置屏幕显示方向
void LCD_Set_Window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t length); //设置窗口
最终显示效果:
最后
以上就是贪玩手机最近收集整理的关于STM32H750V8T6通过CUBEMX工具生成驱动TFTLCD的相关代码操作!的全部内容,更多相关STM32H750V8T6通过CUBEMX工具生成驱动TFTLCD内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复