ESP32 development notes (3) source code example 23_LCD_Test LCD screen test thick line/fine line/angle line/solid rectangle/hollow rectangle/solid triangle/hollow triangle/drawing point/circle/solid circle/string/number

Development board purchase link

https://item.taobao.com/item.htm?spm=a2oq0.12575281.0.0.50111deb2Ij1As&ft=t&id=626366733674

Introduction to development board
development environment to build windows
basic routines:
    0_Hello Bug (ESP_LOGX and printf)     project template/print debugging output
    1_LED                                                     LED on and off control       
    2_LED_Task                                           control LED using task mode
    3_LEDC_PWM                                       use LEDC to control LED to achieve breathing light effect
    4_ADC_LightR                                       use ADC to read Photoresistor to achieve light sensing
    5_KEY_Short_Long                               button long press and short press to achieve
    6_TouchPad_Interrupt                           capacitive touch interrupt to achieve
    7_WS2812_RMT                                   using RMT to achieve RGB_LED rainbow color example
    8_DHT11_RMT to                                     use RMT to read DHT11 temperature and humidity sensor
    9_SPI_SDCard                                     uses SPI bus to implement TF card file system example
    10_IIC_ADXL345                                 uses IIC bus to implement reading ADXL345 angular acceleration sensor
    11_IIC_AT24C02                                  uses IIC bus to implement small-capacity data storage test
    12_IR_Rev_RMT                                 uses RMT to implement infrared remote control receiving and decoding (NEC encoding)
    13_IR_Send_RMT                               uses RMT to implement infrared data transmission (NEC code)
    14_WIFI_Scan                                     nearby WIFI signal scanning example    
    15_WIFI_AP                                         creating a soft AP example
    16_WIFI_AP_TCP_Server                   realizes TCP server                    in soft AP mode
    17_WIFI_AP_TCP_Client realizes TCP client in soft AP mode
    18_WIFI_AP_UDP                              Achieved at the soft AP mode UDP communication
    19_WIFI_STA                                       create STA slave mode connected to the router
    20_WIFI_STA_TCP_Server                 implement TCP server in slave mode STA
    21_WIFI_STA_TCP_Client                  implemented in slave mode STA TCP client
    22_WIFI_STA_UDP                             implemented UDP communications slave mode STA
    23_LCD_Test the LCD LCD touch screen display test 
    24_LVGL_Test LVGL graphics library simple example

Introduction to TFTLCD

TFT-LCD is a thin film transistor liquid crystal display. Its English name is: Thin Film Transistor-Liquid Crystal Display. TFT-LCD is different from the simple matrix of passive TN-LCD and STN-LCD. It is equipped with a thin film transistor (TFT) on each pixel of the liquid crystal display, which can effectively overcome crosstalk during non-gating. Make the static characteristics of the display LCD screen independent of the number of scanning lines, thus greatly improving the image quality. TFT-LCD is also called true color liquid crystal display.

The parameters of the LCD screen ILI9841 used on the development board are as follows
Display color RGB 65K color
Touch chip XPT2046
size 3.2 (inch)
type TFT
driver chip ILI9341
resolution 320*240 (Pixel)
module interface 4-wire SPI interface
effective display area (AA area) 48.6x64.8(mm)
Operating temperature -20℃~60℃
Storage temperature -30℃~70℃
VCC power supply voltage 3.3V~5V
logic IO port voltage 3.3V (TTL)

Introduction to SPI

1. What is SPI?

SPI is the abbreviation of Serial Peripheral Interface. It is a synchronous serial interface technology introduced by Motorola, which is a high-speed, full-duplex, and synchronous communication bus.

2. The advantages of SPI
support full-duplex
communication, simple communication,
data transmission rate block

3. Disadvantages
There is no designated flow control, and there is no response mechanism to confirm whether data is received, so compared with the IIC bus protocol, there are certain defects in data reliability.

4. Features
1): High-speed, synchronous, full-duplex, non-differential, bus type
2): Master-slave communication mode

