本篇详细的记录了如何使用STM32CubeMX配置STM32L431RCT6的硬件SPI外设与ST7789通信,驱动16bit TFT-LCD 屏幕。

0. 前言

学习 SPI 外设驱动LCD屏幕没有必要手写驱动,学习这部分代码的目的是为了了解TFT-LCD的工作原理,每个像素点是如何显示的,不要花过多的精力在弄明白每个命令的意思,建议基于本驱动,学习一下打点,画线算法,画圆算法,画多边形算法等等,还可以学习显示英文字符,中文字符,最后还可以移植STemwin显示界面等等好玩的东西~

1. 准备工作

硬件准备

  • 开发板
    首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):

  • LCD屏幕
    小熊派开发板板载LCD屏幕大小1.3寸,分辨率240*240,色彩深度16bit,使用ST7789V2液晶控制器

软件准备

  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;

Keil MDK和串口助手的安装包都可以关注“小熊派开源社区”微信公众号,在资料教程一栏中可获取安装包。

2.生成MDK工程

选择芯片型号

打开STM32CubeMX,打开MCU选择器:

搜索并选中芯片STM32L431RCT6:

配置时钟源

  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;

这里我都使用外部时钟:

配置LCD控制GPIO

配置SPI2接口

查看小熊派LCD接口的原理图:

引脚对应表如下:

LCD引脚 MCU引脚
SPI2_MOSI PC3
SPI2_CLK PB13
LCD_WR_RS PC6
LCD_RESET PC7
LCD_POWER PB15

MCU只需要通过SPI向LCD控制器发送命令/数据即可,所以硬件上接 SPI2 的 SCK 和 MOSI 引脚,软件上将SPI2配置为发送主机模式,接下来开始配置SPI2接口:

