ST7735s驱动TFT-LCD——8080接口

一、简介:

MCU:GD32F303

显示驱动:ST7735S

LCD硬件接口:8080(8位数据线)

引脚:

数据:D7~D0

片选:CS

数据/命令:RS

写控制:WR

读控制:RD

复位:RST

背光:EN

二、代码:

1、头文件:

#ifndef __ST7735S_LCD_H
#define __ST7735S_LCD_H

#include "main.h"
#include "font.h"

#define USE_DMA

/*
 * 说明:
 * 这是一个1.8寸的TFT_LCD屏幕,显示驱动IC是:ST7735S
 * 分辨率:128*160
 *
 *
 */
#define LCD_WIDTH 128
#define LCD_HEIGHT 160

/用户配置区///
// 支持横竖屏快速定义切换
#define USE_LCM_DIR 2 // 定义液晶屏顺时针旋转方向 	0-0度旋转,1-180度旋转,2-270度旋转,3-90度旋转

// LCD重要参数集
typedef struct
{
    uint16_t width;   // LCD 宽度
    uint16_t height;  // 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;

// LCD参数
extern _lcd_dev lcddev; // 管理LCD重要参数
// LCD的画笔颜色和背景色
extern uint16_t POINT_COLOR; // 默认红色
extern uint16_t BACK_COLOR;  // 背景颜色.默认为白色


//-----------------LCD端口定义----------------//

#define LCD_RESET_Port GPIOC // 复位引脚:PC15
#define LCD_RESET_Pin GPIO_PIN_15
#define LCD_RD_Port LCD_RESET_Port // 读数据引脚:PC14
#define LCD_RD_Pin GPIO_PIN_14
#define LCD_WR_Port LCD_RESET_Port // 写数据引脚:PC13
#define LCD_WR_Pin GPIO_PIN_13
#define LCD_CS_Port LCD_RESET_Port // 片选引脚:PC11
#define LCD_CS_Pin GPIO_PIN_11
#define LCD_RS_Port LCD_RESET_Port // 数据/命令选择引脚:PC10
#define LCD_RS_Pin GPIO_PIN_10
#define LCD_EN_Port LCD_RESET_Port // LCD背光引脚:PC0
#define LCD_EN_Pin GPIO_PIN_0

// 数据线:DB0~DB7
#define LCD_DB_Port GPIOB
#define LCD_DB0_Pin GPIO_PIN_0
#define LCD_DB1_Pin GPIO_PIN_1
#define LCD_DB2_Pin GPIO_PIN_2
#define LCD_DB3_Pin GPIO_PIN_3
#define LCD_DB4_Pin GPIO_PIN_4
#define LCD_DB5_Pin GPIO_PIN_5
#define LCD_DB6_Pin GPIO_PIN_6
#define LCD_DB7_Pin GPIO_PIN_7
// 数据线输出输入
#define DB_PORT_OUTPUT 1
#define DB_PORT_INPUT 0

// 拉高
// #define	LCD_RST_SET     gpio_bit_set(LCD_RESET_Port, LCD_RESET_Pin)   	// 复位        PC15
// #define	LCD_CS_SET      gpio_bit_set(LCD_CS_Port, LCD_CS_Pin)    	    // 片选端口     PC11
// #define	LCD_RS_SET	    gpio_bit_set(LCD_RS_Port, LCD_RS_Pin)    	    // 数据/命令    PC10
// #define	LCD_WR_SET	    gpio_bit_set(LCD_WR_Port, LCD_WR_Pin)           // 写数据		PC13
// #define	LCD_RD_SET	    gpio_bit_set(LCD_RD_Port, LCD_RD_Pin)           // 读数据  	    PC14

// 拉低
// #define	LCD_RST_CLR     gpio_bit_reset(LCD_RESET_Port, LCD_RESET_Pin)
// #define	LCD_CS_CLR      gpio_bit_reset(LCD_CS_Port, LCD_CS_Pin)
// #define	LCD_RS_CLR	    gpio_bit_reset(LCD_RS_Port, LCD_RS_Pin)
// #define	LCD_WR_CLR	    gpio_bit_reset(LCD_WR_Port, LCD_WR_Pin)
// #define	LCD_RD_CLR	    gpio_bit_reset(LCD_RD_Port, LCD_RD_Pin)

// #define LCD_LED(x)      (x ? gpio_bit_set(LCD_EN_Port, LCD_EN_Pin) : gpio_bit_reset(LCD_EN_Port, LCD_EN_Pin))

#define LCD_RST_SET GPIO_BOP(LCD_RESET_Port) = (uint32_t)LCD_RESET_Pin
#define LCD_CS_SET GPIO_BOP(LCD_CS_Port) = (uint32_t)LCD_CS_Pin
#define LCD_RS_SET GPIO_BOP(LCD_RS_Port) = (uint32_t)LCD_RS_Pin
#define LCD_WR_SET GPIO_BOP(LCD_WR_Port) = (uint32_t)LCD_WR_Pin
#define LCD_RD_SET GPIO_BOP(LCD_RD_Port) = (uint32_t)LCD_RD_Pin

// 拉低
#define LCD_RST_CLR GPIO_BC(LCD_RESET_Port) = (uint32_t)LCD_RESET_Pin
#define LCD_CS_CLR GPIO_BC(LCD_CS_Port) = (uint32_t)LCD_CS_Pin
#define LCD_RS_CLR GPIO_BC(LCD_RS_Port) = (uint32_t)LCD_RS_Pin
#define LCD_WR_CLR GPIO_BC(LCD_WR_Port) = (uint32_t)LCD_WR_Pin
#define LCD_RD_CLR GPIO_BC(LCD_RD_Port) = (uint32_t)LCD_RD_Pin

#define LCD_LED(x) (x ? (GPIO_BOP(LCD_EN_Port) = (uint32_t)LCD_EN_Pin) : (GPIO_BC(LCD_EN_Port) = (uint32_t)LCD_EN_Pin))

// PB3~10,作为数据线
// 数据输出
#define DATAOUT(x) DataOut(x)
#define DATAIN DataIn(void) // 数据输入

// 画笔颜色
#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 LGRAY 0XC618      // 浅灰色(PANNEL),窗体背景色

#define LGRAYBLUE 0XA651 // 浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12    // 浅棕蓝色(选择条目的反色)

#define DISP_ON 0x29
#define DISP_OFF 0x28
#define LCD_MADCTL 0x36  // Memory Data Access Control
#define LCD_SLPOUT 0x11  // turns off sleep mode
#define LCD_FRMCTR1 0xB1 // Set the frame frequency of the full colors normal mode
#define LCD_FRMCTR2 0xB2 // Set the frame frequency of the idle mode
#define LCD_FRMCTR3 0xB3 // Set the frame frequency of the Partial mode/full colors
#define LCD_INVCTR 0xB4  // Display inversion mode control
#define LCD_PWCTR1 0xC0  //
#define LCD_READ_ID 0x04 // read lcd id

void DataOut(uint8_t data);
uint8_t DataIn(void);
void LCD_WR_REG(uint8_t data);
void LCD_WR_DATA(uint8_t data);
void LCD_WriteRAM(uint16_t RGB_Code);
void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);
void LCD_WriteRAM_Prepare(void);
void opt_delay(uint8_t i);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);                                       // 关显示
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos);                // 设置光标
void LCD_DrawPoint(uint16_t x, uint16_t y);                      // 画点
void LCD_Fast_DrawPoint(uint16_t x, uint16_t y, uint16_t color); // 快速画点
void LCD_Display_Dir(uint8_t dir);
void LCD_Set_Window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height); // 设置窗口
void LCD_GPIO_Init(void);
void LCD_Init(void); // 初始化
void LCD_DB_Mode(uint8_t mode, uint8_t status);
uint16_t LCD_Read_ID(uint8_t reg);
uint16_t LCD_ReadPoint(uint16_t x, uint16_t y);
void LCD_Clear(uint16_t color);
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color);
void LCD_Color_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color);
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r);
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode);
uint32_t LCD_Pow(uint8_t m, uint8_t n);
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);
void LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, uint8_t *p);
void GUI_DrawFont16(uint16_t x, uint16_t y, uint8_t *s, uint8_t mode);
void GUI_DrawFont24(uint16_t x, uint16_t y, uint8_t *s, uint8_t mode);
void GUI_DrawFont32(uint16_t x, uint16_t y, uint8_t *s, uint8_t mode);
void Show_Str(uint16_t x, uint16_t y, uint8_t *str, uint8_t size, uint8_t mode);
void Gui_Drawbmp16(uint16_t x, uint16_t y, const unsigned char *p); // 显示40*40图片
void Gui_StrCenter(uint16_t x, uint16_t y, uint8_t *str, uint8_t size, uint8_t mode);
void Load_Drow_Dialog(void);
void gui_draw_hline(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color);
void gui_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
void lcd_draw_bline(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t size, uint16_t color);
void tft_lcd_draw_pic(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t *color_buf);
void LCD_Fill_lvgl(uint8_t sx, uint8_t sy, uint8_t ex, uint8_t ey, uint16_t *color);
void logo_disp();