5. Detailed explanation of protocol communication sequence
1): The communication principle of SPI is very simple. It works in a master-slave mode. This mode usually has a master device and one or more slave devices. At least 4 wires are required. In fact, 3 wires are also required. Yes (for one-way transmission). Also common to all SPI-based devices, they are SDI (data input), SDO (data output), SCLK (clock), CS (chip select).
(1) SDO/MOSI-master device data output, slave device data input;
(2) SDI/MISO-master device data input, slave device data output;
(3) SCLK-clock signal, generated by the master device;
(4) CS/SS-slave device enable signal, controlled by the master device. From the time when a plurality of devices, as provided from each
has a chip select pin access to the master machine when the master device and we would need a communication device corresponding to the slave device from the standby The chip select pin level is pulled low or pulled high.

1. Hardware principle

ESP32 has four SPI peripherals, called SPI0, SPI1, HSPI and VSPI. SPI0 is dedicated to flash cache, ESP32 maps the connected SPI flash device to memory. SPI1 and SPI0 use the same hardware line, and SPI1 is used for writing flash chip. HSPI and VSPI can be used arbitrarily. SPI1, HSPI and VSPI have three chip select lines, as SPI master allows them to drive up to three SPI devices

The LCD screen uses VSPI_HOST or SPI3_HOST

Check the schematic diagram, in addition to the four wires that SPI must send, there are actually three control wires, RESET, BL, RS.

RESET is the LCD reset signal line. Because the GPIO of the start board is tight, it is connected with the RESET line of the system. The same BL is the LCD backlight control line, which is also directly connected to 3.3V. RS is the command/data selection signal line. On the IO2 pin, the touch signal will be edited below.

Two, code writing

The code is divided into three files, the main function main file, the LCD bottom driver file, and the gui upper display file

Look at the main file first

Import necessary header files 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "lcd.h"
#include "gui.h"
#include "pic.h"

The main function directly calls the bottom layer initialization and upper layer drawing

void app_main(void)
{
	esp_err_t ret;
	Init_LCD();


	// 实心矩形
	LCD_DrawFillRectangle(20,20,100,100,GREEN);
	// 空心矩形
	LCD_DrawRectangle(20,220,100,200,GREEN);	
	// 画圆
	LCD_Draw_Circle(180,200,40,WHITE);
	// 画实心圆
	LCD_Draw_FillCircle(180,200,30,WHITE);	
	// 画点
	LCD_DrawPoint(120,110,RED);
	// 画线
	LCD_DrawLine(0, 0, 128, 128,RED);
	// 画角度线
	LCD_Draw_AngleLine(100,100,35,85,BLACK);
	// 画粗线1
	LCD_DrawBLine0(20,160,60,190,5,YELLOW);
	// 画粗线2
	LCD_DrawBLine1(40,140,90,190,2,YELLOW);
	// 画三角形
	LCD_DrawTriangel(100,50,30,100,150,150,RED);
	// 画实心三角形
	LCD_DrawFillTriangel(180,30,160,80,200,120,RED);
	// 显示单个字符
	LCD_ShowChar(120,0,BLACK,RED, 'A',12,1);
	LCD_ShowChar(140,0,BLACK,RED, 'B',12,0);	
	LCD_ShowChar(160,0,BLACK,RED, 'A',16,1);
	LCD_ShowChar(180,0,BLACK,RED, 'B',16,0);
	// 显示字符串
	LCD_ShowString(10,240,GREEN,RED,12,"ABCDabcd123",1);
	LCD_ShowString(10,252,GREEN,RED,12,"ABCDabcd123",0);
	LCD_ShowString(10,264,GREEN,RED,16,"ABCDabcd123",1);
	LCD_ShowString(10,280,GREEN,RED,16,"ABCDabcd123",0);
	// 显示数字
	LCD_ShowNum(10,296,WHITE,BLACK,123456,7,16);
	// 显示图片
	LCD_Drawbmp16(100,240,gImage_qq);
}

Next, look at the bottom driver of LCD, including SPI initialization, LCD initialization, setting direction, setting window, SPI write data, write command, etc.

lcd.c

Import necessary header files

#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "stdint.h"
#include "stdbool.h"
#include "driver/gpio.h"
#include "lcd.h"
#include "math.h"  
#include "string.h"

SPI and LCD LCD initialization

