yinwuqing110 发表于 2025-1-5 19:45

【G32A1465测评】驱动TFT-LCD屏

本帖最后由 yinwuqing110 于 2025-1-5 20:10 编辑

一、引言
前段时间在某电子商城上购得一块1.77寸RGB屏,显示驱动芯片是ST7735S,这款显示器驱动芯片比较流行,是由矽创电子股份有限公司生产,非常适合小尺寸屏的集成设计,流行的驱动接口有IIC与SPI两种,笔者这款是采用SPI驱动接口,坛友有采用SPI硬件+DMA方式驱动该类似的TFT屏,本期咱采用GPIO模拟SPI方式来驱动,这种方式移植起来比较方便,不受硬件IO口的局限制。

二、引脚关系图

使用开发板上的IO口与TFT-LCD屏的管脚对应关系

三、实物连接


四、部分驱动代码
lcd_init.h
#ifndef __LCD_INIT_H
#define __LCD_INIT_H

#include "lcd.h"
#include "g32a1xxx_pins.h"

#define USE_HORIZONTAL 1//设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏

#if USE_HORIZONTAL==0||USE_HORIZONTAL==1
#define LCD_W 128
#define LCD_H 160
#else
#define LCD_W 160
#define LCD_H 128
#endif

#define BOARD_LCD_MOSI_GPIO                                        GPIOD
#define BOARD_LCD_PORT_MOSI_BASE                                 PMD
#define BOARD_LCD_GPIO_MOSI_PIN                                    (5U)

#define BOARD_LCD_SCLK_GPIO                                        GPIOD
#define BOARD_LCD_PORT_SCLK_BASE                                 PMD
#define BOARD_LCD_GPIO_SCLK_PIN                                    (1U)

#define BOARD_LCD_CS_GPIO                                          GPIOD
#define BOARD_LCD_PORT_CS_BASE                                 PMD
#define BOARD_LCD_GPIO_CS_PIN                                    (2U)

#define BOARD_LCD_DC_GPIO                                       GPIOD
#define BOARD_LCD_PORT_DC_BASE                                  PMD
#define BOARD_LCD_GPIO_DC_PIN                                     (3U)

#define BOARD_LCD_RES_GPIO                                       GPIOD
#define BOARD_LCD_PORT_RES_BASE                              PMD
#define BOARD_LCD_GPIO_RES_PIN                                 (8U)

#define BOARD_LCD_BLK_GPIO                                       GPIOD
#define BOARD_LCD_PORT_BLK_BASE                              PMD
#define BOARD_LCD_GPIO_BLK_PIN                                 (9U)

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

#define LCD_SCLK_Clr() PINS_WritePin(BOARD_LCD_SCLK_GPIO,BOARD_LCD_GPIO_SCLK_PIN,0)//SCL SCLK
#define LCD_SCLK_Set() PINS_WritePin(BOARD_LCD_SCLK_GPIO,BOARD_LCD_GPIO_SCLK_PIN,1)

#define LCD_CS_Clr()   PINS_WritePin(BOARD_LCD_CS_GPIO,BOARD_LCD_GPIO_CS_PIN,0)//CS
#define LCD_CS_Set()   PINS_WritePin(BOARD_LCD_CS_GPIO,BOARD_LCD_GPIO_CS_PIN,1)

#define LCD_MOSI_Clr() PINS_WritePin(BOARD_LCD_MOSI_GPIO,BOARD_LCD_GPIO_MOSI_PIN,0)//SDA MOSI
#define LCD_MOSI_Set() PINS_WritePin(BOARD_LCD_MOSI_GPIO,BOARD_LCD_GPIO_MOSI_PIN,1)

#define LCD_DC_Clr()   PINS_WritePin(BOARD_LCD_DC_GPIO,BOARD_LCD_GPIO_DC_PIN,0)//DC
#define LCD_DC_Set()   PINS_WritePin(BOARD_LCD_DC_GPIO,BOARD_LCD_GPIO_DC_PIN,1)