#endif

2、源文件:

#include "st7735s_lcd.h"

//=======================================液晶屏接线===========================================//
// 数据总线类型为8位并口
// DB0~DB7   =        GPIOB:0~7         8位数据线
// CS        =        PC11               片选信号
// RS        =        PC10               数据/命令选择控制信号
// WR        =        PC13               写控制信号
// RD        =        PC14               读控制信号
// RST       =        PC15               复位信号
// LED       =        PC0                背光开关控制

// LCD的画笔颜色和背景色
uint16_t POINT_COLOR = RED;  // 画笔颜色
uint16_t BACK_COLOR = BLACK; // 背景色

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

/// @brief 将数据依次写入D0~D7
/// @param data:输入的八位数据
/// eg: 0x11 —— 0001 0001:DB7 ~ DB0
void DataOut(uint8_t data)
{
#if 0
    uint8_t data_buff[8] = {0};
    for(uint8_t i = 0; i < 8; i++)
    {
        data_buff[i] = (data >> (7 - i)) & 0x01; 
    }
    gpio_bit_write(LCD_DB_Port, LCD_DB0_Pin,data_buff[7]);    // LCD_DB0
    gpio_bit_write(LCD_DB_Port, LCD_DB1_Pin,data_buff[6]);
    gpio_bit_write(LCD_DB_Port, LCD_DB2_Pin,data_buff[5]);
    gpio_bit_write(LCD_DB_Port, LCD_DB3_Pin,data_buff[4]);
    gpio_bit_write(LCD_DB_Port, LCD_DB4_Pin,data_buff[3]);
    gpio_bit_write(LCD_DB_Port, LCD_DB5_Pin,data_buff[2]);
    gpio_bit_write(LCD_DB_Port, LCD_DB6_Pin,data_buff[1]);
    gpio_bit_write(LCD_DB_Port, LCD_DB7_Pin,data_buff[0]);     // LCD_DB7
#endif
    GPIO_BOP(GPIOB) = (data & 0x00FF)             // 置位有效位
                      | ((~data & 0x00FF) << 16); // 仅复位PB0~PB7
}

