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