显示屏 LM3033(ST7920主控)

请添加图片描述

简介

这是常用的单色液晶 LCD 显示屏

  • 型号为 LM3033DFW(深圳拓普微)
  • 5V 单电源供电(3.3V不可以,对比度会降低到看不清)
  • 支持并口(8080时序)和串行通讯(SPI)
  • 带字库

框图为:
请添加图片描述
对外通过 20 Pin 排针提供接口:

请添加图片描述
并行接口原理图:
请添加图片描述
串行接口原理图:
请添加图片描述
对于 CS 引脚,绝大多数情况下都建议用 I/O 口控制。这里之所以直接拉高,是因为数据手册中有明确说明。请添加图片描述

建议在将 CS 引脚设置为 低电平 前,将 SCLK 引脚保持为 低电平 ,将 SID 引脚保持在 最后一个电平状态 。对于只有一个 ST7920 和一个 MPU 的最小系统,只需要 SCLK 和 SID 引脚。 CS 引脚应拉高。

电器参数

直流特性

拓普威厂家提供的整机数据手册:
请添加图片描述
ST7920芯片厂家提供的数据手册:
请添加图片描述
这些参数有什么用?

2021 年 12 月,车间反馈其生产的 某设备,出现大量的花屏现象,故障率高达 20% 以上。

  • 排除程序初始化问题
  • 排除接插件涂三防漆接触不良问题
  • 使用示波器观察 SPI 通讯波形,波形时序正确

LCD 是 5V 供电,但单片机使用 3.3V 供电,所以 LCD 的 SPI 通讯接口实际是使用 3.3V 驱动的。

根据手册可知,若 5V 供电,SPI 通讯接口需要的高电平为 0.7 * VDD = 3.5V,单片机引脚最高输出 3.3V ,已经不符合数据手册要求。而经过测量,发生故障的 LCD 供电电压实际达到了5.36V,即显示屏至少需要 3.75V 才能可靠的识别为高电平。换句话说,单片机发送的高电平,LCD 已经不能识别了,所以导致了花屏现象。

经过批量测试,这一批电源的 5V 输出,实际电压在5.15 V ~ 5.38 V 之间,而大于 5.3 V 后,就容易花屏。

所有花屏的设备,将 LCD 供电电压降到 4.8V 后,都恢复了正常。

5V 输出电压为什么波动这么大?

5V 输出电源是使用 LM2674 芯片设计的,其中确定输出电压的电阻精度使用的是 5%精度,这导致大批量生产时,输出电压偏差较大。

显示屏主控

主控采用了 ST7920。驱动编程需要仔细研读该芯片数据手册,下面结合具体例子看一下数据手册中的重点内容。

重复代码有大作用?

2010 年我接手了一个项目,里面有一段代码比较奇怪:对 LCD 的初始化之后,连续调用了 4 次显示内容函数 WriteTextScreen

	// LCD 初始化initLCDM();SdCmd(0x30);          				// 8bit I/F, basic command, graphic offSdCmd(0x01);          				// clr text screen // 显示内容,注意这里连续调用了四次相同的函数WriteTextScreen(dispLCD);WriteTextScreen(dispLCD);WriteTextScreen(dispLCD);WriteTextScreen(dispLCD);

我觉得这样写不对,就去掉了其中 3 个,结果显示立马异常:会花屏!恢复后,显示正常。

离奇!
请添加图片描述
根据温伯格离奇定律:

如果觉得一件事情离奇,大概率只是你眼界不够

我决定到数据手册中寻找原因。通过阅读数据手册发现,当 LCD 主频为 540KHz 时,清屏命令(0x01)需要 1.6ms 的执行时间
在这里插入图片描述而上面的代码在发出清屏命令 SdCmd(0x01) 后,紧接着就调用了显示函数,中间没有任何延时,这就导致显示函数发送的数据没有得到完全执行,从而引起了花屏现象。

指令的执行需要时间!

在这里插入图片描述

向 ST7920 传输多个指令/数据时,**必须考虑指令执行时间。MPU 必须等待上次指令完成,才能发送下一条指令。**ST7920 内部没有指令缓冲区。(Datasheet - Serial Interface P26)

