LCD屏幕

一、LCD屏幕的介绍

        TFTLCD的全称是Thin Film Transistor Liquid Crystal Display,即薄膜晶体管液晶显示器。它是一种使用薄膜晶体管作为开关器件来控制液晶像素的显示技术。TFTLCD屏幕的工作原理基于液晶分子的电光效应,通过薄膜晶体管控制液晶分子的扭曲与排列,从而实现像素的开关与亮度的调节。每个像素都由红色(R)、绿色(G)和蓝色(B)子像素组成,每个子像素都有自己的TFT。这些TFT就像开关一样,控制向每个子像素发送多少电压,当背光和滤色器一起工作时,TFT屏幕可以显示各种颜色和亮度级别。

二、LCD屏幕的特点及原理

1、LCD的特点

位置原则: 行和列来确定具体起始位置

刷屏原则: 逐行刷屏

数据原则: 一个像素点由十六位二进制控制,十六位数据就是一个像素点的颜色数据

                   取模软件的数据表示是否要打点,用来判断的;一位表示一个点;

                   如果要打点传入颜色数据

显示规则:

通过确定起始横坐标和纵坐标,结束横坐标和纵坐标来确定一个区域

区域里有多少个像素点,就传多少次颜色

2、LCD的显示原理

打开背光灯后,通过偏光片的折射,点亮每一个像素点,使之屏幕显示设定好的颜色

屏幕点亮的条件:

  1. 颜色设定
  2. 打开背光灯

3、LCD的显示过程

LCD显示系统

        LCD显示系统的构成分成三部分:MCU、LCD显示驱动芯片、LCD屏。

        CPU将要显示的数据通过地址总线和数据总线发送给LCD显示驱动器,LCD显示驱动器经过一系列处理得到三基色数据,LCD显示驱动器将三基色数据送给TFT-LCD液晶屏显示。

LCD屏幕的相关参数

分辨率:屏幕上能显示的像素点的个数,对于显示器分辨率是指显示器所能显示点数的多少,包括水平分辨率和垂直分辨率。对于TFT-LCD显示器来说,像素的数目和分辨率在数值上是相等的,都等于屏幕上横向和纵向点个数的乘积

帧:显示屏显示一副完整的画面即为一帧。

像素:是由图像和元素两个字母组成。是构成数字图像的最小单位。若把数字图像放大数倍,就会发现数字图像其实是由许多色彩相近的小方格所组成,这些小方格点就是“像素”。

颜色位深:表示RGB颜色的二进制位数。

例:

      24色位深 RGB

        R   G   B

        8   8   8    255

      16位色位深

        R   G   B

        5   6   5   16位   2个字节 要想给一个像素点传入颜色,实际就是给这个像素点传2个字节数据

        发送原则:先高位后低位

三、LCD屏幕的使用过程

1、LCD驱动芯片

 ST7789VM驱动芯片介绍

        本款LCD的驱动芯片是ST7789VM

     显存:显示数据RAM的240x320x18 = 1,382,400 bits,而这款LCD显示所需的内存是240*240*16

        显存,即显示内存,是驱动芯片中用于存储图像数据的存储区域。它负责将接收到的图像数据(如RGB信号)暂存起来,并根据显示控制逻辑将这些数据发送到TFT-LCD显示屏上进行显示。显存的大小和性能直接影响屏幕的分辨率、颜色深度和刷新率等关键参数。    

 通信接口

根据原理图可知,选用的SPI通信  4线 --- 由于不需要返回给内核,所以MISO不需要接

引脚描述

SCK:时钟引脚,用于SPI通信的时钟信号。

MOSI:主输出从输入引脚,用于SPI通信的数据输入。

CS:片选线,用于内核与屏幕的通信,片选线拉低起到断开通信的作用

RST:复位引脚,用于芯片复位操作。不接在最小系统的复位电路上的话,就需要单独接在某个IO口上,以便驱动芯片的启动,所以需要写复位程序  100ms低电平

DCX数据/命令选择引脚,用于区分传输的是数据还是命令。在4-wire模式下,DCX信号线的低电平表示传输的是命令,而高电平则表示传输的是数据

原理图

结合芯片引脚与原理图可得,各引脚连接如下:

LEDK---------------------------------PB1         背光灯引脚        //通用输出   高电平

RESET-------------------------------PB10        复位引脚          //通用输出

LCD_CS------------------------------PB12        片选引脚          //通用输出

LCD_D/C----------------------------PB14        数据命令选择线    //通用输出

LCD_CLK----------------------------PB13        时钟线            //通用输出    ----模拟SPI   

LCD_SDA----------------------------PB15        数据线            //通用输出  - ------模拟SPI

程序设计

