利用 STC32G12K128 的 LCM 驱动 8080 接口的液晶屏

news/2024/11/8 3:37:26/

零、目录

零、目录

一、硬件和参考对象

二、STC32G 的 LCM 

三、简要的初始化流程

四、代码的移植和修改

五、引脚接线

六、运行结果

七、总结和注意事项


一、硬件和参考对象

  1. 本次将使用 STC32G12K128 芯片的 LCM 对 8080 接口的液晶屏(该液晶屏为野火指南者STM32F103开发板的 3.2寸 TFTLCD)进行驱动,目的是成功点亮并在液晶屏中输出英文字符串和绘图
  2. 硬件接线、液晶屏驱动和测试程序均来自野火指南者STM32F103开发板 ,有关的资料可以在野火官网下载。
  3. 用到的参考图文为 STC32G 的库函数手册、STC32G 芯片手册、野火液晶屏原理图。


二、STC32G 的 LCM 

        STC32G 系列单片机内部集成了一个 LCM 接口控制器,可驱动 I8080 接口和 M6800 接口,支持 8位 和 16位 数据宽度。

        本文将使用到 STC 官方提供的库函数来控制 LCM,对于 LCM 的初始化,将使用库文件: STC32G_LCM.H;LCM 的功能引脚切换,将使用库文件:STC32G_Switch().H。

        STC32G 的库函数可以在 STC32G 官网下载。对于 LCM,STC32G_LCM.H 的主要内容如下:

/* 引脚定义 */
sbit LCD_RS 	= P4^5;      	// 数据/命令切换
sbit LCD_RD 	= P4^4;      	// 读控制
sbit LCD_WR 	= P4^2;      	// 写控制sbit LCD_CS 	= P4^0;      	// 片选
sbit LCD_RESET 	= P4^3;   		// 复位
sbit LCD_BK		= P4^1;			// 背光控制/* 数据/指令触发宏定义 */
#define LCM_WRITE_CMD()					LCMIFCR = ((LCMIFCR & ~0x07) | 0x84)
#define LCM_WRITE_DAT()					LCMIFCR = ((LCMIFCR & ~0x07) | 0x85)
#define LCM_READ_CMD()					LCMIFCR = ((LCMIFCR & ~0x07) | 0x86)
#define LCM_READ_DAT()					LCMIFCR = ((LCMIFCR & ~0x07) | 0x87)/* 接口类型和数据宽度类型 */
#define	MODE_I8080			0	//I8080模式
#define	MODE_M6800			1	//M6800模式#define	BIT_WIDE_8			0	//8位数据宽度
#define	BIT_WIDE_16			2	//16位数据宽度/* 初始化结构体 */
typedef struct
{u8	LCM_Enable;					//LCM接口使能  	ENABLE,DISABLEu8	LCM_Mode;						//LCM接口模式  	MODE_I8080,MODE_M6800u8	LCM_Bit_Wide;				//LCM数据宽度  	BIT_WIDE_8,BIT_WIDE_16u8	LCM_Setup_Time;			//LCM通信数据建立时间  	0~7u8	LCM_Hold_Time;			//LCM通信数据保持时间  	0~3
} LCM_InitTypeDef;/* 接口函数 */
void LCM_Inilize(LCM_InitTypeDef *LCM);

LCD_RS、LCD_RD、LCD_WR 的引脚定义受到 LCM 寄存器的控制,具体设置可参考官方手册,如下图所示。本文使用 LCMIFCPS[1:0] = 00 时的功能引脚。

LCD_CS、LCD_RESET、LCD_BK 可任意定义,主要用于 LCD 的片选、复位和背光控制。

触发数据和指令的宏定义用于触发 LCM 模块将数据寄存器中的数据通过端口发送给 LCD,仅用于触发,数据需要在触发前写入数据寄存器

接口类型和数据宽度类型将在 LCM 的初始化结构体里被使用,本次使用的 LCD 的类型是 I8080 接口 和 16位数据宽度。16位 LCM 接口数据脚选择参考官方手册,如下图所示。本文使用的是 LCMIFDPS[1:0] = 11 时的引脚。

