用C语言实现电子纸显示驱动:实现低功耗下的局部刷新与全刷优化
电子纸不是“写显存就出图”的LCD。墨水粒子靠电压时序迁移,驱动IC按波形表(LUT)逐帧加压,画面才定型。 全刷干净但慢(单色常2~5秒、伴闪),局刷快且无闪,但多次会留残影。 低功耗驱动的本质就是:平时不刷、变化才刷、局刷为主、定期全刷兜底。
一、控制器里的两块RAM
以SSD1680类SPI电子纸为例,驱动IC内部通常有:
0x24:当前新帧(黑白位图)
0x26:上一帧基准(局刷差分用)
0x22选刷新模式,0x20触发物理刷新
BUSY高电平表示波形执行中,别抢发命令
MCU侧再维护一份old_buf作软件基准,用来算脏区。
二、显存差分:只发变化行
电子纸SPI量小不代表能偷懒,全屏每次重发既慢又费电。标准做法是字节比对:
#define EPD_W 128
#define EPD_H 296
#define LINE_BYTES (EPD_W/8)
static uint8_t new_buf[EPD_H*LINE_BYTES];
static uint8_t old_buf[EPD_H*LINE_BYTES];
void epd_flush_partial(uint16_t x,uint16_t y,uint16_t w,uint16_t h){
epd_wait_busy(); // BUSY必须低
for(int row=y; row<y+h; row++){
uint8_t* n = &new_buf[row*LINE_BYTES];
uint8_t* o = &old_buf[row*LINE_BYTES];
int x0=LINE_BYTES, x1=-1;
for(int i=0;i<LINE_BYTES;i++){
if(n[i]!=o[i]){
if(i<x0)x0=i; x1=i;
}
}
if(x1<0) continue; // 本行无变化
epd_set_window(x0 * 8, row, (x1+1)*8-1, row);
epd_write_ram(0x24, &n[x0], x1-x0+1);
memcpy(o+x0, n+x0, x1-x0+1);
}
epd_update(EPD_MODE_PARTIAL); // 0x22+0x20
}
局刷窗口一定要覆盖“旧内容实际占的区域”,只框新文字宽度常会留边影。
三、全刷计数器:残影兜底
局刷波形不给粒子完整复位,黑→白大面积切换几次就糊。 工程做法:
static uint8_t partial_cnt = 0;
#define PARTIAL_MAX 8
void epd_update_ui(const uint8_t*frame){
memcpy(new_buf, frame, sizeof(new_buf));
int diff = epd_calc_dirty(new_buf, old_buf);
if(partial_cnt>=PARTIAL_MAX || diff>EPD_H*LINE_BYTES/2){
epd_load_lut(FULL_LUT);
epd_flush_full(new_buf); // 清屏+整帧重写
memcpy(old_buf, new_buf, sizeof(old_buf));
partial_cnt = 0;
}else{
epd_load_lut(PARTIAL_LUT);
epd_flush_partial(0,0,EPD_W,EPD_H);
partial_cnt++;
}
}
判据两条:
局刷次数超阈值 → 全刷
变化像素超比例(换页/切界面)→ 直接全刷
纯更新时间数字可以连刷多次;切菜单必须全刷。
四、LUT别自己拍电压
波形表是屏厂按膜片批次、温度曲线标定的,包含正反压、相位时长、DC平衡。 C代码里只做“选择LUT”,不手搓脉冲序列:
void epd_load_lut(const uint8_t*lut, int len){
epd_cmd(0x32);
for(int i=0;i<len;i++) epd_data(lut[i]);
}
低温场景用厂方给的低温LUT切换,别靠延时凑。
五、低功耗时序
电子纸静止时不耗电,耗电全在刷新瞬间:
唤醒RES(退出deep sleep必须复位)
初始化+装LUT
写0x24/0x26
等BUSY低
触发刷新,再等BUSY低
进0x10 deep sleep
MCU自己STOP/WFI
void epd_sleep(void){
epd_wait_busy();
epd_cmd(0x10); epd_data(0x01); // deep sleep
}
刷新中途别切Wi-Fi/大电流动作,电压跌落会残影。
六、落坑清单
BUSY高时发SPI→命令丢失、控制器卡死
局刷不更新old_buf→下次差分错
只发新文字区→旧字残影
每次都全刷→慢、闪、费电
LUT自己改电压→批次屏发灰
局刷计数不设→半小时糊成一片
deep sleep不复位RES→下次唤不醒
SPI时钟顶太高→长排线丢字节
七、落地顺序
驱动IC确认(SSD1680/UC8151等)
维护new_buf/old_buf两份显存
字节级diff算脏行/脏矩形
局刷走0x24+partial LUT
计数或变化率触发全刷
全刷前装full LUT、整帧重写
每次等BUSY
刷完deep sleep,MCU进STOP
电子纸低功耗显示的关键不在“刷得快”,在“尽量少刷”。局刷解决日常更新功耗,全刷解决残影累积,波形LUT解决显示质量——三层配合起来,墨水屏才能真正做到“电池跑几个月”:静止零功耗,更新只动脏区,几小时一次全刷清底。代码层就是显存差分+模式切换+BUSY守门,别把电子纸当LCD刷。