// 初始化液晶
void Init_LCD(void)
{
	int cmd=0;
	lcd_init_cmd_t ili_init_cmds[]={
		{0xCF, {0x00, 0xD9, 0X30}, 3},
		{0xED, {0x64, 0x03, 0X12, 0X81}, 4},
		{0xE8, {0x85, 0x10, 0x7A}, 3},
		{0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
		{0xF7, {0x20}, 1},
		{0xEA, {0x00, 0x00}, 2},
		{0xC0, {0x1B}, 1},          /*Power control*/
		{0xC1, {0x12}, 1},          /*Power control */
		{0xC5, {0x26, 0x26}, 2},    /*VCOM control*/
		{0xC7, {0xB0}, 1},          /*VCOM control*/
		{0x36, {0x08}, 1},          /*Memory Access Control*/
		{0x3A, {0x55}, 1},			/*Pixel Format Set*/
		{0xB1, {0x00, 0x1A}, 2},
		{0xB6, {0x0A, 0xA2}, 2},
		{0xF2, {0x00}, 1},	
		{0x26, {0x01}, 1},	
		{0xE0, {0x1F, 0x24, 0x24, 0x0D, 0x12, 0x09, 0x52, 0XB7, 0x3F, 0x0C, 0x15, 0x06, 0x0E, 0x08, 0x00}, 15},
		{0XE1, {0x00, 0x1B, 0x1B, 0x02, 0x0E, 0x06, 0x2E, 0x48, 0x3F, 0x03, 0x0A, 0x09, 0x31, 0x37, 0x1F}, 15},
		{0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
		{0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},

		//		
		//{0x2C, {0}, 0},
		//{0xB7, {0x07}, 1},

		{0x11, {0}, 0x80},
		{0x29, {0}, 0x80},
		{0, {0}, 0xff},
	};
	esp_err_t ret;
	// SPI总线配置
	spi_bus_config_t buscfg = {
		.miso_io_num = PIN_NUM_MISO,
		.mosi_io_num = PIN_NUM_MOSI,
		.sclk_io_num = PIN_NUM_CLK,
		.quadwp_io_num = -1,
		.quadhd_io_num = -1,
		.max_transfer_sz=PARALLEL_LINES*320*2+8
	};
	// SPI驱动接口配置
	spi_device_interface_config_t devcfg = {
		.clock_speed_hz = 30*1000*1000,				// SPI时钟 30 MHz
		.mode = 0,									// SPI模式0
		.spics_io_num = PIN_NUM_CS,					// CS片选信号引脚
		.queue_size = 7,							// 事务队列尺寸 7个
		.pre_cb = lcd_spi_pre_transfer_callback,	// 数据传输前回调,用作D/C(数据命令)线分别处理
	};
	// 初始化SPI总线
	ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN);
	ESP_ERROR_CHECK(ret);
	// 添加SPI总线驱动
	ret=spi_bus_add_device(LCD_HOST, &devcfg, &LCD_SPI_Handle);
	ESP_ERROR_CHECK(ret);

	// 初始化其它控制引脚
	gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT);
	//gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT);
	//gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT);

	// Reset the display
	//gpio_set_level(PIN_NUM_RST, 0);
	//vTaskDelay(100 / portTICK_RATE_MS);
	//gpio_set_level(PIN_NUM_RST, 1);
	//vTaskDelay(100 / portTICK_RATE_MS);

	uint32_t lcd_id = LCD_Get_ID();
	printf("LCD ID: %08X\n", lcd_id);

	printf("LCD ILI9341 initialization.\n");

	// 循环发送设置所有寄存器
	while (ili_init_cmds[cmd].databytes!=0xff) {
		LCD_WriteCMD(ili_init_cmds[cmd].cmd);
		LCD_WriteDate(ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes&0x1F);
		if (ili_init_cmds[cmd].databytes&0x80) {
			vTaskDelay(100 / portTICK_RATE_MS);
		}
		cmd++;
	}
    LCD_Set_Orientation(LCD_DISPLAY_ORIENTATION_PORTRAIT);// 纵向

	//LCD_WriteCMD(0x21);// 翻转颜色
	LCD_WriteCMD(0x20);
	LCD_Clear(BLUE);
	// gpio_set_level(PIN_NUM_BCKL, 0);	// 点亮LCD屏
}

