卢阿涛 · 2022年04月03日

【GD32F310开发板试用】驱动ST7735 SPI屏幕

代码篇幅比较多,看测试结果请直接拉到最后。

一、硬件介绍

1. 屏幕介绍

  1. 屏幕驱动 ST7735
  2. 屏幕分辨率 135x240
  3. 驱动接口 SPI

    2. 开发板连接

    对应引脚

    // GND 电源地
    // VCC 接5V或3.3v电源
    // SCL 接PA5(SCL)
    // SDA 接PA7(SDA)
    // CS 接PA4//可以直接接地
    // RES 接PA3
    // DC 接PA2
    // BLK 接PA1

实物图
 title=

注意事项
这里使用的是硬件的SPI0,也就是用到了PA5和PA7这两个引脚,但是这块开发板的PA5是没有直接连接到外扩的引脚,中间这个排针需要跳一下,
 title=

二、软件介绍

1. 开发环境

  1. keil 5.36版本 编写程序
  2. Image2Lcd 2.9 图片取模
  3. PCtoLCD2002 字符取模

    2. 代码

    1.st7735.h

    #ifndef _St7735_H
    #define _St7735_H
    
    #include "gd32f3x0.h"
    #include "systick.h"
    
    
    //              GND     电源地
    //              VCC     接5V或3.3v电源
    //              SCL     接PA5(SCL)
    //              SDA     接PA7(SDA)
    //              CS      接PA4//可以直接接地
    
    //              RES     接PA3
    //              DC      接PA2
    //              BLK     接PA1 
    
    
    #define USE_HORIZONTAL 3  //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
    #define USE_HARDWARESPI   // 设置使用硬件SPI还是软件SPI  
    
    #if USE_HORIZONTAL==0||USE_HORIZONTAL==1
    #define LCD_W 135
    #define LCD_H 240
    
    #else
    #define LCD_W 240
    #define LCD_H 135
    #endif
    
    
    //-----------------LCD端口定义---------------- 
    #ifndef USE_HARDWARESPI
    
    #define LCD_SCLK_RCU                          RCU_GPIOA
    #define LCD_SCLK_PORT                          GPIOA
    #define LCD_SCLK_PIN                           GPIO_PIN_5
    
    #define LCD_MOSI_RCU                          RCU_GPIOA
    #define LCD_MOSI_PORT                          GPIOA
    #define LCD_MOSI_PIN                           GPIO_PIN_7
    
    
    #define LCD_SCLK_Clr() gpio_bit_reset(LCD_SCLK_PORT,LCD_SCLK_PIN)//SCL=SCLK
    #define LCD_SCLK_Set() gpio_bit_set(LCD_SCLK_PORT,LCD_SCLK_PIN)
    
    #define LCD_MOSI_Clr() gpio_bit_reset(LCD_MOSI_PORT,LCD_MOSI_PIN)//SDA=MOSI
    #define LCD_MOSI_Set() gpio_bit_set(LCD_MOSI_PORT,LCD_MOSI_PIN)
    #endif
    
    #define LCD_CS_RCU                          RCU_GPIOA
    #define LCD_CS_PORT                          GPIOA
    #define LCD_CS_PIN                           GPIO_PIN_4
    
    #define LCD_RES_RCU                          RCU_GPIOA
    #define LCD_RES_PORT                       GPIOA
    #define LCD_RES_PIN                           GPIO_PIN_3
    
    #define LCD_DC_RCU                          RCU_GPIOA
    #define LCD_DC_PORT                          GPIOA
    #define LCD_DC_PIN                           GPIO_PIN_2
    
    #define LCD_BLK_RCU                          RCU_GPIOA
    #define LCD_BLK_PORT                     GPIOA
    #define LCD_BLK_PIN                           GPIO_PIN_1
    
    
    #define LCD_CS_Clr()   gpio_bit_reset(LCD_CS_PORT,LCD_CS_PIN)//CS  
    #define LCD_CS_Set()   gpio_bit_set(LCD_CS_PORT,LCD_CS_PIN)
    
    #define LCD_RES_Clr()    gpio_bit_reset(LCD_RES_PORT,LCD_RES_PIN)//RES  
    #define LCD_RES_Set()    gpio_bit_set(LCD_RES_PORT,LCD_RES_PIN)
    
    #define LCD_DC_Clr()   gpio_bit_reset(LCD_DC_PORT,LCD_DC_PIN)//DC 
    #define LCD_DC_Set()   gpio_bit_set(LCD_DC_PORT,LCD_DC_PIN)
               
    #define LCD_BLK_Clr()  gpio_bit_reset(LCD_BLK_PORT,LCD_BLK_PIN)//BLK  
    #define LCD_BLK_Set()  gpio_bit_set(LCD_BLK_PORT,LCD_BLK_PIN)
    
    
    void LCD_GPIO_Init(void);//初始化GPIO
    void LCD_Writ_Bus(uint8_t dat);//模拟SPI时序
    void LCD_WR_DATA8(uint8_t dat);//写入一个字节
    void LCD_WR_DATA(uint16_t dat);//写入两个字节
    void LCD_WR_REG(uint8_t dat);//写入一个指令
    void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);//设置坐标函数
    void LCD_Init(void);//LCD初始化
    
    #endif

