TFTLCD---8080并行接口转换SPI接口

基于正点原子阿波罗F429开发板:

实验12 TFTLCD(MCU屏)实验项目制作

将发送数据并口改为串行发送:

lcd.c

#include "lcd.h"
#include "stdlib.h"
#include "font.h"
#include "usart.h"
#include "delay.h"
//
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//2.8寸/3.5寸/4.3寸/7寸 TFT液晶驱动
//支持驱动IC型号包括:ILI9341/NT35310/NT35510/SSD1963/ST7789/ST7796/ILI9806等
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/1/16
//版本:V1.5
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//********************************************************************************
//修改说明
//V1.2 20211111
//1,新增对ST7789驱动IC的支持
//V1.3 20211208
//修改NT5510 ID读取方式,改为先发送秘钥,然后读取C500和C501,从而获取正确的ID(0X5510)
//V1.4 20211222
//解决因NT5510 ID读取(发送C501指令)导致SSD1963误触发软件复位进而读取不到ID问题,加延时解决
//V1.5 20230608
//新增对ST7796和ILI9806 IC支持
//


//LCD的画笔颜色和背景色
u32 POINT_COLOR = 0xFF000000;		//画笔颜色
u32 BACK_COLOR = 0xFFFFFFFF;  	//背景色

//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;



/****************************/
void LCD_Writ_Bus(char dat)   //串行数据写入
{	
	u8 i;			  
  

	for(i=0;i<8;i++)
	{			  
		OLED_SCLK_Clr();
		if(dat&0x80)
		   OLED_SDIN_Set();
		else 
		   OLED_SDIN_Clr();
		OLED_SCLK_Set();
		dat<<=1;   
	}			
}