SPI write command to LCD

void LCD_WriteCMD(const uint8_t cmd)
{
	esp_err_t ret;
	spi_transaction_t t;
	memset(&t, 0, sizeof(t));		// 清空结构体
	t.length=8;						// 要传输的位数 一个字节 8位
	t.tx_buffer=&cmd;				// 将命令填充进去
	t.user=(void*)0;				// 设置D/C 线,在SPI传输前回调中根据此值处理DC信号线
	ret=spi_device_polling_transmit(LCD_SPI_Handle, &t);		// 开始传输
	assert(ret==ESP_OK);			// 一般不会有问题
}

SPI write data to LCD

void LCD_WriteDate(const uint8_t *data, int len)
{
	esp_err_t ret;
	spi_transaction_t t;
	if (len==0) return;				// 长度为0 没有数据要传输
	memset(&t, 0, sizeof(t));		// 清空结构体
	t.length=len*8;					// 要写入的数据长度 Len 是字节数,len, transaction length is in bits.
	t.tx_buffer=data;				// 数据指针
	t.user=(void*)1;				// 设置D/C 线,在SPI传输前回调中根据此值处理DC信号线
	ret=spi_device_polling_transmit(LCD_SPI_Handle, &t);		// 开始传输
	assert(ret==ESP_OK);			// 一般不会有问题
}

Callback DC signal line processing before SPI transmission

void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
	int dc = (int)t->user;
	gpio_set_level(PIN_NUM_DC, dc);
}

Set screen orientation, 4 directions

// 设置屏幕方向
void LCD_Set_Orientation(uint8_t orientation)
{
	const char *orientation_str[] = {"PORTRAIT", "PORTRAIT_INVERTED", "LANDSCAPE", "LANDSCAPE_INVERTED"};
	printf("%s->Display orientation: %s\n",TAG, orientation_str[orientation]);
	uint8_t data[] = {(1<<3)|(0<<6)|(0<<7), (1<<3)|(1<<6)|(1<<7), (1<<3)|(0<<7)|(1<<6)|(1<<5), (1<<3)|(1<<7)|(1<<5)};
	//(1<<3)|(0<<6)|(0<<7));		// BGR==1,MY==0,MX==0,MV==0
	//(1<<3)|(0<<7)|(1<<6)|(1<<5));	// BGR==1,MY==1,MX==0,MV==1
	//(1<<3)|(1<<6)|(1<<7));		// BGR==1,MY==0,MX==0,MV==0
	//(1<<3)|(1<<7)|(1<<5));		// BGR==1,MY==1,MX==0,MV==1
	LCD_Orientation = orientation;
	if(orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT || orientation == LCD_DISPLAY_ORIENTATION_PORTRAIT_INVERTED){
		LCD_Width = 240;		// LCD 宽度
		LCD_Height = 320;		// LCD 高度
	}else if(orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE || orientation == LCD_DISPLAY_ORIENTATION_LANDSCAPE_INVERTED){
		LCD_Width = 320;		// LCD 宽度
		LCD_Height = 240;		// LCD 高度
	}

	printf("%s->0x36 command value: 0x%02X\n",TAG, data[orientation]);
	LCD_WriteCMD(0x36);
	LCD_WriteDate((void *) &data[orientation], 1);
}

Clear the screen to the specified color

// 清屏指定颜色
void LCD_Clear(uint16_t Color)
{
	unsigned int i,m;  
	uint8_t databuf[2] = {0,0};
	LCD_SetWindows(0,0,LCD_Width-1,LCD_Height-1);   
	for(i=0;i<LCD_Height;i++){
		for(m=0;m<LCD_Width;m++){	
			databuf[0] = (Color>>8)&0xFF;
			databuf[1] = Color&0xFF;
			LCD_WriteDate(databuf,2);
		}
	}
} 

Setting window