uint8_t DataIn(void)
{
    uint8_t data = 0;
    uint8_t data_buff[8] = {0};

    data_buff[0] = gpio_input_bit_get(LCD_DB_Port, LCD_DB0_Pin);
    data_buff[1] = gpio_input_bit_get(LCD_DB_Port, LCD_DB1_Pin);
    data_buff[2] = gpio_input_bit_get(LCD_DB_Port, LCD_DB2_Pin);
    data_buff[3] = gpio_input_bit_get(LCD_DB_Port, LCD_DB3_Pin);
    data_buff[4] = gpio_input_bit_get(LCD_DB_Port, LCD_DB4_Pin);
    data_buff[5] = gpio_input_bit_get(LCD_DB_Port, LCD_DB5_Pin);
    data_buff[6] = gpio_input_bit_get(LCD_DB_Port, LCD_DB6_Pin);
    data_buff[7] = gpio_input_bit_get(LCD_DB_Port, LCD_DB7_Pin);

    // Combine bits from data_buff into data
    for (uint8_t i = 0; i < 8; i++)
    {
        data |= (data_buff[i] << i);
    }
    return data;
}

// 写寄存器函数
// data:寄存器值
// eg:0xB1 :1011 0001 -- D7~D0
// D/CX WRX RDX D17-8 D7 D6 D5 D4 D3 D2 D1 D0
//  0    ↑   1    -   1  0  1  1  0  0  0  1
//
void LCD_WR_REG(uint8_t data)
{
    LCD_RS_CLR;    // 数据/命令:0——命令、1——数据
    LCD_CS_CLR;    // 片选拉低(开始传输)
    DATAOUT(data); // 写入命令
    LCD_WR_CLR;    // Wr下降沿(开始写入)
    LCD_WR_SET;    // Wr上升沿(数据锁存)
    LCD_CS_SET;    // CS拉高(结束传输)
}

// 写数据函数
// data:寄存器值
void LCD_WR_DATA(uint8_t data)
{
    LCD_RS_SET;    // 设置DCX信号,1:数据
    LCD_CS_CLR;    // CS拉低
    DATAOUT(data); // 写入数据
    LCD_WR_CLR;
    LCD_WR_SET;
    LCD_CS_SET;
}

// LCD写GRAM
// RGB_Code:颜色值
void LCD_WriteRAM(uint16_t RGB_Code)
{
    // 写十六位GRAM
    LCD_WR_DATA(RGB_Code >> 8); // 先送高8为
    LCD_WR_DATA(RGB_Code);      // 后送低8为
}

// 写寄存器
// LCD_Reg:寄存器编号
// LCD_RegValue:要写入的值
void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue)
{
    LCD_WR_REG(LCD_Reg);
    LCD_WriteRAM(LCD_RegValue);
}

// 开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
    LCD_WR_REG(lcddev.wramcmd); // 0x2C
}

// 当mdk -O1时间优化时需要设置,(没用到)
// 延时i
void opt_delay(uint8_t i)
{
    while (i--)
        ;
}

// LCD开启显示
void LCD_DisplayOn(void)
{
    LCD_WR_REG(DISP_ON); // 开启显示
}

// LCD关闭显示
void LCD_DisplayOff(void)
{
    LCD_WR_REG(DISP_OFF); // 关闭显示
}

// 设置光标位置
// 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_REG(lcddev.setycmd);
    LCD_WR_DATA(Ypos >> 8);
    LCD_WR_DATA(Ypos & 0XFF);
}

// 画点
// x,y:坐标
// POINT_COLOR:此点的颜色
void LCD_DrawPoint(uint16_t x, uint16_t y)
{
    LCD_SetCursor(x, y);    // 设置光标位置
    LCD_WriteRAM_Prepare(); // 开始写入GRAM
    LCD_WriteRAM(POINT_COLOR);
}

// 快速画点
// x,y:坐标
// color:颜色
void LCD_Fast_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
    // 设置光标位置
    LCD_SetCursor(x, y);
    // 写入颜色
    LCD_WriteReg(lcddev.wramcmd, color);
}