LCM 结构体公有 5个成员函数,STC 在注释中给出了可设置的范围。结构体配置完成后通过函数 LCM_Inilize() 对 LCM 进行初始化。

功能引脚切换使用 STC32G_Switch() 中提供的宏定义:

#define  LCM_CTRL_SW(Pin)			LCMIFCFG2 = (LCMIFCFG2 & ~0x60) | (Pin << 5)
#define  LCM_DATA_SW(Pin)			LCMIFCFG = (LCMIFCFG & ~0x0C) | (Pin << 2)


三、简要的初始化流程

  1. 野火程序的简单分析。下图为笔者对野火液晶屏参考示例的程序运行简单摘要(如有错误或理解有误可以在评论区指出)
  2. STM32 与 STC32G 的异同点比较
    STM32STC32G
    GPIO都是对需要的 GPIO 进行初始化

        驱动 LCD 的外设

    采用 FSMC 控制采用 LCM 控制
    液晶屏配置对于液晶屏的配置函数,只要基本的读写函数能够实现,基本不需要做修改
    读写函数基于 FSMC 的读写触发基于 LCM 的读写触发
    LCD 控制引脚通过 FSMC ,自动控制的对应的引脚实现控制需要用户来手动控制引脚的高低电平
               


四、代码的移植和修改

        提前准备好需要的库函数和驱动程序,本文的中断函数将使用 STC32G 库函数自带 ISR 函数。具体使用到的有关文件请参考下表:

STC32G 库函数STM32 参考程序

STC32G_Delay

STC32G_GPIO

STC32G_LCM

STC32G_NVIC

STC32G_SWITCH

STC32G_UART

bsp_ili9341_lcd

font

        创建 KEIL C251 项目,先将 STC32G 的文件导入到项目中,并实现通过串口发送 Hello World 的程序,以此确保 STC32G 的库函数移植无误。

        接下来添加 STM32 的液晶屏驱动程序和字模 到工程项目中。在 bsp_ili9341_lcd.h 中删除有关 FSMC 的所有定义,并针对 bsp_ili9341_lcd.c 的需要,补充基本的类型定义,并包含下表所需要的头文件:

头文件作用
STC32G_GPIO对引脚进行初始化
STC32G_LCM提供对 LCM 的控制
STC32G_NVIC中断嵌套配置,用于配置外设中断
STC32G_Delay延时函数
STC32G_Switch提供功能引脚切换

        接下来对需要修改的函数进行重定义。

需要重定义的函数函数功能
ILI9341_Write_Cmd()向 ILI9341 写指令
ILI9341_Write_Data()向 ILI9341 写数据
ILI9341_Read_Data()向 ILI9341 读数据

           ILI9341_Delay()

延时函数

           ILI9341_GPIO_Config()

GPIO 初始化

           ILI9341_FSMC_Config()

LCM 初始化

           ILI9341_Init()

初始化外设并对液晶屏进行基本配置

           ILI9341_BackLed_Control()

背光控制

           ILI9341_Rst()

复位控制

        首先对 ILI9341_Write_Cmd()、ILI9341_Write_Data()、ILI9341_Read_Data() 和 ILI9341_Delay() 进行重定义,如下:

/*** @brief  向ILI9341写入命令* @param  usCmd :要写入的命令(表寄存器地址)* @retval 无*/
void ILI9341_Write_Cmd(uint16_t usCmd)
{//* ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_CMD ) = usCmd;LCD_RS = 0;LCMIFDATL = usCmd & 0x00ff;LCMIFDATH = (usCmd >> 8) & 0x00ff;LCM_WRITE_CMD();
}/*** @brief  向ILI9341写入数据* @param  usData :要写入的数据* @retval 无*/
void ILI9341_Write_Data(uint16_t usData)
{//* ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) = usData;LCD_RS = 0;LCMIFDATL = usData & 0x00ff;LCMIFDATH = (usData >> 8) & 0x00ff;LCM_WRITE_DAT();
}/*** @brief  从ILI9341读取数据* @param  无* @retval 读取到的数据*/
uint16_t ILI9341_Read_Data(void)
{// return ( * ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) );LCD_RS = 1;LCM_READ_DAT();return (LCMIFDATH << 8) | LCMIFDATL;
}/*** @brief  用于 ILI9341 简单延时函数* @param  nCount :延时计数值* @retval 无*/
static void ILI9341_Delay(uint16_t ms)
{delay_ms(ms);
}

          重定义 GPIO 初始化函数,具体的初始化端口依据实际用到的端口来决定。