花屏

某年的11月份,为了降低 LCD 刷屏时间,我将 LCD SPI 接口的速率由 400KHz 提高到了 800KHz。程序通过了自测、中式,然后下发给车间生产。几个月之后,车间负责人打电话说,发现这批次的 LCD 屏幕有小概率会花屏。他们测试了 50 块显示屏,其中有 6 块会花屏。

进一步测试发现,花屏与温度有关,现在是夏天,室温达到了30多摄氏度,出现了花屏。

温度影响了什么地方,导致花屏呢?

根据上面的例子,我们已经知道了一个可能:LCD 显示屏来不及执行指令,可能会花屏。

设计程序验证假设:找到一个会花屏的 LCD,保持 SPI 主频不变的情况下,在指令与指令之间增加延时,发现花屏现象消失,即便放到 60℃ 的高温箱也不会花屏,但只要去掉指令与指令之间的延时,就会花屏。

这验证了我们的假设,即指令来不及执行。

这说明 LCD 屏的主频有了较大的波动。查看数据手册,主频大小由 OSC1 和 OSC2 引脚间的电阻决定,其关系为:
在这里插入图片描述
LM3033 显示屏使用的电阻是 24K 欧姆,根据电阻丝印推测是 5% 精度。

这个电阻会随温度和批次变化,温度升高,电阻阻值变大(金属薄膜电阻),当电阻实际值比 24K 大时,LCD 的主频会降低,执行指令的时间会增加,这样就会造成 LCD 屏来不及执行指令而产生花屏。

令人震惊的耗时

写满屏汉字大约多少时间?

一次非规程序更新之后,客户反馈只要操作菜单界面,设备就会断电!断电是因为设备判断接入的传感器发生了故障,传感器故障会引起分站断电。

实际测试发现,传感器通讯数据正常,是设备误判了。之所以会误判,是因为在菜单中某个函数运行很耗时,导致处理传感器数据时,已经触发了通讯超时条件。之前之所以没有问题,是因为之前要连续发生 3次 超时,才认为是真的发生超时故障,而这个非规程序为了提高故障断电响应速度,将 3 次判断条件改为了 1 次。

测量了菜单中涉及的函数,发现显示一行汉字只需要 0.88ms。

在这里插入图片描述
但是将焦点反白下移一行(上图黑底区域),需要 138ms

请添加图片描述
这时间耗在哪里?是怎么耗掉的?

在这里插入图片描述

启动传输时,需要先发送一个起始字节,用于同步和指示读/写和选择寄存器/数据。后续的每 1 个字节都被分成 2 部分传输:高 4 位和低 4 位。

所以每发送 1 字节命令或数据, 实际需要发送 3 字节

一般的芯片都有块写和块读功能,即设置一个起始地址后,就可以一直写数据或者读数据。而这个芯片则是每 1 个字节都要分成 3 字节传输,没有第二个选项。
在这里插入图片描述

怪异的显示

代码:

uint8_t full_screen_buf[] = {"这是测试第一行  ""这是测试第二行  ""这是测试第三行  ""这是测试第四行  "
};
WriteTxtAny(1, 1, full_screen_buf);             //满屏显示

得到的显示结果却是:
在这里插入图片描述
???
在这里插入图片描述
原因在于主控最多只能显示 16 个汉字 x 2 行,但被按照 8 个汉字 x 4 行来显示

在这里插入图片描述

LCD 显示范围是 16 汉字 x 2 行。

在这里插入图片描述
这种显示方式,给我们编程带来了麻烦,但是硬件容易实现啊,又不是不能用,你们凑合一点吧。

莫名其妙的乱码

代码:

WriteTxtAny(2, 1, "123我会显示乱码");

代码执行结果是:
在这里插入图片描述
???
在这里插入图片描述原因是 CGRAM 字体和 CGROM 字体只能显示在每个地址的起始位置!

在这里插入图片描述

奇怪的地址表示(现有驱动)

代码:

