【正点原子探索者STM32F4】TFTLCD实验学习记录

【正点原子探索者STM32】LCD实验学习记录

  • 硬件
  • 硬件连接
  • 软件设计
    • 变量类型定义
      • LCD参数结构体
      • LCD地址结构体
    • 函数定义
      • 读写命令和数据简介
      • 6个基本函数
      • 坐标设置函数
      • 画点函数
      • 读点函数
      • 字符显示函数
      • LCD初始化
  • 小结
  • 参考

硬件

STM32F407、4.3寸LCD屏

硬件连接

在这里插入图片描述

LCD_BL(背光控制)对应 PB15;
LCD_CS 对应 PG12 即 FSMC_NE4;
LCD _RS 对应 PF12 即 FSMC_A6;
LCD _WR 对应 PD5 即 FSMC_NWE;
LCD _RD 对应 PD4 即 FSMC_NOE;
LCD _D[15:0]则直接连接在 FSMC_D15~FSMC_D0;

软件设计

变量类型定义

LCD参数结构体

//LCD重要参数集
typedef struct  
{										    u16 width;			//LCD 宽度u16 height;			//LCD 高度u16 id;				//LCD IDu8  dir;			//横屏还是竖屏控制:0,竖屏;1,横屏。	u16	wramcmd;		//开始写gram指令u16  setxcmd;		//设置x坐标指令u16  setycmd;		//设置y坐标指令 
}_lcd_dev; 	  

LCD地址结构体

LCD _RS 对应 PF12,即 FSMC_A6,RS:命令/数据标志(0,读写命令; 1,读写数据)
STM32F4 的 FSMC 存储块 1(Bank1)被分为 4 个区,每个区管理 64M 字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。
Bank1 的 256M 字节空间由 28 根地址线(HADDR[27:0])寻址。
228 等价于210 ×210 ×256 ,** 对应256M的字节。**
这 里 HADDR 是内 部 AHB 地址总 线 ,其 中 HADDR[25:0]来自外部存储器地 址FSMC_A[25:0],而 HADDR[26:27]对 4 个区进行寻址。
在这里插入图片描述

这里 LCD是 16 位宽度存储器: HADDR[25:1]→ FSMC_A[24:0],16位正好是2个字节,所以地址是一个隔一个,即低位都为0.相当于右移了一位。因此,FSMC_A[6]对应0x00000080,作为数据的地址偏移量,此地址减2得到命令的地址偏移量。
不论外部接 8 位/16 位宽设备, FSMC_A[0]永远接在外部设备地址 A[0]。

//LCD地址结构体
typedef struct
{vu16 LCD_REG;//命令变量  ((u32)(0x6C000000 | 0x0000007E))vu16 LCD_RAM;//数据变量  ((u32)(0x6C000000 | 0x00000080))
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线 
//注意设置时STM32内部会右移一位对其! 111 1110=0X7E			    
#define LCD_BASE        ((u32)(0x6C000000 | 0x0000007E))
#define LCD             ((LCD_TypeDef *) LCD_BASE)//强制类型转换,LCD为LCD_TypeDef的指针

函数定义

读写命令和数据简介

LCD->LCD_REG=CMD; //写命令
LCD->LCD_RAM=DATA; //写数据
CMD= LCD->LCD_REG;//读 LCD 寄存器
DATA = LCD->LCD_RAM;//读 LCD 数据

6个基本函数

//写寄存器函数
//regval:寄存器值
void LCD_WR_REG(vu16 regval)
{ regval=regval; //使用-O2 优化的时候,必须插入的延时LCD->LCD_REG=regval;//写入要写的寄存器序号
}//写 LCD 数据
//data:要写入的值
void LCD_WR_DATA(vu16 data)
{ data=data; //使用-O2 优化的时候,必须插入的延时LCD->LCD_RAM=data;
}
//读 LCD 数据
//返回值:读到的值
u16 LCD_RD_DATA(void)
{ vu16 ram; //防止被优化ram=LCD->LCD_RAM;return ram;
}
//写寄存器
//LCD_Reg:寄存器地址
//LCD_RegValue:要写入的数据
void LCD_WriteReg(vu16 LCD_Reg, vu16 LCD_RegValue)
{ LCD->LCD_REG = LCD_Reg; //写入要写的寄存器序号LCD->LCD_RAM = LCD_RegValue; //写入数据
}
//读寄存器
//LCD_Reg:寄存器地址
//返回值:读到的数据
u16 LCD_ReadReg(vu16 LCD_Reg)
{ LCD_WR_REG(LCD_Reg); //写入要读的寄存器序号delay_us(5);return LCD_RD_DATA(); //返回读到的值
}
//开始写 GRAM
void LCD_WriteRAM_Prepare(void)
{ LCD->LCD_REG=lcddev.wramcmd;//0X2C00
}
//LCD 写 GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{ LCD->LCD_RAM = RGB_Code;//写十六位 GRAM
}