// 设置窗口
void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{	
	uint8_t databuf[4] = {0,0,0,0};
	databuf[0] = xStar>>8;
	databuf[1] = 0xFF&xStar;	
	databuf[2] = xEnd>>8;
	databuf[3] = 0xFF&xEnd;
	LCD_WriteCMD(0x2A);
	LCD_WriteDate(databuf,4);

	databuf[0] = yStar>>8;
	databuf[1] = 0xFF&yStar;	
	databuf[2] = yEnd>>8;
	databuf[3] = 0xFF&yEnd;
	LCD_WriteCMD(0x2B);	
	LCD_WriteDate(databuf,4);

	LCD_WriteCMD(0x2C);	//开始写入GRAM			
}   

The upper driver of gui.c contains drivers for drawing graphics, strings, numbers, and pictures

Import the necessary header files, including the database math.h

#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "stdint.h"
#include "stdbool.h"
#include "../LCD/include/lcd.h"
#include "gui.h"
#include "font.h"
#include "math.h"  
#include "string.h"

Also define a π to calculate the angle

//π值定义
#define	app_pi	3.1415926535897932384626433832795 

Stroke

// 画点
void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
{
	LCD_SetCursor(x,y);//设置光标位置 
	LCD_WriteDate16(color); 
}

Draw a circle

// 画圆
void LCD_Draw_Circle(uint16_t x0,uint16_t y0,uint16_t r,uint16_t color)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判断下个点位置的标志
	while(a<=b){
		LCD_DrawPoint(x0+a,y0-b,color);		//5
 		LCD_DrawPoint(x0+b,y0-a,color);		//0
		LCD_DrawPoint(x0+b,y0+a,color);		//4
		LCD_DrawPoint(x0+a,y0+b,color);		//6
		LCD_DrawPoint(x0-a,y0+b,color);		//1
 		LCD_DrawPoint(x0-b,y0+a,color);
		LCD_DrawPoint(x0-a,y0-b,color);		//2
  		LCD_DrawPoint(x0-b,y0-a,color);		//7
		a++;
		//使用Bresenham算法画圆
		if(di<0){
			di +=4*a+6;
		}else{
			di+=10+4*(a-b);
			b--;
		}
	}
}

Draw a solid circle

// 画实心圆
void LCD_Draw_FillCircle(uint16_t x0,uint16_t y0,uint16_t r,uint16_t color)
{
	uint16_t a,b;
	int di;//uint16_t di 画实心菱形
	a=0;b=r;
	di=3-(r<<1);	// 判断下个点位置的标志
	while(a<=b){
		int i = a,p = b;
		while(i>0){
			LCD_DrawPoint(x0+b,y0-i,color);
			LCD_DrawPoint(x0-i,y0+b,color);
			i--;
		}
		while(p>0){
			LCD_DrawPoint(x0-a,y0-p,color);
			LCD_DrawPoint(x0-p,y0-a,color);
			LCD_DrawPoint(x0+a,y0-p,color);
			LCD_DrawPoint(x0-p,y0+a,color);
			LCD_DrawPoint(x0+a,y0+p,color);
			LCD_DrawPoint(x0+p,y0+a,color);
			p--;
		}
		a++;
		//Bresenham算法画圆
		if(di<0){
			di +=4*a+6;
		}else{
			di+=10+4*(a-b);
			b--;
		}
	}
	LCD_DrawPoint(x0,y0,color); //圆心坐标
}

Line drawing (single pixel)

// 画线(单像素)
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t 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(uRow,uCol,color);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) { 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) { 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
}

Draw a line at a specified angle

// 画角度线
void LCD_Draw_AngleLine(uint16_t x,uint16_t y,uint16_t Angle,uint16_t r,uint16_t color)
{
	int sx=x-r;
	int sy=y-r;
	int px0,px1;
	int py0,py1;  
	uint8_t r1; 
	int d = r;
	r1=d/2+3;
	px0=x;//sx+r+(r-d-7)*sin((app_pi/30)*Angle); 
	py0=y;//sy+r-(r-d-7)*cos((app_pi/30)*Angle); 
	px1=sx+r+r1*sin((app_pi/180)*Angle); 
	py1=sy+r-r1*cos((app_pi/180)*Angle); 
	LCD_DrawLine(px0,py0,px1,py1,color);
}

Draw thick lines