con_disp_16(0x81, 0x90, 2, 1);                  //第2行第2列反白2个汉字区域    
con_disp_16(0x8D, 0x80, 2, 1);                  //第3行第6列反白2个汉字区域

是为了在 LCD 上显示两处反白:
在这里插入图片描述
道理我都明白,可这一堆数字是什么鬼???

我只是想做个显示界面而已!!!
在这里插入图片描述
要想明白 0x810x8F0x8D0x80,需要看手册关于图形 RAM 的设置。

在这里插入图片描述
现有的驱动程序:

与具体硬件耦合在一起,不是模块化代码,移植不方便

代码中有不明意义的数字(魔术数):

LCD_SSP->DR = 0xF8;
LCD_SSP->DR = 0xFA;
write_com(0x01);
write_com(0x06);
write_com(0x0C);
write_com(0x30);
write_com(0x34);
write_com(0x36);

这些垃圾代码是从哪里来的?

答案是:拓扑微官网 提供的范例。

ST7920 模块化代码

编译器需使能 -C99

代码结构:
在这里插入图片描述
其中:

  • lcd_func.h:模块的接口,对外提供的 API 函数
  • lcd_func.c:接口的实现,依赖的函数(以弱引用修复符 __weak 修饰)
  • lcd_func_cfg.h:默认配置和跨编译器相关特性

需要一个用户配置头文件 app_lcd_func_cfg.h ,用于根据自身应用特性来自定义配置和编译器相关特性。

使用方法:

  1. 查看模块代码是否是只读属性,如果不是,将它们设置为只读的。
  2. 将模块化代码加入工程
  3. 编写硬件相关驱动(函数名和参数已预先指定)
  4. 设置用户配置参数
  5. 调用模块 API 函数,完成指定功能

模块只读属性,意味着用户不能修改模块,如果想添加新特性或者修改 BUG ,需向模块维护者提交申请。

驱动包给出了一个在 Keil 平台下的用户配置文件 app_lcd_func_cfg.h,就连相关的硬件驱动,我也给出了公司内部常用 CPU 驱动代码,包括硬件 SPI 和软件 SPI, 可以说是贴心的喂到了嘴边!

在这里插入图片描述
1.意义不明的魔数

修改前:

LCD_SSP->DR = 0xF8;
LCD_SSP->DR = 0xFA;write_com(0x01);
write_com(0x06);
write_com(0x0C);
write_com(0x30);
write_com(0x34);
write_com(0x36);

修改后,用合理命名的宏来代替魔数,用合理命名的函数名来描述行为功能,遵循代码自描述原则:

#define SERIAL_MODE_WRITE_INSTRUCTION_CODE  0xF8 
#define SERIAL_MODE_WRITE_DATA_CODE         0xFA
lcd_send_data(SERIAL_MODE_WRITE_INSTRUCTION_CODE);
lcd_send_data(SERIAL_MODE_WRITE_DATA_CODE);clear_ddram();
set_ac_direction(LCD_AC_INCREASED);
display_control(LCD_DESPLAY_ON, LCD_CURSOR_OFF, LCD_BLINK_OFF);
enable_basic_instruction();
enable_extended_instruction();
graphic_display_on();

2.满屏显示例子

修改前:

WriteTxtAny(1, 1, full_screen_buf);             //满屏显示

修改后:

disp_txt_by_specify_location(LCD_ROW_1, LCD_COLUMN_1, full_screen_buf);

修改后的代码更清晰,显示所见即所得,比如上面那个满屏显示的例子:

uint8_t full_screen_buf[] = {"这是测试第一行  ""这是测试第二行  ""这是测试第三行  ""这是测试第四行  "
};

原来代码第二行和第三行在显示屏上是颠倒的,但是用新的驱动程序,显示和代码是一致的,而且可以实现自动换行的功能。模块内部将原驱动怪异的显示进行了修正,将复杂处理隐藏起来,给出的接口是易用的、不违反常规的。

3.反白例子

修改前:

