【正点原子探索者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 ID
	u8  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函数中赋值  0X2A00
	LCD_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(); //开始写入 GRAM
	LCD->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,延时 2us
	
	LCD_RD_DATA(); //dummy Read
	opt_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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

传输层 --- TCP (上篇)

目录 1. TCP 1.1. TCP协议段格式 1.2. TCP的两个问题 1.3. 如何理解可靠性 1.4. 理解确认应答机制 2. TCP 报头中字段的分析 2.1. 序号和确认序号 2.1.1. 序号和确认序号的初步认识 2.1.2. 如何正确理解序号和确认序号 2.2. TCP是如何做到全双工的 2.3. 16位窗口大小…

Redis Desktop Manager可视化工具

可视化工具 Redis https://www.alipan.com/s/uHSbg14XmsL 提取码: 38cl 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。 官网下载&#xff08;不推荐&#xff09;&#xff1a;http…

【智能优化算法】IHAOAVOA(一种改进的混合天鹰优化算法(AO)和非洲秃鹫优化算法(AVOA))

发表在Mathematical Biosciences and Engineering的文章&#xff1a;IHAOAVOA: An improved hybrid aquila optimizer and African vultures optimization algorithm for global optimization problems.https://www.x-mol.com/paperRedirect/1572654041256222720 01.引言 天鹰…

Linux 安装系统可视化监控工具 Netdata

目录 About 监控工具 NetdataLinux 系统安装 Netdata关于 openEuler1、查看内核信息2、查看主机信息3、查看 dnf 包管理器的版本 Netdata 安装1、更新系统环境相关 rpm 包2、查看 netdata 包信息3、安装 netdata 包4、编辑 netdata.conf 配置5、启动 netdata 服务6、查看 netda…

页面静态化:Freemarker入门案例和常用指令教程

页面静态化其实就是将原来的动态网页(例如通过ajax请求动态获取数据库中的数据并展示的网页)改为通过静态化技术生成的静态网页&#xff0c;这样用户在访问网页时&#xff0c;服务器直接给用户响应静态html页面&#xff0c;没有了动态查询数据库的过程。 那么这些静态HTML页面…

TestNG Include and exclude

在这篇文章中&#xff0c;我们将详细讨论TestNG的包含和排除标签。下面是我们将在这篇文章中看到的要点- 包含和排除包第二&#xff0c;包括和排除测试方法最后&#xff0c;包括和排除组 我们只能将exclude标记与packages、methods和run标记&#xff08;groups的子标记&#…

公园景区小红书抖音打造线上流量运营策划方案

【干货资料持续更新&#xff0c;以防走丢】 公园景区小红书抖音打造线上流量运营策划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 共70页可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 公园的线上运营方案&#xff1a; 一、运营目标 1. 品…

微电网优化:基于小龙虾优化算法COA的微电网优化(提供MATLAB代码)

一、微电网优化模型 微电网是一个相对独立的本地化电力单元&#xff0c;用户现场的分布式发电可以支持用电需求。为此&#xff0c;您的微电网将接入、监控、预测和控制您本地的分布式能源系统&#xff0c;同时强化供电系统的弹性&#xff0c;保障您的用电更经济。您可以在连接…

TCP三次握手过程及抓包分析

TCP三次握手过程 一、TCP分段格式二、TCP三次握手三、Wireshark抓包分析 一、TCP分段格式 二、TCP三次握手 三、Wireshark抓包分析

cmake中报错undefined reference to `pthread_create‘的解决方法

出现报错&#xff1a; 解决方法 一般网上会建议在终端指令g/gcc后面增加参数-pthread,但是我们没有用到g/gcc指令. cmake的解决方法是在CMakeLists.txt文件里面增加一行. add_executable(server2 main.cpp) target_link_libraries(server2 pthread)问题就解决了

[VulnHub靶机渗透] pWnOS 2.0

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

lora pingpang系统 4

1 深入了解LoRa技术原理 1.1 LoRa扩频通信原理 1.1.1 模拟无线通信&#xff1a; 模拟无线通信是一种使用模拟信号传输数据的通信方式。这种通信方式已经被数字无线通信所取代&#xff0c;因为数字通信具有更高的效率和可靠性。 天线&#xff1a;从空中接收到的无线电波转换成…

用友NC Cloud importhttpscer 任意文件上传漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,基于云原生架构,深度应用新一代数字技术,打造开放、 互联、融合、智能的一体化云平台,支持公有云、混合云、专属云…

ViewModel 使用及原理解析

public final MutableLiveData mUserLiveData new MutableLiveData<>(); public UserModel() { //模拟从网络加载用户信息 mUserLiveData.postValue(new User(1, “name1”)); } //模拟 进行一些数据骚操作 public void doSomething() { User user mUserLiveDat…

【RMSNorm】Root Mean Square Layer Normalization

【RMSNorm】Root Mean Square Layer Normalization 论文信息 阅读评价 Abstract Introduction Related Work Background RMSNorm Experiments 论文信息 名称内容论文标题Root Mean Square Layer Normalization论文地址https://arxiv.org/abs/1910.07467发表时间2019-…

linux练习-交互式传参

在shell脚本中&#xff0c;read 向用户显示一行文本并接受用户输入 #!/bin/bash read -p 依次输入你的姓名、年龄、家乡 name age home echo 我是$name,年龄$age,我来自$home

12种常见的软件架构风格

什么是软件架构&#xff1f; 软件架构是定义软件系统的高级结构和组织的过程。它涉及识别和选择正确的组件&#xff0c;决定它们之间如何交互&#xff0c;以及确定它们应该如何组织以实现特定的目标。软件架构的目标是创建一个可维护、可扩展和安全的系统&#xff0c;能够满足…

小红书自动化仿写发文机器人了解一下

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通…

权限认证SpringCloud GateWay、SpringSecurity、OAuth2.0、JWT一网打尽!

权限认证SpringCloud GateWay、SpringSecurity、OAuth2.0、JWT一网打尽 一、SpringCloud GateWay 1.它是如何工作的&#xff1f; ​ 客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配&#xff0c;它将被发送到Gateway Web处理程序。…

蓝桥杯第十四届--异或和之和

题目描述 给定一个数组 Ai&#xff0c;分别求其每个子段的异或和&#xff0c;并求出它们的和。或者说&#xff0c;对于每组满足 1 ≤ L ≤ R ≤ n 的 L, R &#xff0c;求出数组中第 L 至第 R 个元素的异或和。然后输出每组 L, R 得到的结果加起来的值。 输入格式 输入的第一…