#define LCD_RES_Clr()PINS_WritePin(BOARD_LCD_RES_GPIO,BOARD_LCD_GPIO_RES_PIN,0)//RES
#define LCD_RES_Set()PINS_WritePin(BOARD_LCD_RES_GPIO,BOARD_LCD_GPIO_RES_PIN,1)

#define LCD_BLK_Clr()PINS_WritePin(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,0)//BLK
#define LCD_BLK_Set()PINS_WritePin(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,1)

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
lcd_init.c
#include "lcd_init.h"
#include "board.h"
#include "g32a1xxx_clock.h"
#include "osif.h"

/******************************************************************************
      函数说明:LCD串行数据写入函数
      入口数据:dat要写入的串行数据
      返回值:无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{      
      u8 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();      
}

/******************************************************************************
      函数说明:LCD写入数据
      入口数据:dat 写入的数据
      返回值:无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
      LCD_Writ_Bus(dat);
}

/******************************************************************************
      函数说明:LCD写入数据
      入口数据:dat 写入的数据
      返回值:无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
      LCD_Writ_Bus(dat>>8);
      LCD_Writ_Bus(dat);
}

/******************************************************************************
      函数说明:LCD写入命令
      入口数据:dat 写入的命令
      返回值:无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
      LCD_DC_Clr();//写命令
      LCD_Writ_Bus(dat);
      LCD_DC_Set();//写数据
}

/******************************************************************************
      函数说明:设置起始和结束地址
      入口数据:x1,x2 设置列的起始和结束地址
                y1,y2 设置行的起始和结束地址
      返回值:无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
      if(USE_HORIZONTAL==0)
      {
                LCD_WR_REG(0x2a);//列地址设置
                LCD_WR_DATA(x1+2);
                LCD_WR_DATA(x2+2);
                LCD_WR_REG(0x2b);//行地址设置
                LCD_WR_DATA(y1+1);
                LCD_WR_DATA(y2+1);
                LCD_WR_REG(0x2c);//储存器写
      }
      else if(USE_HORIZONTAL==1)
      {
                LCD_WR_REG(0x2a);//列地址设置
                LCD_WR_DATA(x1+2);
                LCD_WR_DATA(x2+2);
                LCD_WR_REG(0x2b);//行地址设置
                LCD_WR_DATA(y1+1);
                LCD_WR_DATA(y2+1);
                LCD_WR_REG(0x2c);//储存器写
      }
      else if(USE_HORIZONTAL==2)
      {
                LCD_WR_REG(0x2a);//列地址设置
                LCD_WR_DATA(x1+1);
                LCD_WR_DATA(x2+1);
                LCD_WR_REG(0x2b);//行地址设置
                LCD_WR_DATA(y1+2);
                LCD_WR_DATA(y2+2);
                LCD_WR_REG(0x2c);//储存器写
      }
      else
      {
                LCD_WR_REG(0x2a);//列地址设置
                LCD_WR_DATA(x1+1);
                LCD_WR_DATA(x2+1);
                LCD_WR_REG(0x2b);//行地址设置
                LCD_WR_DATA(y1+2);
                LCD_WR_DATA(y2+2);
                LCD_WR_REG(0x2c);//储存器写
      }
}

void LCD_Init(void)
{
      /* Enable Clock to Port D */
      CLOCK_SYS_ConfigModuleClock(PMD_CLK, NULL);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_MOSI_BASE, BOARD_LCD_GPIO_MOSI_PIN, PM_MUX_AS_GPIO);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_SCLK_BASE, BOARD_LCD_GPIO_SCLK_PIN, PM_MUX_AS_GPIO);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_CS_BASE, BOARD_LCD_GPIO_CS_PIN, PM_MUX_AS_GPIO);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_DC_BASE, BOARD_LCD_GPIO_DC_PIN, PM_MUX_AS_GPIO);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_RES_BASE, BOARD_LCD_GPIO_RES_PIN, PM_MUX_AS_GPIO);
      PINS_SetMuxModeSel(BOARD_LCD_PORT_BLK_BASE, BOARD_LCD_GPIO_BLK_PIN, PM_MUX_AS_GPIO);
      PINS_SetPinIntSel(BOARD_LCD_PORT_MOSI_BASE, BOARD_LCD_GPIO_MOSI_PIN, PM_DMA_INT_DISABLED);
      PINS_SetPinIntSel(BOARD_LCD_PORT_SCLK_BASE, BOARD_LCD_GPIO_SCLK_PIN, PM_DMA_INT_DISABLED);
      PINS_SetPinIntSel(BOARD_LCD_PORT_CS_BASE,BOARD_LCD_GPIO_CS_PIN, PM_DMA_INT_DISABLED);
      PINS_SetPinIntSel(BOARD_LCD_PORT_DC_BASE,BOARD_LCD_GPIO_DC_PIN, PM_DMA_INT_DISABLED);
      PINS_SetPinIntSel(BOARD_LCD_PORT_RES_BASE, BOARD_LCD_GPIO_RES_PIN, PM_DMA_INT_DISABLED);
      PINS_SetPinIntSel(BOARD_LCD_PORT_BLK_BASE, BOARD_LCD_GPIO_BLK_PIN, PM_DMA_INT_DISABLED);
      
      PINS_SetPins(BOARD_LCD_MOSI_GPIO, 1U << BOARD_LCD_GPIO_MOSI_PIN);
      PINS_SetPins(BOARD_LCD_SCLK_GPIO, 1U << BOARD_LCD_GPIO_SCLK_PIN);
      PINS_SetPins(BOARD_LCD_CS_GPIO, 1U << BOARD_LCD_GPIO_CS_PIN);
      PINS_SetPins(BOARD_LCD_DC_GPIO, 1U << BOARD_LCD_GPIO_DC_PIN);
      PINS_SetPins(BOARD_LCD_RES_GPIO, 1U << BOARD_LCD_GPIO_RES_PIN);
      PINS_SetPins(BOARD_LCD_BLK_GPIO, 1U << BOARD_LCD_GPIO_BLK_PIN);

      PINS_SetPinDir(BOARD_LCD_MOSI_GPIO, BOARD_LCD_GPIO_MOSI_PIN, 1U);
      PINS_SetPinDir(BOARD_LCD_SCLK_GPIO, BOARD_LCD_GPIO_SCLK_PIN, 1U);
      PINS_SetPinDir(BOARD_LCD_CS_GPIO, BOARD_LCD_GPIO_CS_PIN, 1U);
      PINS_SetPinDir(BOARD_LCD_DC_GPIO, BOARD_LCD_GPIO_DC_PIN, 1U);
      PINS_SetPinDir(BOARD_LCD_RES_GPIO, BOARD_LCD_GPIO_RES_PIN, 1U);
      PINS_SetPinDir(BOARD_LCD_BLK_GPIO, BOARD_LCD_GPIO_BLK_PIN, 1U);
      
      LCD_RES_Clr();//复位
      OSIF_TimeDelay(10);
      LCD_RES_Set();
      OSIF_TimeDelay(10);
      LCD_BLK_Set();//打开背光
      OSIF_TimeDelay(120);
      LCD_WR_REG(0x11); //Sleep out
      OSIF_TimeDelay(120);

      LCD_WR_REG(0xB1);
      LCD_WR_DATA8(0x05);
      LCD_WR_DATA8(0x3C);
      LCD_WR_DATA8(0x3C);
      LCD_WR_REG(0xB2);
      LCD_WR_DATA8(0x05);
      LCD_WR_DATA8(0x3C);
      LCD_WR_DATA8(0x3C);
      LCD_WR_REG(0xB3);
      LCD_WR_DATA8(0x05);
      LCD_WR_DATA8(0x3C);
      LCD_WR_DATA8(0x3C);
      LCD_WR_DATA8(0x05);
      LCD_WR_DATA8(0x3C);
      LCD_WR_DATA8(0x3C);
      LCD_WR_REG(0xB4);
      LCD_WR_DATA8(0x03);
      LCD_WR_REG(0xC0);
      LCD_WR_DATA8(0x28);
      LCD_WR_DATA8(0x08);
      LCD_WR_DATA8(0x04);
      LCD_WR_REG(0xC1);
      LCD_WR_DATA8(0XC0);
      LCD_WR_REG(0xC2);
      LCD_WR_DATA8(0x0D);
      LCD_WR_DATA8(0x00);
      LCD_WR_REG(0xC3);
      LCD_WR_DATA8(0x8D);
      LCD_WR_DATA8(0x2A);
      LCD_WR_REG(0xC4);
      LCD_WR_DATA8(0x8D);
      LCD_WR_DATA8(0xEE);
      LCD_WR_REG(0xC5);
      LCD_WR_DATA8(0x1A);
      LCD_WR_REG(0x36); //MX, MY, RGB mode
      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(0xE0);
      LCD_WR_DATA8(0x04);
      LCD_WR_DATA8(0x22);
      LCD_WR_DATA8(0x07);
      LCD_WR_DATA8(0x0A);
      LCD_WR_DATA8(0x2E);
      LCD_WR_DATA8(0x30);
      LCD_WR_DATA8(0x25);
      LCD_WR_DATA8(0x2A);
      LCD_WR_DATA8(0x28);
      LCD_WR_DATA8(0x26);
      LCD_WR_DATA8(0x2E);
      LCD_WR_DATA8(0x3A);
      LCD_WR_DATA8(0x00);
      LCD_WR_DATA8(0x01);
      LCD_WR_DATA8(0x03);
      LCD_WR_DATA8(0x13);
      LCD_WR_REG(0xE1);
      LCD_WR_DATA8(0x04);
      LCD_WR_DATA8(0x16);
      LCD_WR_DATA8(0x06);
      LCD_WR_DATA8(0x0D);
      LCD_WR_DATA8(0x2D);
      LCD_WR_DATA8(0x26);
      LCD_WR_DATA8(0x23);
      LCD_WR_DATA8(0x27);
      LCD_WR_DATA8(0x27);
      LCD_WR_DATA8(0x25);
      LCD_WR_DATA8(0x2D);
      LCD_WR_DATA8(0x3B);
      LCD_WR_DATA8(0x00);
      LCD_WR_DATA8(0x01);
      LCD_WR_DATA8(0x04);
      LCD_WR_DATA8(0x13);
      LCD_WR_REG(0x3A); //65k mode
      LCD_WR_DATA8(0x05);
      LCD_WR_REG(0x29); //Display on
}
main.c
#include "user_config.h"
#include "g32a1xxx_pins.h"
#include "board.h"
#include <stdio.h>
#include "osif.h"
#include "lcd.h"
#include "lcd_init.h"
#include "pic.h"