con_disp_16(0x81, 0x90, 2, 1);                  //第2行第2列反白2个汉字区域    
con_disp_16(0x8D, 0x80, 2, 1);                  //第3行第6列反白2个汉字区域

修改后,统一坐标系,隐藏了不必要的地址信息,提供简洁的 API 接口:

disp_backlight(LCD_ROW_2, LCD_COLUMN_2, 2);     //第2行第2列反白2个汉字区域    
disp_backlight(LCD_ROW_3, LCD_COLUMN_6, 2);     //第3行第6列反白2个汉字区域






读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
千金难买知识,但可以买好多奶粉

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

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

相关文章

git stash 对当前分支修改的内容进行暂存

我们在开发的时候往往会遇到这种情况, 在一个分支开发,写了不少内容,但是突然来了一个紧急的需求需要切换分支,去做这个需求,但是当前的分支又因为没有开发完成,不想形成一条无效的commit记录,这时我们就到暂存上场了 git stash 暂存 // 切分支之前 对当前分支修改的内容进行暂…

制作一个RISC-V的操作系统五-RISC-V汇编语言编程二

文章目录 RISC-V汇编指令操作对象RISC-V汇编指令编码格式小端序的概念RISC-V汇编指令分类RISC-V汇编伪指令 RISC-V汇编指令操作对象 RV32I:RISC-V32位机器整数指令集 指令集分非特权指令集和特权指令集 XLEN:变量代表当前机器的字长(32位 64…

ModbusRTU\TCP消息帧解析(C#实现报文发送与解析)

目录 知识点常用链接一、Modbus1.ModbusRTU消息帧解析2.主站poll、从站slave通讯仿真-modbusRTU1.功能码01读线圈状态2.功能码03读保持寄存器报文解析(寄存器存整型)报文解析(寄存器存float) 3.C#模拟主站Poll(ModbusR…

Go 语言中的反射机制

欢迎大家到我的博客浏览&#xff0c;更好的阅读体验请点击 反射 | YinKais Blog 反射在大多数的应用和服务中并不常见&#xff0c;但是很多框架都依赖 Go 语言的反射机制简化代码。<!--more-->因为 Go 语言的语法元素很少、设计简单&#xff0c;所以它没有特别强的表达能…

Mysql的所有数据类型和它们的区别

一、数值类型 1. 普通整数数值类型 以下数据类型只能用以保存整数 整数数值类型类型存储大小&#xff08;字节&#xff09;有符号的取值范围&#xff08;允许存在负数&#xff09;无符号的取值范围TINYINT1-128 ~ 1270 ~ 255SMALLINT2- 327678 ~ 327670 ~ 65535MEDIUMINT3- 8…

华清远见嵌入式学习——C++——作业6

作业要求&#xff1a; 代码&#xff1a; #include <iostream>using namespace std;class Animal { public:virtual void perform() 0;};class Lion:public Animal { private:string foods;string feature; public:Lion(){}Lion(string foods,string feature):foods(foo…

【Spring Boot】如何在IntelliJ IDEA中由同一份spring boot源码运行多个不同端口的实例

我们需要使用一个服务有多个实例的测试场景&#xff0c;那么我们就需要在IntelliJ IDEA中通过不同的端口运行不同的实例&#xff0c;并且运行时的源代码是一样的&#xff0c;那么我们可以在IntelliJ IDEA这样操作&#xff0c;接下来以UserApplication服务为例&#xff1a; 复制…

使用Java API操作HDFS

文章目录 一、了解HDFS Java API&#xff08;一&#xff09;HDFS Java API概述1、配置&#xff08;Configuration&#xff09;2、文件系统&#xff08;FileSystem&#xff09;3、路径&#xff08;Path&#xff09;4、输入输出流&#xff08;FSDataInputStream 和 FSDataOutputS…

codeforces 题目 Powers Of Two

目录 题目&#xff1a; 题目描述&#xff1a; 思路&#xff1a; AC代码&#xff1a; 题目&#xff1a; 题目描述&#xff1a; 给你两个整数 n 和 k 问是否能找到 k 个2的幂&#xff0c;使其总和为 n 若能&#xff0c;则输出这 k 个 2的幂&#xff1b;若不能&#xff0c;…

预览控制;预见控制;预测控制;预观控制(preview control)

预演控制&#xff08;preview control&#xff09;作为一种新兴的控制方法&#xff0c;首次在轮式车辆中被提出。 参考文献&#xff1a; https://www.sciencedirect.com/science/article/pii/S0016003219300390https://www.sciencedirect.com/science/article/pii/S0016003219…

Ardupilot开源飞控之VTOL之旅:配件试装

Ardupilot开源飞控之VTOL之旅&#xff1a;配件试装 1. 源由2. 分析2.1 【修改使用】FC & PDB & GPS打印件2.2 【直接使用】VTX & CRSF打印件 3. 试装3.1 【结构】问题1&#xff1a;GPS座子尺寸非常紧凑&#xff0c;需要用力压入卡座内。3.2 【结构】问题2&#xff…

实验报告-实验四(时序系统实验)

软件模拟电路图 说明 SW&#xff1a;开关&#xff0c;共六个Q1~Q3&#xff1a;输出Y0~Y3&#xff1a;输出 74LS194 首先&#xff0c;要给S1和S0高电位&#xff0c;将A~D的数据存入寄存器中&#xff08;如果开始没有存入数据&#xff0c;那么就是0000在里面移位&#xff0c;不…

智慧小区园区如何布局网络对讲系统

智慧小区园区如何布局网络对讲系统 随着小区住宅的不断更新发展&#xff0c;小区的管理人员也对小区内部的通讯也有了新的要求&#xff0c;要求在工作区域无盲区、语音通讯清晰&#xff0c;小区的安保后勤都能够随时在小区的地下室和室外工作区域、任何时间进行通信。提高小区…

Python 云服务器应用,Https,定时重启

Python 云服务器应用,Https,定时重启 环境搭建Python模块模块导入生成Flask实例GET处理启动服务器打开网页验证 GET接入证书 支持https申请证书下载证书保留 xxx.crt 和 xxx.key文件就可以了 copy到python项目目录ssl_context 配置 宝塔面板操作在www目录下新建python工作目录在…

CRM立项正当时|走过复杂多变的2023年,明年如何锚定确定性增长?

正值年末&#xff0c;又到复盘今年、规划明年的重要节点。 2023年&#xff0c;黑天鹅和新风口轮番登场&#xff0c;当不确定成常态&#xff0c;环境愈发错综复杂&#xff0c;企业家们如何深谋远虑&#xff0c;带领企业实现可持续、高质量发展&#xff1f;这里提供三个思考视角…

LoadRunner12.55的简介与安装

提示&#xff1a;https://mp.weixin.qq.com/s/iK-fh0VP7v8mNSDNxjkBow 文章目录 LoadRunner的简介与安装loadrunner概述loadrunner的下载与安装 LoadRunner的使用启用VuGen LoadRunner的简介与安装 LoadRunner官网&#xff1a;https://www.microfocus.com/zh-cn/products/load…

智能优化算法应用:基于水基湍流算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于水基湍流算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于水基湍流算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.水基湍流算法4.实验参数设定5.算法结果6.参考…

递增子序列(回溯)

题目描述 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#xff0c;也可以视作递增序列的一种特殊情况。 样例…

Unity使用打成图集的Sprite作为模型贴图使用的问题

大家好&#xff0c;我是阿赵。   有时候用Unity引擎做项目的时候&#xff0c;会遇到这样的需求&#xff0c;美术做了一些模型或者特效&#xff0c;然后策划想在游戏运行的时候&#xff0c;读取一些游戏图标放在特效或者模型上面当做贴图使用。   这个需求实现起来很简单&am…

销售人员如何自我提升?

销售人员如何自我提升&#xff1f; 在美国有这么一句流行语&#xff1a;不当总统就干销售员。其实在国内很多老板&#xff0c;高收入人群等大部分是来自销售岗位。因为销售是离钱最近的职业&#xff0c;在销售职业生涯中能收获到很多&#xff0c;比如人际关系能力&#xff0c;…