使用SPI驱动串行LCD的驱动实现(STM32F4)

目录

概述

1. 硬件介绍

1.1 ST7796-LCD

1.2 MCU IO与LCD PIN对应关系

2 功能实现

2.1 使用STM32Cube配置Project

 2.2 STM32Cube生成工程

3 代码实现

3.1 SPI接口实现

3.2 LCD驱动程序实现

3.3 测试程序实现

 4 测试


源代码下载地址:

https://gitee.com/mftang/stm32_open_test_proj/tree/master/stm32_f407_lcd_proj/UserCode/lcd_drv

测试视频:

使用SPI驱动串行LCD的驱动实现(STM32F4)

概述

本文主要讲述使用STM32硬件SPI接口驱动ST7796-LCD,主控MCU为STM32F407芯片。笔者详细介绍整个驱动的实现过程,并使用STM32Cube生成一个工程,测试驱动程序的功能。

1. 硬件介绍

1.1 ST7796-LCD

LCD的PIN引脚功能介绍

序号模块引脚引脚说明
1VCC屏电源正
2GND屏电源地
3LCD_CS液晶屏片选控制信号,低电平有效
4LCD_RST液晶屏复位控制信号,低电平复位
5LCD_RS液晶屏命令/数据选择控制信号

高电平:数据,低电平:命令

6SDI(MOSI)SPI总线写数据信号(SD卡和液晶屏共用)
7SCKSPI总线时钟信号(SD卡和液晶屏共用)
8LED液晶屏背光控制信号(如需要控制,请接引脚,如不需要控制,可以不接)
9SDO(MISO)SPI总线读数据信号(SD卡和液晶屏共用)
10CTP_SCL电容触摸屏IIC总线时钟信号(无触摸屏的模块不需连接)
11CTP_RST电容触摸屏复位控制信号,低电平复位(无触摸屏的模块不需连接)
12CTP_SDA电容触摸屏IIC总线数据信号(无触摸屏的模块不需连接)
13CTP_INT电容触摸屏IIC总线触摸中断信号,产生触摸时,输入低电平到主控(无触摸屏的模块不需连接)
14SD_CSSD卡片选控制信号,低电平有效(不使用SD卡功能,可不接)

实体LCD Port对应关系如下图所示

1.2 MCU IO与LCD PIN对应关系

STM32 PIN引脚LCD PIN引脚
PB5-MOSIMOSI
PB4-MISOMISO
PB3-SCKSCK
PB6CS
PB9RST
PB8RS

2 功能实现

2.1 使用STM32Cube配置Project

1) 配置SPI接口

SPI的参数

2)配置LCD的控制引脚

3)使能外部晶振

 2.2 STM32Cube生成工程

使用STM32Cube生成工程,并创建两个目录

User/lcd_drv     驱动文件目录

User/test           测试文件目录

3 代码实现

3.1 SPI接口实现

在spi.c文件中实现读写接口函数,具体实现如下:

/* USER CODE BEGIN 1 */void hal_spi_writebyte( uint8_t byte )
{uint8_t buff[1];buff[0] = byte;HAL_SPI_Transmit( &hspi3, buff, 1, 1000);
}uint8_t hal_spi_readbyte(void)
{uint8_t buff[1];buff[0] = 0xff;return HAL_SPI_Receive( &hspi3, buff, 1, 1000);
}/* USER CODE END 1 */

3.2 LCD驱动程序实现

创建lcd_drv.c实现驱动程序,lcd_spi.c实现和MCU之间的驱动接口

 1)lcd_drv.c 程序实现

