先把学习过程中看过的资料整理一下
- 墨水屏模块的工作原理
https://www.waveshare.net/wiki/2.66inch_e-Paper_Module_Manual#.E9.80.9A.E4.BF.A1.E6.96.B9.E5.BC.8F - 图像处理算法
https://www.waveshare.net/wiki/E-Paper_ESP32_Driver_Board#.E5.9B.BE.E5.83.8F.E5.A4.84.E7.90.86.E7.AE.97.E6.B3.95 - 墨水屏的显示原理及lut
https://blog.csdn.net/chenqide163/article/details/107363303
https://andelf.github.io/blog/2021/01/14/play-with-2-13-inch-e-ink-display/ - python Pillow(PIL)库的文档
https://pillow.readthedocs.io/en/stable/ - ssd1619文档
https://www.e-paper-display.cn/SSD1619Aspec0b5f.pdf?method=picker&flag=all&id=d8146bd7-cccc-4a81-b148-54a02b5c07d5&fileId=1112&v=1.zip
尝试在2.66寸墨水屏中修改lut
开始在网上买了块二手的2.66的墨水屏和转接板,尝试着怎么驱动墨水屏。
通过微雪的驱动demo,可以驱动。最终实现了使用抖动算法显示图片(python PIL库生成)。
又从网上了解到通过修改lut表可以实现灰阶,但我在芯片文档上找不到具体的lut修改过程,反复修改代码也不行,我甚至不确定这块墨水屏是不是使用的这个芯片,最后只好放弃。
在4.2寸墨水屏中修改lut,并叠加显示实现灰阶
2.66寸的墨水屏lut没修改成功,有点不甘心,又从网上掏了块二手的4.2寸墨水屏,400*300像素,排线上写着HINK-E042A43-A0。
到手后开始尝试使用微雪的demo驱动,但好像不行。
再在网上搜索,发现和大连佳显的一块4.2长得很像,驱动是UC8276,但通过读取温度寄存器发现不是,而是SSD1619,大连佳显三色4.2有两种芯片类型。驱动demo是stm32的,把驱动过程移到我的esp8266,可以驱动。
这次在文档上找到了明确的lut表的格式,lut数据总共76字节,前70字节是波形数据,寄存器是0x32。开始一直搞不懂它这个lut表的格式是怎样的,但经过反复看,以及通过代码测试,有点懂了,使用python生成的分层数据可以实现灰度。
- ssd1619的lut文档
- TP[nX]表示第n个大组X子组的持续时间,值为0-255, 0表式跳过这组波形
- RP[n]表示第n个大组的重复次数,值为0-255,0表时重复一次
- VS [nX-LUTn]表示第n个大组X子组第n个lut的电压级别,可以具体定位到两bit,值 00–VSS 01–VSH1 10–VSL 11–VSH2
附上匹配16级灰的lut表,TP与RP对应的波形组关系如下,为了让寄存器数据显示的更直观和方便修改,使用python生成了二进制定义表
#include "bin_define.h"
unsigned char lut16[]={
//group0 //grou1 //group2 //group3 //group4 //group5 //group6 大组
//A_B_C_D //A_B_C_D //A_B_C_D //A_B_C_D //A_B_C_D //A_B_C_D //A_B_C_D 子组
B_11000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,//lut0 B 值 00 – VSS, 01 – VSH1, 10 – VSL, 11-VSH2
B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,//lut1 W 值 00 – VSS, 01 – VSH1, 10 – VSL, 11-VSH2
B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,//lut2 R 值 00 – VSS, 01 – VSH1, 10 – VSL, 11-VSH2
B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,//lut3 R 值 00 – VSS, 01 – VSH1, 10 – VSL, 11-VSH2
B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,B_00000000,//lut4 VCOM 值 00 –DCVCOM, 01 – VSH1+DCVCOM, 10 – VSL+ DCVCOM
3,0,0,0,3, //TP[0A]、TP[0B]、TP[0C]、TP[0D]、RP[0] 前4个为子组持续时间,第5个为大组重复次数
0,0,0,0,0, //TP[1A]、TP[1B]、TP[1C]、TP[1D]、RP[1]
0,0,0,0,0, //TP[2A]、TP[2B]、TP[2C]、TP[2D]、RP[2]
0,0,0,0,0, //TP[3A]、TP[3B]、TP[3C]、TP[3D]、RP[3]
0,0,0,0,0, //TP[4A]、TP[4B]、TP[4C]、TP[4D]、RP[4]
0,0,0,0,0, //TP[5A]、TP[5B]、TP[5C]、TP[5D]、RP[5]
0,0,0,0,0, //TP[6A]、TP[6B]、TP[6C]、TP[6D]、RP[6]
};
- 这个lut设置了一层显示的颜色深度,通过增加组、增加持续时间、增加重复次数可以增加一层的颜色深度
- 灰度级别低可以把一层的颜色调深一些,级别高就调浅一些
- 设置lut后不会清屏,先使用原有的lut清屏,再自定义lut
- 这里只设置了黑白色,设置黑白的灰度调第一行的波形就行
- 第一列的前两bit列为第0A,34bit列为0B…第二列的前两bit列为1A,34bit列为1B…
- 灰度的级别要和lut匹配,不然再高的灰度级别也不会有好的显示效果
附上生成二进制定义的python代码
data=''
for i in range(256):
data+=('#define '+'B_{0:0>8b}'.format(i)+' '+hex(i))+'\n'
with open('./bin_define.h','w') as f:
f.write(data)
数据的生成
图像数据的生成可以使用python的PIL库,代码就不放了,说下过程
- 先把图像旋转、剪切
- 把图像转成灰度图
- 默认是256的灰度图,把每一个灰度值转成指定灰度级别的数据,16级就是 gray*16/256
- 把灰度数据分层,16级就分16层(这个过程可以使用多线程加速)
- 分别把每一层的数据,每8个合成一字节(墨水屏是1字节控制8像素)(这个过程可以使用多线程加速)
- 把n层数据分别写入文件
最后把生成的数据上传到esp8266的文件系统中(还可通过wifi把数据传到单片机中,lut也一起传过去,这样lut调起来更方便)
在esp8266上显示灰度图数据
- 生成的数据很大,16级灰度数据有300* 400/ 8* 16==240000B=234KB,我把它放在文件系统中,16层就是16个文件,
循环显示16次,让每一层的数据叠加,像素叠一次就会深一点 - 显示一次的时间大概需要2秒,16层就是32秒
部分代码
// set lut
EPD_4IN2FE_SendCommand(0x32);
for (int i = 0; i < 70; i++)
{
EPD_4IN2FE_SendData(lut[i]);
}
// 使用原有lut清屏
EPD_4IN2FE_Display(board1, board2);
EPD_4IN2FE_TurnOnDisplay();
int gray = 108;
EPD_4IN2FE_SetLut(gray);
for (int i = 0; i < gray; i++)
{
unsigned long start = millis();
String path = "/image_gray" + String(i) + ".bin";
File file = LittleFS.open(path, "r");
for(int i=0;file.available();i++)
{
board1[i]=(unsigned char)file.read();
}
file.close();
EPD_4IN2FE_Display(board1, board2);
EPD_4IN2FE_TurnOnDisplay();
Serial.println(i);
Serial.println(millis() - start); // 1850 2s
}
放几张效果图
抖动算法![]() | 16级灰![]() |
32级灰![]() | 64级灰,已经看不出太大差别了![]() |
108级灰![]() |