typedef struct
{
      unsigned char Index;
      unsigned char Msk;
}typFNT_GB16;

extern const typFNT_GB16 tfont16[];

#define LED_GPIO            GPIOD
#define BLUE_LED_PIN      (0U)
#define RED_LED_PIN         (15U)
#define GREEN_LED_PIN       (16U)

#define WHITE_LED_PIN       (~0x00018001)

/*!
* @brief   Pins module initialization LED light
*/
void PINS_Led_Init()
{
    /* Enable Clock to Port D */
    CLOCK_SYS_ConfigModuleClock(PMD_CLK, NULL);
    /* Set pin mode */
    PINS_SetMuxModeSel(LED_RED_PORT_BASE, LED_RED_PIN, PM_MUX_AS_GPIO);
    PINS_SetMuxModeSel(LED_GREEN_PORT_BASE, LED_GREEN_PIN, PM_MUX_AS_GPIO);
    PINS_SetMuxModeSel(LED_BLUE_PORT_BASE, LED_BLUE_PIN, PM_MUX_AS_GPIO);
    /* Set pin interrupt */
    PINS_SetPinIntSel(LED_RED_PORT_BASE, LED_RED_PIN, PM_DMA_INT_DISABLED);
    PINS_SetPinIntSel(LED_GREEN_PORT_BASE, LED_GREEN_PIN, PM_DMA_INT_DISABLED);
    PINS_SetPinIntSel(LED_BLUE_PORT_BASE, LED_BLUE_PIN, PM_DMA_INT_DISABLED);
    /* GPIO Initialization */
    PINS_SetPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
    PINS_SetPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
    PINS_SetPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
    /* Set pin as output */
    PINS_SetPinDir(LED_RED_GPIO_BASE, LED_RED_PIN, 1U);
    PINS_SetPinDir(LED_GREEN_GPIO_BASE, LED_GREEN_PIN, 1U);
    PINS_SetPinDir(LED_BLUE_GPIO_BASE, LED_BLUE_PIN, 1U);
}