程序中所用到的宏定义:

#define LCD_W  240
#define LCD_H  240

/* 背景色 */
#define Backgroundcolor 1
#define NoBackgroundcolor 0


/* 颜色定义开始 */
#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 LGRAY 			 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE        0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE           0X2B12 //浅棕蓝色(选择条目的反色)
/* 颜色定义结束 */

#define LCD_SPI_SCL_H 	    GPIO_SetBits(GPIOB, GPIO_Pin_13)
#define LCD_SPI_SCL_L   	GPIO_ResetBits(GPIOB, GPIO_Pin_13)
#define LCD_MOSI_H 			GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define LCD_MOSI_L 			GPIO_ResetBits(GPIOB, GPIO_Pin_15)

#define LCD_RES_H 	  GPIO_SetBits(GPIOB, GPIO_Pin_10)
#define LCD_RES_L 	  GPIO_ResetBits(GPIOB, GPIO_Pin_10)
#define LCD_CS_H	  GPIO_SetBits(GPIOB,GPIO_Pin_12)
#define LCD_CS_L	  GPIO_ResetBits(GPIOB,GPIO_Pin_12)
#define LCD_DATA	  GPIO_SetBits(GPIOB,GPIO_Pin_14)
#define LCD_CMD       GPIO_ResetBits(GPIOB,GPIO_Pin_14)
#define LCD_LED_ON	  GPIO_SetBits(GPIOB,GPIO_Pin_1)
#define LCD_LED_OFF	  GPIO_ResetBits(GPIOB,GPIO_Pin_1)
①SPI通信相关函数

SPI所用IO口的初始化函数

/**************************************************
*函数名    :LCD_spi_IO_init
*函数功能  :模拟SPI的管脚初始函数
*函数参数  :无
*函数返回值:无
*函数描述  :0,0模式---IO口模拟配置
			LCD_CLK----------------------------PB13--推挽输出     
			LCD_SDA----------------------------PB15--推挽输出
****************************************************/
void LCD_spi_IO_init(void)
{
	/*IO口控制器配置*/
	//使能端口时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	//PB13、PB15
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//输出模式
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStruct.GPIO_Pin = (GPIO_Pin_13) | (GPIO_Pin_15) ;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	
	//空闲
	LCD_SPI_SCL_L;
}

SPI发送一字节函数

/**************************************************
*函数名    :LCD_spi_byte
*函数功能  :SPI传输一个字节函数
*函数参数  :u8 data
*函数返回值:无
*函数描述  :传一位收一位
****************************************************/
void LCD_spi_byte(u8 data)
{
	u8 i;

	for(i=0;i<8;i++)
	{
		LCD_SPI_SCL_L;//拉低时钟线,以便主机写入数据
		
		if(data & 0x80) LCD_MOSI_H;
		else LCD_MOSI_L;
		
		LCD_SPI_SCL_H;//主机帮从机拉高时钟线,以便从机读取数据	
		data = data << 1;//下一位数据
	}
	
}

②LCD屏幕相关函数

LCD屏幕所用IO口的初始化函数

{

        /*IO控制器配置*/

        /*初始状态*/

        //片选拉高

        //背光灯关闭

}

具体程序:

/**************************************************
*函数名    :LCD_IO_init
*函数功能  :LCD的管脚初始函数
*函数参数  :无
*函数返回值:无
*函数描述  : LEDK-----PB1         背光灯引脚        //通用输出
			 RESET----PB10        复位引脚          //通用输出
			 LCD_CS---PB12        片选引脚          //通用输出	
			 LCD_D/C--PB14        数据命令选择线    //通用输出		  
****************************************************/
void LCD_IO_init(void)
{
	//GPIO初始化
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	//推挽输出
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_1 | GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_14;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOB, &GPIO_InitStruct);	
	
	//初始状态
	LCD_LED_OFF;               //背光关   
	LCD_CS_H;                  //片选拉高  
}

对LCD复位函数

{

        //拉低复位线

        //延时100ms

        //拉高复位线

}

具体程序:

/**************************************************
*函数名    :st7789vm_rest
*函数功能  :对LCD复位函数
*函数参数  :无
*函数返回值:无
*函数描述  :  
****************************************************/
void st7789vm_rest(void)
{
	LCD_RES_L;//拉低复位线  
	tim5_delay_ms(100);
	LCD_RES_H;//拉高复位线  
}

发送命令函数(u8)

{

        //片选线拉低

        //DC线拉低

        //调用SPI发送一字节函数

        //片选线拉高

}

具体程序:


/**************************************************
*函数名    :st7789vm_write_command
*函数功能  :对LCD写命令函数
*函数参数  :u8 cmd
*函数返回值:无
*函数描述  :DCX信号线的低电平表示传输的是命令,而高电平则表示传输的是数据    
****************************************************/
void st7789vm_write_command(u8 cmd)
{
	LCD_CS_L;//拉低片选线
	LCD_CMD;//拉低DC线-指令
	LCD_spi_byte(cmd);//发送指令
	LCD_CS_H;//拉高片选线
}

发送命令数据函数(u8)

{

        //片选线拉低

        //DC线拉高

        //调用SPI发送一字节函数

        //片选线拉高

}

具体程序:


/**************************************************
*函数名    :st7789vm_write_command_parameter
*函数功能  :对LCD写命令参数值函数
*函数参数  :u8 cmd
*函数返回值:无
*函数描述  :DCX信号线的低电平表示传输的是命令,而高电平则表示传输的是数据    
****************************************************/
void st7789vm_write_command_parameter(u8 cmd)
{
	LCD_CS_L;//拉低片选线
	LCD_DATA;//拉高DC线-数据
	LCD_spi_byte(cmd);//发送指令
	LCD_CS_H;//拉高片选线
	
}

发送数据函数(u16)

{

        //片选线拉低

        //DC线拉高

        //发送高八位--调用SPI发送一字节函数

        //发送低八位--调用SPI发送一字节函数

        //片选线拉高

}

具体程序:

/**************************************************
*函数名    :st7789vm_write_data
*函数功能  :对LCD写数据函数
*函数参数  :u16 data
*函数返回值:无
*函数描述  :DCX信号线的低电平表示传输的是命令,而高电平则表示传输的是数据
			坐标值/颜色值   
****************************************************/
void st7789vm_write_data(u16 data)
{
	LCD_CS_L;//拉低片选线
	LCD_DATA;//拉高DC线-数据
	LCD_spi_byte(data>>8);//发送高八位
	LCD_spi_byte(data);//发送低八位
	LCD_CS_H;//拉高片选线
}

发送原则:先发高位再发低位

接收原则:先接高位再接低位

清屏函数

{

        /*确定区域*/

        //确定X轴

        //发送命令

        //起始横坐标

        //结束横坐标

        //确定X轴

        //发送命令

        //起始纵坐标

        //结束纵坐标

        /*确定颜色*/

        //发送命令

        //循环发送颜色数据

}

具体程序:

/**************************************************
*函数名    :LCD_clear
*函数功能  :清屏
*函数参数  :u16 color
*函数返回值:无
*函数描述  :像素的数目等于屏幕上横向和纵向点个数的乘积。
****************************************************/
void LCD_clear(u16 color)
{

	/*确定区域*/
	//确定起始和结束的横坐标
	st7789vm_write_command(0x2A);//发送命令
	
	st7789vm_write_data(0);//起始横坐标
	st7789vm_write_data(LCD_W-1);//结束横坐标
	
	//确定起始和结束的纵坐标
	st7789vm_write_command(0x2B);//发送命令
	
	st7789vm_write_data(0);//起始纵坐标
	st7789vm_write_data(LCD_H-1);//起始纵坐标

	
	/*确定颜色*/
	st7789vm_write_command(0x2C);//发送命令
	for(u32 i=0;i<LCD_W*LCD_H;i++)//逐个刷
	{
		st7789vm_write_data(color);
	}
    /*或者
    //逐行刷
	for(u16 i=0;i<LCD_W;i++)
	{
		//每行的像素点
		for(u16 j=0;j<LCD_H;j++)
		{
			st7789vm_write_data(color);
		}
		
	}*/
}

LCD屏幕初始化

{

        //SPI所用IO初始化函数

        //LCD所用IO初始化函数

        //复位程序

        /*移植屏幕IC驱动代码*/

        //开背光灯

        //清屏

}

什么是IC驱动?

IC驱动,即集成电路(Integrated Circuit,简称IC)驱动,是指用于控制和驱动集成电路工作的技术或组件。在电子领域中,驱动IC扮演着至关重要的角色,它们能够接收来自处理器或其他控制源的信号,并将这些信号转换为适合驱动外部设备(如显示器、电机、传感器等)的信号

具体程序:

