说实话,现在还在折腾 RA8835 这颗控制器的人,我打赌多半是被老设备或者工控屏给“教育”过的。这颗芯片在很多国产 320240 液晶屏方案里几乎是标配级的角色,和经典的 SED1335 基本兼容,但又不完全一样。今天这篇就把深圳驰宇微做的 3.8 寸、5.1 寸、5.7 寸三款 320240 屏放一起聊——怎样接线、怎样初始化、怎样清屏画点、出了白屏花屏怎么排查,一次性给它捋清楚。
如果你手头正好有一批这类屏,或者正在做老设备替换、新项目选型,这篇文章就是给你准备的。里面有些参数和代码可以直接抄,但更重要的是我会把每一步“为什么要这样做”讲明白,毕竟搞 RA8835 这种老掉牙又没死透的控制器,最怕的不是写不出来,而是照着网上的零散资料抄了个初始化序列,结果屏幕还是一脸冷漠。
1. 这套方案是什么:RA8835 与 320240 屏幕的关系
1.1 为什么 2025 年还要用 RA8835
先把这个最扎心的问题说清楚。RA8835 不是什么新技术,它是一颗上世纪九十年代风格的单色/伪彩 LCD 控制器,最大管理分辨率一般就是 320x240,内部负责显存寻址、扫描时序、图层合成和光标生成。为什么现在还有大量深圳液晶屏厂拿它出货?一个核心原因是:工业设备生命周期太长了。
很多数控系统、医疗监护仪、电力和通讯设备上的 320240 液晶屏,十多年前就是用 SED1335 或 RA8835 做的方案。设备没坏,但屏幕背光老化、偏光片发黄,需要替换。这时候如果新屏换了一颗完全不同的控制器,那整个主控板程序、时序、接口全部要重写,成本没人愿意承担。所以屏幕厂干脆继续出“接口兼容、控制器老配方”的屏,让客户换屏不动主板。驰宇微这套 3.8 寸、5.1 寸、5.7 寸就是典型的兼容替换和初次选型并行的产品线。
另外一点是 RA8835 本身确实“穷且好用”。它只需要一组 8 位并口,不像 RGB 接口那样需要持续刷新,也不像 SPI 串口屏那样刷新率捉急。对于显示数字、汉字、曲线这种静态或慢动态界面,它用一个很廉价的 MCU 就能跑得很稳。这在成本敏感、环境恶劣的工控场合反而是巨大优势。
1.2 3.8寸、5.1寸、5.7寸到底差在哪
三款屏幕的分辨率都是 320x240,控制器逻辑上完全一样,区别主要出在玻璃尺寸、点距、背光功耗、偏压和视角表现上。我从实际做样机和替代表更换的角度,把几个关键差异列成一张表:
| 项目 | 3.8寸 | 5.1寸 | 5.7寸 |
|---|---|---|---|
| 分辨率 | 320x240 | 320x240 | 320x240 |
| 画面比例 | 4:3 | 4:3 | 4:3 |
| 典型点距 | 约 0.24mm | 约 0.30mm | 约 0.36mm |
| 视觉密度 | 高,适合近距离小面板 | 中等,手持/便携设备多 | 低,远视距工控屏经典 |
| 背光电流 | 小,约 30-60mA | 中等,约 60-120mA | 较大,约 120-250mA |
| 常用偏压 | 较低,VLCD 12-15V | 中等,VLCD 14-18V | 较高,VLCD 16-22V |
| 典型场景 | 仪表、便携设备 | 医疗手持、工业手持终端 | 机床面板、电力监控 |
这里一个特别容易踩的坑是:尺寸越大,背光供电越不能偷懒。3.8 寸那种小屏你用 MCU 引脚加个三极管就能推,5.7 寸的背光电流往往上百毫安,如果直接从逻辑电源 5V 上拉,不仅背光亮度不稳定,还会导致整块屏初始化时电压跌落,出现“上电白屏、一写命令又闪烁”的诡异现象。我的建议是 5.1 寸以上就老实上恒流或限流驱动,至少也要用独立 LDO 单独供背光。
2. 硬件层设计与选型
2.1 RA8835 总线接口与最小系统
RA8835 这颗控制器的对外接口非常经典,基本就是一组 8 位并口加几条控制线。以最常见的 8080 时序为例,你需要接的引脚包括:
- D0-D7:8 位数据总线,双向
- A0:寄存器选择,1 为数据寄存器,0 为指令寄存器
- /RD:读信号,低有效
- /WR:写信号,低有效
- /CS:片选,低有效
- RESET:复位,低有效
- 晶振或外部时钟输入,常见 8MHz 或 10MHz
有些屏把 A0 标成 RS 或者 D/C,其实是一个意思。6800 时序和 8080 的区别在于控制线组合,8080 用独立的 /RD 和 /WR,6800 用 E 和 R/W。绝大多数 51 和 STM32 工程都走 8080 时序,所以你在接屏之前第一步就是确认模块上的 IO 是哪种电平、默认接的是哪种时序。很多屏模块上有硬件跳线或者配置电阻,如果接到了错误的模式,你怎么写命令它都不理你。
从最小系统角度看,RA8835 需要一个显示缓冲区。320x240 单色屏一屏数据量为 320x240/8 = 9600 字节,控制器管理的显存地址空间比这个大得多,但单色应用中最少要保证 9600 字节以上的 SRAM 可用。控制器会持续扫描这块显存并映射到液晶驱动电极上,所以 MCU 的职责不是逐像素刷屏,而是往显存里填数据,这个架构在做界面时非常舒服。
2.2 三款屏幕的电源、背光与偏压差异
电源设计是整个方案的灵魂,比代码更容易让人翻车。RA8835 控制器本身需要稳定的逻辑电压,常见 5V 系统直接供电即可,3.3V 系统则要看屏模块是否支持 3.3V 逻辑。驰宇微这三款屏如果按典型模块设计,一般是可以接受 3.3V 或 5V 的,但你不能想当然,一定要看规格书或问客服要原理图。
液晶玻璃本身需要偏压。单色 STN 液晶的驱动是靠交流波形和偏压来实现的,RA8835 会输出一组 LCD 驱动电源控制信号,模块上通常有电荷泵或者负压产生电路,负责生成 VLCD。这个电压直接决定对比度和显示均匀度。3.8 寸和 5.7 寸因为玻璃厚度、液晶材料参数不同,最佳 VLCD 不一样。模块上一般会有一颗对比度电位器,你调它本质就是在调 VLCD。如果模块没有电位器,那就要在控制器外围的电阻分压网络上做文章。
我实际测试时的经验是:3.8 寸屏调到淡淡有字和清晰无残影之间的临界点,5.7 寸则往往需要比小屏高 3-5V 的偏压。如果屏幕刚上电时字很淡,温度升高后变深甚至发黑,那基本就是偏压偏高或波形参数不匹配,这是 STN 屏的固有特性,不是屏坏了。
3. 寄存器与初始化逻辑拆解
3.1 命令/数据通道与时序
RA8835 的指令机制不复杂:先把 A0 拉低,写一个命令字节;然后把 A0 拉高,连续写这个命令需要的参数。不同的命令要求的参数个数不一样,控制器内部有地址自增机制,所以初始化的时候经常一次性连写很多个参数。写完后可以通过读状态或者延时来确保控制器处理完成。
很多朋友第一次调 RA8835 时犯的错是:把命令和数据混在一个函数里,写命令后不切换 A0 直接写参数。结果控制器把参数当成新命令执行,屏幕自然就是乱的。正确的通用写法是:
void lcd_write_cmd(uint8_t cmd) { LCD_A0_LOW(); LCD_CS_LOW(); LCD_WR_LOW(); LCD_DATA_OUT(cmd); LCD_WR_HIGH(); LCD_CS_HIGH(); } void lcd_write_data(uint8_t data) { LCD_A0_HIGH(); LCD_CS_LOW(); LCD_WR_LOW(); LCD_DATA_OUT(data); LCD_WR_HIGH(); LCD_CS_HIGH(); }关于时序,RA8835 并不算苛刻,GPIO 模拟时也能跑,但不能毫秒级墨迹。一个实际的判断标准是:如果你用 STM32 之类几十 MHz 的 MCU 直接模拟并口,写数据时在 WR 低电平期间保持数据稳定即可,一般加个几十纳秒延时或者什么都不加也能稳住。但用 51 单片机跑 12MHz 晶振、又开了很重的延时函数时,初始化慢不是问题,刷屏时就能明显感觉到拖影,所以刷屏代码里尽量少做无谓延时,让传输连续起来。
3.2 SYSTEM SET、SCROLL、OVLAY、显示开关参数到底在设置什么
RA8835 的命令很多,但驱动 320240 单色屏真正必须吃透的就几条。
SYSTEM SET 是系统的总配置,它的参数包括显示方向、字体宽度、字体高度、每行字符数、每行总字节数、扫描行数等。很多人看到这一串数字就头大,其实核心逻辑是:控制器要知道你的屏幕是 320 个点一行,而它每一行按字节输出,320/8=40 字节,所以每行有效字节数往往是 40。为了兼容扫描时序,每行总字节数会留点余量,比如 40 或 42。这里的数字如果设错,会出现“屏幕左右错位”或者“内容斜着分裂”的经典花屏。
SCROLL 命令用来设置显存分区和各分区显示的行数。在单色图形模式下,我们可以把整个显存看作一个连续区域,从地址 0 开始分配给第一层,让它显示 240 行。这样后续往显存里写数据时,控制器就会按顺序把每个字节映射到屏幕对应位置。如果 SCROLL 参数错误,最常见的现象是“画面的一半是黑的”或者“显示内容重复堆叠”。
OVLAY 是图层叠加方式设置。RA8835 支持多个显示图层,可以把它们按 OR、AND、EXOR 等方式叠加。单色应用下一般用第一层,OVLAY 参数设置成符合你图形内容的方式即可。最后是 DISP ON/OFF,它控制整个显示是否开启、是否闪烁。需要注意,初始化最后不开这个命令,前面全白干,屏幕会一直空白。
3.3 一套可复用的 320240 初始化序列
下面给出一套我实际调通过、并且驰宇微三款屏上都能跑出稳定图像的初始化序列。需要强调一下:不同批次、不同尺寸的玻璃,偏压和时序参数可能有差异,所以你拿到屏后还是要对着规格书微调。这里的数值是从常见 320240 单色 STN 屏例程中沉淀下来的基准模板:
void ra8835_init(void) { // 复位 LCD_RES_LOW(); delay_ms(50); LCD_RES_HIGH(); delay_ms(50); // SYSTEM SET lcd_write_cmd(0x40); lcd_write_data(0x30); // 8位接口,内部时钟配置 lcd_write_data(0x07); // 字体宽 - 1 lcd_write_data(0x07); // 字体高 - 1 lcd_write_data(0x27); // 每行有效字符数 - 1 = 39,即40字节 lcd_write_data(0x2A); // 每行总字节数 = 42,兼容扫描时序 lcd_write_data(0x2A); // 帧扫描行数相关,需按240行调整 lcd_write_data(0x00); // 扫描参数低位 // SCROLL lcd_write_cmd(0x44); lcd_write_data(0x00); // 第一显示区首地址低字节 lcd_write_data(0x00); // 第一显示区首地址高字节 lcd_write_data(0xF0); // 第一显示区行数 lcd_write_data(0x00); lcd_write_data(0xF0); lcd_write_data(0x00); lcd_write_data(0xF0); lcd_write_data(0x00); lcd_write_data(0xF0); lcd_write_data(0x00); // HDOT SCR,平滑滚动设置 lcd_write_cmd(0x5A); lcd_write_data(0x00); // OVLAY 图层叠加 lcd_write_cmd(0x5B); lcd_write_data(0x1C); // 显示开启 lcd_write_cmd(0x59); lcd_write_data(0x54); }这段代码不是万能药,但它能给你一个非常合理的起点。真到调屏环节,你主要盯着的就是 SYSTEM SET 的“每行总字节数”和 SCROLL 的“显示区行数”,因为这两个参数跟屏幕物理扫描关系最密切,也最容易因为照抄别的尺寸例程而出错。
4. 实际驱动:清屏、画点、显示图片
4.1 显存映射:320x240 单色一屏 9600 字节
在动手刷图之前,先把 RA8835 的显存模型搞清楚。320x240 单色屏,每个像素 1 bit,一行 320 个点就是 320/8 = 40 字节,240 行总计 40*240 = 9600 字节。RA8835 在图形模式下会把显存字节按位展开到屏幕,通常一个字节的最高位对应最左边的像素,最低位对应最右边的像素,前提是你没有设置左右反转或者逆显示。
熟悉这个模型之后,很多问题就变得好理解了。比如你想往屏幕左上角第一个像素写一个黑点,实际要操作的是显存地址 0 的 bit7。想让整屏显示黑色,就要往 0 到 9599 这 9600 个地址全部写入 0xFF。清屏则是全部写 0x00。因为控制器支持地址自增,你可以用连续写数据的方式很快刷完一整屏,而不需要每写一个字节都发一次地址命令。
这个映射关系也是后面用取模软件时的依据。你从取模软件里导出的数组顺序,必须和 RA8835 显存扫描顺序一致,否则图像会镜像、颠倒或者出现奇怪的斜条纹。
4.2 画点/清除/刷图的实现
实际工程里最常用的三个函数就是清屏、画点和整屏刷图。清屏最简单,先把显示地址设置到显存起始位置,然后连续写 9600 个 0x00。这里要注意,如果你用的命令是设置光标地址,写完一屏后控制器地址已经停在末尾,下一次刷图前必须重新把地址指回起点。
画点这个操作看似简单,实际上有一个经典隐患:单色屏一个字节包含 8 个像素,你如果直接修改这个字节,损坏的是同一字节里没被选中的其他 7 个点。所以推荐的做法是“软件缓冲区”。在 MCU 内存里维护一个 9600 字节的数组,所有画点操作都针对数组进行,需要显示时再把整块数组一次性写给 RA8835。这样画点、画线、显示汉字都变成纯内存操作,逻辑清晰且不用依赖控制器的显存读回功能。
下面是一套很典型的点阵写入思路:
#define LCD_WIDTH 320 #define LCD_HEIGHT 240 #define LCD_BUF_SIZE (LCD_WIDTH * LCD_HEIGHT / 8) uint8_t lcd_buffer[LCD_BUF_SIZE]; void lcd_set_pixel(uint16_t x, uint16_t y, uint8_t color) { if (x >= LCD_WIDTH || y >= LCD_HEIGHT) return; uint16_t index = y * (LCD_WIDTH / 8) + (x / 8); uint8_t bit = 0x80 >> (x % 8); if (color) { lcd_buffer[index] |= bit; } else { lcd_buffer[index] &= ~bit; } } void lcd_flush(void) { // 设置显存起始地址 lcd_write_cmd(0x46); // 设置光标地址 lcd_write_data(0x00); lcd_write_data(0x00); lcd_write_data(0x00); // 连续写入整块缓冲区 for (uint16_t i = 0; i < LCD_BUF_SIZE; i++) { lcd_write_data(lcd_buffer[i]); } }如果你不想额外维护这个缓冲区,也可以直接利用 RA8835 的显存读回功能:先设置读地址,再从数据口读回一个字节,改其中一位后再写回去。缺点是每次画点都要经历“读-改-写”三步,碰上刷曲线、动态刷新会很别扭。我的经验是最小系统内存够就优先用软件缓冲区,整个驱动会清爽很多。
4.3 关于“读回显存”的取舍与软件缓冲
为什么我反复强调软件缓冲区?因为 RA8835 这类控制器虽然支持读显存,但实际模块上很多厂家并不会把 /RD 引脚完整引出,或者主控 GPIO 资源紧张根本不想接读线。没有读回能力,你就没法知道当前屏幕上那个字节是什么,画个交叉线都会变成“把另一个图形擦掉”的灾难。
软件缓冲区的思路本质上是在内存里做一张屏幕的“草稿纸”,你随便画,最后统一提交。这套模式的额外好处是,你可以非常方便地叠加 UI 上各种元素,比如背景图、汉字、光标、曲线,操作的都是同一块内存。最后刷屏时连续写 9600 字节,以 RA8835 的写入速度来看也就是几毫秒级别,完全够用。
如果你的 MCU 内存小、实在挤不出 9600 字节,那就退而求其次,把 /RD 接上,写一个基于控制器读回的画点函数。但前提是你要确认模块设计支持读操作,万一是“写保护”的简化模块,读回来全是 0xFF,那这个方案就直接报废。
5. 三个尺寸共模调试与差异排查
5.1 踩坑记录:白屏、花屏、对比度
先说说白屏。白屏是最常见的初始化失败症状,而我遇到过最离谱的一次是屏本身没问题,但模块上的对比度电位器被拧到了最底,导致 VLCD 不够,屏上实际有内容却淡到看不见。所以白屏不要第一时间怀疑代码,先把背光供电、VLCD 电位器和复位时序排查一遍。
花屏则要分两种看。第一种是“整屏黑白乱码但有规律”,这种大概率是初始化参数中的每行总字节数或 SCROLL 行数设置不对,导致显存地址和屏幕扫描错位。第二种是“只有局部区域花”,这种往往是地址计算越界,或者刷屏时缓冲区数据和显存映射顺序不匹配。
对比度问题在单色 STN 屏上尤其突出。很多人把字调黑了,但背景全是“鬼影”;把背景调干净了,字又淡到几乎消失。这种问题靠改代码解决不了,它本质上还是偏压波形和 VLCD 没匹配好。可以试着在规格书推荐范围附近把 VLCD 调节电位器扫一遍,找到“背景干净、字体清晰”的甜点区间。如果模块支持外部 PWM 控制偏压,那就用软件校准,这在批量产线上比手调电位器靠谱得多。
5.2 常见问题速查表
| 现象 | 可能原因 | 检查/解决方法 |
|---|---|---|
| 上电白屏 | 复位时序太短、VLCD 不对、显示开关未打开 | 拉长复位低电平时间到50ms以上;调对比度电位器;查初始化最后是否执行 DISP ON |
| 全屏有背光但无内容 | A0 接反、命令/数据未正常写入 | 用示波器查 /WR 和 A0 波形;确认 A0=0 写命令、A0=1 写数据 |
| 画面左右分割或斜条纹 | 每行总字节数与实际扫描不匹配 | 核对 SYSTEM SET 中的每行总字节数,320点/8=40,总字节数保持一致性 |
| 画面上下错乱、重复堆叠 | SCROLL 显示区行数设置错误 | 设置第一显示区行数为 240 或按规格书微调 |
| 显示淡、背景花 | VLCD 偏低或偏高 | 调模块对比度电位器;用外部直流电源验证最佳偏压范围 |
| 刷图后某些列花掉 | 取模顺序与屏显存映射不一致 | 检查取模软件是否选择 MSB first、行扫描、单色格式 |
| 大屏背光开启瞬间 MCU 复位 | 背光电流导致电源跌落 | 背光独立供电,或加电容缓冲;不要与逻辑电源共用一根细线 |
| 3.8寸正常、5.7寸花屏 | 大屏扫描负载重,偏压不足 | 单独调整 VLCD 和背光电流,两套初始化参数按尺寸区分 |
还有一个很容易被忽略的细节:不同尺寸切换时,代码里的初始化序列不是百分之百复用。RA8835 命令集一样,但玻璃的物理扫描参数和偏压范围不同。我建议在产品代码里把三款屏的初始化参数做成独立的配置表格,通过宏或者配置项切换,而不是每次改屏都重新编译一个版本。
调试时最好准备一个逻辑分析仪,哪怕是最便宜的 8 通道款也行。重点抓 A0、/WR、D0-D7 这几条线,看命令发出后参数是否连续、A0 切换是否正确。做老设备维修替换更是如此,很多“屏故障”其实是主板时序老化了,逻辑分析仪一抓便能看出端倪,免得误换屏。
最后再分享一个我自己的习惯:每次拿到新尺寸的 RA8835 屏,我都会先写一个最简测试程序,只做“清屏为黑、清屏为白、画对角线”三个动作。不用任何复杂 UI,就这三项,能在十分钟内判断屏幕硬件、偏压、初始化参数和显存映射是否基本正常。确认板级没问题后,再开始叠加汉字、图片和正式界面——这个顺序帮我省掉的排查时间,比我写驱动代码的时间还多。