STM32开发学习笔记之七【LCD显示图片】

STM32开发学习笔记之七【LCD显示图片】

LCD显示是单片机最常用的功能之一。今天来学学单片机驱动ST7735芯片在160*80的LCD屏幕上显示一幅图片的过程。

一、用STM32CubeMX创建STM32工程

本文中不涉及STM32CubeMX的下载及安装,需要的请到 https://www.st.com/en/development-tools/stm32cubemx.html#get-software自行下载安装。

(一)新建工程

新建工程文件项目名称设为"lcd_img",本笔记中项目文件存放在"E:\prj\stm32\lcd_img"路径下。启动Stm32CubeMX程序在File菜单单击【新建项目】进入CPU选择界面

(二)选择芯片型号

开发板CPU型号为STM32H743VIT6,所以在Commercial Part Number编辑框输入型号。如果事先没有确定型号而是通过项目需求筛选的话可以在左侧导航栏筛选。输入型号后右侧会显示具体封装的列表,双击正确CPU进入系统引脚与配置窗口

如果出现下面窗口选"NO",因为本项目不涉及复杂的内核配置。

进入引脚与配置窗口 后如下图:

(三)SD卡接口配置

本案例要把SD上的24位bmp图片读出来显示到屏幕上,所以这里要打开SD卡的IO口。选择【SDMMC1】后模式要选4位总线类型,下面的分频系数填4

打开SD卡的中断使能

IO引脚的工作模式用默认值就行

(四)LCD接口配置

1、数据接口SPI配置

本LCD屏硬件设计连接到了SPI4口。所以选择【SPI4】后模式要选【Half-Duplex Master】半双工主控制器,数据传输位宽【Data Size】设为8位,SPI时钟分频系数【Prescaler】设为8,使通信速率为15Mhz。

SPI4口是可重定向IO口,默认情况下指向PE2和PE6,如下图:

对应引脚图如下:

但是我们开发板上硬件设计时选用了它的重定向引脚PE12和PE14,所以还得把它们改过来。具体操作是先按住Ctrl键,然后鼠标左键单击【引脚图】绿色的PE2引脚并且按住,等到PE12开始闪烁以后,拖放PE2到PE12即可,PE6改成PE14如法砲制。

接口速度选高速

2、控制接口GPIO口配置

屏幕还有两个辅助接口使用了PE11(片选)和PE13(读写使能),所以搜索两个引脚后设置为【输出】,引脚属性也有改动

3、背光接口PWM口配置

LCD还需要一个PWM信号调节背光亮度,本案例选用定时器提供信号输出,打开【TIM1】定时器,设置通道2为;【PWM Generation CH2N】(调背光用)

IO口仍然需要重定向到PE10,如下图:

基础参数如下:

IO引脚的工作模式用默认值就行。以上5个引脚配置好以后LCD的接口就配置完了。

(五)RCC时钟源配置

1、HSE时钟配置

打开高速时钟源 HSE,设为外部驱动。如图所示。

首先打开外部时钟,同时因为本案例使用的SPI要用到外设120Mhz的时钟,需要RCC时钟参数配置这里将工号调整等级设为0(值越大功耗越低)。

2、时钟树配置

进入 【Clock Configuration】 配置栏之后可以看到,界面展现一个完整的 STM32H7 时钟系统框图。从这个时钟树配置图可以看出,配置的主要是外部晶振大小,分频系数,倍频系数以及选择器。在我们配置的工程中,时钟值会动态更新,如果某个时钟值在配置过程中超过允许值,那么相应的选项框会红色提示。

上图时钟配置的关键点是:确定主频、外频和SD卡外设时钟,接下来在时钟树下面进一步配置SPI外设和SD卡外设时钟。

(六)中间件配置

FAT32中间件

和上一个文档不同,这回我们需要让单片机亲自去读SD内容了,因为SD卡是被格式化成FAT32型文件系统了,所以中间件必须为我们提供FAT格式的解释器。因此选中中间件【FATFS】,模式选择【SD Card】,下面红色框选上对应项

其它选默认值。

(七)生成工程文件

1、工程设置

接下来我们设置生成一个工程,如下图所示。选择 Project Manager-> Project选项用来配置工程的选项,我们了解一下里面的信息。

Project Name:工程名称,填入工程名称(这里填lcd_img)(半角,不能有中文字符)

Project Location:工程保存路径,点击 Browse 选择保存的位置(这里填E:\prj\stm32\lcd_img)(半角,不能有中文字符)

Toolchain Folder Location:工具链文件夹位置,默认即可。