// dir:方向选择 	0-0度旋转,1-180度旋转,2-270度旋转,3-90度旋转
void LCD_Display_Dir(uint8_t dir)
{
    if (dir == 0 || dir == 1) // 竖屏
    {
        lcddev.dir = 0; // 竖屏
        lcddev.width = 128;
        lcddev.height = 160;

        lcddev.wramcmd = 0X2C;
        lcddev.setxcmd = 0X2A;
        lcddev.setycmd = 0X2B;

        if (dir == 0) // 0-0度旋转
        {
            LCD_WR_REG(0x36);                                       // 设置屏幕扫描方向命令
            LCD_WR_DATA((0 << 3) | (1 << 7) | (1 << 6) | (0 << 5)); // 0xC0
        }
        else // 1-180度旋转
        {
            LCD_WR_REG(0x36);
            LCD_WR_DATA((0 << 3) | (0 << 7) | (0 << 6) | (0 << 5)); // 0x00
        }
    }
    else if (dir == 2 || dir == 3)
    {

        lcddev.dir = 1;      // 横屏模式
        lcddev.width = 160;  // 实际物理宽度(旋转后的逻辑宽度) 宽160
        lcddev.height = 128; // 实际物理高度(旋转后的逻辑高度) 高128

        // 设置GRAM相关指令(ST7735S芯片固定值)
        lcddev.wramcmd = 0X2C; // 写GRAM指令
        lcddev.setxcmd = 0X2A; // 设置X/列坐标指令
        lcddev.setycmd = 0X2B; // 设置Y/行坐标指令

        if (dir == 2) // 2-270度旋转
        {
            LCD_WR_REG(0x36);                                       // 发送屏幕方向控制命令
            LCD_WR_DATA((0 << 3) | (0 << 7) | (1 << 6) | (1 << 5)); // 参数组合:0<<3 | 0<<7 | 1<<6 | 1<<5 → 二进制01100000 (0x60)
        }
        else // 3-90度旋转
        {
            LCD_WR_REG(0x36);
            LCD_WR_DATA((0 << 3) | (1 << 7) | (0 << 6) | (1 << 5)); // (0xA0)
        }
    }

    // 设置有效显示区域
    LCD_WR_REG(lcddev.setxcmd);
    LCD_WR_DATA(0); LCD_WR_DATA(0);         // X起始地址 0
    LCD_WR_DATA((lcddev.width - 1) >> 8);   // X结束地址高字节:0x00 (159>>8=0)
    LCD_WR_DATA((lcddev.width - 1) & 0XFF); // X结束地址低字节:0x9F (159)
    
    LCD_WR_REG(lcddev.setycmd);             // 设置Y轴坐标
    LCD_WR_DATA(0); LCD_WR_DATA(0);
    LCD_WR_DATA((lcddev.height - 1) >> 8);
    LCD_WR_DATA((lcddev.height - 1) & 0XFF);
}

// 设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).
// sx,sy:窗口起始坐标(左上角)
// width,height:窗口宽度和高度,必须大于0!!
// 窗体大小:width*height.
void LCD_Set_Window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
    uint16_t twidth, theight;   // 160
    twidth = sx + width - 1;    // 减1是因为计算机图形学中从0开始计数的特性,以及硬件寄存器对结束地址的定义,确保窗口范围准确无误。
    theight = sy + height - 1;  // 0+128-1 计算窗口下边界
                                // 设置X坐标
    LCD_WR_REG(lcddev.setxcmd); // 发送设置X坐标命令
    LCD_WR_DATA(sx >> 8);       // 取x坐标高8位,高位先发送
    LCD_WR_DATA(sx & 0XFF);     // 取x坐标低8位
    LCD_WR_DATA(twidth >> 8);   // 取x坐标高8位,高位先发送
    LCD_WR_DATA(twidth & 0XFF); // 取x坐标低8位
                                // 设置Y坐标
    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);
}

void LCD_GPIO_Init(void)
{
    // 开启时钟GPIOB|C
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);

    // 配置引脚
    gpio_init(LCD_EN_Port, GPIO_MODE_OUT_PP, GPIO_OSPEED_MAX, LCD_EN_Pin);
    gpio_init(LCD_CS_Port, GPIO_MODE_OUT_PP, GPIO_OSPEED_MAX,
              LCD_CS_Pin | LCD_RS_Pin | LCD_WR_Pin | LCD_RD_Pin | LCD_RESET_Pin);
    gpio_bit_set(LCD_CS_Port, LCD_CS_Pin);
    gpio_bit_set(LCD_RS_Port, LCD_RS_Pin);
    gpio_bit_set(LCD_WR_Port, LCD_WR_Pin | LCD_RD_Pin | LCD_RESET_Pin);

    gpio_init(LCD_DB_Port, GPIO_MODE_OUT_PP, GPIO_OSPEED_MAX, LCD_DB0_Pin | LCD_DB3_Pin | LCD_DB4_Pin | LCD_DB5_Pin | LCD_DB6_Pin | LCD_DB7_Pin);

    dbg_trace_pin_disable();         // 禁用跟踪引脚分配, 跟踪引脚分配使能由DBG_CTL控制寄存器控制
    rcu_periph_clock_enable(RCU_AF); // 使能映射功能的时钟
    /* PB3、PB4默认为JTAG引脚,需要重新映射;不要将JTAG-DP与SW-DP同时关闭,否侧将无法烧录程序 */
    gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
    gpio_init(LCD_DB_Port, GPIO_MODE_OUT_PP, GPIO_OSPEED_MAX, LCD_DB1_Pin | LCD_DB2_Pin);

    gpio_bit_set(LCD_DB_Port, LCD_DB0_Pin | LCD_DB1_Pin | LCD_DB2_Pin | LCD_DB3_Pin |
                                  LCD_DB4_Pin | LCD_DB5_Pin | LCD_DB6_Pin | LCD_DB7_Pin);
}