/*** @brief  初始化ILI9341的IO引脚* @param  无* @retval 无*/
static void ILI9341_GPIO_Config(void)
{GPIO_InitTypeDef gpio;// 选用 P7 P6 作为数据/指令发送信号线,16线制gpio.Mode = GPIO_PullUp;gpio.Pin = GPIO_Pin_All;GPIO_Inilize(GPIO_P6, &gpio);GPIO_Inilize(GPIO_P7, &gpio);// LCD 控制信号线配置gpio.Pin = GPIO_Pin_All;GPIO_Inilize(GPIO_P4, &gpio);
}

        重定义 LCM 初始化函数,此处函数名没有修改。

/*** @brief  LCD  FSMC 模式配置* @param  无* @retval 无*/
static void ILI9341_FSMC_Config(void)
{LCM_InitTypeDef lcm;lcm.LCM_Bit_Wide = BIT_WIDE_16;lcm.LCM_Enable = ENABLE;lcm.LCM_Hold_Time = 1;lcm.LCM_Setup_Time = 1;lcm.LCM_Mode = MODE_I8080;LCM_Inilize(&lcm);NVIC_LCM_Init(ENABLE, Priority_1);LCM_CTRL_SW(LCM_CTRL_P45_P44_P42);LCM_DATA_SW(LCM_D16_P6_P7);
}

        重定义 ILI9341 复位函数。

/*** @brief  ILI9341G 软件复位* @param  无* @retval 无*/
void ILI9341_Rst(void)
{// digitalL( GPIOE,GPIO_PIN_1);	 //低电平复位LCD_RESET = 0;ILI9341_Delay(50);// digitalH( GPIOE,GPIO_PIN_1);LCD_RESET = 1;ILI9341_Delay(50);
}

        重定义 ILI9341 背光控制函数。