Application Structure:应用的结构,选择 Advanced,不勾选 Do not generate the main(),因为我们要其生成 main 函数。

Toolchain/IDE:工具链/集成开发环境,我们使用 Keil,因此选择 MDK-ARM,Min Version 选择 V5.27,这里根据 CubeMX 的版本可能会有差异,我们默认使用 V5 以上的版本即可。

Linker Settings 链接器设置:

Minimum Heap Size 最小堆大小,调整到2000。

Minimum Stack Size 最小栈大小,调整到2000。

MCU and Firmware Package 是 MCU 及固件包设置:

MCU Reference:目标 MCU 系列名称。

Firmware Package Name and Version:固件包名称及版本。

勾选 Use Default Firmware Location,文本框里面的路径就是固件包的存储地址,我们使用默认地址即可。(这里因为我有两个版本的固件包,所以它默认使用最新的,这个关系不大,就用新的)。

2、代码生成器设置

打开 Project Manager-> Code Generator 选项,Generated files 生成文件选项,勾选 Generate peripheral initialization as a pair of '.c/.h'files per peripheral,勾选这个选项的话将会将每个外设单独分开成一组.c、.h 文件,使得代码结构更加的清晰,如图所示。

由于 CubeMX 默认勾选了复制所有的库,即工程中不使用到的代码也会复制进来,为了节省 CubeMX 生成工程的空间,我们勾选生成工程时只复制用到的库(这一步是可选操作,大家根据自己的实际选择)

3、保存工程

至此工程最基础配置就已经完成,点击蓝色按钮(SENERATE CODE)就可以生成工程。

4、生成工程

如果我们的 CubeMX 工程放置配置路径中没有中文,生成代码后会弹出类似下图的提示窗口,点击 【Open Project】 就打开 MDK 工程(如果是中文路径则会报错)。

到此为止CubeMX任务就结束了。

二、STM32系统C程序设计

打开生成的C代码项目已经假设在你的计算机安装了MDK,如果MDK还没有安装请自行下载并安装。https://www.keil.com/download/product/
注意!不要下载最新版,有可能存在问题!

(一)用MDK打开工程

在MDK的keil编程界面中打开工程后的主界面如下图:

上图看到的LCD驱动部分参照STM32开发学习笔记之六【LCD显示文本】中的内容添加到项目当中。头文件部分增加了全局变量头文件【myGlobal.h】具体代码的编写参考后面内容。

(二)编写LCD的驱动程序

LCD模块在出厂时已经提供了相关的BSP(Board Support Package)底层驱动程序。这些代码文件存放在【BSP\ST7735】文件夹中。

1. 在项目中添加全局变量文件

添加的【myGlobal.h】文件存放在core文件夹,打开项目的界面把该文件添加到和main.c相同的文件夹

在该头文件里加入下面代码:

c 复制代码
//============ myGlobal.h =================
#include "stdint.h"
#ifndef MY_GLOBAL_H
#define MY_GLOBAL_H

#define LCDIMGWIDTH 	80	//图像显存宽度
#define LCDIMGHEIGHT 	80	//图像显存高度
#define LCDIMGNUM		2	//图像显存数量
#define LCDTXTWIDTH 	20	//文本显存宽度

extern uint8_t LCDIMGBUF[LCDIMGNUM][LCDIMGHEIGHT*LCDIMGWIDTH*2];// 图像显存
extern uint8_t LCDIMGIDX;										// 显存ID
extern uint8_t LCDTXTBUF[LCDTXTWIDTH];							// 文本显存

#endif

2. 改写LCD.C中的代码

在lcd.c中加入头文件包含myGlobal.h

c 复制代码
#include "myGlobal.h"

在lcd.c文件中加入显示初始化代码,该部分主要设定屏幕显示方向、清屏幕和设置背光,这部分和上一个案例一致

c 复制代码
void LCD_Disp_Init(void)
{
	ST7735Ctx.Orientation = ST7735_ORIENTATION_LANDSCAPE_ROT180;// 横屏原点左下
	ST7735Ctx.Panel = HannStar_Panel;			// 瀚宇面板
	ST7735Ctx.Type = ST7735_0_9_inch_screen;	// 0.9寸屏
	
	ST7735_RegisterBusIO(&st7735_pObj,&st7735_pIO);
	ST7735_LCD_Driver.Init(&st7735_pObj,ST7735_FORMAT_RBG565,&ST7735Ctx);
	
	ST7735_LCD_Driver.FillRect(&st7735_pObj, 0, 0, ST7735Ctx.Width,ST7735Ctx.Height, BLACK);	// 涂黑全屏
	LCD_SetBrightness(500);		// 设置背光亮度			

}

