
简介一套基于51单片机的12864大液晶屏Proteus仿真设计资源适合单片机初学者、课程设计与毕业设计学生使用。项目以12864点阵液晶屏为显示终端完整覆盖51单片机基础、C语言编程、液晶屏驱动协议、Proteus电路搭建与调试等关键环节。资源共19个文件压缩包约55KB主要包含6个C源码文件、6个头文件、Keil工程文件(Uv2/Hex)以及Proteus工程文件(DSN/DBK/PWI)等可直接在Proteus中加载仿真也可结合Keil进行代码修改与重构。通过该设计可掌握并行/串行接口控制、字符与图形绘制、初始化流程等核心知识体会从需求分析到软硬件联调的完整流程。已有279人学习下载对入门嵌入式显示应用具备不错的参考价值。 做单片机项目做到显示这一环很多人会卡在“用什么屏”上。1602能显示的内容太少OLED要折腾I2C时序而12864大液晶屏几乎是性价比最高、也最容易出效果的选择——4行中文、自带字库、还能画波形做好了整个项目的交互质感立刻就上来了。但一上来就直接买屏焊板子成本不低调试麻烦还容易在硬件问题上消耗掉大半热情。所以我更建议先走一遍基于51单片机的12864 Proteus仿真设计把连线逻辑、驱动时序、常见翻车点全部跑通之后再碰实物会顺手得多。这篇文章把我在仿真里完整的搭建过程、驱动思路和排错经验都写出来适合刚学完C51基础、准备做显示类课程设计或DIY项目的朋友参考。1. 为什么先用Proteus跑12864而不是直接买屏1.1 12864到底强在哪12864这个名字已经剧透了核心参数横向128个点纵向64个点一共是128x64的点阵。对比1602那种字符屏12864的显示密度高了一大截能显示4行汉字每行8个汉字如果显示英文字符一行能塞下16个。更关键的是它内部带ST7920控制器这个控制器直接内置了GB2312简体中文字库你要显示“温”“度”“湿”这些汉字不需要自己做字模代码里直接写字符串就行。而对于课程设计、电子竞赛、个人DIY这类场景一块12864屏幕往往就能把整个系统的状态界面撑起来。做万年历它可以一屏显示年月日、星期、农历做温度采集它可以把实时曲线画出来做菜单交互它甚至可以做到图形化图标。功能上限比1602高很多。1.2 仿真设计解决的核心问题很多人学单片机有一个误区觉得Proteus仿真不如实物高端能跳过就跳过。但实际上Proteus跑12864能帮你把真正的难点提前暴露出来。12864的问题不在于单条指令多复杂而在于并行时序、引脚模式、初始化顺序这些环节任何一个出错屏幕都是黑乎乎的没反应。如果直接上手实物你要同时面对接线错误、电平不匹配、模块损坏风险很难判断问题到底出在哪一步。仿真环境的好处就是状态完全可控。你可以把单片机程序反复烧录可以把某个引脚用电平探针盯着看可以随时暂停运行观察时序波形。等仿真里跑出正确显示效果说明你的驱动逻辑已经没问题了剩下就是照搬到真实电路。所以我一般建议先仿真验证方案可行性再动手做实物。1.3 适用人群和前置基础这篇文章面向的是已经学过C51基础语法、大概知道GPIO怎么控制的人。不需要你会多少复杂算法但至少要会用Keil写一个main函数、能编译生成HEX文件。Proteus这边只要会用元件拾取和连线就行深入操作我在后文会一步步讲。如果你之前只点过LED灯、做过数码管那这篇文章的难度对你来说刚刚好。2. 接线前必须搞懂的引脚功能与并串模式选择2.1 ST7920控制器和两种接口模式市面上几乎所有12864液晶模块核心都是ST7920控制器。这块控制器支持两种访问方式8位并行和串行。并行就是RS、RW、E加DB0到DB7一共11根线一次传输一个字节串行模式下RS变成片选CSRW变成数据线SIDE变成时钟SCLK总共只需要3根控制线。我的建议是仿真里优先用8位并行模式。第一并行模式下代码逻辑最直观写命令和写数据分别控制RS电平你很容易理解屏幕的工作原理第二Proteus里的ST7920模型对并行模式的支持非常稳定新手不容易被时序问题劝退。串行模式我后面会单独讲等并行模式跑通了再去换思路会清晰很多。2.2 引脚功能一张表说清楚12864模块上引脚的名称和功能不同的屏会有细微差别但绝大多数模块引脚定义如下表引脚名称功能说明并行模式接法1VSS电源地GND2VDD电源正极5V3V0液晶对比度调节接10k电位器分压4RS(CS)并行:命令/数据选择串行:片选接P2.05RW(SID)并行:读/写选择串行:数据线接P2.16E(SCLK)并行:使能信号串行:时钟接P2.27~14DB0~DB78位数据总线接P0.0~P0.715PSB并/串模式选择接VCC(并行)16RST复位引脚接VCC17BLA背光源正极串电阻接VCC或PWM18BLK背光源负极GND这张表里最容易忽略的是PSB和V0。PSB必须接高电平芯片才工作在并行模式如果悬空或者接地后续所有并口指令全部无效屏幕死活不亮。V0则负责调节屏幕的对比度在仿真里如果不接电位器或者电位器调在极限位置屏幕会全黑或者完全看不到字。2.3 推荐的并行接线方案与理由控制线我建议接P2口的前三位数据线接P0口。这样安排的好处是驱动代码简单宏定义一看就懂。由于P0口是开漏输出无法主动输出高电平必须在P0口和VCC之间接一个10k排阻做上拉不然高电平状态根本驱动不起来。这个上拉排阻在Proteus仿真里经常被漏掉漏掉的典型症状就是屏幕出现随机乱码。如果你手头没有排阻用8个独立10k电阻分别接P0.0到P0.7也可以。仿真图中排阻元件名搜索RESPACK-8拉出来后注意让公共端COM接VCC电阻端分别接到P0口。注意仿真里PSB引脚如果找不到对应的引脚号可以直接点击引脚连线后接VCC不要悬空。悬空等同于不确定电平是12864不显示的常见原因之一。3. Proteus建图、烧程序、跑起来的三步实操3.1 元件搜索与放置Proteus版本不同元件库名字略有差异但搜索关键词基本通用。新建工程后点击左侧工具栏的“P”进入元件拾取界面依次搜索下面几个元件AT89C51单片机主体用AT89C52也可以驱动逻辑一样。12864液晶屏搜索关键词可以试“12864”“AMPIRE128X64”“LGM12641BS1R”。不同版本Proteus里12864模型名称不太一样AMPIRE128X64是我在Proteus 8系列里用得比较多的一个模型也可以搜“LM12864F”一类名称找到像素点阵是128x64的即可。RESPACK-88位排阻给P0口做上拉。CRYSTAL晶体振荡器默认12MHz。CAP电容两个30pF配合晶振使用。RES电阻10k用于复位电路。POT-HG电位器用来调节12864的V0对比度。在Proteus 8里12864的搜索框也可以直接输入“ST7920”试试有些版本会直接关联到对应液晶模型。3.2 从连线到加载HEX的完整操作元件都放好后按照第2章的接线表逐个连线。这里有个经验虽然Proteus支持总线工具但第一次做12864仿真时建议直接用普通导线一根根连尤其是DB0到DB7这8根数据线一根根连过去能强迫你检查每根线的顺序。如果用总线一旦中间标号标错排查起来非常痛苦。复位电路采用经典方案晶振两个引脚分别接30pF电容到地1脚和2脚之间跨接晶振本体即可。单片机RST引脚接一个10uF电解电容到VCC再接一个10k电阻到GND这是最常用的上电复位电路。双击AT89C51芯片在弹出的属性对话框中把Program File一栏选择你Keil生成的HEX文件路径同时把Clock Frequency设置为12MHz和晶振保持一致。然后点界面左下角的运行按钮就可以观察屏幕状态了。3.3 Keil配置生成HEX的那一步别漏Keil工程如果编译完没有生成HEX文件是因为默认只生成AXF需要手动开启。在Options for Target对话框里选择Output选项卡勾选Create HEX File然后重新编译工程目录下才会出现HEX文件。这一步是Proteus能烧录程序的前提漏掉的话Proteus里等于跑了一个空单片机屏幕上当然什么都没有。如果你用的编译环境是Keil C51记得在Device里选择Atmel AT89C51或AT89C52。Target选项卡里可以保持默认的12MHz晶振参数但更重要的是延时函数的时间基准要和实际晶振一致。Proteus仿真的时钟是理想时钟和代码里延时函数的匹配度直接影响显示时序晚点会讲到。4. 驱动代码逐段拆解从初始化到中文显示4.1 初始化顺序为什么是这样ST7920上电以后需要一串初始化指令这串指令的顺序是硬性的不能乱。核心包括0x30切换到8位并行基本指令集。前三次延时发送是为了让控制器内部状态机稳定手写驱动时不要省略中间两个delay_ms。0x0C开显示同时关闭光标。如果想显示光标可以用0x0E但一般界面场景不需要。0x01清屏同时把DDRAM地址指针归零必须给几毫秒延时等清屏动作完成。0x06设置写入数据后地址指针自动加1、光标右移。这样连续写入字符串时就不用每写一个字符就重设一次地址。很多网上找的代码在仿真里不显示问题就出在初始化时只发了一遍0x30就急着后续操作。ST7920内部从复位状态切换到基本指令集需要时间稳妥的做法是上电延时40毫秒以上再重复发送三次0x30中间各留5毫秒间隔。4.2 写命令和写数据函数并行模式的核心就是两个函数写命令和写数据。写命令时RS置0写数据时RS置1RW在整个写操作里保持0。E引脚是使能信号锁存时刻在E的下降沿也就是E从高电平跳变到低电平的那一瞬间。#include reg52.h #define uchar unsigned char #define uint unsigned int sbit RS P2^0; sbit RW P2^1; sbit E P2^2; #define DATA P0 void delay_us(uint t) { while(t--); } void delay_ms(uint t) { uint i, j; for(i 0; i t; i) for(j 0; j 120; j); } void LCD_WriteCmd(uchar cmd) { RS 0; RW 0; DATA cmd; E 1; delay_us(50); E 0; delay_us(50); } void LCD_WriteData(uchar dat) { RS 1; RW 0; DATA dat; E 1; delay_us(50); E 0; delay_us(50); }这里有个细节先给数据、再拉高E等数据稳定后拉低E完成锁存。顺序反过来就容易出现把上一条总线残留数据写进屏幕的情况表现就是显示内容错位。初始化函数和清屏函数如下void LCD_Init(void) { delay_ms(40); LCD_WriteCmd(0x30); delay_ms(5); LCD_WriteCmd(0x30); delay_ms(5); LCD_WriteCmd(0x30); delay_ms(5); LCD_WriteCmd(0x0C); LCD_WriteCmd(0x01); delay_ms(2); LCD_WriteCmd(0x06); }4.3 显示英文、数字与中文的底层逻辑初始化完成后写入命令0x80加行内偏移量就可以定位第一行的起始地址。后面每次写一个字节地址指针自动加1所以连续写一串字符就能显示出来。12864的DDRAM行地址映射和1602不一样这是一个特别容易踩坑的点物理行行起始命令第1行0x80第2行0x90第3行0x88第4行0x98第三行和第四行的地址并不是很多人以为的0xA0、0xB0而是0x88和0x98。这个地址跳跃是因为ST7920把横向64个字每个字对应两个DDRAM地址单元做了一个折行映射。如果按连续的0x80、0x90、0xA0、0xB0去写第三行和第四行的字会跑乱。12864每个汉字占两个字节长度因为内部字库用GB2312编码匹配。英文和数字是单字节所以一行16个英文字符宽度等同于8个汉字宽度。4.4 直接用的一段Demo代码下面的代码实现两行字符串显示中英文混合也没问题void LCD_ShowString(uchar row, uchar col, uchar *str) { uchar addr; uchar i 0; switch(row) { case 0: addr 0x80 col; break; case 1: addr 0x90 col; break; case 2: addr 0x88 col; break; case 3: addr 0x98 col; break; default: addr 0x80 col; } LCD_WriteCmd(addr); while(str[i] ! \0) { LCD_WriteData(str[i]); i; if(i 16) break; } } void main() { LCD_Init(); LCD_ShowString(0, 0, 12864 LCD TEST); LCD_ShowString(2, 1, HELLO 12864); while(1); }编译烧进Proteus屏幕应该能显示两行内容。注意到第0行和第2行都用到了第三、四行地址也能正常显示因为代码里用的是映射后的0x88和0x98。提示在Keil里写中文字符串时默认编码是GB2312能正常显示。但如果你用VS Code或者某些现代编辑器写代码再拿到Keil里编译源码编码可能变成UTF-8中文字符串在12864上就会显示成乱码。遇到这个情况把源文件重新另存为ANSI或GB2312编码再编译即可。5. 仿真中几个高概率翻车点与完整排查链路5.1 全黑屏或无显示的排查过程第一次上电屏幕全黑或者完全没反应是最常见的现象。遇到这种情况不要急着改代码按下面的链路一步一步走基本5分钟内能定位到问题。第一步先检查HEX文件到底加载进去没有。双击AT89C51看Program File属性框里有没有文件路径。我见过不少学员在Proteus里放了个单片机但根本没烧录程序相当于让一个空芯片在跑屏幕当然没反应。第二步检查PSB引脚是不是接了高电平。仿真和实物一样PSB悬空或者接地都会让芯片进入串行模式并口指令全是废操作屏幕自然没有任何显示也不会出现黑块。第三步检查V0对比度电压。V0直接接VCC或者直接接地都会让屏幕黑死或者完全看不见字。正确做法是用POT-HG电位器中间抽头接V0两端分别接VCC和GND。仿真运行时双击电位器调整比例让V0落在1V到3V之间再观察屏幕。第四步如果屏幕上能看到整齐的黑色方块阵列但自己的内容不显示说明对比度没问题问题在初始化或时序。把延时调大例如所有delay_us(50)改成delay_us(500)看是否有改善。Proteus的ST7920模型在E脉冲过窄时偶尔会锁存不上数据加大延时是最直接的测试手段。5.2 乱码、花屏的排查过程第二类高发问题是屏幕亮了但显示的内容是乱码或者花屏。这个现象的根源往往是总线数据不干净。先检查数据线顺序。DB0到DB7必须一一对应接P0.0到P0.7如果中间交叉了一根比如DB0接到P0.1而DB1接到P0.0显示必然乱码。这种错误用肉眼核对一次就能发现但在总线下容易隐藏所以前面我强调第一次连线尽量用单根导线。再检查P0口的上拉排阻。P0是开漏输出没有上拉的话高电平会偏弱Proteus里会表现为数据不稳定某一位读到了错误的0或1。排阻公共端接VCC另一端分别接P0口接反了也会导致全部高电平失效。还要注意显示位置。如果写入的字符串超过了16个英文字符宽度地址会溢出到屏幕之外视觉上表现为内容断掉或花屏。显示字符串前想清楚这一行能容纳几多个字符不要让i超过15。5.3 排查速查表现象可能原因检查方法全黑无显示HEX未加载/PSB悬空/V0电压不对双击单片机查加载路径PSB接VCC电位器调V0有黑块但无内容初始化指令不完整/时序太快补重复0x30初始化加大E引脚延时英文字符错位行地址映射错误确认第3、4行用0x88/0x98乱码花屏DB0~DB7交叉/上拉缺失/编码错误单线核对接线补排阻源文件存为ANSI汉字显示乱码Keil源文件编码不是GB2312将源文件另存为ANSI/GB2312仿真能显示实物不行实物对比度负压/背光限流问题实物V0接负压调节串电阻限背光注意Proteus里12864模型对于E脉冲宽度要求比真实芯片更严格一些网上有些老代码在实物上能用、在Proteus里反而黑屏多半是初始化延时不够。解决办法就是照着4.2节的延时重写一遍基本都能解决。6. 让12864更有用绘图模式、串行模式与实物移植6.1 绘图模式让屏幕变成示波器ST7920除了文本模式还内置了一个绘图模式。进入绘图模式要发扩展指令集命令0x34然后操作GDRAM。GDRAM横向64字节、纵向64位实际上被分成上下两个64x64区域所以绘制点时计算坐标会绕一些。绘图模式最典型的应用是波形显示。做温度采集或电压采集时可以把采样值换算成Y坐标每隔一段时间画一个点再配合延时就能在屏幕上看到实时曲线滚动。很多“单片机波形显示”课程设计就是这么做的。不过绘图模式对地址计算的要求高建议先在文本模式跑通后再单独调试绘图部分。至少要让“画点函数”能正确显示一个像素点再去做曲线。绘图模式下汉字显示和画点不能同时混用退出绘图模式要再发0x30切回基本指令集这一点很多人会忘记。6.2 串行模式的省IO思路如果你的项目还有矩阵键盘、传感器、电机驱动等外设并行模式占用的11个IO口确实有点多。这时可以把屏幕切换到串行模式只需要3根IO线。接线方法是PSB接GNDRS接CS、RW接SID、E接SCLK数据从高位到低位逐位输出。串行模式的时序本质是模拟三线SPI每次先发5个同步位“11111”再发两位RS标志位写命令是00写数据是10最后发8位数据。代码实现时要自己写移位循环时序必须严格按照数据手册来不能直接复用并行模式的代码。在Proteus里串行模式的模型也同样支持可以用来验证。但我认为调试串行模式之前先确认并行模式已经完全理解并且能独立写出来不然两个模式的问题叠在一起会越调越乱。6.3 从仿真走向实物的经验最后说说从仿真到实物移植时的几个经验。仿真跑通之后做实物时我遇到过三个和仿真不太一样的坑第一V0电压。仿真里V0用电位器从VCC分压到地直接可调但很多实物12864模块的V0需要接一个负压才能正常调节对比度直接用滑动变阻器接法会发现屏幕对比度调到最大还是发暗。第二背光限流。实物模块的BLA引脚需要串联一个几十欧的限流电阻再接到5V直接接5V虽然也能亮但模块发热明显长期运行有风险。PWM调背光时注意背光电流不是逻辑电平需要三极管或者MOS管驱动不能直接接单片机IO。第三电平匹配。如果你用的是3.3V系统单片机而12864是5V模块逻辑高电平可能达不到芯片要求需要在RS、RW、E、DB0到DB7上做电平转换或者直接用带电平转换的模块。仿真里不存在这个问题但实物设计必须考虑。我个人在实际操作中的体会是12864这块屏最值得花时间的地方不是把某个字符串显示出来而是把并行的读写时序彻底搞明白。一旦你对“RS决定命令还是数据、E下降沿锁存”这个机制形成肌肉记忆后面再看其他带并行接口的屏幕比如TFT彩屏、LCD2004上手速度会快很多。如果只是把代码抄进去看到屏幕亮了就结束那仿真和实物的差距迟早会再回来找你一次。本文还有配套的精品资源点击获取