### 2.st7735.c  

    #include "St7735.h"
    #include "GUI.h"
    #include "spi.h"
    
    
    void LCD_GPIO_Init(void)
    {
     #ifndef USE_HARDWARESPI
     /* SCLK */
     rcu_periph_clock_enable(LCD_SCLK_RCU);
     gpio_mode_set(LCD_SCLK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_SCLK_PIN);
     gpio_output_options_set(LCD_SCLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_SCLK_PIN);
     
     /* MOSI */
     rcu_periph_clock_enable(LCD_MOSI_RCU);
     gpio_mode_set(LCD_MOSI_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_MOSI_PIN);
     gpio_output_options_set(LCD_MOSI_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_MOSI_PIN);
     #endif
     
     /* CS */
     rcu_periph_clock_enable(LCD_CS_RCU);
     gpio_mode_set(LCD_CS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_CS_PIN);
     gpio_output_options_set(LCD_CS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_CS_PIN);    
      gpio_bit_set(LCD_CS_PORT,LCD_CS_PIN);
     
     /* RES */
     rcu_periph_clock_enable(LCD_RES_RCU);
     gpio_mode_set(LCD_RES_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_RES_PIN);
     gpio_output_options_set(LCD_RES_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_RES_PIN);    
      gpio_bit_set(LCD_RES_PORT,LCD_RES_PIN);
     
     /* DC */
     rcu_periph_clock_enable(LCD_DC_RCU);
     gpio_mode_set(LCD_DC_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_DC_PIN);
     gpio_output_options_set(LCD_DC_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_DC_PIN);    
      gpio_bit_set(LCD_DC_PORT,LCD_DC_PIN);
     
     /* BLK */
     rcu_periph_clock_enable(LCD_BLK_RCU);
     gpio_mode_set(LCD_BLK_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LCD_BLK_PIN);
     gpio_output_options_set(LCD_BLK_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, LCD_BLK_PIN);    
    }
    
    
    #ifdef USE_HARDWARESPI
    
    /******************************************************************************
       函数说明:LCD串行数据写入函数
       入口数据:dat  要写入的串行数据
       返回值:  无
    ******************************************************************************/
    void LCD_Writ_Bus(uint8_t dat) 
    {    
     LCD_CS_Clr();
     spi_ReadWriteByte(dat);
     //delay_1ms(1);
     LCD_CS_Set();    
    }
    
    #else 
    /******************************************************************************
       函数说明:LCD串行数据写入函数
       入口数据:dat  要写入的串行数据  硬件SPI
       返回值:  无
    ******************************************************************************/
    void LCD_Writ_Bus(uint8_t dat) 
    {    
     uint8_t i;
     LCD_CS_Clr();
     for(i=0;i<8;i++)
     {              
         LCD_SCLK_Clr();
         if(dat&0x80)
         {
            LCD_MOSI_Set();
         }
         else
         {
            LCD_MOSI_Clr();
         }
         LCD_SCLK_Set();
         dat<<=1;
     }    
      LCD_CS_Set();    
    }
    
    #endif
    
    
    /******************************************************************************
       函数说明:LCD写入数据
       入口数据:dat 写入的数据
       返回值:  无
    ******************************************************************************/
    void LCD_WR_DATA8(uint8_t dat)
    {
     LCD_Writ_Bus(dat);
    }
    
    
    /******************************************************************************
       函数说明:LCD写入数据
       入口数据:dat 写入的数据
       返回值:  无
    ******************************************************************************/
    void LCD_WR_DATA(uint16_t dat)
    {
     LCD_Writ_Bus(dat>>8);
     LCD_Writ_Bus(dat);
    }
    
    
    /******************************************************************************
       函数说明:LCD写入命令
       入口数据:dat 写入的命令
       返回值:  无
    ******************************************************************************/
    void LCD_WR_REG(uint8_t dat)
    {
     LCD_DC_Clr();//写命令
     LCD_Writ_Bus(dat);
     LCD_DC_Set();//写数据
    }
    
    
    /******************************************************************************
       函数说明:设置起始和结束地址
       入口数据:x1,x2 设置列的起始和结束地址
                 y1,y2 设置行的起始和结束地址
       返回值:  无
    ******************************************************************************/
    void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
     
    {
     if(USE_HORIZONTAL==0)
     {
         LCD_WR_REG(0x2a);//列地址设置
         LCD_WR_DATA(x1+52);
         LCD_WR_DATA(x2+52);
         LCD_WR_REG(0x2b);//行地址设置
         LCD_WR_DATA(y1+40);
         LCD_WR_DATA(y2+40);
         LCD_WR_REG(0x2c);//储存器写
     }
     else if(USE_HORIZONTAL==1)
     {
         LCD_WR_REG(0x2a);//列地址设置
         LCD_WR_DATA(x1+53);
         LCD_WR_DATA(x2+53);
         LCD_WR_REG(0x2b);//行地址设置
         LCD_WR_DATA(y1+40);
         LCD_WR_DATA(y2+40);
         LCD_WR_REG(0x2c);//储存器写
     }
     else if(USE_HORIZONTAL==2)
     {
         LCD_WR_REG(0x2a);//列地址设置
         LCD_WR_DATA(x1+40);
         LCD_WR_DATA(x2+40);
         LCD_WR_REG(0x2b);//行地址设置
         LCD_WR_DATA(y1+53);
         LCD_WR_DATA(y2+53);
         LCD_WR_REG(0x2c);//储存器写
     }
     else
     {
         LCD_WR_REG(0x2a);//列地址设置
         LCD_WR_DATA(x1+40);
         LCD_WR_DATA(x2+40);
         LCD_WR_REG(0x2b);//行地址设置
         LCD_WR_DATA(y1+52);
         LCD_WR_DATA(y2+52);
         LCD_WR_REG(0x2c);//储存器写
     }
    }
    
    
    void LCD_Init(void)
    {
     LCD_GPIO_Init();//初始化GPIO
     
     LCD_RES_Clr();//复位
     delay_1ms(100);
     LCD_RES_Set();
     delay_1ms(50);
     
     LCD_BLK_Set();//打开背光
     delay_1ms(100);
     
     LCD_WR_REG(0x11);                                             //无此指令,不能正常初始化芯片,无显示
     delay_1ms(120); 
     LCD_WR_REG(0x36);                                             //设置内存扫描方向,0X00正常扫描,从上往下,从左往右,RGB方式
     if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
     else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
     else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
     else LCD_WR_DATA8(0xA0);
    
     LCD_WR_REG(0x3A);                                             //数据格式,65K色,565
     LCD_WR_DATA8(0x05);
    
     LCD_WR_REG(0xB2);                                             //帧频设置
     LCD_WR_DATA8(0x0C);
     LCD_WR_DATA8(0x0C);
     LCD_WR_DATA8(0x00);
     LCD_WR_DATA8(0x33);
     LCD_WR_DATA8(0x33); 
    
     LCD_WR_REG(0xB7);                                             //GATE 设置
     LCD_WR_DATA8(0x35);  
    
     LCD_WR_REG(0xBB);                                             //VCOM设置 
     LCD_WR_DATA8(0x19);
    
     LCD_WR_REG(0xC0);                                             //LCM设置,默认0x2c
     LCD_WR_DATA8(0x2C);
    
     LCD_WR_REG(0xC2);                                             //VDV&VRH SET ,默认0x01
     LCD_WR_DATA8(0x01);
    
     LCD_WR_REG(0xC3);                                             //VRHS SET,默认0x0b
     LCD_WR_DATA8(0x12);                                           //此处根据实际情况修正
    
     LCD_WR_REG(0xC4);                                             //VDV SET,默认0x20
     LCD_WR_DATA8(0x20);  
    
     LCD_WR_REG(0xC6);                                             // FR SET, 默认0x0F
     LCD_WR_DATA8(0x0F);    
    
     LCD_WR_REG(0xD0);                                             //电源控制1
     LCD_WR_DATA8(0xA4);                                           //该参数不变  
     LCD_WR_DATA8(0xA1);                                           //此处根据实际情况修改
    
     LCD_WR_REG(0xE0);                                             //正极性GAMMA调整 
     LCD_WR_DATA8(0xD0);
     LCD_WR_DATA8(0x04);
     LCD_WR_DATA8(0x0D);
     LCD_WR_DATA8(0x11);
     LCD_WR_DATA8(0x13);
     LCD_WR_DATA8(0x2B);
     LCD_WR_DATA8(0x3F);
     LCD_WR_DATA8(0x54);
     LCD_WR_DATA8(0x4C);
     LCD_WR_DATA8(0x18);
     LCD_WR_DATA8(0x0D);
     LCD_WR_DATA8(0x0B);
     LCD_WR_DATA8(0x1F);
     LCD_WR_DATA8(0x23);
    
     LCD_WR_REG(0xE1);                                              //负极性GAMMA调整
     LCD_WR_DATA8(0xD0);
     LCD_WR_DATA8(0x04);
     LCD_WR_DATA8(0x0C);
     LCD_WR_DATA8(0x11);
     LCD_WR_DATA8(0x13);
     LCD_WR_DATA8(0x2C);
     LCD_WR_DATA8(0x3F);
     LCD_WR_DATA8(0x44);
     LCD_WR_DATA8(0x51);
     LCD_WR_DATA8(0x2F);
     LCD_WR_DATA8(0x1F);
     LCD_WR_DATA8(0x1F);
     LCD_WR_DATA8(0x20);
     LCD_WR_DATA8(0x23);
    
     LCD_WR_REG(0x21);                                             //反显开,默认是0X20,正常模式
    
     LCD_WR_REG(0x29);                                             //显示开,等待MCU数传送
    }