lcd.c文件中显示函数改写成如下形式

c 复制代码
void LCD_Disp(void)
{
	ST7735_FillRGBRect(&st7735_pObj, 0, 0, LCDIMGBUF[LCDIMGIDX], LCDIMGWIDTH, LCDIMGHEIGHT);	//显存刷新到LCD
	LCD_ShowString(110, 30, ST7735Ctx.Width, 16, 16, LCDTXTBUF);	// 文本输出到屏幕
}

从上面改写LCD.C中的代码可以看出,开发板上16080点阵的0.96寸显示器被分成两个8080的区域,左边用于显示图像,右边【110,30】这个坐标的位置用于显示文本。

(三)编写main.c程序

1、编写读取SD卡文件函数

主函数中要先读取SD卡中的图片然后编码成16位图像存到显存当中,代码如下。

c 复制代码
int ReadSD(void)
{
	FATFS fs;							// 文件系统指针
	FIL file;							// 文件指针
	FRESULT res;						// 函数返回值
	UINT bytes_read;					// 读字节数
	uint8_t image_buf[LCDIMGWIDTH*3];	// 数据缓冲区
	char *filename = "cat.bmp";
	uint32_t width = 0;
	
	uint8_t		*p;
	uint8_t 	r,g,b;
	uint16_t	color565;
	
	// 1. 挂载FATFS到SD卡
    res = f_mount(&fs, "0:", 1);
    if(res != FR_OK) 
	{
        return -1;
    }
    
    // 2. 打开文件
    res = f_open(&file, filename, FA_READ);
    if(res != FR_OK) 
	{
        return -1;
    }
    
    // 3. 读文件
    res = f_read(&file, image_buf, 54, &bytes_read);
	if(res == FR_OK && bytes_read == 54) 
	{
		if(image_buf[0] == 'B' && image_buf[1] == 'M') 
		{
			width  = *(uint32_t*)&image_buf[18];
			
			// 读图像数据
			for(int row=LCDIMGHEIGHT-1;row>=0;row--)
			{
				for(int num=0;num<2;num++)
				{
					f_read(&file, image_buf, width*3/2, &bytes_read);
					p = image_buf;
					for(int col=0;col<LCDIMGWIDTH*2;col+=2)
					{
						b = *(p++);
						g = *(p++);
						r = *(p++);
						
						color565 = r>>3&0x1F;
						color565 = color565<<6; 
						color565 |= g>>2&0x3F;
						color565 = color565<<5; 
						color565 |= b>>3&0x1F;
							
						LCDIMGBUF[num][row*160+col] = color565>>8;
						LCDIMGBUF[num][row*160+col+1] = color565;
						
					}
				}	
			}
		} 
		else 
		{
			return -1;
		}
	} 
	else 
	{
		return -1;
	}
 	
	sprintf((char *)&LCDTXTBUF, "Cat");
	
	f_close(&file);
	return 0;
}

2、添加主程序代码

在主函数前面调用初始化显示函数和读取SD的函数,在主循环中延时交替显示两个显存中的图像。

(四)编译下载

单击编译按钮等一段时间系统编译完成会有如上图的错误或者警告信息(都是0最好)。编译通过以后,通过项目设置窗口的Debug标签确认程序下载器是否正确连接并安装好驱动程序

如果下载器没问题单击download下载按钮,下载器一边闪烁一边把编好的程序下载到STM32的FLASH当中,按下复位键开发板就可以工作了。

有问题欢迎留言,我再学新东西的时候和刚入门的小伙伴一起分享...

相关推荐
问道飞鱼2 小时前
【大模型学习】提示词工程(Prompt Engineering)技术深度报告
学习·prompt·提示词
hssfscv2 小时前
Javaweb学习笔记——后端实战7 springAOP
笔记·后端·学习
来两个炸鸡腿2 小时前
【Datawhale组队学习202601】Base-NLP task06 大模型训练与量化
人工智能·学习·自然语言处理
bylander2 小时前
【AI学习】TM Forum自智网络L4级标准体系
人工智能·学习·智能体·自动驾驶网络
我想我不够好。2 小时前
2026.1.28 消防监控学习
学习
Engineer邓祥浩2 小时前
设计模式学习(24) 23-22 策略模式
学习·设计模式·策略模式
Hammer_Hans2 小时前
DFT笔记26
笔记
2601_949720262 小时前
flutter_for_openharmony手语学习app实战+手语识别实现
学习·flutter
小程同学>o<2 小时前
嵌入式之C/C++(二)内存
c语言·开发语言·c++·笔记·嵌入式软件·面试题库