/**************************************************
*函数名    :LCD_init
*函数功能  :对LCD初始函数
*函数参数  :无
*函数返回值:无
*函数描述  :  
****************************************************/
void LCD_init(void)
{
	//SPI所用IO初始化函数
	LCD_spi_IO_init();
	//LCD所用IO初始化函数
	LCD_IO_init();
	//复位程序
	st7789vm_rest();
	
	//IC驱动代码移植
	/*设置显示方向*/  //0x36是方向控制命令,0x00是参数,表示默认方向(通常是横向)
	st7789vm_write_command(0x36);   
	st7789vm_write_command_parameter(0x00);

  /*设置颜色深度*/  //0x3A是颜色格式设置命令,0x05表示16位颜色(RGB565)。
	st7789vm_write_command(0x3A); 
	st7789vm_write_command_parameter(0x05);

	/*设置电源管理相关的参数*/
	st7789vm_write_command(0xB2);
	st7789vm_write_command_parameter(0x0C);
	st7789vm_write_command_parameter(0x0C);
	st7789vm_write_command_parameter(0x00);
	st7789vm_write_command_parameter(0x33);
	st7789vm_write_command_parameter(0x33); 
	
	
	st7789vm_write_command(0xB7); 
	st7789vm_write_command_parameter(0x35);  
	
	/*设置VCOM(垂直方向公共电极电压)的幅度*/
	st7789vm_write_command(0xBB);
	st7789vm_write_command_parameter(0x19);

	/*设置显示对比度*/
	st7789vm_write_command(0xC0);
	st7789vm_write_command_parameter(0x2C);

	/*设置显示模式相关的参数*/  //如RGB接口、扫描方向等。
	st7789vm_write_command(0xC2);
	st7789vm_write_command_parameter(0x01);

	st7789vm_write_command(0xC3);
	st7789vm_write_command_parameter(0x12);   

	st7789vm_write_command(0xC4);
	st7789vm_write_command_parameter(0x20);  

	st7789vm_write_command(0xC6); 
	st7789vm_write_command_parameter(0x0F);    
	
	/*设置显示时钟、输出频率*/
	st7789vm_write_command(0xD0); 
	st7789vm_write_command_parameter(0xA4);
	st7789vm_write_command_parameter(0xA1);

	/*设置伽马校正,以优化显示效果*/
	st7789vm_write_command(0xE0);
	st7789vm_write_command_parameter(0xD0);
	st7789vm_write_command_parameter(0x04);
	st7789vm_write_command_parameter(0x0D);
	st7789vm_write_command_parameter(0x11);
	st7789vm_write_command_parameter(0x13);
	st7789vm_write_command_parameter(0x2B);
	st7789vm_write_command_parameter(0x3F);
	st7789vm_write_command_parameter(0x54);
	st7789vm_write_command_parameter(0x4C);
	st7789vm_write_command_parameter(0x18);
	st7789vm_write_command_parameter(0x0D);
	st7789vm_write_command_parameter(0x0B);
	st7789vm_write_command_parameter(0x1F);
	st7789vm_write_command_parameter(0x23);

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

	/*显示启动*/
	st7789vm_write_command(0x21); //退出睡眠模式
	st7789vm_write_command(0x11); //进入数据模式(准备接收显示数据)
	st7789vm_write_command(0x29); // 开启显示
	
	
	//开背光灯
	LCD_LED_ON;
	
	//清屏
	LCD_clear(YELLOW);

}

打点函数

/**************************************************
*函数名    :LCD_point
*函数功能  :打点函数
*函数参数  :u16 x,u16 y,u16 color
*函数返回值:无
*函数描述  :对于打点操作来说,我们不需要定义一个区域(即起始和结束坐标之间的间隔),
			而只是需要指定一个精确的位置。
****************************************************/
void LCD_point(u16 x,u16 y,u16 color)
{
		/*确定区域*/
	//确定x方向
	st7789vm_write_command(0x2A);     //横坐标命令
	//起始横坐标
	 st7789vm_write_data(x);
	//结束横坐标
	 st7789vm_write_data(x);
	
	//确定Y方向
	st7789vm_write_command(0x2B);     //纵坐标命令
	//起始纵坐标
	st7789vm_write_data(y);
	//结束纵坐标
	st7789vm_write_data(y);
	
	
	/*确定颜色*/
	st7789vm_write_command(0x2C);     //颜色命令
	st7789vm_write_data(color);
	
}

2、LCD屏幕显示

①命令介绍
确定横坐标

0x2A:设置LCD屏的X轴坐标 (起始横坐标 结束横坐标)  

确定横坐标

0x2B:设置LCD屏的Y轴坐标 (起始坐标 结束坐标)

确定颜色

0x2C:设置区域中某一个点的颜色

注意:通常以图像的左上角为原点,横轴(u轴或x轴)表示像素的列数,纵轴(v轴或y轴)表示像素的行数。在这个坐标系中,每个像素点的坐标都是唯一的,并且可以用整数表示

②功能函数

基于LCD屏幕的相关底层函数可以实现以下功能

显示空心圆和实心圆
方法1:利用勾股定理

Rx=R*cos(Rad)

Ry=R*sin(Rad)