/*****************************/
void LCD_WR_DATA8(char da) //发送数据-8位参数
{	//OLED_CS_Clr();
    OLED_DC_Set();
	LCD_Writ_Bus(da);  
	//OLED_CS_Set;
}  
//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(vu16 regval)
{
//    regval = regval;		//使用-O2优化的时候,必须插入的延时
//    LCD->LCD_REG = regval; //写入要写的寄存器序号
	
	//	OLED_CS_Clr();
    OLED_DC_Clr();
	LCD_Writ_Bus(regval>>8);
    LCD_Writ_Bus(regval);
	//OLED_CS_Set();
}
//写LCD数据
//data:要写入的值
void LCD_WR_DATA(vu16 data)
{
//    data = data;			//使用-O2优化的时候,必须插入的延时
//    LCD->LCD_RAM = data;
	
	//	OLED_CS_Clr();
    OLED_DC_Set();
	LCD_Writ_Bus(data>>8);
    LCD_Writ_Bus(data);
	//OLED_CS_Set();
}
//读LCD数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{
    vu16 ram;			//防止被优化
   
    return ram;
}
//写寄存器
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)
{
//    LCD->LCD_REG = LCD_Reg;		//写入要写的寄存器序号
//    LCD->LCD_RAM = LCD_RegValue;//写入数据
	
	//OLED_CS_Clr();
    LCD_WR_REG(LCD_Reg);
		LCD_WR_DATA(LCD_RegValue);
	//OLED_CS_Set();
}
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
u16 LCD_ReadReg(u16 LCD_Reg)
{
    LCD_WR_REG(LCD_Reg);		//写入要读的寄存器序号
    delay_us(5);
    return LCD_RD_DATA();		//返回读到的值
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
    LCD_WR_REG(lcddev.wramcmd);		//写入要读的寄存器序号
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{
    LCD_WR_REG(RGB_Code);//写十六位GRAM
}
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
u16 LCD_BGR2RGB(u16 c)
{
    u16  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(u8 i)
{
    while (i--);
}

//LCD开启显示
void LCD_DisplayOn(void)
{
    if (lcddev.id == 0X5510)    //5510开启显示指令
    {
        LCD_WR_REG(0X2900);     //开启显示
    }
    else                        //9341/5310/1963/7789/7796/9806 等发送开启显示指令
    {
        LCD_WR_REG(0X29);       //开启显示
    }
}
//LCD关闭显示
void LCD_DisplayOff(void)
{
    if (lcddev.id == 0X5510)    //5510关闭显示指令
    {
        LCD_WR_REG(0X2800);     //关闭显示
    }
    else                        //9341/5310/1963/7789/7796/9806 等发送关闭显示指令
    {
        LCD_WR_REG(0X28);       //关闭显示
    }
}
//设置光标位置(对RGB屏无效)
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
//				lcddev.setxcmd = 0x2a;
//				lcddev.setycmd = 0x2b;
//        LCD_WR_REG(lcddev.setxcmd);
//        LCD_WR_DATA(Xpos >> 8);
//        LCD_WR_DATA(Xpos & 0XFF);
//        LCD_WR_REG(lcddev.setycmd);
//        LCD_WR_DATA(Ypos >> 8);
//        LCD_WR_DATA(Ypos & 0XFF);
	
	LCD_WR_REG(0x2a);
   LCD_WR_DATA8(Xpos>>8);
   LCD_WR_DATA8(Xpos);
	LCD_WR_DATA8(Xpos>>8);
	
   LCD_WR_REG(0x2b);
   LCD_WR_DATA8(Ypos>>8);
   LCD_WR_DATA8(Ypos);
	LCD_WR_DATA8(Ypos>>8);
   LCD_WR_DATA8(Ypos);
	
	  LCD_WR_REG(0x2C);	
  
}
void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{ 
	LCD_WR_REG(0x2a);
   LCD_WR_DATA8(x1>>8);
   LCD_WR_DATA8(x1);
   LCD_WR_DATA8(x2>>8);
   LCD_WR_DATA8(x2);
  
   LCD_WR_REG(0x2b);
   LCD_WR_DATA8(y1>>8);
   LCD_WR_DATA8(y1);
   LCD_WR_DATA8(y2>>8);
   LCD_WR_DATA8(y2);

   LCD_WR_REG(0x2C);					 						 
}
//设置LCD的自动扫描方向(对RGB屏无效)
//注意:其他函数可能会受到此函数设置的影响(尤其是9341),
//所以,一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
//dir:0~7,代表8个方向(具体定义见lcd.h)
//9341/5310/5510/1963/7789等IC已经实际测试
void LCD_Scan_Dir(u8 dir)
{
   
        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.height - 1) >> 8);
        LCD_WR_DATA((lcddev.height - 1) & 0XFF);
   
}
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x, u16 y)
{
    LCD_SetCursor(x, y);		//设置光标位置
//    LCD_WriteRAM_Prepare();	//开始写入GRAM
    LCD_WR_DATA(POINT_COLOR);
}
//快速画点
//x,y:坐标
//color:颜色
void LCD_Fast_DrawPoint(u16 x, u16 y, u32 color)
{
    LCD_SetCursor(x, y);		//设置光标位置
//    LCD_WriteRAM_Prepare();	//开始写入GRAM
    LCD_WR_DATA(color);
}
//SSD1963 背光设置
//pwm:背光等级,0~100.越大越亮.
void LCD_SSD_BackLightSet(u8 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(u8 dir)
{
     lcddev.dir = dir;       //竖屏/横屏

    if (dir == 0)           //竖屏
    {
        lcddev.width = 240;
        lcddev.height = 320;     
    }
    else     //横屏
    {
        lcddev.width = 320;
        lcddev.height = 240;

        
    }

//    LCD_Scan_Dir(DFT_SCAN_DIR);     //默认扫描方向
}

//设置窗口(对RGB屏无效),并自动设置画点坐标到窗口左上角(sx,sy).
//sx,sy:窗口起始坐标(左上角)
//width,height:窗口宽度和高度,必须大于0!!
//窗体大小:width*height.
void LCD_Set_Window(u16 sx, u16 sy, u16 width, u16 height)
{
    u16 twidth, theight;
    twidth = sx + width - 1;
    theight = sy + height - 1;

    if (lcddev.id == 0X1963 && lcddev.dir != 1)     //1963竖屏特殊处理
    {
        sx = lcddev.width - width - sx;
        height = sy + height - 1;
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_DATA((sx + width - 1) >> 8);
        LCD_WR_DATA((sx + width - 1) & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_DATA(height >> 8);
        LCD_WR_DATA(height & 0XFF);
    }
    else if (lcddev.id == 0X5510)
    {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_REG(lcddev.setxcmd + 1);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_REG(lcddev.setxcmd + 2);
        LCD_WR_DATA(twidth >> 8);
        LCD_WR_REG(lcddev.setxcmd + 3);
        LCD_WR_DATA(twidth & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_REG(lcddev.setycmd + 1);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_REG(lcddev.setycmd + 2);
        LCD_WR_DATA(theight >> 8);
        LCD_WR_REG(lcddev.setycmd + 3);
        LCD_WR_DATA(theight & 0XFF);
    }
    else     //9341/5310/7789/1963/7796/9806横屏 等 设置窗口
    {
        LCD_WR_REG(lcddev.setxcmd);
        LCD_WR_DATA(sx >> 8);
        LCD_WR_DATA(sx & 0XFF);
        LCD_WR_DATA(twidth >> 8);
        LCD_WR_DATA(twidth & 0XFF);
        LCD_WR_REG(lcddev.setycmd);
        LCD_WR_DATA(sy >> 8);
        LCD_WR_DATA(sy & 0XFF);
        LCD_WR_DATA(theight >> 8);
        LCD_WR_DATA(theight & 0XFF);
    }
}

//初始化lcd
//该初始化函数可以初始化各种型号的LCD(详见本.c文件最前面的描述)
void LCD_Init(void)
{
     GPIO_InitTypeDef GPIO_Initure;
    
   __HAL_RCC_GPIOB_CLK_ENABLE();       //使能GPIOB时钟
		//PB6,7,8,9
    GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;             
    GPIO_Initure.Pull=GPIO_PULLUP;                  //上拉
    GPIO_Initure.Speed=GPIO_SPEED_FAST;             //快速            
    HAL_GPIO_Init(GPIOB,&GPIO_Initure);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);	//PB6置1  
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);	//PB7置1  
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);	//PB8置1 
	  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);	//PB9置1 
		printf("\r\n 串行TFFTLCD屏幕引脚: DC:PB6 RES:PB7 SDA:PB8 SCK:PB9 \r\n");

    
    /* 特别注意, 如果在main函数里面屏蔽串口1初始化, 则会卡死在printf
     * 里面(卡死在f_putc函数), 所以, 必须初始化串口1, 或者屏蔽掉下面
     * 这行 printf 语句 !!!!!!!
     */
    printf(" LCD ID:%x\r\n", lcddev.id); //打印LCD ID

     //7789初始化
		 
				 //OLED_CS_Clr();  //打开片选使能
			 OLED_RST_Clr();
			delay_ms(20);
			OLED_RST_Set();
			delay_ms(20);
			//	OLED_BLK_Set;
    