参数设置如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUX2uXV4-1581661413301)(http://mculover666.cn/image/20190829/1DHh2ytSwgcp.png?imageslim)]

SPI2默认SCK引脚是PB10,和开发板不对应,所以重新修改引脚为PB13:

配置时钟树

STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可:

生成工程设置

代码生成设置

最后设置生成独立的初始化文件:

生成代码

点击GENERATE CODE即可生成MDK-V5工程:

3. 编写LCD驱动(ST7789)—— 封装宏和底层函数

3.1. 封装控制LCD控制引脚高低电平的宏

控制引脚宏定义已经包含在 main.h 中,如图:

在编写驱动的过程中需要不断的控制这些控制引脚的电平,所以首先在 lcd_spi2_drv.h 头文件中编写控制这些引脚的宏:

#include "main.h"#define   LCD_PWR(n)      (n?\HAL_GPIO_WritePin(LCD_PWR_GPIO_Port,LCD_PWR_Pin,GPIO_PIN_SET):\HAL_GPIO_WritePin(LCD_PWR_GPIO_Port,LCD_PWR_Pin,GPIO_PIN_RESET))
#define LCD_WR_RS(n)    (n?\HAL_GPIO_WritePin(LCD_WR_RS_GPIO_Port,LCD_WR_RS_Pin,GPIO_PIN_SET):\HAL_GPIO_WritePin(LCD_WR_RS_GPIO_Port,LCD_WR_RS_Pin,GPIO_PIN_RESET))
#define LCD_RST(n)      (n?\HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin,GPIO_PIN_SET):\HAL_GPIO_WritePin(LCD_RST_GPIO_Port,LCD_RST_Pin,GPIO_PIN_RESET))

3.2. 宏定义屏幕分辨率和颜色值

//LCD屏幕分辨率定义
#define LCD_Width   240
#define LCD_Height  240
//颜色定义
#define WHITE   0xFFFF  //白色
#define YELLOW  0xFFE0  //黄色
#define BRRED   0XFC07  //棕红色
#define PINK    0XF81F  //粉色
#define RED     0xF800  //红色
#define BROWN   0XBC40  //棕色
#define GRAY    0X8430  //灰色
#define GBLUE   0X07FF  //兰色
#define GREEN   0x07E0  //绿色
#define BLUE    0x001F  //蓝色
#define BLACK   0x0000  //黑色

接下来开始在 lcd_spi2_drv.c 编写驱动程序~

3.3. 封装LCD控制引脚初始化函数

首先包含必要的头文件:

#include "lcd_spi2_drv.h"
#include "gpio.h"
#include "spi.h"

这个函数只能在本文件内由LCD初始化函数调用,所以使用static修饰为静态的:

/***@brief    LCD控制引脚和通信接口初始化*@param    none*@retval   none
*/
static void LCD_GPIO_Init(void)
{/* 初始化引脚 */MX_GPIO_Init();/* 复位LCD */LCD_PWR(0);LCD_RST(0);HAL_Delay(100);LCD_RST(1);/* 初始化SPI2接口 */MX_SPI2_Init();
}

3.4. 封装LCD发送数据和发送命令函数

数据都是由 SPI2 的MOSI发送,由 LCD_WR_RS 引脚指明该数据是命令还是数据。

首先在 spi.c 的最后调用HAL库封装一个函数,供驱动程序调用:

/* USER CODE BEGIN 1 */
/*** @brief    SPI 发送字节函数* @param    TxData   要发送的数据* @param    size 发送数据的字节大小* @return  0:写入成功,其他:写入失败*/
uint8_t SPI_WriteByte(uint8_t *TxData,uint16_t size)
{return HAL_SPI_Transmit(&hspi2,TxData,size,1000);
}
/* USER CODE END 1 */

不要忘了在spi.h中声明该函数!

然后基于spi发送字节函数,在驱动文件中继续封装一个向LCD发送数据的函数,一个向LCD发送命令的函数:

/*** @brief   写命令到LCD* @param   cmd —— 需要发送的命令* @return  none*/
static void LCD_Write_Cmd(uint8_t cmd)
{LCD_WR_RS(0);SPI_WriteByte(&cmd, 1);
}/*** @brief   写数据到LCD* @param   dat —— 需要发送的数据* @return  none*/
static void LCD_Write_Data(uint8_t dat)
{LCD_WR_RS(1);SPI_WriteByte(&dat, 1);
}

4. 编写LCD驱动(ST7789)—— 对照datasheet编程

4.1. 打开/关闭背光函数

这两个函数比较简单,直接调用控制LCD背光的引脚控制宏即可:

/*** @breif   打开LCD显示背光* @param   none* @return  none*/
void LCD_DisplayOn(void)
{LCD_PWR(1);
}
/*** @brief   关闭LCD显示背光* @param   none* @return  none*/
void LCD_DisplayOff(void)
{LCD_PWR(0);
}

4.2. 指定显示RAM操作地址

根据数据手册,当要改变某个区域像素点的颜色时,首先应该确定X方向起始地址和X方向结束地址:

然后确定Y方向起始地址和Y方向结束地址:

最后再确定该区域内每个像素点的值(16bit):

综上,我们每次操作的时候都需要指定操作区域,所以编写该函数:

/*** @brief   设置数据写入LCD显存区域* @param   x1,y1    —— 起点坐标* @param   x2,y2    —— 终点坐标* @return  none*/
void LCD_Address_Set(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{/* 指定X方向操作区域 */LCD_Write_Cmd(0x2a);LCD_Write_Data(x1 >> 8);LCD_Write_Data(x1);LCD_Write_Data(x2 >> 8);LCD_Write_Data(x2);/* 指定Y方向操作区域 */LCD_Write_Cmd(0x2b);LCD_Write_Data(y1 >> 8);LCD_Write_Data(y1);LCD_Write_Data(y2 >> 8);LCD_Write_Data(y2);/* 发送该命令,LCD开始等待接收显存数据 */LCD_Write_Cmd(0x2C);
}

4.3. 清屏函数

编写完指定显存操作区域后,趁热打铁,编写清屏函数就很简单啦,直接调用上面编写的函数,指定操作地址为全屏幕,然后循环发送颜色值即可:

#define LCD_TOTAL_BUF_SIZE   (240*240*2)
#define LCD_Buf_Size 1152
static uint8_t lcd_buf[LCD_Buf_Size];
/*** @brief   以一种颜色清空LCD屏* @param   color —— 清屏颜色(16bit)* @return  none*/
void LCD_Clear(uint16_t color)
{uint16_t i, j;uint8_t data[2] = {0};  //color是16bit的,每个像素点需要两个字节的显存/* 将16bit的color值分开为两个单独的字节 */data[0] = color >> 8;data[1] = color;/* 显存的值需要逐字节写入 */for(j = 0; j < LCD_Buf_Size / 2; j++){lcd_buf[j * 2] =  data[0];lcd_buf[j * 2 + 1] =  data[1];}/* 指定显存操作地址为全屏幕 */LCD_Address_Set(0, 0, LCD_Width - 1, LCD_Height - 1);/* 指定接下来的数据为数据 */LCD_WR_RS(1);/* 将显存缓冲区的数据全部写入缓冲区 */for(i = 0; i < (LCD_TOTAL_BUF_SIZE / LCD_Buf_Size); i++){SPI_WriteByte(lcd_buf, (uint16_t)LCD_Buf_Size);}
}

4.4. LCD初始化函数

至此,LCD的一些操作函数全部编写完成,最后编写初始化LCD模式的函数:

/*** @brief   LCD初始化* @param   none* @return  none*/
void LCD_Init(void)
{/* 初始化和LCD通信的引脚 */LCD_GPIO_Init();HAL_Delay(120);/* 关闭睡眠模式 */LCD_Write_Cmd(0x11);HAL_Delay(120);/* 开始设置显存扫描模式,数据格式等 */LCD_Write_Cmd(0x36);LCD_Write_Data(0x00);/* RGB 5-6-5-bit格式  */LCD_Write_Cmd(0x3A);LCD_Write_Data(0x65);/* porch 设置 */LCD_Write_Cmd(0xB2);LCD_Write_Data(0x0C);LCD_Write_Data(0x0C);LCD_Write_Data(0x00);LCD_Write_Data(0x33);LCD_Write_Data(0x33);/* VGH设置 */LCD_Write_Cmd(0xB7);LCD_Write_Data(0x72);/* VCOM 设置 */LCD_Write_Cmd(0xBB);LCD_Write_Data(0x3D);/* LCM 设置 */LCD_Write_Cmd(0xC0);LCD_Write_Data(0x2C);/* VDV and VRH 设置 */LCD_Write_Cmd(0xC2);LCD_Write_Data(0x01);/* VRH 设置 */LCD_Write_Cmd(0xC3);LCD_Write_Data(0x19);/* VDV 设置 */LCD_Write_Cmd(0xC4);LCD_Write_Data(0x20);/* 普通模式下显存速率设置 60Mhz */LCD_Write_Cmd(0xC6);LCD_Write_Data(0x0F);/* 电源控制 */LCD_Write_Cmd(0xD0);LCD_Write_Data(0xA4);LCD_Write_Data(0xA1);/* 电压设置 */LCD_Write_Cmd(0xE0);LCD_Write_Data(0xD0);LCD_Write_Data(0x04);LCD_Write_Data(0x0D);LCD_Write_Data(0x11);LCD_Write_Data(0x13);LCD_Write_Data(0x2B);LCD_Write_Data(0x3F);LCD_Write_Data(0x54);LCD_Write_Data(0x4C);LCD_Write_Data(0x18);LCD_Write_Data(0x0D);LCD_Write_Data(0x0B);LCD_Write_Data(0x1F);LCD_Write_Data(0x23);/* 电压设置 */LCD_Write_Cmd(0xE1);LCD_Write_Data(0xD0);LCD_Write_Data(0x04);LCD_Write_Data(0x0C);LCD_Write_Data(0x11);LCD_Write_Data(0x13);LCD_Write_Data(0x2C);LCD_Write_Data(0x3F);LCD_Write_Data(0x44);LCD_Write_Data(0x51);LCD_Write_Data(0x2F);LCD_Write_Data(0x1F);LCD_Write_Data(0x1F);LCD_Write_Data(0x20);LCD_Write_Data(0x23);/* 显示开 */LCD_Write_Cmd(0x21);LCD_Write_Cmd(0x29);/* 清屏为白色 */LCD_Clear(WHITE);/*打开显示*/LCD_PWR(1);
}

至此,驱动编写完成。

5. 测试驱动程序

main函数 中编写驱动测试代码,在 while(1) 之前添加如下代码:

  /* USER CODE BEGIN 2 */LCD_Init();LCD_Clear(GREEN);/* USER CODE END 2 */

测试结果如图:

绿绿的,是不是很好看哈哈(斜眼笑.jpg)~

至此,我们已经学会如何使用硬件SPI驱动LCD屏幕(ST7789),下一节将讲述如何使用硬件QSPI接口读写SPI Flash的数据。

STM32单片机基础17——使用硬件SPI驱动TFT-LCD(ST7789)相关推荐

  1. 嵌入式开发-STM32硬件SPI驱动TFT屏

    嵌入式开发-STM32硬件SPI驱动TFT屏 这次用到的TFT屏 CubeMX设置 代码编写 增加的内容 需要注意问题 代码下载 这次用到的TFT屏 现在的TFT屏幕已经很便宜了,65536色屏幕,2 ...

  2. ESP8266+MicroPython开发:ESP8266使用硬件SPI驱动TFT屏幕(ST7735)

    由于上次模拟SPI驱动TFT屏幕太慢,所以,本次采用硬件SPI来进行驱动,但是,当我直接把对应SPI接口更换时,发现TFT屏幕驱动并没有因此得到好转,依然是非常的满,然后只能从对应花点铺色,显示字符串 ...

  3. 【STM32Cube_17】使用硬件SPI驱动TFT-LCD(ST7789)

    上一篇:[STM32Cube_16]使用硬件CRC校验数据(以SHT30为例) 寻求更好的阅读体验,请移步:Mculover666的个人博客. 本篇详细的记录了如何使用STM32CubeMX配置STM ...

  4. STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片

    STM32CubeMX | 基于STM32使用HAL库硬件SPI驱动WK2124一拖四SPI转四路串口芯片 STM32基础工程生成 首先使用STM32CUBEMX生成STM32的基础工程,配置时钟到7 ...

  5. STM32使用硬件SPI驱动RC522门禁模块

    0.前言 RC522射频门禁识别模块非常常用,某宝卖家提供的程序基本都是使用软件模拟SPI的方式进行驱动的,但是实测使用软件模拟SPI识别速率.准确性没有硬件SPI驱动时高,因此本篇博客用于记录使用S ...

  6. stm32硬件SPI驱动3线SPI-LCD的方法

    1.基本控制原理 三线SPI LCD, 顾名思义,最少只需要3个IO控制LCD显示,如果采用硬件控制上电时序和背光,最少只需要接SCK,CS,MOSI三个引脚即可控制LCD,并且不管接不接其他引脚,控 ...

  7. STM32硬件SPI驱动OLED

    文章目录 一.OLED相关 1.OLED简介 2.0.96寸的OLED模块概述 3.模块引脚说明 4.汉字点阵编码原理 二.硬件SPI 1.SPI简介 2.SPI的引脚映射关系 三.SPI驱动的OLE ...

  8. MSP430杂谈--AD7793硬件SPI驱动与模拟SPI驱动

    最近项目中用到了AD7793读取铂电阻值来得到相应的温度,编写了基于MSP430的硬件驱动程序和模拟驱动程序,并且能成功运行,现在记录一下分享给大家. AD7793硬件IIC驱动完整版下载链接:htt ...

  9. 联盛德 HLK-W806 (十一): 软件SPI和硬件SPI驱动ST7567液晶LCD

    目录 联盛德 HLK-W806 (一): Ubuntu20.04下的开发环境配置, 编译和烧录说明 联盛德 HLK-W806 (二): Win10下的开发环境配置, 编译和烧录说明 联盛德 HLK-W ...

最新文章

  1. 纯css的accordion效果
  2. python推荐入门书籍-学python入门看什么书
  3. Optimized Purchasing基础知识
  4. linux c语言中如何通过进程名获取进程PID(awk命令行指令)popen、pclose
  5. Lotus 下部门间用户的移动操作
  6. Docker:集装箱式“运输”在软件上的实现
  7. python全局变量修改_python中全局变量的修改
  8. php怎么用递归函数遍历多维数组,php递归遍历多维数组的方法
  9. #include,#import ,@class 有什么区别?
  10. js中立即执行函数会预编译吗_javascript引擎执行的过程的理解--执行阶段
  11. MySQL生成随机姓名
  12. Arduino基础学习
  13. java5兼容性,兼容性问题 (适用于 UNIX 的 Sun Java Enterprise System 5 发行说明)
  14. 冯诺依曼计算机的英文简称,冯诺依曼计算机,von neumann machine,音标,读音,翻译,英文例句,英语词典...
  15. 牙医管家牙科软件APP功能-“看牙无忧”口腔分期功能介绍
  16. java繁体_Java-汉字繁体拼音转换
  17. 在局域网内主动封堵BT下载使用
  18. SQL零基础入门学习(十)
  19. 年轻人,你的目标不该是成为斜杠青年
  20. web前端期末大作业 魅力广西我的家乡介绍网页制作(HTML+CSS)

热门文章

  1. Pandas数据类型转换
  2. 四年级上册计算机课程内容,小学四年级上册信息技术教案3篇(人教版)
  3. 2017华为codecraft 《大视频时代布局》
  4. 修改阿里云服务器登录默认欢迎语
  5. 婴儿摇铃玩具亚马逊审查要求做CPC认证标准要求
  6. 信息系统项目管理师必背核心考点(三十三)老七工具
  7. 超性能服务器,绝地求生国服超性能服务器是什么 绝地求生国服超性能服务器详解...
  8. requests InsecureRequestWarning: Unverified HTTPS request is being made.
  9. element的container布局铺满
  10. Https 公钥私钥交换过程