Rad=Angle*3.14/180

核心:在LCD屏幕上绘制一个圆,确定好圆心跟半径,然后从0°遍历到359°

思路:

1、圆心绘制:定点圆心

2、循环绘制圆的边缘:

函数通过一个从0到359的循环来遍历圆的每一个角度(Angle)。对于每一个角度,它执行以下步骤:

①角度转弧度:由于cos和sin函数在C语言中通常接受弧度作为参数,而不是角度,因此需要将角度转换为弧度。这通过Rad = Angle * 3.14 / 180;实现,其中3.14是π的近似值。

②计算坐标:对于当前的弧度Rad,使用cos(Rad)和sin(Rad)计算出该弧度对应的x轴和y轴上的分量(Rx和Ry),然后乘以半径r得到圆上该点的实际坐标相对于圆心的偏移量。

③绘制点:最后,使用打点函数,将计算出的点绘制在LCD屏幕上。这里,Rx+x和Ry+y是将圆的偏移量转换为屏幕上的绝对坐标。

 具体程序:

/********************************************************
*函数名    :LCD_DrawCircle
*函数功能  :LCD屏幕画圆函数
*函数参数  :
			x:圆心的横坐标。
			y:圆心的纵坐标。
			r:圆的半径。
			colour:用于绘制圆的颜色
*函数返回值:无
*函数描述  :
						Rx=R*cos(Rad)
						Ry=R*sin(Rad)
						Rad=Angle*3.14/180
***********************************************************/
void LCD_DrawCircle(u16 x,u16 y,u16 r,u16 colour)
{
	float Rx,Ry,Angle,Rad;
	//画圆心
	LCD_point(x,y,RED);
	for(Angle=0;Angle<360;Angle++)
	{
		//角度转弧度
		Rad = Angle * 3.14 / 180;
		//坐标
		Rx=r * cos(Rad);
		Ry=r * sin(Rad);
		//画点
		LCD_point(Rx+x,Ry+y,RED);
	}
	
}

/********************************************************
*函数名    :LCD_Ring_shi
*函数功能  :LCD屏幕画圆函数实心圆
*函数参数  :x:圆心的横坐标。
			y:圆心的纵坐标。
			r:圆的半径。
			colour:用于绘制圆的颜色
*函数返回值:无
*函数描述  :
					
***********************************************************/
void LCD_SolidCircle(u16 x,u16 y,u16 r,u16 colour)
{
	//画圆心
	LCD_point(x,y,RED);
	for(u8 i=0;i<=r;i++)
	{
		LCD_DrawCircle(100,100,i,RED);
	}
	
}
方法2:利用圆的标准形式

(x - x0)² + (y - y0)² = r²

核心:LCD屏幕上绘制一个圆环,确定好圆心跟半径,然后遍历横坐标和纵坐标