// 初始化lcd
void LCD_Init(void)
{
    LCD_GPIO_Init();

    // RCC->APB2ENR|=1<<0;    //开启辅助时钟
    // JTAG_Set(SWD_ENABLE);  //开启SWD

    /* 复位 */
    LCD_RST_SET;
    delay_1ms(1);
    LCD_RST_CLR;
    delay_1ms(10);
    LCD_RST_SET;
    delay_1ms(120);

    //************* Start Initial Sequence **********//
    delay_1ms(120); // ms

    LCD_WR_REG(0x11); // 退出睡眠

    delay_1ms(120); // delay_1ms 120ms

    LCD_WR_REG(LCD_FRMCTR1); // 帧速率控制(处于正常模式/全色模式)
    LCD_WR_DATA(0x00);       // frame rate=85.3Hz
    LCD_WR_DATA(0x2C);       //
    LCD_WR_DATA(0x2B);

    LCD_WR_REG(LCD_FRMCTR2); // 设置空闲模式的帧频率。
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x01);
    LCD_WR_DATA(0x01);

    LCD_WR_REG(LCD_FRMCTR3); // In partial mode
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x01);
    LCD_WR_DATA(0x01);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x01);
    LCD_WR_DATA(0x01);

    LCD_WR_REG(LCD_INVCTR); DOT反转显示反转控制
    LCD_WR_DATA(0x03);

    LCD_WR_REG(0xB9); // In normal mode
    LCD_WR_DATA(0xFF);
    LCD_WR_DATA(0x83);
    LCD_WR_DATA(0x47);

    LCD_WR_REG(0xC0); // VRH: Set the GVDD
    LCD_WR_DATA(0xA2);
    LCD_WR_DATA(0x02);
    LCD_WR_DATA(0x84);

    LCD_WR_REG(0xC1);  // set VGH/ VGL
    LCD_WR_DATA(0x02); //??02 VGH=16.6 VGL=-7.5  00 VGH=11.6 VGL=-7.5  06 VGH=16.6  VGL=-10

    LCD_WR_REG(0xC2); // APA: adjust the operational amplifier DCA: adjust the booster Voltage
    LCD_WR_DATA(0x0A);
    LCD_WR_DATA(0x00);

    LCD_WR_REG(0xC3); // In Idle mode (8-colors)
    LCD_WR_DATA(0x8A);
    LCD_WR_DATA(0x2A);

    LCD_WR_REG(0xC4); // In partial mode + Full color
    LCD_WR_DATA(0x8A);
    LCD_WR_DATA(0xEE);

    LCD_WR_REG(0xC5); // VCOM
    LCD_WR_DATA(0x09);

    LCD_WR_REG(0x20); // Display inversion

    LCD_WR_REG(0xC7);
    LCD_WR_DATA(0x10);

    LCD_WR_REG(0x36);  // MX, MY, RGB mode
    LCD_WR_DATA(0xC0); // 08

    LCD_WR_REG(0xE0);
    LCD_WR_DATA(0x0C);
    LCD_WR_DATA(0x1C);
    LCD_WR_DATA(0x1B);
    LCD_WR_DATA(0x1A);
    LCD_WR_DATA(0x2F);
    LCD_WR_DATA(0x28);
    LCD_WR_DATA(0x20);
    LCD_WR_DATA(0x24);
    LCD_WR_DATA(0x23);
    LCD_WR_DATA(0x22);
    LCD_WR_DATA(0x2A);
    LCD_WR_DATA(0x36);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x05);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x10);

    LCD_WR_REG(0xE1);
    LCD_WR_DATA(0x0C);
    LCD_WR_DATA(0x1A);
    LCD_WR_DATA(0x1A);
    LCD_WR_DATA(0x1A);
    LCD_WR_DATA(0x2E);
    LCD_WR_DATA(0x27);
    LCD_WR_DATA(0x21);
    LCD_WR_DATA(0x24);
    LCD_WR_DATA(0x24);
    LCD_WR_DATA(0x22);
    LCD_WR_DATA(0x2A);
    LCD_WR_DATA(0x35);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x05);
    LCD_WR_DATA(0x00);
    LCD_WR_DATA(0x10);

    LCD_WR_REG(0x35); // 65k mode
    LCD_WR_DATA(0x00);

    LCD_WR_REG(0x3A); // 65k mode
    LCD_WR_DATA(0x05);

    LCD_WR_REG(0x29); // Display on
    // LCD_DisplayOff();
    LCD_Display_Dir(USE_LCM_DIR); // 屏幕方向
    LCD_LED(0);
    // LCD_Clear(BLACK);
}

// brief:设置数据线模式
// para:mode,0--输入、1--输出
void LCD_DB_Mode(uint8_t mode, uint8_t status)
{
    if (mode)
    {
        // DB0~7:通用推挽输出模式
        gpio_init(LCD_DB_Port, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, LCD_DB0_Pin | LCD_DB1_Pin | LCD_DB2_Pin | LCD_DB3_Pin | LCD_DB4_Pin | LCD_DB5_Pin | LCD_DB6_Pin | LCD_DB7_Pin);
    }
    else
    {
        // DB0~7: 上拉输入模式
        gpio_init(LCD_DB_Port, GPIO_MODE_IPU, GPIO_OSPEED_10MHZ, LCD_DB0_Pin | LCD_DB1_Pin | LCD_DB2_Pin | LCD_DB3_Pin | LCD_DB4_Pin | LCD_DB5_Pin | LCD_DB6_Pin | LCD_DB7_Pin);
    }
    // 全部输出
    gpio_bit_write(LCD_DB_Port, LCD_DB0_Pin | LCD_DB1_Pin | LCD_DB2_Pin | LCD_DB3_Pin | LCD_DB4_Pin | LCD_DB5_Pin | LCD_DB6_Pin | LCD_DB7_Pin, status);
}

