一、前言
年尾事情比较多,评测转眼即将结束了,说来惭愧,帖子拖延段时间了。今天来分享一下使用ME32G070开发板驱动SPI串口屏。该屏是基于ST7735S方案的,屏尺寸为1.77寸,分辨率128*160。驱动屏有SPI硬件方式与软件模拟方式,此次使用GPIO模拟SPI。
二、管脚分布
这里使用P2接口的PD1~PD6。

ME32G070RBT6开发板与TFT-LCD屏的管脚连接对应关系:

TFT-LCD屏的管脚分布如下:

三、硬件连线

四、参考源码
这里通过配置SYS_PLL方式将系统主频提升到72MHz。
main.c
#include "me32g070.h"
#include "me32g070_ioconfig.h"
#include "me32g070_gpio.h"
#include "me32g070_sys.h"
#include "lcd.h"
#include "lcd_init.h"
#include "pic.h"
typedef struct
{
unsigned char Index[2];
unsigned char Msk[32];
}typFNT_GB16;
extern const typFNT_GB16 tfont16[];
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,(u8 *)&tfont16[0],BLUE,GREEN,16,0);
LCD_ShowChinese(56,10,(u8 *)&tfont16[1],BLUE,GREEN,16,0);
LCD_ShowChinese(72,10,(u8 *)&tfont16[2],BLUE,GREEN,16,0);
LCD_ShowChinese(88,10,(u8 *)&tfont16[3],BLUE,GREEN,16,0);
LCD_ShowChinese(104,10,(u8 *)&tfont16[4],BLUE,GREEN,16,0);
LCD_ShowChinese(8,30,(u8 *)&tfont16[5],BLUE,GREEN,16,0);
LCD_ShowChinese(24,30,(u8 *)&tfont16[6],BLUE,GREEN,16,0);
LCD_ShowString(40,30,(u8 *)"ME32G070RB",BLUE,GREEN,16,0);
LCD_ShowChinese(8,50,(u8 *)&tfont16[7],BLUE,GREEN,16,0);
LCD_ShowChinese(24,50,(u8 *)&tfont16[8],BLUE,GREEN,16,0);
LCD_ShowChinese(40,50,(u8 *)&tfont16[9],BLUE,GREEN,16,0);
LCD_ShowChinese(8,80,(u8 *)&tfont16[17],WHITE,RED,16,0);
LCD_ShowString(24,80,(u8 *)":",WHITE,RED,16,0);
LCD_ShowChinese(40,100,(u8 *)&tfont16[10],WHITE,RED,16,0);
LCD_ShowChinese(56,100,(u8 *)&tfont16[11],WHITE,RED,16,0);
LCD_ShowChinese(72,100,(u8 *)&tfont16[12],WHITE,RED,16,0);
LCD_ShowChinese(88,100,(u8 *)&tfont16[13],WHITE,RED,16,0);
LCD_ShowChinese(40,120,(u8 *)&tfont16[14],WHITE,RED,16,0);
LCD_ShowChinese(56,120,(u8 *)&tfont16[15],WHITE,RED,16,0);
LCD_ShowChinese(72,120,(u8 *)&tfont16[14],WHITE,RED,16,0);
LCD_ShowChinese(88,120,(u8 *)&tfont16[16],WHITE,RED,16,0);
LCD_ShowString(104,120,(u8 *)" ",LIGHTBLUE,LIGHTBLUE,16,0);
LCD_ShowString(43,140,(u8 *)"2025-01-08",WHITE,RED,16,0);
SYS_Delay(0x127FFF);
}
int main(void)
{
SystemInit();
PD7_INIT(PD7_OSC_IN);
PD10_INIT(PD10_OSC_OUT);
SYS_Powerup_HSE_CLK();
SYS_PLL_Config(HSE_CLK,72000000);
SYS_SelectMainClkSrc(PLL_CLK);
LCD_Init();
SYS_Delay(0x76660);
LCD_Fill(0,0,LCD_W,LCD_H,YELLOW);
SYS_Delay(0x76660);
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
PB->DIR_b.DIR10 =0x1;
while(1)
{
LCD_ShowPicture(0,0,128,160,gImage_1);
SYS_Delay(0x1D9980);
Display_title();
PB->CLR_b.CLR10 = 0x1;
SYS_Delay(0x76660);
PB->SET_b.SET10 = 0x1;
SYS_Delay(0x76660);
PB->CLR_b.CLR10 = 0x1;
SYS_Delay(0x76660);
PB->SET_b.SET10 = 0x1;
}
}
下面关于LCD初始化部分的代码详情如下:
lcd_init.h
#ifndef __LCD_INIT_H
#define __LCD_INIT_H
#include "lcd.h"
#include "me32g070_gpio.h"
#define USE_HORIZONTAL 1
#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 LCD_SCLK_Clr() PD->CLR_b.CLR1 = 0x1
#define LCD_SCLK_Set() PD->SET_b.SET1 = 0x1
#define LCD_CS_Clr() PD->CLR_b.CLR2 = 0x1
#define LCD_CS_Set() PD->SET_b.SET2 = 0x1
#define LCD_MOSI_Clr() PD->CLR_b.CLR3 = 0x1
#define LCD_MOSI_Set() PD->SET_b.SET3 = 0x1
#define LCD_DC_Clr() PD->CLR_b.CLR4 = 0x1
#define LCD_DC_Set() PD->SET_b.SET4 = 0x1
#define LCD_RES_Clr() PD->CLR_b.CLR5 = 0x1
#define LCD_RES_Set() PD->SET_b.SET5 = 0x1
#define LCD_BLK_Clr() PD->CLR_b.CLR6 = 0x1
#define LCD_BLK_Set() PD->SET_b.SET6 = 0x1
void LCD_GPIO_Init(void);
void LCD_Writ_Bus(uint8_t dat);
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);
#endif
lcd_init.c
#include "lcd_init.h"
#include "me32g070_gpio.h"
#include "me32g070.h"
#include "me32g070_sys.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)
{
PD->DIR_b.DIR1 = 0x1;
PD->DIR_b.DIR2 = 0x1;
PD->DIR_b.DIR3 = 0x1;
PD->DIR_b.DIR4 = 0x1;
PD->DIR_b.DIR5 = 0x1;
PD->DIR_b.DIR6 = 0x1;
LCD_RES_Clr();//复位
SYS_Delay(0x5EB8);
LCD_RES_Set();
SYS_Delay(0x5EB8);
LCD_BLK_Set();//打开背光
SYS_Delay(0x470A0);
//************* Start Initial Sequence **********//
LCD_WR_REG(0x11); //Sleep out
SYS_Delay(0x470A0);
//------------------------------------ST7735S Frame Rate-----------------------------------------//
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);
//------------------------------------End ST7735S Frame Rate---------------------------------//
LCD_WR_REG(0xB4); //Dot inversion
LCD_WR_DATA8(0x03);
//------------------------------------ST7735S Power Sequence---------------------------------//
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);
//---------------------------------End ST7735S Power Sequence-------------------------------------//
LCD_WR_REG(0xC5); //VCOM
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);
//------------------------------------ST7735S Gamma Sequence---------------------------------//
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);
//------------------------------------End ST7735S Gamma Sequence-----------------------------//
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x29); //Display on
}
五、驱动效果
这里画图使用“Img2Lcd”工具来导出数组数据,中文字符需要使用“PCtoLCD2002”工具来生成C代码。由于官方SDK工程是基于compiler version 5进行编译的,因此显示汉字需要引入内码,这里通过以下链接,在线进行汉字转内码处理。
ASCII/GBK/GB2312中文汉字区位码,内码,编码在线查询软件
*附件:Image2Lcd 2.9.zip
*附件:PCtoLCD2002.zip
使用“Img2Lcd”工具,导入画好的16位真彩bmp图片,具体设置如下,导入则是一个C数组,直接调用即可完成画图。

编译、下载、运行,驱屏效果正如下视频所示,呈现的效果比较流畅,主频提升到72MHz,数据处理速度很好。