#include "lcd_drv.h"
#include "lcd_spi.h"_lcd_dev lcddev;void LCD_WR_REG(uint8_t data)
{ LCD_CS_CLR;LCD_RS_CLR; SPI_WriteByte(data);LCD_CS_SET;
}void LCD_WR_DATA(uint8_t data)
{LCD_CS_CLR;LCD_RS_SET;SPI_WriteByte(data);LCD_CS_SET;
}uint8_t LCD_RD_DATA(void)
{uint8_t data;LCD_CS_CLR;LCD_RS_SET;data = SPI_ReadByte();LCD_CS_SET;return data;
}void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{LCD_WR_REG(LCD_Reg);  LCD_WR_DATA(LCD_RegValue); 
}uint8_t LCD_ReadReg(uint8_t LCD_Reg)
{LCD_WR_REG(LCD_Reg);return LCD_RD_DATA();
}void LCD_WriteRAM_Prepare(void)
{LCD_WR_REG(lcddev.wramcmd);
}void Lcd_WriteData_16Bit(uint16_t Data)
{LCD_CS_CLR;LCD_RS_SET;SPI_WriteByte(Data>>8);SPI_WriteByte(Data);LCD_CS_SET;
}uint16_t Lcd_ReadData_16Bit(void)
{uint16_t r,g;LCD_CS_CLR;LCD_RS_CLR;SPI_WriteByte(lcddev.rramcmd);LCD_RS_SET;SPI_ReadByte();r = SPI_ReadByte();g = SPI_ReadByte();LCD_CS_SET;r<<=8;r|=g;return r;
}void LCD_DrawPoint(uint16_t x,uint16_t y, uint16_t color)
{LCD_SetCursor(x,y);Lcd_WriteData_16Bit(color); 
}uint16_t LCD_ReadPoint(uint16_t x,uint16_t y)
{uint16_t color;LCD_SetCursor(x,y);color = Lcd_ReadData_16Bit();return color;
}void LCD_Clear(uint16_t Color)
{uint16_t i,m; LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);LCD_CS_CLR;LCD_RS_SET;for(i=0;i<lcddev.height;i++){for(m=0;m<lcddev.width;m++){SPI_WriteByte(Color>>8);SPI_WriteByte(Color);}}LCD_CS_SET;
} void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(xStar>>8);LCD_WR_DATA(0x00FF&xStar);LCD_WR_DATA(xEnd>>8);LCD_WR_DATA(0x00FF&xEnd);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(yStar>>8);LCD_WR_DATA(0x00FF&yStar);LCD_WR_DATA(yEnd>>8);LCD_WR_DATA(0x00FF&yEnd);LCD_WriteRAM_Prepare();
} void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
}void LCD_direction(uint8_t direction)
{ lcddev.setxcmd=0x2A;lcddev.setycmd=0x2B;lcddev.wramcmd=0x2C;lcddev.rramcmd=0x2E;lcddev.dir = direction%4;switch(lcddev.dir){  case 0:lcddev.width=LCD_W;lcddev.height=LCD_H;LCD_WriteReg(0x36,(1<<3)|(1<<6));break;case 1:lcddev.width=LCD_H;lcddev.height=LCD_W;LCD_WriteReg(0x36,(1<<3)|(1<<5));break;case 2:lcddev.width=LCD_W;lcddev.height=LCD_H;LCD_WriteReg(0x36,(1<<3)|(1<<7));break;case 3:lcddev.width=LCD_H;lcddev.height=LCD_W;LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<6)|(1<<5));break;default:break;}
} uint16_t LCD_Read_ID(void)
{uint8_t i,val[3] = {0};LCD_WR_REG(0xF0);     // Command Set ControlLCD_WR_DATA(0xC3);   LCD_WR_REG(0xF0);     LCD_WR_DATA(0x96);  LCD_CS_CLR;for(i=1;i<4;i++){LCD_RS_CLR;	  SPI_WriteByte(0xFB);LCD_RS_SET;SPI_WriteByte(0x10+i);LCD_RS_CLR;	  SPI_WriteByte(0xD3);LCD_RS_SET;val[i-1] = SPI_ReadByte();LCD_RS_CLR;	  SPI_WriteByte(0xFB);LCD_RS_SET;SPI_WriteByte(0x00);}LCD_CS_SET;LCD_WR_REG(0xF0);     // Command Set ControlLCD_WR_DATA(0x3C);   LCD_WR_REG(0xF0);     LCD_WR_DATA(0x69);  lcddev.id=val[1];lcddev.id<<=8;lcddev.id|=val[2];return lcddev.id;
}void LCD_RESET(void)
{LCD_RST_CLR;lcd_delay_us(100);LCD_RST_SET;lcd_delay_us(50);
}void LCD_Init(void)
{  LCD_RESET();          //LCD//*************3.5 ST7796S IPSLCD_WR_REG(0x11);     lcd_delay_us(120);    //Delay 120mslcd_delay_us(120);    //Delay 120msLCD_WR_REG(0x36);     // Memory Data Access Control MY,MX~~LCD_WR_DATA(0x48);   LCD_WR_REG(0x3A);     LCD_WR_DATA(0x55);   LCD_WR_REG(0xF0);     // Command Set ControlLCD_WR_DATA(0xC3);   LCD_WR_REG(0xF0);     LCD_WR_DATA(0x96);   LCD_WR_REG(0xB4);     LCD_WR_DATA(0x01);   LCD_WR_REG(0xB7);     LCD_WR_DATA(0xC6);   //LCD_WR_REG(0xB9);     //LCD_WR_DATA(0x02);//LCD_WR_DATA(0xE0);LCD_WR_REG(0xC0);     LCD_WR_DATA(0x80);   LCD_WR_DATA(0x45);   LCD_WR_REG(0xC1);     LCD_WR_DATA(0x13);   //18  //00LCD_WR_REG(0xC2);     LCD_WR_DATA(0xA7);   LCD_WR_REG(0xC5);     LCD_WR_DATA(0x0A);   LCD_WR_REG(0xE8);     LCD_WR_DATA(0x40);LCD_WR_DATA(0x8A);LCD_WR_DATA(0x00);LCD_WR_DATA(0x00);LCD_WR_DATA(0x29);LCD_WR_DATA(0x19);LCD_WR_DATA(0xA5);LCD_WR_DATA(0x33);LCD_WR_REG(0xE0);LCD_WR_DATA(0xD0);LCD_WR_DATA(0x08);LCD_WR_DATA(0x0F);LCD_WR_DATA(0x06);LCD_WR_DATA(0x06);LCD_WR_DATA(0x33);LCD_WR_DATA(0x30);LCD_WR_DATA(0x33);LCD_WR_DATA(0x47);LCD_WR_DATA(0x17);LCD_WR_DATA(0x13);LCD_WR_DATA(0x13);LCD_WR_DATA(0x2B);LCD_WR_DATA(0x31);LCD_WR_REG(0xE1);LCD_WR_DATA(0xD0);LCD_WR_DATA(0x0A);LCD_WR_DATA(0x11);LCD_WR_DATA(0x0B);LCD_WR_DATA(0x09);LCD_WR_DATA(0x07);LCD_WR_DATA(0x2F);LCD_WR_DATA(0x33);LCD_WR_DATA(0x47);LCD_WR_DATA(0x38);LCD_WR_DATA(0x15);LCD_WR_DATA(0x16);LCD_WR_DATA(0x2C);LCD_WR_DATA(0x32);LCD_WR_REG(0xF0);     LCD_WR_DATA(0x3C);   LCD_WR_REG(0xF0);     LCD_WR_DATA(0x69);   lcd_delay_us(120);LCD_WR_REG(0x21);     LCD_WR_REG(0x29); LCD_direction(USE_HORIZONTAL);LCD_Clear(DARKBLUE);
}/* End of this file */