void LCD_DrawBLine0(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint8_t size,uint16_t color)
{
	uint16_t t; 
	uint16_t xerr=0,yerr=0,delta_x,delta_y,distance; 
	uint16_t incx,incy,uRow,uCol; 
	if(x1<size|| x2<size||y1<size|| y2<size)return;
	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_Draw_FillCircle(uRow,uCol,size,color);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance){xerr-=distance;uRow+=incx;}  
		if(yerr>distance){yerr-=distance;uCol+=incy;}
	}  
} 

Draw thick line 2, line thickness only supports 0-2

void LCD_DrawBLine1(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint8_t size,uint16_t color)
{
	int t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 

	delta_x=x1-x0; //计算坐标增量 
	delta_y=y1-y0; 
	uRow=x0; 
	uCol=y0; 
	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++ ){//画线输出 
		if(size==0)LCD_DrawPoint(uRow,uCol,color);//画点 
		if(size==1){
			LCD_DrawPoint(uRow,uCol,color);//画点 
			LCD_DrawPoint(uRow+1,uCol,color);//画点 
			LCD_DrawPoint(uRow,uCol+1,color);//画点 
			LCD_DrawPoint(uRow+1,uCol+1,color);//画点 
		}
		if(size==2){
			LCD_DrawPoint(uRow,uCol,color);//画点 
			LCD_DrawPoint(uRow+1,uCol,color);//画点 
			LCD_DrawPoint(uRow,uCol+1,color);//画点 
			LCD_DrawPoint(uRow+1,uCol+1,color);//画点 
			LCD_DrawPoint(uRow-1,uCol+1,color);//画点 
			LCD_DrawPoint(uRow+1,uCol-1,color);//画点
			LCD_DrawPoint(uRow-1,uCol-1,color);//画点  
			LCD_DrawPoint(uRow-1,uCol,color);//画点 
			LCD_DrawPoint(uRow,uCol-1,color);//画点  
		}
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) { 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) { 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}
}

Drawing triangle

// 画三角形
void LCD_DrawTriangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{
	LCD_DrawLine(x0,y0,x1,y1,color);
	LCD_DrawLine(x1,y1,x2,y2,color);
	LCD_DrawLine(x2,y2,x0,y0,color);
}

Draw a solid triangle

// 画实心三角形
void LCD_DrawFillTriangel(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{
	uint16_t a, b, y, last;
	int dx01, dy01, dx02, dy02, dx12, dy12;
	long sa = 0;
	long sb = 0;
	if (y0 > y1) {
		LCD_Swap(&y0,&y1); 
		LCD_Swap(&x0,&x1);
	}
	if (y1 > y2) {
		LCD_Swap(&y2,&y1); 
		LCD_Swap(&x2,&x1);
	}
	if (y0 > y1) {
		LCD_Swap(&y0,&y1); 
		LCD_Swap(&x0,&x1);
	}
	if(y0 == y2) { 
		a = b = x0;
		if(x1 < a){
			a = x1;
		}else if(x1 > b){
			b = x1;
		}
		if(x2 < a){
			a = x2;
		}else if(x2 > b){
			b = x2;
		}
		LCD_DrawFillRectangle(a,y0,b,y0,color);
		return;
	}
	dx01 = x1 - x0;
	dy01 = y1 - y0;
	dx02 = x2 - x0;
	dy02 = y2 - y0;
	dx12 = x2 - x1;
	dy12 = y2 - y1;
	
	if(y1 == y2){
		last = y1; 
	}else{
		last = y1-1; 
	}
	for(y=y0; y<=last; y++) {
		a = x0 + sa / dy01;
		b = x0 + sb / dy02;
		sa += dx01;
		sb += dx02;
		if(a > b){
			LCD_Swap(&a,&b);
		}
		LCD_DrawFillRectangle(a,y,b,y,color);
	}
	sa = dx12 * (y - y1);
	sb = dx02 * (y - y0);
	for(; y<=y2; y++) {
		a = x1 + sa / dy12;
		b = x0 + sb / dy02;
		sa += dx12;
		sb += dx02;
		if(a > b){
			LCD_Swap(&a,&b);
		}
		LCD_DrawFillRectangle(a,y,b,y,color);
	}
}

Draw rectangle

// 画矩形
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color)
{
	LCD_DrawLine(x1,y1,x2,y1,color);
	LCD_DrawLine(x1,y1,x1,y2,color);
	LCD_DrawLine(x1,y2,x2,y2,color);
	LCD_DrawLine(x2,y1,x2,y2,color);
} 