坐标设置函数

//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{if(lcddev.id==0X9341||lcddev.id==0X5310){LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);//高8位LCD_WR_DATA(Xpos&0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);}else if(lcddev.id==0X6804){if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏时处理LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);}else if(lcddev.id==0X5510){LCD_WR_REG(lcddev.setxcmd);//lcddev.setxcmd在LCD_Display_Dir函数中赋值  0X2A00LCD_WR_DATA(Xpos>>8);LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);}else{if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//横屏其实就是调转 x,y 坐标LCD_WriteReg(lcddev.setxcmd, Xpos);LCD_WriteReg(lcddev.setycmd, Ypos);}
}

画点函数

//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{LCD_SetCursor(x,y); //设置光标位置LCD_WriteRAM_Prepare(); //开始写入 GRAMLCD->LCD_RAM=POINT_COLOR;
}

读点函数

//读取个某点的颜色值
//x,y:坐标
//返回值:此点的颜色
u16 LCD_ReadPoint(u16 x,u16 y)
{vu16 r=0,g=0,b=0;if(x>=lcddev.width||y>=lcddev.height)return 0; //超过了范围,直接返回LCD_SetCursor(x,y);if(lcddev.id==0X9341||lcddev.id==0X6804||lcddev.id==0X5310)LCD_WR_REG(0X2E);//9341/6804/3510 发送读 GRAM 指令else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00);//5510 发送读 GRAM 指令else LCD_WR_REG(R34); //其他 IC 发送读 GRAM 指令if(lcddev.id==0X9320)opt_delay(2); //FOR 9320,延时 2usLCD_RD_DATA(); //dummy Readopt_delay(2);r=LCD_RD_DATA(); //实际坐标颜色if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510){ //9341/NT35310/NT35510 要分 2 次读出opt_delay(2);b=LCD_RD_DATA();g=r&0XFF;//9341/5310/5510 等,第一次读取的是 RG 的值,R 在前,G 在后,各占 8 位g<<=8;}if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0XB505||lcddev.id==0XC505)return r; //这几种 IC 直接返回颜色值else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return (((r>>11)<<11)|((g>>10)<<5)|(b>>11)); //ILI9341/NT35310/NT35510 需要公式转换一下else return LCD_BGR2RGB(r); //其他 IC
}

字符显示函数

//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{u8 temp,t1,t; u16 y0=y;u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字体一个字符对应点阵集所占的字节数//设置窗口num=num-' ';//得到偏移后的值for(t=0;t<csize;t++){if(size==12)temp=asc2_1206[num][t]; //调用 1206 字体else if(size==16)temp=asc2_1608[num][t]; //调用 1608 字体else if(size==24)temp=asc2_2412[num][t]; //调用 2412 字体else return; //没有的字库for(t1=0;t1<8;t1++){if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);temp<<=1;y++;if(y>=lcddev.height)return; //超区域了if((y-y0)==size){y=y0; x++;if(x>=lcddev.width)return; //超区域了break;}}}
}