2)lcd_spi.c 程序实现

#include "lcd_spi.h"#if !IO_SPI
#include "spi.h"
#endifvoid lcd_gpio_init(void)
{
#if IO_SPIGPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(LCD_GPIO_PORT, lcd_sck_Pin|lcd_mosi_Pin|lcd_cs_Pin|lcd_rs_Pin|lcd_rst_Pin, GPIO_PIN_RESET);/*Configure GPIO pins : PBPin PBPin PBPin PBPinPBPin */GPIO_InitStruct.Pin = lcd_sck_Pin|lcd_mosi_Pin|lcd_cs_Pin|lcd_rs_Pin|lcd_rst_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(LCD_GPIO_PORT, &GPIO_InitStruct);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = lcd_miso_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(lcd_miso_GPIO_Port, &GPIO_InitStruct);
#endif}void lcd_delay_us(uint32_t us)
{uint32_t i=0;while(us--){for(i=0;i<1000;i++);}
}void SPI_WriteByte(uint8_t Byte)
{
#if IO_SPIuint8_t i=0;for(i=0;i<8;i++){if(Byte&0x80){SPI_MOSI_SET;}else{SPI_MOSI_CLR;}SPI_SCLK_CLR;SPI_SCLK_SET;Byte<<=1;}
#elsehal_spi_writebyte( Byte );
#endif
} uint8_t SPI_ReadByte(void)
{
#if IO_SPIuint8_t value=0,i=0,byte=0xFF;for(i=0;i<8;i++){value<<=1;if(byte&0x80){SPI_MOSI_SET;}else{SPI_MOSI_CLR;}byte<<=1;SPI_SCLK_CLR;lcd_delay_us(100);if(SPI_MISO_READ){value += 1;}SPI_SCLK_SET;lcd_delay_us(100);}return value;
#elsereturn hal_spi_readbyte();
#endif
} 

3.3 测试程序实现

创建lcd_test.c文件,编写测试程序

 4 测试

在如下文件中调用测试程序,其主要实现每隔1s时间刷新屏幕的颜色。

详细代码:

void StartDefaultTask(void *argument)
{/* USER CODE BEGIN StartDefaultTask */int count;LCD_Init();LCD_Read_ID();/* Infinite loop */for(;;){osDelay(1);if(count%1000 == 0){lcd_test();}count++;}/* USER CODE END StartDefaultTask */
}

运行结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/325445.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用Linux命令详细总结

一、文档编辑、过滤、查看命令 1、cp 复制文件和目录 -a 复制文件并保持文件属性 -d 若源文件为链接文件&#xff0c;则复制链接文件属性而非文件本身 -i 覆盖文件前提示&#xff0c;如果不要提示&#xff0c;在命令前加上\ -r 递归复制&#xff0c;通常用于目录的复制 …

C++的数据结构(三):栈

栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;LIFO, Last In First Out&#xff09;的数据结构&#xff0c;它只允许在一端&#xff08;称为栈顶&#xff09;进行插入和删除操作。栈的这种特性使得它在解决函数调用、括号匹配、表达式求值等问题时具有天然的优势…

SpringCloud 2023.0.1

本文介绍如何使用 springboot3及cloud2023 进行微服务模块化开发 采用父-module 模块开发 父工程 demo-java pom.xml <!--配置 springboot的依赖的版本号, 方便 module 进行继承--><dependencyManagement><dependencies><!--增加 springboot的依赖--&g…

宝塔安装多个版本的PHP,如何设置默认的PHP版本

如何将默认的PHP版本设置为7.3.32&#xff0c; 创建软链接指向7.3版本&#xff0c;关键命令&#xff1a;ln -sf /www/server/php/73/bin/php /usr/bin/php 然后再查看PHP版本验证一下结果 [rootlocalhost ~]# ln -sf /www/server/php/73/bin/php /usr/bin/php [rootlocalho…

zabbix“专家坐诊”第238期问答

问题一 Q&#xff1a;请问一下 zabbix 如何监控服务器端口的出和入流量?就类似iftop这样的。 A&#xff1a;可以用snmp去监控。 问题二 Q&#xff1a;各位有什么工具能导出zabbix主机列表成execl格式吗&#xff1f; A&#xff1a;进mysql&#xff0c;到hostid&#xff0c;然…

WEB后端复习——监听器、过滤器

Listener监听器 是Servlet规范中定义的一种特殊类&#xff0c;它用于监听web应用程序中的ServletContext, HttpSession和ServletRequest等域对象的创建与销毁事件&#xff0c;以及监听这些域对象中的属性发生修改的事件。 注解WebListener 1.ServletContextListener 监听Serv…

Python3 + Appium + 安卓模拟器实现APP自动化测试并生成测试报告

这篇文章主要介绍了Python3 Appium 安卓模拟器实现APP自动化测试并生成测试报告,本文给大家介绍的非常详细&#xff0c;对大家的学习或工作具有一定的参考借鉴价值&#xff0c;需要的朋友可以参考下 本文主要分为以下几个部分 安装Python3 安装Python3的Appium库 安装Andr…

K-CU12和利时工控单元

K-CU12和利时工控单元。控制策略组态&#xff0c;使用专用的组态软件 人机界面HMI设计&#xff1a;操作员站画面设计&#xff0c;使用专用的组态软件 K-CU12和利时工控单元文件组态 2文档管理软件 在工程师站上进行系统组态的主要工作&#xff1a; K-CU12和利时工控单元。系统配…

【全开源】Fastflow工作流系统(源码搭建/上线/运营/售后/维护更新)

一款基于FastAdminThinkPHP开发的可视化工作流程审批插件&#xff0c;帮助用户基于企业业务模式和管理模式自行定义所需的各种流程应用&#xff0c;快速构建企业自身的流程管控体系&#xff0c;快速融合至企业协同OA办公系统。 提供全部无加密服务端源码和前端源代码&#xff0…

如何在 Linux / Ubuntu 上下载和安装 JMeter?

Apache JMeter 是一个开源的负载测试工具&#xff0c;可以用于测试静态和动态资源&#xff0c;确定服务器的性能和稳定性。在本文中&#xff0c;我们将讨论如何下载和安装 JMeter。 安装 Java&#xff08;已安装 Java 的此步骤可跳过&#xff09; 安装 Java 要下载 Java&…

【计算机网络篇】数据链路层(10)在物理层扩展以太网

文章目录 &#x1f354;扩展站点与集线器之间的距离&#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 &#x1f354;扩展站点与集线器之间的距离 &#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 以太网集线器一般具有8~32个接口&#xff0c;如果要连接的站点数量超过了…

使用Three.js绘制快速而逼真的水

本文将利用GPUComputationRenderer来实现水波纹的绘制&#xff0c;相似的案例可以看threejs官方的GPGPU Water示例。更多精彩内容尽在数字孪生平台。 什么是 GPGPU GPGPU代表通用图形处理单元&#xff08;General-Purpose Graphic Processing Unit&#xff09;&#xff0c;意思…

从0开始linux(2)——热键、如何查阅手册

欢迎来到博主的专栏——从0开始linux 博主ID&#xff1a;代码小豪 博主使用的linux发行版&#xff1a;CentOS 7.6 文章目录 热键[Tab]热键Ctrl cshift[pageup]和[pagedown] 查阅手册\-\-help在线手册maninfo手册 热键 我们的命令行模式中存在很多的组合热键&#xff0c;这些按…

神经网络中的算法优化(皮毛讲解)

抛砖引玉 在深度学习中&#xff0c;优化算法是训练神经网络时至关重要的一部分。 优化算法的目标是最小化&#xff08;或最大化&#xff09;一个损失函数&#xff0c;通常通过调整神经网络的参数来实现。 这个过程可以通过梯度下降法来完成&#xff0c;其中梯度指的是损失函数…

利用“AnaTraf“网络流量分析仪轻松诊断和优化网络

网络性能监测和诊断(NPMD)是网络管理和优化的重要环节,准确快速地定位和排除网络故障对于保障业务正常运转至关重要。作为一款专业的网络流量分析设备,AnaTraf网络流量分析仪凭借其强大的流量分析和故障诊断功能,为网络管理者提供了一个高效的网络优化解决方案。 全面掌握网络…

计算机网络实验1:交换机基本配置管理

实验目的和要求 安装Packer Tracer&#xff0c;了解Packer Tracer的基本操作掌握交换机基本命令集实验项目内容 认识Packet Tracer软件 交换机的基本配置与管理 交换机的端口配置与管理 交换机的端口聚合配置 交换机划分Vlan配置 实验环境 硬件&#xff1a;PC机&#x…

体验MouseBoost PRO,让Mac操作更高效

还在为Mac的右键功能而烦恼吗&#xff1f;试试MouseBoost PRO for Mac吧&#xff01;这款强大的鼠标右键增强软件&#xff0c;能让你通过简单操作即可激活多种实用功能&#xff0c;让你的工作变得更加轻松。其高度定制化的设计&#xff0c;更能满足你的个性化需求。赶快下载体验…

【ubuntu】ubuntu-18.04开机卡在Starting User Manager for UID 120....问题解决方案

错误截图 解决方案 启动系统&#xff0c;开机界面单击按键esc键&#xff0c;注意需要将鼠标定位到菜单界面&#xff0c;移动键盘上下键选择Advanced options for Ubuntu 进入如下菜单&#xff0c;选择recovery mode 回车之后会弹出如下界面&#xff0c;选择如下root&#xff0…

瀚高数据库(HighGoDB)Windows安装使用

1.下载 2.安装 瀚高数据库下载与安装&#xff08;Windows版&#xff09;-CSDN博客 3.连接工具 4.建库、建表操作 瀚高数据库管理工具-CSDN博客 *报错Cant access non-default database&#xff0c;需要右键数据库-设为活动对象 5.导入外部数据&#xff08;迁移、对比&…

生信人写程序1. Perl语言模板及配置

生物信息领域常用语言 个人认为&#xff1a;是否能熟悉使用Shell(项目流程搭建)R(数据统计与可视化)Perl/Python/Java…(胶水语言&#xff0c;数据格式转换&#xff0c;软件间衔接)三门语言是一位合格生物信息工程师的标准。 生物信息常用语言非常广泛&#xff0c;我常用的有…