//        LCD_WR_REG(0x11);

//        delay_ms(120);

        LCD_WR_REG(0x36); 
				LCD_WR_DATA8(0x00);

				LCD_WR_REG(0x3A); 
				LCD_WR_DATA8(0x05);

				LCD_WR_REG(0xB2);
				LCD_WR_DATA8(0x0C);
				LCD_WR_DATA8(0x0C);
				LCD_WR_DATA8(0x00);
				LCD_WR_DATA8(0x33);
				LCD_WR_DATA8(0x33);

				LCD_WR_REG(0xB7); 
				LCD_WR_DATA8(0x35);  

				LCD_WR_REG(0xBB);
				LCD_WR_DATA8(0x19);

				LCD_WR_REG(0xC0);
				LCD_WR_DATA8(0x2C);

				LCD_WR_REG(0xC2);
				LCD_WR_DATA8(0x01);

				LCD_WR_REG(0xC3);
				LCD_WR_DATA8(0x12);   

				LCD_WR_REG(0xC4);
				LCD_WR_DATA8(0x20);  

				LCD_WR_REG(0xC6); 
				LCD_WR_DATA8(0x0F);    

				LCD_WR_REG(0xD0); 
				LCD_WR_DATA8(0xA4);
				LCD_WR_DATA8(0xA1);

				LCD_WR_REG(0xE0);
				LCD_WR_DATA8(0xD0);
				LCD_WR_DATA8(0x04);
				LCD_WR_DATA8(0x0D);
				LCD_WR_DATA8(0x11);
				LCD_WR_DATA8(0x13);
				LCD_WR_DATA8(0x2B);
				LCD_WR_DATA8(0x3F);
				LCD_WR_DATA8(0x54);
				LCD_WR_DATA8(0x4C);
				LCD_WR_DATA8(0x18);
				LCD_WR_DATA8(0x0D);
				LCD_WR_DATA8(0x0B);
				LCD_WR_DATA8(0x1F);
				LCD_WR_DATA8(0x23);

				LCD_WR_REG(0xE1);
				LCD_WR_DATA8(0xD0);
				LCD_WR_DATA8(0x04);
				LCD_WR_DATA8(0x0C);
				LCD_WR_DATA8(0x11);
				LCD_WR_DATA8(0x13);
				LCD_WR_DATA8(0x2C);
				LCD_WR_DATA8(0x3F);
				LCD_WR_DATA8(0x44);
				LCD_WR_DATA8(0x51);
				LCD_WR_DATA8(0x2F);
				LCD_WR_DATA8(0x1F);
				LCD_WR_DATA8(0x1F);
				LCD_WR_DATA8(0x20);
				LCD_WR_DATA8(0x23);

				LCD_WR_REG(0x21); 

				LCD_WR_REG(0x11); 
				//Delay (120); 

				LCD_WR_REG(0x29); 
    
   
    LCD_Display_Dir(0);		//默认为竖屏
    LCD_LED = 1;				//点亮背光
    LCD_Clear(GRED);
}
//清屏函数
//color:要清屏的填充色
void LCD_Clear(u32 color)
{
    u32 index = 0;
    u32 totalpoint = lcddev.width;
    totalpoint *= lcddev.height; 			//得到总点数
    Address_set(0,0,lcddev.width-1,lcddev.height-1);
//		LCD_SetCursor(0,0);
    for (index = 0; index < totalpoint; index++)
    {
        LCD_WR_DATA(color);	
    }
}
//在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u32 color)
{
    u16 i, j;
    u16 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_WR_DATA(color);	//显示颜色
    }
}
//在指定区域内填充指定颜色块
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16 *color)
{
    u16 height, width;
    u16 i, j;
    width = ex - sx + 1; 			//得到填充的宽度
    height = ey - sy + 1;			//高度

    for (i = 0; i < height; i++)
    {
        LCD_SetCursor(sx, sy + i);   	//设置光标位置
//        LCD_WriteRAM_Prepare();     //开始写入GRAM

        for (j = 0; j < width; j++)LCD_WR_DATA(color[i * width + j]); //写入数据
    }
}
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
    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 <= 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(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);
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r    :半径
void LCD_Draw_Circle(u16 x0, u16 y0, u8 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--;
        }
    }
}
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24/32
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x, u16 y, u8 num, u8 size, u8 mode)
{
	u8 temp;
	u8 pos,t;
	u16 x0=x;    
	u8 csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);		//得到字体一个字符对应点阵集所占的字节数  
	num=num-' ';//得到偏移后的值
	if(!mode) //非叠加方式
	{
		for(pos=0;pos<csize;pos++)
		{ 
			temp=asc2_1608[num][pos];		 //调用1608字体
			for(t=0;t<8;t++)
		    {                 
		        if(temp&0x01)LCD_Fast_DrawPoint(x, y, POINT_COLOR);
				else LCD_Fast_DrawPoint(x, y, BACK_COLOR);
				temp>>=1; 
				x++;
		    }
			x=x0;
			y++;
		}	
	}else//叠加方式
	{
		for(pos=0;pos<16;pos++)
		{
		    temp=asc2_1608[num][pos];		 //调用1608字体
			for(t=0;t<8;t++)
		    {                 
		        if(temp&0x01)LCD_Fast_DrawPoint(x+t,y+pos, POINT_COLOR);//画一个点     
		        temp>>=1; 
		    }
		}
	}
}
//m^n函数
//返回值:m^n次方.
u32 LCD_Pow(u8 m, u8 n)
{
    u32 result = 1;

    while (n--)result *= m;

    return result;
}
//显示数字,高位为0,则不显示
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//color:颜色
//num:数值(0~4294967295);
void LCD_ShowNum(u16 x, u16 y, u32 num, u8 len, u8 size)
{
    u8 t, temp;
    u8 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(u16 x, u16 y, u32 num, u8 len, u8 size, u8 mode)
{
    u8 t, temp;
    u8 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,height:区域大小
//size:字体大小
//*p:字符串起始地址
void LCD_ShowString(u16 x, u16 y, u16 width, u16 height, u8 size, u8 *p)
{
    u8 x0 = x;
    width += x;
    height += y;

    while ((*p <= '~') && (*p >= ' ')) //判断是不是非法字符!
    {
        if (x >= width)
        {
            x = x0;
            y += size;
        }

        if (y >= height)break; //退出

        LCD_ShowChar(x, y, *p, size, 0);
        x += size / 2;
        p++;
    }
}

串口发送可以直接使用SPI进行发送,为了以后使用DMA进行发送,使用SPI记得提前做好引脚配置。

void SPI_LCD_Writ_Bus_ex(u8 dat,u8 channel)   //串行数据写入
{	
//	u8 i;			  
//  

//	for(i=0;i<8;i++)
//	{			  
//		SPI_OLED_SCLK_Clr;
//		if(dat&0x80)
//		   SPI_OLED_SDIN_Set;
//		else 
//		   SPI_OLED_SDIN_Clr;
//		SPI_OLED_SCLK_Set;
//		dat<<=1;   
//	}
	if(channel == 0 ){		//串口发出
		SPI2_WriteByte(dat);
	}
	if(channel == 1){			//spi发出,为未来DMA发送做准备
		LCD_Writ_Bus_ex(dat);
	}		
}

lcd.h

#ifndef __LCD_H
#define __LCD_H		
#include "sys.h"	 
#include "stdlib.h" 
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//2.8寸/3.5寸/4.3寸/7寸 TFT液晶驱动	  
//支持驱动IC型号包括:ILI9341/NT35310/NT35510/SSD1963/ST7789/ST7796/ILI9806等
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2015/12/9
//版本:V1.5
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved	 
//********************************************************************************
//修改说明
//V1.2 20211111
//1,新增对ST7789驱动IC的支持
//V1.3 20211208
//修改NT5510 ID读取方式,改为先发送秘钥,然后读取C500和C501,从而获取正确的ID(0X5510)
//V1.4 20211222
//解决因NT5510 ID读取(发送C501指令)导致SSD1963误触发软件复位进而读取不到ID问题,加延时解决
//V1.5 20230608
//新增对ST7796和ILI9806 IC支持
//	 

//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参数
extern _lcd_dev lcddev;	//管理LCD重要参数
//LCD的画笔颜色和背景色	   
extern u32  POINT_COLOR;//默认红色    
extern u32  BACK_COLOR; //背景颜色.默认为白色


//	 
//-----------------MCU屏 LCD端口定义---------------- 
#define	LCD_LED PBout(5) 	//LCD背光	PB5	    

//
	 
//扫描方向定义
#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 DFT_SCAN_DIR  L2R_U2D  //默认的扫描方向

//画笔颜色
#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 //灰色
//GUI颜色

#define DARKBLUE      	 0X01CF	//深蓝色
#define LIGHTBLUE      	 0X7D7C	//浅蓝色  
#define GRAYBLUE       	 0X5458 //灰蓝色
//以上三色为PANEL的颜色 
 
#define LIGHTGREEN     	 0X841F //浅绿色
//#define LIGHTGRAY        0XEF5B //浅灰色(PANNEL)
#define LGRAY 			 0XC618 //浅灰色(PANNEL),窗体背景色

#define LGRAYBLUE        0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE           0X2B12 //浅棕蓝色(选择条目的反色)
	    															  
void LCD_Init(void);													   	//初始化
void LCD_DisplayOn(void);													//开显示
void LCD_DisplayOff(void);													//关显示
void LCD_Clear(u32 Color);	 												//清屏
void LCD_SetCursor(u16 Xpos, u16 Ypos);										//设置光标
void LCD_DrawPoint(u16 x,u16 y);											//画点
void LCD_Fast_DrawPoint(u16 x,u16 y,u32 color);								//快速画点
u32  LCD_ReadPoint(u16 x,u16 y); 											//读点 
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);						 			//画圆
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);							//画线
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);		   				//画矩形
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color);		   				//填充单色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);				//填充指定颜色
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);						//显示一个字符
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size);  						//显示一个数字
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);				//显示 数字
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);		//显示一个字符串,12/16字体

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue);
u16 LCD_ReadReg(u16 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
void LCD_SSD_BackLightSet(u8 pwm);							//SSD1963 背光控制
void LCD_Scan_Dir(u8 dir);									//设置屏扫描方向
void LCD_Display_Dir(u8 dir);								//设置屏幕显示方向
void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height);	//设置窗口					   						   																			 
//LCD分辨率设置
#define SSD_HOR_RESOLUTION		240		//LCD水平分辨率
#define SSD_VER_RESOLUTION		320		//LCD垂直分辨率