void Display_title(void)
{
      LCD_Fill(0,0,LCD_W,LCD_H,LIGHTBLUE);
      LCD_ShowIntNum(8,10,2025,4,BLUE,GREEN,16);
      LCD_ShowChinese(40,10,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(56,10,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(72,10,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(88,10,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(104,10,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(8,30,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(24,30,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(40,30,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(56,30,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowString(72,30,"A1465",RED,GREEN,16,0);
      LCD_ShowChinese(8,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(24,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(40,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(56,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(72,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(88,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowChinese(104,50,&tfont16,BLUE,GREEN,16,0);
      LCD_ShowString(43,140,"2025-01-05",BLUE,GREEN,16,0);
      OSIF_TimeDelay(500);
}

/*!
* @brief   Main function
*/
int main(void)
{
    /* Initialize clock */
    CLOCK_SYS_Init(&g_clockConfig);
    /* led init */
    PINS_Led_Init();
    /* uart init */
    COM_Init();
    /* Initialize LCD */
    LCD_Init();
    OSIF_TimeDelay(200U);
    LCD_Fill(0,0,LCD_W,LCD_H,YELLOW);
    OSIF_TimeDelay(200);
    LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
    PINS_WritePins(LED_GPIO,WHITE_LED_PIN);
    while (1)
    {
                              PINS_ClrPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
                              PINS_SetPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
                              PINS_SetPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
                              OSIF_TimeDelay(200);
                              PINS_SetPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
                              PINS_ClrPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
                              PINS_SetPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
                              OSIF_TimeDelay(200);
                              PINS_SetPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
                              PINS_SetPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
                              PINS_ClrPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
                              OSIF_TimeDelay(200);
                              PINS_SetPins(LED_RED_GPIO_BASE, 1U << LED_RED_PIN);
                              PINS_SetPins(LED_GREEN_GPIO_BASE, 1U << LED_GREEN_PIN);
                              PINS_SetPins(LED_BLUE_GPIO_BASE, 1U << LED_BLUE_PIN);
                              LCD_ShowPicture(0,0,128,160,gImage_1);
                              OSIF_TimeDelay(800);
                              Display_title();
    }
}
五、画图效果
画图采用“Img2Lcd”工具,轻松实现由图片转C代码的处理,至于中文字符的生成,可借助“PCtoLCD2002”工具,如见以下附件,具体使用方法这里不再赘述。


使用工具导入图片后设置如下,导出则是C数组,直接调用则行。

屏上画出来的效果如下:

驱动程序点屏效果展现如下:


可怜的小弗朗士 发表于 2025-1-7 15:43

这个极小海的玩偶好可爱

沉浮的茶叶 发表于 2025-1-8 17:15

这个是软件模拟的吗
页: [1]
查看完整版本: 【G32A1465测评】驱动TFT-LCD屏