### 3.GUI.h  

    #ifndef _GUI_H
    #define _GUI_H
    
    #include "gd32f3x0.h"
    #include "systick.h"
    
    //画笔颜色
    #define bg  0xE73D
    #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 //浅棕蓝色(选择条目的反色)
    
    void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color);//指定区域填充颜色
    void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color);//在指定位置画一个点
    void LCD_DrawLine(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color);//在指定位置画一条线
    void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color);//在指定位置画一个矩形
    void Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r,uint16_t color);//在指定位置画一个圆
    
    void LCD_ShowChinese(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示汉字串
    void LCD_ShowChinese12x12(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示单个12x12汉字
    void LCD_ShowChinese16x16(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示单个16x16汉字
    void LCD_ShowChinese24x24(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示单个24x24汉字
    void LCD_ShowChinese32x32(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示单个32x32汉字
    
    void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示一个字符
    void LCD_ShowString(uint16_t x,uint16_t y,const uint8_t *p,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode);//显示字符串
    uint32_t mypow(uint8_t m,uint8_t n);//求幂
    void LCD_ShowIntNum(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey);//显示整数变量
    void LCD_ShowFloatNum1(uint16_t x,uint16_t y,float num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey);//显示两位小数变量
    
    void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[]);//显示图片
    
    
    #endif

### 4.GUI.c  

    #include "GUI.h"
    #include "lcdfont.h"
    #include "St7735.h"
    
    
    /******************************************************************************
       函数说明:在指定区域填充颜色
       入口数据:xsta,ysta   起始坐标
                 xend,yend   终止坐标
                                 color       要填充的颜色
       返回值:  无
    ******************************************************************************/
    void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
    {          
     uint16_t i,j; 
     LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
     for(i=ysta;i<yend;i++)
     {                                                                
         for(j=xsta;j<xend;j++)
         {
             LCD_WR_DATA(color);
         }
     }                               
    }
    
    /******************************************************************************
       函数说明:在指定位置画点
       入口数据:x,y 画点坐标
                 color 点的颜色
       返回值:  无
    ******************************************************************************/
    void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
    {
     LCD_Address_Set(x,y,x,y);//设置光标位置 
     LCD_WR_DATA(color);
    } 
    
    
    /******************************************************************************
       函数说明:画线
       入口数据:x1,y1   起始坐标
                 x2,y2   终止坐标
                 color   线的颜色
       返回值:  无
    ******************************************************************************/
    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;
         }
     }
    }
    
    
    /******************************************************************************
       函数说明:画矩形
       入口数据:x1,y1   起始坐标
                 x2,y2   终止坐标
                 color   矩形的颜色
       返回值:  无
    ******************************************************************************/
    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);
    }
    
    
    /******************************************************************************
       函数说明:画圆
       入口数据:x0,y0   圆心坐标
                 r       半径
                 color   圆的颜色
       返回值:  无
    ******************************************************************************/
    void Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r,uint16_t color)
    {
     int a,b;
     a=0;b=r;      
     while(a<=b)
     {
         LCD_DrawPoint(x0-b,y0-a,color);             //3           
         LCD_DrawPoint(x0+b,y0-a,color);             //0           
         LCD_DrawPoint(x0-a,y0+b,color);             //1                
         LCD_DrawPoint(x0-a,y0-b,color);             //2             
         LCD_DrawPoint(x0+b,y0+a,color);             //4               
         LCD_DrawPoint(x0+a,y0-b,color);             //5
         LCD_DrawPoint(x0+a,y0+b,color);             //6 
         LCD_DrawPoint(x0-b,y0+a,color);             //7
         a++;
         if((a*a+b*b)>(r*r))//判断要画的点是否过远
         {
             b--;
         }
     }
    }
    
    /******************************************************************************
       函数说明:显示汉字串
       入口数据:x,y显示坐标
                 *s 要显示的汉字串
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号 可选 16 24 32
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChinese(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     while(*s!=0)
     {
         if(sizey==12) LCD_ShowChinese12x12(x,y,s,fc,bc,sizey,mode);
         else if(sizey==16) LCD_ShowChinese16x16(x,y,s,fc,bc,sizey,mode);
         else if(sizey==24) LCD_ShowChinese24x24(x,y,s,fc,bc,sizey,mode);
         else if(sizey==32) LCD_ShowChinese32x32(x,y,s,fc,bc,sizey,mode);
         else return;
         s+=2;
         x+=sizey;
     }
    }
    
    /******************************************************************************
       函数说明:显示单个12x12汉字
       入口数据:x,y显示坐标
                 *s 要显示的汉字
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChinese12x12(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     uint8_t i,j,m=0;
     uint16_t k;
     uint16_t HZnum;//汉字数目
     uint16_t TypefaceNum;//一个字符所占字节大小
     uint16_t x0=x;
     TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
                              
     HZnum=sizeof(tfont12)/sizeof(typFNT_GB12);    //统计汉字数目
     for(k=0;k<HZnum;k++) 
     {
         if((tfont12[k].Index[0]==*(s))&&(tfont12[k].Index[1]==*(s+1)))
         {     
             LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
             for(i=0;i<TypefaceNum;i++)
             {
                 for(j=0;j<8;j++)
                 {    
                     if(!mode)//非叠加方式
                     {
                         if(tfont12[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
                         else LCD_WR_DATA(bc);
                         m++;
                         if(m%sizey==0)
                         {
                             m=0;
                             break;
                         }
                     }
                     else//叠加方式
                     {
                         if(tfont12[k].Msk[i]&(0x01<<j))    LCD_DrawPoint(x,y,fc);//画一个点
                         x++;
                         if((x-x0)==sizey)
                         {
                             x=x0;
                             y++;
                             break;
                         }
                     }
                 }
             }
         }                      
         continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
     }
    } 
    
    /******************************************************************************
       函数说明:显示单个16x16汉字
       入口数据:x,y显示坐标
                 *s 要显示的汉字
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChinese16x16(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     uint8_t i,j,m=0;
     uint16_t k;
     uint16_t HZnum;//汉字数目
     uint16_t TypefaceNum;//一个字符所占字节大小
     uint16_t x0=x;
      TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
     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_Address_Set(x,y,x+sizey-1,y+sizey-1);
             for(i=0;i<TypefaceNum;i++)
             {
                 for(j=0;j<8;j++)
                 {    
                     if(!mode)//非叠加方式
                     {
                         if(tfont16[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
                         else LCD_WR_DATA(bc);
                         m++;
                         if(m%sizey==0)
                         {
                             m=0;
                             break;
                         }
                     }
                     else//叠加方式
                     {
                         if(tfont16[k].Msk[i]&(0x01<<j))    LCD_DrawPoint(x,y,fc);//画一个点
                         x++;
                         if((x-x0)==sizey)
                         {
                             x=x0;
                             y++;
                             break;
                         }
                     }
                 }
             }
         }                      
         continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
     }
    } 
    
    
    /******************************************************************************
       函数说明:显示单个24x24汉字
       入口数据:x,y显示坐标
                 *s 要显示的汉字
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChinese24x24(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     uint8_t i,j,m=0;
     uint16_t k;
     uint16_t HZnum;//汉字数目
     uint16_t TypefaceNum;//一个字符所占字节大小
     uint16_t x0=x;
     TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
     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_Address_Set(x,y,x+sizey-1,y+sizey-1);
             for(i=0;i<TypefaceNum;i++)
             {
                 for(j=0;j<8;j++)
                 {    
                     if(!mode)//非叠加方式
                     {
                         if(tfont24[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
                         else LCD_WR_DATA(bc);
                         m++;
                         if(m%sizey==0)
                         {
                             m=0;
                             break;
                         }
                     }
                     else//叠加方式
                     {
                         if(tfont24[k].Msk[i]&(0x01<<j))    LCD_DrawPoint(x,y,fc);//画一个点
                         x++;
                         if((x-x0)==sizey)
                         {
                             x=x0;
                             y++;
                             break;
                         }
                     }
                 }
             }
         }                      
         continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
     }
    } 
    
    /******************************************************************************
       函数说明:显示单个32x32汉字
       入口数据:x,y显示坐标
                 *s 要显示的汉字
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChinese32x32(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     uint8_t i,j,m=0;
     uint16_t k;
     uint16_t HZnum;//汉字数目
     uint16_t TypefaceNum;//一个字符所占字节大小
     uint16_t x0=x;
     TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
     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_Address_Set(x,y,x+sizey-1,y+sizey-1);
             for(i=0;i<TypefaceNum;i++)
             {
                 for(j=0;j<8;j++)
                 {    
                     if(!mode)//非叠加方式
                     {
                         if(tfont32[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
                         else LCD_WR_DATA(bc);
                         m++;
                         if(m%sizey==0)
                         {
                             m=0;
                             break;
                         }
                     }
                     else//叠加方式
                     {
                         if(tfont32[k].Msk[i]&(0x01<<j))    LCD_DrawPoint(x,y,fc);//画一个点
                         x++;
                         if((x-x0)==sizey)
                         {
                             x=x0;
                             y++;
                             break;
                         }
                     }
                 }
             }
         }                      
         continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
     }
    }
    
    
    /******************************************************************************
       函数说明:显示单个字符
       入口数据:x,y显示坐标
                 num 要显示的字符
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {
     uint8_t temp,sizex,t,m=0;
     uint16_t i,TypefaceNum;//一个字符所占字节大小
     uint16_t x0=x;
     sizex=sizey/2;
     TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
     num=num-' ';    //得到偏移后的值
     LCD_Address_Set(x,y,x+sizex-1,y+sizey-1);  //设置光标位置 
     for(i=0;i<TypefaceNum;i++)
     { 
         if(sizey==12)temp=ascii_1206[num][i];               //调用6x12字体
         else if(sizey==16)temp=ascii_1608[num][i];         //调用8x16字体
         else if(sizey==24)temp=ascii_2412[num][i];         //调用12x24字体
         else if(sizey==32)temp=ascii_3216[num][i];         //调用16x32字体
         else return;
         for(t=0;t<8;t++)
         {
             if(!mode)//非叠加模式
             {
                 if(temp&(0x01<<t))LCD_WR_DATA(fc);
                 else LCD_WR_DATA(bc);
                 m++;
                 if(m%sizex==0)
                 {
                     m=0;
                     break;
                 }
             }
             else//叠加模式
             {
                 if(temp&(0x01<<t))LCD_DrawPoint(x,y,fc);//画一个点
                 x++;
                 if((x-x0)==sizex)
                 {
                     x=x0;
                     y++;
                     break;
                 }
             }
         }
     }              
    }
    
    
    /******************************************************************************
       函数说明:显示字符串
       入口数据:x,y显示坐标
                 *p 要显示的字符串
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
                 mode:  0非叠加模式  1叠加模式
       返回值:  无
    ******************************************************************************/
    void LCD_ShowString(uint16_t x,uint16_t y,const uint8_t *p,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
    {         
     while(*p!='\0')
     {       
         LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
         x+=sizey/2;
         p++;
     }  
    }
    
    
    /******************************************************************************
       函数说明:显示数字
       入口数据:m底数,n指数
       返回值:  无
    ******************************************************************************/
    uint32_t mypow(uint8_t m,uint8_t n)
    {
     uint32_t result=1;     
     while(n--)result*=m;
     return result;
    }
    
    
    /******************************************************************************
       函数说明:显示整数变量
       入口数据:x,y显示坐标
                 num 要显示整数变量
                 len 要显示的位数
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
       返回值:  无
    ******************************************************************************/
    void LCD_ShowIntNum(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
    {             
     uint8_t t,temp;
     uint8_t enshow=0;
     uint8_t sizex=sizey/2;
     for(t=0;t<len;t++)
     {
         temp=(num/mypow(10,len-t-1))%10;
         if(enshow==0&&t<(len-1))
         {
             if(temp==0)
             {
                 LCD_ShowChar(x+t*sizex,y,' ',fc,bc,sizey,0);
                 continue;
             }else enshow=1; 
               
         }
          LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
     }
    } 
    
    
    /******************************************************************************
       函数说明:显示两位小数变量
       入口数据:x,y显示坐标
                 num 要显示小数变量
                 len 要显示的位数
                 fc 字的颜色
                 bc 字的背景色
                 sizey 字号
       返回值:  无
    ******************************************************************************/
    void LCD_ShowFloatNum1(uint16_t x,uint16_t y,float num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
    {             
     uint8_t t,temp,sizex;
     uint16_t num1;
     sizex=sizey/2;
     num1=num*100;
     for(t=0;t<len;t++)
     {
         temp=(num1/mypow(10,len-t-1))%10;
         if(t==(len-2))
         {
             LCD_ShowChar(x+(len-2)*sizex,y,'.',fc,bc,sizey,0);
             t++;
             len+=1;
         }
          LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
     }
    }
    
    
    /******************************************************************************
       函数说明:显示图片
       入口数据:x,y起点坐标
                 length 图片长度
                 width  图片宽度
                 pic[]  图片数组    
       返回值:  无
    ******************************************************************************/
    void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[])
    {
     uint16_t i,j;
     uint32_t k=0;
     LCD_Address_Set(x,y,x+length-1,y+width-1);
     for(i=0;i<length;i++)
     {
         for(j=0;j<width;j++)
         {
             LCD_WR_DATA8(pic[k*2]);
             LCD_WR_DATA8(pic[k*2+1]);
             k++;
         }
     }            
    }

### 5.main.c  

    /*!
     \file    main.c
     \brief   led spark with systick, USART print and key example
    
     \version 2017-06-06, V1.0.0, firmware for GD32F3x0
     \version 2019-06-01, V2.0.0, firmware for GD32F3x0
     \version 2020-09-30, V2.1.0, firmware for GD32F3x0
     \version 2022-01-06, V2.2.0, firmware for GD32F3x0
    */
    
    /*
     Copyright (c) 2022, GigaDevice Semiconductor Inc.
    
     Redistribution and use in source and binary forms, with or without modification,
    are permitted provided that the following conditions are met:
    
     1. Redistributions of source code must retain the above copyright notice, this
        list of conditions and the following disclaimer.
     2. Redistributions in binary form must reproduce the above copyright notice,
        this list of conditions and the following disclaimer in the documentation
        and/or other materials provided with the distribution.
     3. Neither the name of the copyright holder nor the names of its contributors
        may be used to endorse or promote products derived from this software without
        specific prior written permission.
    
     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
    OF SUCH DAMAGE.
    */
    
    #include "gd32f3x0.h"
    #include "systick.h"
    #include <stdio.h>
    #include "main.h"
    
    
    #include "led.h"
    #include "St7735.h"
    #include "spi.h"
    #include "GUI.h"
    #include "pic.h"
    
    
    /*!
     \brief      main function
     \param[in]  none
     \param[out] none
     \retval     none
    */
    int main(void)
    {
     /* configure systick */
     systick_config();
    
     led_init(); // led初始化
     
     #ifdef  USE_HARDWARESPI
     spi_config();
     #endif
     LCD_Init();//LCD初始化
     LCD_Fill(0,0,LCD_W,LCD_H,RED);
    
     while(1) {
    
    //        LED1_ON;  // 亮
    //        delay_1ms(1000);
    //        
    //        LED1_OFF;    // 灭
    //        delay_1ms(1000);
         
             LCD_ShowChinese(50,0,"测试",YELLOW,RED,32,0);//
             LCD_ShowString(50+32*2,0,"GD32",YELLOW,RED,32,0);
         
             LCD_ShowString(40,40,"LCD_W:",BLUE,RED,16,0);
             LCD_ShowIntNum(40 + 48,40,LCD_W,3,BLACK,RED,16);
             LCD_ShowString(40 + 80,40,"LCD_H:",BLUE,RED,16,0);
             LCD_ShowIntNum(40 +128,40,LCD_H,3,BLACK,RED,16);
         
             LCD_ShowPicture(50,60,140,67,gImage_GD32_logo_140x67);
     }
    }

### 6.lcdfont.h  
太多了。
### 7.pic.h  
太多了,请自行取模。

3.可调配置

1.横屏和竖屏

在st7735头文件中有一个宏 USE\_HORIZONTAL
配置为0和1 为竖屏显示 配置为2和3位横屏显示
 title=

2. 软件SPI和硬件SPI

在st7735头文件中有一个宏USE\_HARDWARESPI
当定义这个宏的时候使用硬件SPI,注释掉这个宏使用软件SPI
 title=

三、测试结果

可以显示字符,汉字和图片。
 title=
特写:
 title=

推荐阅读
关注数
10694
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息