LCD初始化

  1. GPIO,FSMC 时钟使能
  2. GPIO 初始化设置
  3. 引脚复用映射设置
  4. FSMC 初始化
  5. 使能 FSMC 不同的 LCD
  6. 驱动器不同的初始化设置

特别注意: 本函数使用了 printf 来打印 LCD ID。

小结

在LCD.h头文件中定义了LCD地址结构体和LCD参数结构体。在LCD.c声明LCD参数结构体变量并在LCD_Display_Dir函数初始化。

参考

STM32F4开发指南-库函数版本_V1.2

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

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

相关文章

OCP Java17 SE Developers 复习题11

答案 A, C, D, E. A method that declares an exception isnt required to throw one, making option A correct. Unchecked exceptions can be thrown in any method, making options C and E correct. Option D matches the exception type declared, so its also correct…

漂亮易用且功能强大的最酷的开源在线海报图片设计器:Poster-Design

Poster-Design&#xff1a;最酷的开源在线海报图片设计器&#xff0c;让您轻松创作&#xff0c;尽享设计之美与强大功能的完美结合&#xff01;- 精选真开源&#xff0c;释放新价值。 概览 Poster-Design 是一款高度评价的在线设计工具&#xff0c;专为用户提供便捷而高效的海…

C++:类与对象(一)

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;类与对象&#xff08;一&#xff09;》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 面向对象和面向过程的区别1.类的引入2.…

C++从入门到精通——类对象模型

类对象模型 前言一、如何计算类对象的大小问题 二、类对象的存储方式猜测对象中包含类的各个成员代码只保存一份&#xff0c;在对象中保存存放代码的地址只保存成员变量&#xff0c;成员函数存放在公共的代码段问题总结 三、结构体内存对齐规则四、例题结构体怎么对齐&#xff…

知识图谱基本概念:数据、信息和知识

目录 前言1 数据&#xff1a;信息的基础1.1 数据的定义1.2 数据的重要性1.3 数据的例子1.4 数据的处理1.5 数据分析 2 信息&#xff1a;知识的基础2.1 信息的本质2.2 信息的转化过程2.3 信息的特点2.4 信息的示例 3 知识&#xff1a;智慧的体现3.1 知识的本质3.2 知识的形成过程…

【数据结构】红黑树详解

目录 前言&#xff1a; 红黑树的概念&#xff1a; 红黑树的性质: 红黑树节点的定义&#xff1a; 红黑树的插入&#xff1a; 情况1&#xff1a;cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u存在且为红 情况2&#xff1a;cur为红&#xff0c;p为红&#xff0c…

C++从入门到精通——类的作用域及类的实例化

类的作用域及类的实例化 前言一、类的作用域二、类的实例化引例类是对对象进行描述的示例 一个类可以实例化出多个对象示例 示例 前言 类的作用域是指类中定义的变量和方法的可见性和可访问性范围。在类的内部&#xff0c;所有成员&#xff08;包括属性和方法&#xff09;都具…

GIT版本管理使用示例

一、创建好远程代码仓库后&#xff0c;复制远程仓库的地址 二、新建一个文件夹&#xff0c;在文件夹里打开Git Bash Here 三、输入git clone 远程仓库地址&#xff0c;仓库就初始化完成了 四、新建一个文本文件&#xff0c;假设这是我们开发的代码 五、打开文本&#xff0c;假设…

小秦网站部署上线

叮&#xff5e;您有一份消息&#xff0c;请注意查收&#xff01; 小秦个人网站终于上线了&#xff1a; 网站主要有&#xff1a;免费听歌、看小姐姐、AI女友、留言板等功能&#xff0c;建议收藏、收藏、再收藏、重要事情说三遍&#xff01;&#xff01;&#xff01; 网站&#x…

java实现运行脚本文件

在最近的项目中&#xff0c;有一个需求是前端传给我一个脚本文件&#xff0c;然后我需要运行脚本文件后将结果进行返回&#xff0c;那接下来就让我们看看是怎么做的吧&#xff01; public R runScripts(Integer id) {ScriptsInfo scriptsInfo this.baseMapper.selectById(id);…