//-----------------OLED端口定义----------------  					   
#define OLED_SCLK_Clr() 		PBout(9)=0	//PB9置0 //CLK
#define OLED_SCLK_Set()     PBout(9)=1	//PB9置1 

#define OLED_SDIN_Clr() 		PBout(8)=0//DIN
#define OLED_SDIN_Set() 		PBout(8)=1

#define OLED_RST_Clr()			PBout(7)=0//RES
#define OLED_RST_Set()			PBout(7)=1

#define OLED_DC_Clr()			PBout(6)=0//DC
#define OLED_DC_Set() 			PBout(6)=1



#endif  

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
/************************************************
 ALIENTEK 阿波罗STM32F429开发板实验12
 TFTLCD显示实验--HAL库函数版
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com  
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/


int main(void)
{
		u8 zf_h = 16;
    u32 tt=0;
    HAL_Init();                     //初始化HAL库   
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED 
//		lcddev.setxcmd = 0x2a;
//		lcddev.setycmd = 0x2b;	
    LCD_Init();	                    //初始化LCD 
    POINT_COLOR=RED; 
		LCD_Clear(WHITE); 
		LCD_ShowString(10,110,SSD_HOR_RESOLUTION,zf_h,zf_h,"ATOM@ALIENTEK");      					 
		LCD_ShowString(10,150,SSD_HOR_RESOLUTION,zf_h,zf_h,"2025/1/6");	    
    while(1)
    {
     tt= tt+1;
		LCD_ShowxNum(10,10,tt,8,zf_h,0);	
		LED0=!LED0;	 
		delay_ms(100);	
	}
}
相关推荐
暗碳1 小时前
stm32 74hc238流水灯
stm32·单片机·嵌入式硬件
1101 11011 小时前
STM32-温湿度上传OneNET项目
stm32·单片机·嵌入式硬件
余衫马2 小时前
ESP32-S3 实战指南:BOOT-KEY 按键驱动开发全解析
驱动开发·单片机·嵌入式硬件
文军的烹饪实验室5 小时前
处理器架构、单片机、芯片、光刻机之间的关系
单片机·嵌入式硬件·架构
Leiditech__6 小时前
人工智能时代电子机器人静电问题及电路设计防范措施
人工智能·嵌入式硬件·机器人·硬件工程
jmlinux6 小时前
STM32 HAL库USART串口DMA IDLE中断编程:避坑指南
stm32·单片机·嵌入式硬件
沐欣工作室_lvyiyi8 小时前
基于单片机的智能电表设计(论文+源码)
单片机·嵌入式硬件·电能表·数字电能表
半导体老登8 小时前
新能源汽车核心元件揭秘:二极管、三极管结构与工作原理解析(2/2)
人工智能·单片机·嵌入式硬件·汽车
猿~~~10 小时前
STM32的HAL库开发---多通道ADC采集(DMA读取)实验
stm32·单片机·嵌入式硬件
Freak嵌入式11 小时前
开源一款I2C电机驱动扩展板-FreakStudio多米诺系列
嵌入式硬件·嵌入式·智能硬件·开源硬件·micropython·电机驱动·电子模块