// 读LCD数据
// 返回值:读到的值
uint16_t LCD_RD_DATA(void)
{
    uint16_t t;
    // 数据线输入,全部输出0
    LCD_DB_Mode(DB_PORT_INPUT, 0);
    LCD_RS_SET;
    LCD_CS_CLR;
    // 读取数据(读寄存器时,并不需要读2次)
    LCD_RD_CLR;
    t = DataIn();
    LCD_RD_SET;
    LCD_CS_SET;
    // 数据线输出,全部输出高
    LCD_DB_Mode(DB_PORT_OUTPUT, 1);

    return t = t >> 8;
}

// 读显示屏 ID   指令:0X04
uint16_t LCD_Read_ID(uint8_t reg)
{
    LCD_WR_REG(reg);
    LCD_RD_DATA(); // dummy read
    LCD_RD_DATA();
    lcddev.id = LCD_RD_DATA();
    lcddev.id <<= 8;
    lcddev.id |= LCD_RD_DATA();

    return lcddev.id;
}

// 读取个某点的颜色值
// x,y:坐标
// 返回值:此点的颜色
uint16_t LCD_ReadPoint(uint16_t x, uint16_t y)
{
    uint16_t r, g, b;
    if (x >= lcddev.width || y >= lcddev.height)
        return 0; // 超过了范围,直接返回
    LCD_SetCursor(x, y);
    //		LCD_SetCursor(28,28);
    LCD_WR_REG(0X2E); // 9341/6804/3510/1963 发送读GRAM指令

    // GPIOB->CRL=0X88888888; 							//PB0-7  上拉输入
    // GPIOB->CRH=0X88888888; 							//PB8-15 上拉输入
    // GPIOB->ODR=0XFFFF;     							//全部输出高
    LCD_DB_Mode(DB_PORT_INPUT, 1);

    LCD_RS_SET;
    LCD_CS_CLR;
    // 读取数据(假读)
    LCD_RD_CLR;
    opt_delay(2); // 延时
    // r=DATAIN;  //dummy READ
    LCD_RD_SET;

    // 读取数据(假读)
    LCD_RD_CLR;
    opt_delay(2); // 延时
    // r=DATAIN;  //dummy READ
    LCD_RD_SET;

    // 读取数据(假读)
    LCD_RD_CLR;
    opt_delay(2); // 延时
    // r=DATAIN;  //dummy READ
    LCD_RD_SET;

    // 读取数据(读GRAM时,前四次为假读)
    LCD_RD_CLR;
    opt_delay(2); // 延时
    // r=DATAIN;  //dummy READ
    LCD_RD_SET;

    LCD_RD_CLR;
    opt_delay(2); // 延时
    r = DataIn(); // 读取红色值
    r = r >> 8;
    LCD_RD_SET;

    LCD_RD_CLR;
    opt_delay(2); // 延时
    g = DataIn(); // 读取绿色值
    g = g >> 8;
    LCD_RD_SET;

    LCD_RD_CLR;
    opt_delay(2); // 延时
    b = DataIn(); // 读取蓝色值
    b = b >> 8;
    LCD_RD_SET;

    LCD_CS_SET;

    r = r & 0xFF;
    g = g & 0xFF;
    b = b & 0xFF;

    // GPIOB->CRL=0X33333333; 		//PB0-7  上拉输出
    // GPIOB->CRH=0X33333333; 		//PB8-15 上拉输出
    // GPIOB->ODR=0XFFFF;    		//全部输出高
    LCD_DB_Mode(DB_PORT_OUTPUT, 1);

    return (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
    //	return r;
}

// 清屏函数
// color:要清屏的填充色
void LCD_Clear(uint16_t color)
{
    uint32_t index = 0;
    uint32_t totalpoint = lcddev.width;
    totalpoint *= lcddev.height; // 得到总点数
    LCD_SetCursor(0x00, 0x0000); // 设置光标位置
    LCD_WriteRAM_Prepare();      // 开始写入GRAM
    for (index = 0; index < totalpoint; index++)
    {
        LCD_WriteRAM(color);
    }
}

// 在指定区域内填充指定颜色
// 区域大小:(xend-xsta+1)*(yend-ysta+1)
// xsta
// color:要填充的颜色
void LCD_Fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
{
    uint16_t i, j;
    uint16_t xlen = 0;
    uint16_t temp;
    if ((lcddev.id == 0X6804) && (lcddev.dir == 1)) // 6804横屏的时候特殊处理
    {
        temp = sx;
        sx = sy;
        sy = lcddev.width - ex - 1;
        ex = ey;
        ey = lcddev.width - temp - 1;
        lcddev.dir = 0;
        lcddev.setxcmd = 0X2A;
        lcddev.setycmd = 0X2B;
        LCD_Fill(sx, sy, ex, ey, color);
        lcddev.dir = 1;
        lcddev.setxcmd = 0X2B;
        lcddev.setycmd = 0X2A;
    }
    else
    {
        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_WriteRAM(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 height, width;
    uint16_t 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_WriteRAM(color[i * width + j]); // 写入数据
    }
}

// 画线
// x1,y1:起点坐标
// x2,y2:终点坐标
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t 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--;
        }
    }
}

// 在指定位置显示一个字符
// x,y:起始坐标
// num:要显示的字符:" "--->"~"
// size:字体大小 12/16/24
// 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
            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.height)
                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,height:区域大小
// size:字体大小
//*p:字符串起始地址
void LCD_ShowString(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, uint8_t *p)
{
    uint8_t 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++;
    }
}