工业4g路由器联网后迅速掉线是什么原因?

工业4G路由器连接上网后迅速掉线可能是由多种因素造成的。以下是一些建议的检查和解决步骤&#xff1a; 1、信号问题&#xff1a; 信号强度&#xff1a;检查工业路由器信号强度指示灯&#xff0c;如果信号弱&#xff0c;尝试移动路由器位置或添加外部天线来增强信号。 网络拥…

求m和n的最大公约数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int remainder 1;int m 0;int n 0;int middle 0;//提示用户&#xff1b;printf("请输入整数m和n的值&#xff…

基于 OpenHarmony compress 三方件使用说明

关于 提供了一个轻量级的图像压缩库。将允许您将大照片压缩成小 尺寸的照片&#xff0c;图像质量损失或可以忽略不计 compress 的依赖添加 为你的应用添加 compress-debug.har。将 compress-debug.har 复制到 entry\libs 目录下即可&#xff08;由于 build.gradle 中已经依赖…

TopOn x Google Admob 自动创建广告源功能上线,支持一键添加广告单元 | TopOn产品速递

合作官宣 TopOn 正式成为亚太地区首家支持自动创建Admob bidding广告源的聚合平台。目前&#xff0c;在TopOn后台添加Admob广告平台&#xff0c;您只需要重新授权Google账号&#xff0c;即可开通自动创建功能。此前&#xff0c;TopOn 已在24年2月6日官方聚合支持Google biddin…

飞书文档如何在不同账号间迁移

今天由于个人需要新建了一个飞书账号&#xff0c;遇到个需求就是需要把老帐号里面的文档迁移到新的账号里面。在网上搜了一通&#xff0c;发现关于此的内容似乎不多&#xff0c;只好自己动手解决&#xff0c;记录一下过程以便分享&#xff0c;主要有以下几个步骤。 1. 添加新账…

python打印杨辉三角形

杨辉三角形&#xff0c;这个在国外被叫做帕斯卡三角形&#xff0c;中华文明为何立于世界之颠&#xff0c;这个就是最好的证明&#xff0c;古人的杨辉至少是这个帕斯卡的鼻祖辈&#xff0c;比帕某早了393年发现&#xff0c;那时候可没有知识产权概率&#xff0c;不然就是妥妥的侵…

JavaEE 初阶篇-深入了解线程池(线程池创建、线程池如何处理任务)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 线程池概述 1.1 线程池的优点 1.2 不使用线程池的问题 1.3 线程池的工作原理图 1.4 如何创建线程池&#xff1f; 2.0 通过 ThreadPoolExecutor 类自定义创建线程…

撸代码时,有哪些习惯一定要坚持?

我从2011年开始做单片机开发&#xff0c;一直保持以下撸代码的习惯。 1.做好代码版本管理 有些人&#xff0c;喜欢一个程序干到底&#xff0c;直到实现全部的产品功能&#xff0c;我以前做51单片机的项目就是这样。 如果功能比较多的产品&#xff0c;我不建议这样做&#xff0…

如何搭建APP分发平台分发平台搭建教程

搭建一个APP分发平台可以帮助开发者更好地分发和管理他们的应用程序。下面是一个简要的教程&#xff0c;介绍如何搭建一个APP分发平台。 1.确定需求和功能&#xff1a;首先&#xff0c;确定你的APP分发平台的需求和功能。考虑以下几个方面&#xff1a; 用户注册和登录&#xff…

Anritsu MS9740B与MS9740A 光谱分析仪 的区别?

MS9740B与MS9740A的主要区别在于测量处理时间的缩短和对高速信号处理技术的应用。MS9740B在保持原有功能和性能的同时&#xff0c;将测量处理时间缩短了一半。这一点通过提高生产效率和减少测量及检查时间来实现&#xff0c;从而提高了光有源设备制造商的生产力。此外&#xff…