两个圆之间的区域

 R²<(x - x0)² + (y - y0< r² (R小于r)

思路:

1、遍历坐标

函数通过两个嵌套的for循环遍历所有可能的点(i, j),这些点的坐标范围是从(x-r, y-r)(x+r, y+r)。这个范围确保了所有可能位于圆环内的点都被检查。

2、判断点是否在圆环内

对于每个点(i, j),函数计算它到圆环中心(x, y)的距离的平方,即(i-x)*(i-x) + (j-y)*(j-y)

然后,这个距离的平方被用来判断点是否在圆环的范围内。圆环的范围由两个条件定义:

外边界:(i-x)*(i-x) + (j-y)*(j-y) <= r*r,即点到中心的距离不超过外半径r

内边界:(i-x)*(i-x) + (j-y)*(j-y) >= (r-2)*(r-2),即点到中心的距离大于r-2

如果一个点同时满足这两个条件,那么它就被认为是圆环的一部分。

3、绘制点

对于每个在圆环内的点,函数调用LCD_point(i,j,colour)来在LCD屏幕上绘制这个点,并赋予它指定的颜色。

具体程序:

/***************************************************
*函数名    :LCD_Ring
*函数功能  :LCD屏幕画圆函数
*函数参数  :u16 x, u16 y:指定了圆环中心的坐标。
			u16 r:指定了圆环的外半径。
			u16 colour:指定了圆环的颜色。
*函数返回值:无
*函数描述  :
						(x - x0)^2 + (y - y0)^2  == r*r 
*****************************************************/
void LCD_Ring(u16 x,u16 y,u16 r,u16 colour)
{
	u8 i,j;
	//确认长度  遍历横坐标
	for(i=x-r;i<x+r;i++)
	{
		//确定宽度  遍历纵坐标
		for(j=y-r;j<y+r;j++)
		{
			if((i-x)*(i-x)+(j-y)*(j-y)>=(r-2)*(r-2) && (i-x)*(i-x)+(j-y)*(j-y)<=r*r)
			{
				LCD_point(i,j,colour); //将遍历到的点打出来
			}
		}
		
	}
}


/********************************************************
*函数名    :LCD_Ring_shi
*函数功能  :LCD屏幕画圆函数实心圆
*函数参数  :u16 x,u16 y,u16 r,u16 colour 
*函数返回值:无
*函数描述  :
						(x - x0)^2 + (y - y0)^2  <= r*r 
***********************************************************/
void LCD_Ring_shi(u16 x,u16 y,u16 r,u16 colour)
{
	u16 i,j;
	
	for(i=x-r;i<x+r;i++)         //遍历横坐标
	{
		for(j=y-r;j<y+r;j++)       //遍历纵坐标
		{
			if((i-x)*(i-x) + (j-y)*(j-y) <=r*r)   //判断遍历的点是否符合条件
			{
				//打点函数
				LCD_point(i,j,colour); //将遍历到的点打出来
			}
		}
	}
	
}

显示可设定大小的字符

字模软件的使用

下面的字符或者汉字取模数据全是以一维数组的形式存储的

显示一个16*16的字符函数:

按ASC码顺序取模数据存储到一维数组中

用一个变量保存用所要显示的字符减去空格字符的偏移量

一行8位需要一个字节的数据([n*16+i]),用一个变量保存每一行的数据

取模数据仅仅是用来判断是否需要打点,真正起到传输坐标和颜色的是打点函数

是否需要背景色取决于字符是否在同一个坐标

关于16*16的字符模数据:文章顶部

具体程序: 

/**************************************************
*函数名    :LCD_show_ch16
*函数功能  :LCD显示16*16字符数据函数
*函数参数  :u16 x,u16 y,u8 ch,u16 colour,u8 mode,u16 b_colour
*函数返回值:无
*函数描述  : ch --- 所要显示的字符
			 mode ---传入1 有背景色 在同一个位置显示    背景色参数随便传
			 mode ---传入0 无背景色 不在同一个位置显示  背景色参数根据需求设定
****************************************************/
void LCD_show_ch16(u16 x,u16 y,u8 ch,u16 colour,u8 mode,u16 b_colour)
{
	u8 n,i,j;
	u8 temp;
	//用所要显示的字符减去空格字符
	n = ch - ' ';
	
	//遍历行
	for(i=0;i<16;i++)
	{
		//拿一行的数据
		temp = ASC16[n*16+i];
		//遍历每行的每一个像素点
		for(j=0;j<8;j++)
		{
			//下标偏移&判断打点
			if(temp & (1 << (7 - j)))
			{
				//判断哪个像素点是否打点
				LCD_point(x+j,y+i,colour);
			}
			else
			{
				//在同一个位置显示
				if(mode == 1)
				//不打点的地方为背景色
				LCD_point(x+j,y+i,b_colour);
			}
		}
		
	}
}

显示一个32*32的字符函数:

按ASC码顺序取模数据存储到一维数组中

用一个变量保存用所要显示的字符减去空格字符的偏移量

一行16位需要两个字节的数据[(n*64+2i]<<8,[n*64+2i+1]),用一个变量保存每一行的数据

取模数据仅仅是用来判断是否需要打点,真正起到传输坐标和颜色的是打点函数

是否需要背景色取决于字符是否在同一个坐标

关于32*32的字符模数据:文章顶部

具体程序 :


/******************************************************************************
*函数名    :LCD_show_ch32
*函数功能  :LCD屏幕显示32*32的字符
*函数参数  :u16 x,u16 y,u8 ch,u16 color,u8 mode,u16 b_color
*函数返回值:无
*函数描述  :mode 传入0   无背景色  背景色参数随便传
             mode 传入1   有背景色  背景色参数根据需求设定
********************************************************************************/
void LCD_show_ch32(u16 x,u16 y,u8 ch,u16 colour,u8 mode,u16 b_colour)
{
	u8 n,i,j;
	u16 temp;
	//用所要显示的字符减去空格字符
	n = ch - ' ';
	
	//遍历行
	for(i=0;i<32;i++)
	{
		//拿一行的数据 
		temp = ASC32[n*64+2*i]<<8 | ASC32[n*64+2*i+1];
		//遍历每行的每一个像素点
		for(j=0;j<16;j++)
		{
			//下标偏移&判断打点
			if(temp & (1 << (15 - j)))
			{
				LCD_point(x+j,y+i,colour);
			}
			else
			{
				//在同一个位置显示
				if(mode == 1)
				//不打点的地方为背景色
				LCD_point(x+j,y+i,b_colour);
			}
		}

		
	}
	
}

优化程序:

显示一个可选择大小的字符函数

按ASC码顺序分别取模16*16和32*32的字符数据存储到一维字模数组中

用一个变量保存用所要显示的字符减去空格字符的偏移量

遍历行-->取出每一行数据

遍历每行的每一个像素点-->根据所取出每一行数据,判断打点

具体程序:

/******************************************************************************
*函数名    :LCD_show_ch
*函数功能  :LCD屏幕显示可设定大小的字符
*函数参数  :u16 x,u16 y,u16 color,u8 ch,u8 size ,u8 mode,u16 b_color 
*函数返回值:无
*函数描述  :
			size 字号大小   16  32
			mode 传入1  就带背景颜色
			mode 传入0  就不带背景颜色
********************************************************************************/
void LCD_show_ch(u16 x,u16 y,u8 ch,u16 colour,u8 size ,u8 mode,u16 b_colour)
{
	u8 n,i,j;
	u16 temp;
	//用所要显示的字符减去空格字符
	n = ch - ' ';
	
	//遍历行
	for(i=0;i<size;i++)
	{
		if(size == 16)
		{
			//拿一行的数据
			temp = ASC16[n*16+i];
		}
		else if(size ==32)
		{
			//拿一行的数据 
		  temp = ASC32[n*64+2*i]<<8 | ASC32[n*64+2*i+1];
		}
		//遍历每行的每一个像素点
		for(j=0;j<size/2;j++)
		{
			//下标偏移&判断打点
			if(temp & (1 << (size / 2 - 1 - j)))
			{
				LCD_point(x+j,y+i,colour);
			}
			else
			{
				//在同一个位置显示
				if(mode == 1)
				//不打点的地方为背景色
				LCD_point(x+j,y+i,b_colour);
			}
		}

		
	}
	
}

显示可设定大小的汉字

思路:

把所要显示的汉字存储到一维字库数组

把所要显示的汉字按顺序分别取模16*16和32*32的字库数据存储到一维字模数组

通过传入想要打印的汉字在字库中查找,计算出所要显示的汉字与字库中的第一个汉字的偏移量

需要避免所要找的汉字不是字库里的,并且如果不是字库里的,则需要退出程序

如果是字库里的,则:

遍历行-->取出每一行数据

遍历每行的每一个像素点-->根据所取出每一行数据,判断打点

注意:一个汉字占两个字节,在数组中占两个元素--->汉字的编码:区码和位码

具体程序:

/**************************************************
*函数名    :lcd_show_chinese
*函数功能  :显示中文初始函数
*函数参数  :无
*函数返回值:无
*函数描述  :size 字号大小   16  32
						mode 传入1  就带背景颜色
						mode 传入0  就不带背景颜色
****************************************************/
void LCD_show_chinese(u16 x, u16 y, u8*hz, u16 colour,u8 size ,u8 mode,u16 b_colour)
{
		u8 n = 0;
		u8 i, j;
		u32 temp;
		
		/*计算要显示的汉字与第一个汉字的偏移量*/
		while(table[2*n] != '\0')//避免所要找的汉字不是汉字库里的
		{
			if(*hz==table[2*n] && *(hz+1)==table[2*n+1])
			{
				break;
			}
			n++;
		}
		//n值就是汉字个数偏移量
		if(table[2*n] == '\0')
		{
			return ;
		}
		//遍历行
        for(i=0;i<size;i++)
		{
			if(size == 16)  
			{
				//拿一行的数据
				temp = hz16[n*16+2*i]<<8 | hz16[n*16+2*i+1];
			}
			else if(size == 32) 
			{
				//拿一行的数据 
				temp = hz32[n*128+4*i]<<24| hz32[n*128+4*i+1]<<16 | hz32[n*128+4*i+2]<<8 | hz32[n*128+4*i+3];
			}
			//遍历每行的每一个像素点
		for(j=0;j<size;j++)
		{
			//下标偏移&判断打点
			if(temp & (1 << (size - 1 - j)))
			{
				LCD_point(x+j,y+i,colour);
			}
			else
			{
				//在同一个位置显示
				if(mode == 1)
				//不打点的地方为背景色
				LCD_point(x+j,y+i,b_colour);
			}
		}
		}
		
 

}

显示可选大小的汉字或字符(混合)

接收字符串,通过指针偏移循环查找所显示的字符或汉字

判断字符-->避免宽度不够(换行),显示字符,偏移到下一个元素(字符占一个字节),偏移到下个像素点,调用显示可设定大小的字符函数

否则是汉字-->避免宽度不够(换行),显示汉字,偏移到下一个元素(汉字占两个字节),偏移到下个像素点,调用显示可设定大小的汉字函数

具体程序:

/******************************************************************************
*函数名    :LCD_show
*函数功能  :LCD屏幕显示可选大小的汉字和字符混合
*函数参数  :u16 x,u16 y,u16 color,u8 *str,u8 size ,u8 mode,u16 b_color 
*函数返回值:无
*函数描述  :
						size 字号大小   16  32
						mode 传入1  就带背景颜色
						mode 传入0  就不带背景颜色

********************************************************************************/
void LCD_show(u16 x, u16 y, u8*str, u16 colour,u8 size ,u8 mode,u16 b_colour)
{
	while(*str != '\0')
	{
		/*判断是字符*/
		if(32<=*str && *str<=127)
		{
			//以防宽度不够
			if(x > LCD_W - size)
			{
				x = 0;//换行
				y+=size;
			}
			/*显示字符*/
			LCD_show_ch( x, y,*str,colour, size , mode, b_colour);
			str++;//偏移到下一个元素
			x+=size/2;//偏移到下个像素点
			
		}
	  /*汉字*/
		else
		{
			//以防宽度不够
			if(x > LCD_W - size)
			{
				x = 0;//换行
				y+=size;
			}
			/*显示字符*/
			LCD_show_chinese( x, y,str,colour, size , mode, b_colour);
			str+=2;//偏移到下一个元素
			x+=size;//偏移到下个像素点
		}	
	}
	
}

显示任意大小的图片

取模软件的使用

图片显示原理,同在屏幕某一区域显示颜色。

注意:图片取模数组的前8个元素代表头数据

typedef struct _HEADCOLOR

{

unsigned char scan;   //扫描方向

unsigned char gray;   //灰度值

unsigned short w;     //宽

unsigned short h;     //高

unsigned char is565;  // 5 6 5

unsigned char rgb;    //RGB

}HEADCOLOR;   

图片的 宽和高 通过结构体成员 w ,h 成员确定。

图片的颜色数据是从 数组的 8 号元素开始。

数组中的两个数据是一个像素点的颜色

思路:

用取模软件将图片的模数据取出,再定义图片头数据的结构体,最后声明

确定区域-->定义结构体指针指向图片内的空间,得到图片的宽和高

确定颜色-->定义数据类型为u16的指针指向图片内的空间并且使用指针跳过头数据(8位),   最后通过传输颜色数据,在区域内显示图片的颜色

具体程序:

typedef struct _HEADCOLOR
{
   unsigned char scan;
   unsigned char gray;
   unsigned short w;
   unsigned short h;
   unsigned char is565;
   unsigned char rgb;
}HEADCOLOR;

/**********************************************
*函数名    :LCD_show_pic
*函数功能  :LCD屏幕显示任意大小图片
*函数参数  :u16 x,u16 y,const u8 *pic
*函数返回值:无
*函数描述  :x,y为起始坐标
************************************************/
void LCD_show_pic(u16 x,u16 y,const u8 *pic)
{
	HEADCOLOR* head;
	u16 *p;
	
	head = (HEADCOLOR*)pic;//指向图片地址
	p = (u16*)(pic + sizeof(HEADCOLOR));//指向图片地址(跳过头数据)
	
	/*确定区域*/
	//确定x方向  
	st7789vm_write_command(0x2A);     //横坐标命令
	//起始横坐标
	st7789vm_write_data(x);
	st7789vm_write_data(x+head->w-1);
	
	//确定Y方向
	st7789vm_write_command(0x2B);     //纵坐标命令
	//起始纵坐标
	st7789vm_write_data(y);
	st7789vm_write_data(y+head->h-1);
	
	
	/*确定颜色*/
	st7789vm_write_command(0x2C);     //颜色命令
	for(u32 i=0;i<(head->w)*(head->h);i++)
	{
		st7789vm_write_data(*p);//除头数据以外
		p++;//地址偏移   16位-2个字节
	}
}	

需求:一个按键控制切换图片,模拟电子相册

利用标志位锁定和标志位解锁的方式来切换,但是图片多的时候就显得代码很冗余

所以优化程序:

利用指针数组存放每张图片的地址,用按键控制变量来寻找图片的地址空间,以实现在LCD屏幕上实现切换图片

具体程序:

//自己添加的图片
const u8 *pic[]={gImage_dog_pic,gImage_girl1_pic,gImage_girl2_pic,gImage_us_pic};
int main(void)
{
	u8 keynum;
	key_init();
	LCD_init();
	printf("硬件初始化成功\r\n");
	while(1)
	{
		keynum = key2_scan();
		if(keynum == 2)
		{
			num++;
			LCD_show_pic(0,0,pic[num-1]);
		}


	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值