#if 0
//汉字 16*16
void GUI_DrawFont16(uint16_t x, uint16_t y, uint8_t *s, uint8_t mode)
{
	uint8_t i,j;
	uint16_t k;
	uint16_t HZnum;
	uint16_t x0=x;
	HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);	//自动统计汉字数目
	
			
	for (k=0;k<HZnum;k++) 
	{
	  if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
	  { 	LCD_Set_Window(x,y,16,16);
				LCD_WriteRAM_Prepare();
		    for(i=0;i<16*2;i++)
		    {
				for(j=0;j<8;j++)
		    	{	
					if(!mode) //非叠加方式
					{
						if(tfont16[k].Msk[i]&(0x80>>j))	LCD_WriteRAM(POINT_COLOR);
						else LCD_WriteRAM(BACK_COLOR);
					}
					else
					{
						//POINT_COLOR=fc;
						if(tfont16[k].Msk[i]&(0x80>>j))	LCD_DrawPoint(x,y);//画一个点
						x++;
						if((x-x0)==16)
						{
							x=x0;
							y++;
							break;
						}
					}

				}
				
			}
			
			
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}

	LCD_Set_Window(0,0,lcddev.width,lcddev.height);//恢复窗口为全屏  
} 


//汉字 24*24
void GUI_DrawFont24(uint16_t x, uint16_t y, uint8_t *s,uint8_t mode)
{
	uint8_t i,j;
	uint16_t k;
	uint16_t HZnum;
	uint16_t x0=x;
	HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);	//自动统计汉字数目
		
			for (k=0;k<HZnum;k++) 
			{
			  if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
			  { 	LCD_Set_Window(x,y,24,24);
						LCD_WriteRAM_Prepare();
				    for(i=0;i<24*3;i++)
				    {
							for(j=0;j<8;j++)
							{
								if(!mode) //非叠加方式
								{
									if(tfont24[k].Msk[i]&(0x80>>j))	LCD_WriteRAM(POINT_COLOR);
									else LCD_WriteRAM(BACK_COLOR);
								}
							else
							{
								//POINT_COLOR=fc;
								if(tfont24[k].Msk[i]&(0x80>>j))	LCD_DrawPoint(x,y);//画一个点
								x++;
								if((x-x0)==24)
								{
									x=x0;
									y++;
									break;
								}
							}
						}
					}
					
					
				}				  	
				continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
			}

	LCD_Set_Window(0,0,lcddev.width,lcddev.height);//恢复窗口为全屏  
}

//汉字 32*32
void GUI_DrawFont32(uint16_t x, uint16_t y, uint8_t *s,uint8_t mode)
{
	uint8_t i,j;
	uint16_t k;
	uint16_t HZnum;
	uint16_t x0=x;
	HZnum=sizeof(tfont32) / sizeof(typFNT_GB32);	//自动统计汉字数目
	for (k=0;k<HZnum;k++) 
			{
			  if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1)))
			  { 	LCD_Set_Window(x,y,32,32);
						LCD_WriteRAM_Prepare();
				    for(i=0;i<32*4;i++)
				    {
						for(j=0;j<8;j++)
				    	{
							if(!mode) //非叠加方式
							{
								if(tfont32[k].Msk[i]&(0x80>>j))	LCD_WriteRAM(POINT_COLOR);
								else LCD_WriteRAM(BACK_COLOR);
							}
							else
							{
								//POINT_COLOR=fc;
								if(tfont32[k].Msk[i]&(0x80>>j))	LCD_DrawPoint(x,y);//画一个点
								x++;
								if((x-x0)==32)
								{
									x=x0;
									y++;
									break;
								}
							}
						}
					}
					
					
				}				  	
				continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
			}
	
	LCD_Set_Window(0,0,lcddev.width,lcddev.height);//恢复窗口为全屏  
}

#endif

// 显示汉字或者字符串
void Show_Str(uint16_t x, uint16_t y, uint8_t *str, uint8_t size, uint8_t mode)
{
    uint16_t x0 = x;
    uint8_t bHz = 0;  // 字符或者中文   默认为英文
    while (*str != 0) // 数据未结束
    {
        if (!bHz)
        {
            if (x > (lcddev.width - size / 2) || y > (lcddev.height - size))
                return;
            if (*str > 0x80)
                bHz = 1; // 中文
            else         // 字符
            {
                if (*str == 0x0D) // 换行符号
                {
                    y += size;
                    x = x0;
                    str++;
                }
                else
                {
                    if (size >= 24) // 字库中没有集成12X24 16X32的英文字体,用8X16代替
                    {
                        LCD_ShowChar(x, y, *str, 24, mode);
                        x += 12; // 字符,为全字的一半
                    }
                    else
                    {
                        LCD_ShowChar(x, y, *str, size, mode);
                        x += size / 2; // 字符,为全字的一半
                    }
                }
                str++;
            }
        }
        else // 中文
        {
            if (x > (lcddev.width - size) || y > (lcddev.height - size))
                return;
            bHz = 0; // 有汉字库
            /* 屏蔽掉中文显示 */
            // if(size==32)
            // GUI_DrawFont32(x,y,str,mode);
            // else if(size==24)
            // GUI_DrawFont24(x,y,str,mode);
            // else
            // GUI_DrawFont16(x,y,str,mode);

            str += 2;
            x += size; // 下一个汉字偏移
        }
    }
}