Draw a solid rectangle

// 实心矩形
void LCD_DrawFillRectangle(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t color)
{  	
	uint16_t i,j;			
	uint16_t width=ex-sx+1; 		//得到填充的宽度
	uint16_t height=ey-sy+1;		//高度
	LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口
	for(i=0;i<height;i++){
		for(j=0;j<width;j++)
		LCD_WriteDate16(color);	//写入数据 	 
	}
	LCD_SetWindows(0,0,LCD_Width-1,LCD_Height-1);//恢复窗口设置为全屏
}

Display a single character

// 显示单个字符
void LCD_ShowChar(uint16_t x,uint16_t y,uint16_t bcolor,uint16_t fcolor, uint8_t ch,uint8_t size,uint8_t mode)
{
	uint8_t temp,pos,t;
	ch=ch-' ';//得到偏移后的值
	LCD_SetWindows(x,y,x+size/2-1,y+size-1);//设置单个文字显示窗口
	if(!mode){ //非叠加方式
		for(pos=0;pos<size;pos++){
			if(size==12)temp=asc2_1206[ch][pos];//调用1206字体
			else temp=asc2_1608[ch][pos];		 //调用1608字体
			for(t=0;t<size/2;t++){
				if(temp&0x01)LCD_WriteDate16(fcolor); 
				else LCD_WriteDate16(bcolor); 
				temp>>=1; 
			}
		}
	}else{//叠加方式
		for(pos=0;pos<size;pos++){
			if(size==12)temp=asc2_1206[ch][pos];//调用1206字体
			else temp=asc2_1608[ch][pos];		 //调用1608字体
			for(t=0;t<size/2;t++){
				if(temp&0x01)LCD_DrawPoint(x+t,y+pos,fcolor);//画一个点
				temp>>=1; 
			}
		}
	}
	LCD_SetWindows(0,0,LCD_Width-1,LCD_Height-1);//恢复窗口为全屏
}

Display string

// 显示字符串
void LCD_ShowString(uint16_t x,uint16_t y,uint16_t bcolor,uint16_t fcolor,uint8_t size,char *p,uint8_t mode)
{
	while((*p<='~')&&(*p>=' ')){//判断是不是非法字符!
		if(x>(LCD_Width-1)||y>(LCD_Height-1)) 
		return;
		LCD_ShowChar(x,y,bcolor,fcolor,*p,size,mode);
		x+=size/2;
		p++;
	}
} 

Display number

// 显示数字
void LCD_ShowNum(uint16_t x,uint16_t y,uint16_t bcolor,uint16_t fcolor,uint32_t num,uint8_t len,uint8_t size)
{
	uint8_t t,temp,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,bcolor,fcolor,' ',size,0);
				continue;
			}else enshow=1;
		}
	 	LCD_ShowChar(x+(size/2)*t,y,bcolor,fcolor,temp+'0',size,0);
	}
} 

display image

//显示40*40 QQ图片
void LCD_Drawbmp16(uint16_t x,uint16_t y,const unsigned char *p) 
{
  	int i; 
	unsigned char picH,picL; 
	LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置
    for(i=0;i<40*40;i++)
	{	
	 	picL=*(p+i*2);	//数据低位在前
		picH=*(p+i*2+1);				
		LCD_WriteDate16(picH<<8|picL);  						
	}	
	LCD_SetWindows(0,0,LCD_Width-1,LCD_Height-1);//恢复窗口为全屏
}

Three, download test

Open ESP-IDF Command Prompt

cd command to enter this project directory

cd F:\ESP32_DevBoard_File\23_LCD_Test

View the serial port number of the development board in the computer device manager

Execute idf.py -p COM9 flash monitor to download and run from serial port 9 and open the port to display device debugging information Ctrl+c to exit

The display effect is as follows

Guess you like

Origin blog.csdn.net/cnicfhnui/article/details/108612147