/*** @brief  ILI9341G背光LED控制* @param  enumState :决定是否使能背光LED*   该参数为以下值之一:*     @arg ENABLE :使能背光LED*     @arg DISABLE :禁用背光LED* @retval 无*/
void ILI9341_BackLed_Control(FunctionalState enumState)
{if (enumState){// digitalL( GPIOD, GPIO_PIN_12);LCD_BK = 0;		// 用的 PNP 型三极管做开关,因此低电平点亮}else{// digitalH( GPIOD, GPIO_PIN_12);LCD_BK = 1;}
}

        在 ILI9341 初始化函数中补上 LCD 片选控制。

/*** @brief  ILI9341初始化函数,如果要用到lcd,一定要调用这个函数* @param  无* @retval 无*/
void ILI9341_Init(void)
{ILI9341_GPIO_Config();ILI9341_FSMC_Config();LCD_CS = 0;ILI9341_BackLed_Control(ENABLE); // 点亮LCD背光灯ILI9341_Rst();ILI9341_REG_Config();// 设置默认扫描方向,其中 6 模式为大部分液晶例程的默认显示方向ILI9341_GramScan(LCD_SCAN_MODE);ILI9341_Clear(0, 0, ILI9341_LESS_PIXEL, ILI9341_MORE_PIXEL);
}

        将 bsp_ili9341_lcd.h 包含到 main.c 中。编写测试程序。其中 gpio_init() 和 uart_init() 是针对串口输出做的初始化。

void main(void)
{__STC32G_DRIVER_INIT();gpio_init();uart_init();ILI9341_Init();LCD_SetTextColor(BLACK);ILI9341_DrawRectangle(0, 0, ILI9341_LESS_PIXEL, ILI9341_MORE_PIXEL, 1);LCD_SetFont(&Font8x16);LCD_SetColors(YELLOW, BLACK);EA = 1;while(1){printf("Hello world\r\n");LCD_SetColors(YELLOW, BLACK);ILI9341_DispStringLine_EN(LINE(0), "Hello LCM I8080!");delay_ms(1000);// 画线LCD_ClearLine(LINE(4)); /* 清除单行文字 */LCD_SetColors(YELLOW, BLACK);ILI9341_DispStringLine_EN(LINE(4), "Draw line:");LCD_SetColors(RED, BLACK);ILI9341_DrawLine(50, 170, 210, 230);ILI9341_DrawLine(50, 200, 210, 240);LCD_SetColors(GREEN, BLACK);ILI9341_DrawLine(100, 170, 200, 230);ILI9341_DrawLine(200, 200, 220, 240);LCD_SetColors(BLUE, BLACK);ILI9341_DrawLine(110, 170, 110, 230);ILI9341_DrawLine(130, 200, 220, 240);delay_ms(2500);ILI9341_Clear(0, 16 * 8, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 8); /* 清屏,显示全黑 */// 画矩形LCD_ClearLine(LINE(4)); /* 清除单行文字 */LCD_SetColors(GREEN, BLACK);ILI9341_DispStringLine_EN(LINE(4), "Draw Rectangle:");LCD_SetColors(RED, BLACK);ILI9341_DrawRectangle(50, 200, 100, 30, 1);LCD_SetColors(GREEN, BLACK);ILI9341_DrawRectangle(160, 200, 20, 40, 0);LCD_SetColors(BLUE, BLACK);ILI9341_DrawRectangle(170, 200, 50, 20, 1);delay_ms(2500);ILI9341_Clear(0, 16 * 8, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 8); /* 清屏,显示全黑 */// 画圆LCD_ClearLine(LINE(4)); /* 清除单行文字 */LCD_SetColors(GREEN, BLACK);ILI9341_DispStringLine_EN(LINE(4), "Draw Circle:");LCD_SetColors(RED, BLACK);ILI9341_DrawCircle(100, 200, 20, 0);LCD_SetColors(GREEN, BLACK);ILI9341_DrawCircle(100, 200, 10, 1);LCD_SetColors(BLUE, BLACK);ILI9341_DrawCircle(140, 200, 20, 0);delay_ms(2500);ILI9341_Clear(0, 0, LCD_X_LENGTH, LCD_Y_LENGTH); /* 清屏,显示全黑 */}
}

        编译项目,若无报错则说明文件移植没有语法错误。


五、引脚接线

        已经接线对照表如下。

        实物接线图如下。 


六、运行结果

        烧录后,液晶屏正常点亮并显示测试程序:首先显示字符串 “Hello LCM I8080”,然后显示字符串“Draw Line”,绘制测试直线,之后显示字符串“Draw Rectangle”,绘制测试矩形,最后显示字符串“Draw Circle”,绘制测试圆形。运行结果如下图所示。


七、总结

        1. BUG 汇总

问题可能的原因解决方法
程序卡死未开启外设或中断

1. 使能外设

2. 开启中断,STC32G 的库函数开启外设中断的方式是使用 NVIC 提供的接口

未定义正确的中断函数或未清空标志位本文使用 STC32G 库函数提供的默认中断函数,可用于参考
使用 printf 时未正确指定串口确定 printf 使用的串口是连接到电脑端的串口
未正确初始化相关外设确认 GPIO、LCM、UART 等外设初始化正确
串口有输出,屏幕没有点亮LCB_BK 接线不正确或电平值不正确检查 LCB_BK 电平值是否正确,或检查引脚是否接线正确
可能是因为片选引脚 LCB_CS 电平不对LCB_CS 处于低电平时 LCD 被选中
GPIO 未正确初始化检查 GPIO 的引脚配置是否正确
屏幕点亮,没有显示字符串和图像接线错误或未正确指定功能引脚检查接线是否正常,检查是否进行了正确的功能引脚切换
驱动程序未正确重定义检查需要重定义的函数是否都正确重定义
数据建立时间和数据保存时间数值不正确初始化 LCM 时,依据实际情况赋值进行测试,笔者的两个值都为 1
清屏函数仅清屏部分区域

ILI9341_FillColor() 的传参不正确

ILI9341_FillColor() 第一个参数是 uint32_t 类型,调用该函数时,需要将参数进行强制类型转换到 uint32_t,建议将 bsp_ili9341_lcd.c 中所有用到 ILI9341_FillColor() 的地方都手动补上强制类型转换的语句。
屏幕输出字符串像素点不完整数据建立时间和数据保存时间数值不正确初始化 LCM 时,依据实际情况赋值进行测试,笔者的两个值都为 1
填充区块时出现白屏闪烁问题数据建立时间和数据保存时间数值不正确初始化 LCM 时,依据实际情况赋值进行测试,笔者的两个值都为 1
调用了 ILI9341_FillColor()该问题目前暂未解决,除了黑色填充外,其他颜色进行填充时都会导致白色屏闪的情况,推测可能和 STC32G 的执行速度有关系。

        2. LCM 使用感受

        STC32G 提供的 LCM 对驱动 TFTLCD 提供了便利的帮助,官方库函数的提供让使用这一外设变得更加简单。STC8A8K64D4 也具有 LCM 功能,通用官方也提供了相应的库函数,而 STC8A8K64D4 的时钟频率能调节到 45MHz,比 STC32G 在 ISP 上能调节的范围更广,也许用起来会比 STC32G 更好吧(可能)。

        可惜适配 51 的 GUI 太少了,虽然 STC 完成了 FreeRTOS 的移植(据说可以尝试 uC/GUI,没试过不清楚)。


http://www.ppmy.cn/news/223646.html

相关文章

科研热点|科研人专属身份证来了,国产ORCID ID启动!

2023年6月1日&#xff0c;国家自然科学基金委员会发布了《国家自然科学基金委员会关于推广和发布基础研究科研人员标识&#xff08;BRID&#xff09;有关工作安排的通告》&#xff0c;宣布从即日起&#xff0c;国家自然科学基金委员会&#xff08;以下简称自然科学基金委&#…

应届生在校招中选择银行的原因?

六大行资产庞大&#xff0c;并且业务全面、制度比较规范&#xff0c;收入都维持在一个较高水平。面对日益严峻的就业压力&#xff0c;银行愈加成为很多同学毕业后首选的工作去向&#xff0c;今天来说说应届生选择银行的原因&#xff0c;从如信银行考试中心了解到&#xff1a; 一…

幕布使用快捷键

ctrl / 查看帮助。

我爱上了幕布这个软件

一键自动生成思维导图&#xff0c;清晰&#xff0c;有条理

“幕布”的安装与使用

一、“幕布”介绍。 幕布是一款思维笔记&#xff0c;助你结构化思考&#xff0c;支持一键转换思维导图并编辑和知识可视化&#xff0c;并且支持多端自动同步&#xff0c;随时随地阅读创作。可以直接用网页版&#xff0c;个人喜欢非网页版。 二、“幕布”的下载与安装。 2.1 “幕…

购买窗帘时哪些可以不做?-江南爱窗帘十大品牌

在家居软装上&#xff0c;窗帘的选择很重要&#xff0c;因为它的存在感很强&#xff0c;占据了墙面的半壁江山。选对了&#xff0c;满心欢喜&#xff0c;选错了&#xff0c;就只能悔恨痛苦了。 1.不做拼色、花纹&#xff1a;拼色窗帘在酒店十分常见&#xff0c;但是不建议照搬回…

Effie,Xmind,幕布,Up主软件评测

时代风云迭起&#xff0c;自媒体行业从单纯的文字&#xff0c;图片&#xff0c;到今天的音视频开始了三连跳。有些 Up主步履蹒跚的前行摸索&#xff0c;有些已经成为了一方霸主。一个人的成就与孜孜不倦的事先准备离不开&#xff0c;合格的 Up 主需要做大量的文案&#xff0c;今…

幕布, Ulysses , Effie , 来自于一位写稿爱好者的评测

因为各种机缘巧合&#xff0c;成为了一名爱写稿的文字工作者。可能一开始是生活所迫&#xff0c;逼着自己用仅剩的能力去抵抗生活所带来的各种压力&#xff0c;也或许是真的爱好写稿。从 2018 年以来&#xff0c;每天都会跟文字打交道&#xff0c;满脑子都是写稿&#xff0c;修…