// 显示40*40图片
void Gui_Drawbmp16(uint16_t x, uint16_t y, const unsigned char *p) // 显示40*40图片
{
    uint16_t i;
    uint8_t picH, picL;
    LCD_Set_Window(x, y, 40, 40);
    LCD_WriteRAM_Prepare();

    for (i = 0; i < 40 * 40; i++)
    {
        picL = *(p + i * 2); // 数据低位在前
        picH = *(p + i * 2 + 1);
        LCD_WriteRAM(picH << 8 | picL);
    }
    LCD_Set_Window(0, 0, lcddev.width, lcddev.height); // 恢复显示窗口为全屏
}

// 居中显示
void Gui_StrCenter(uint16_t x, uint16_t y, uint8_t *str, uint8_t size, uint8_t mode)
{
    uint16_t x1;
    uint16_t len = strlen((const char *)str);
    if (size > 16)
    {
        x1 = (lcddev.width - len * (size / 2)) / 2;
    }
    else
    {
        x1 = (lcddev.width - len * 8) / 2;
    }

    Show_Str(x + x1, y, str, size, mode);
}

void Load_Drow_Dialog(void)
{
    LCD_Clear(WHITE);   // 清屏
    POINT_COLOR = BLUE; // 设置字体为蓝色
    BACK_COLOR = WHITE;
    LCD_ShowString(lcddev.width - 24, 0, 200, 16, 16, "RST"); // 显示清屏区域
    POINT_COLOR = RED;                                        // 设置画笔蓝色
}

// 电容触摸屏专有部分
// 画水平线
// x0,y0:坐标
// len:线长度
// color:颜色
void gui_draw_hline(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color)
{
    if (len == 0)
        return;
    LCD_Fill(x0, y0, x0 + len - 1, y0, color);
}
// 画实心圆
// x0,y0:坐标
// r:半径
// color:颜色
void gui_fill_circle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color)
{
    uint32_t i;
    uint32_t imax = ((uint32_t)r * 707) / 1000 + 1;
    uint32_t sqmax = (uint32_t)r * (uint32_t)r + (uint32_t)r / 2;
    uint32_t x = r;
    gui_draw_hline(x0 - r, y0, 2 * r, color);
    for (i = 1; i <= imax; i++)
    {
        if ((i * i + x * x) > sqmax) // draw lines from outside
        {
            if (x > imax)
            {
                gui_draw_hline(x0 - i + 1, y0 + x, 2 * (i - 1), color);
                gui_draw_hline(x0 - i + 1, y0 - x, 2 * (i - 1), color);
            }
            x--;
        }
        // draw lines from inside (center)
        gui_draw_hline(x0 - x, y0 + i, 2 * x, color);
        gui_draw_hline(x0 - x, y0 - i, 2 * x, color);
    }
}

// 画一条粗线
//(x1,y1),(x2,y2):线条的起始坐标
// size:线条的粗细程度
// color:线条的颜色
void lcd_draw_bline(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t size, uint16_t color)
{
    uint16_t t;
    int xerr = 0, yerr = 0, delta_x, delta_y, distance;
    int 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++) // 画线输出
    {
        gui_fill_circle(uRow, uCol, size, color); // 画点
        xerr += delta_x;
        yerr += delta_y;
        if (xerr > distance)
        {
            xerr -= distance;
            uRow += incx;
        }
        if (yerr > distance)
        {
            yerr -= distance;
            uCol += incy;
        }
    }
}

void tft_lcd_draw_pic(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t *color_buf)
{
    uint16_t i;
    uint32_t total_point = (x_end - x_start) * (y_end - y_start);
    LCD_Set_Window(x_start, y_start, x_end, y_end);
    LCD_WriteRAM_Prepare();

    for (i = 0; i < total_point; i++)
    {
        LCD_WriteRAM(*color_buf);
        color_buf++;
    }
    LCD_Set_Window(0, 0, lcddev.width, lcddev.height); // 恢复显示窗口为全屏
}

void LCD_Fill_lvgl(uint8_t sx, uint8_t sy, uint8_t ex, uint8_t ey, uint16_t *color)
{
    uint8_t i, j;
    uint8_t width = ex - sx;  // 得到填充的宽度
    uint8_t height = ey - sy; // 高度

    LCD_Set_Window(sx, sy, ex, ey); // 设置显示窗口
    LCD_WriteRAM_Prepare();
    for (i = 0; i < height; i++)
    {
        for (j = 0; j < width; j++)
        {
            LCD_WriteRAM(*color); // 写入数据
            color++;
        }
    }
}

void logo_disp()
{
    tft_lcd_draw_pic(0, 0, LCD_HEIGHT, LCD_WIDTH, (uint16_t *)gImage_start);
    LCD_LED(1); // 点亮背光
}

三、部分代码解析

/// @brief 将数据依次写入D0~D7
/// @param data:输入的八位数据
/// eg: 0x11 —— 0001 0001:DB7 ~ DB0
void DataOut(uint8_t data)
{
    GPIO_BOP(GPIOB) = (data & 0x00FF)             // 置位有效位
                      | ((~data & 0x00FF) << 16); // 仅复位PB0~PB7
}

GPIO_BOP寄存器:端口位操作寄存器 (GPIOx_BOP, x=A..G)

分步解析:
假设输入data = 0xA5(二进制10100101)
1、置位操作部分:
data & 0x00FF → 0xA5(保留低8位)
对应二进制:10100101
置位GPIOB的PB0~7

2、复位操作部分:
~data → 0x5A(01011010)
(~data & 0x00FF) << 16 → 0x5A0000
高16位的第16-23位有效(对应复位PB0-PB7)
复位GPIOB的PB0~7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值