将单色像素值转换成灰阶屏的灰度序列的算法
就是想办法把单色OLED 屏幕的字库转换给灰阶屏用,并且代码中可以根据设置的灰度参数,用一种字体显示出多种深浅颜色。本来感觉会挺复杂的,想了想突然发现其实很简单。
灰阶屏原理
适用于ST7571 或SSD1328,以及类似的灰阶屏主控。以4 级 / 2bit 灰阶为例,发送显示数据时,一次要发送2 个字节,对应1 列8 个像素,每个像素点的灰度分别用前后两个字节中相同位置的2 个bit 来决定。如果用的屏幕是黑白液晶屏,发送的两个字节分别为0b0000'0001
和0b0000'0001
,最低位的两个1 组合成11
,表示全黑;00
就表示全白,01
和10
分别是浅灰和深灰。如果是带灰阶的OLED,就反过来,黑色11
表示最亮,以此类推。16 级 / 4bit 灰阶原理是相同,只是要一次发送4 个字节才能控制8 个像素。
这类灰阶屏的像素对应关系和普通单色OLED 是一样的,如果不知道页(Page)、列(Column)、行(row)这些术语都代表什么,可以先去看单色OLED 屏的教程。
顺便一说,还有一种灰阶屏,比如2bit 灰阶的ST7586S,它是用一个字节里的2 个bit 表示一个像素,发送1 字节控制3 个像素,感觉有点恶心,反正我没用过。
灰度序列生成算法
还是以2bit 灰阶为例。单色屏幕用的字库都是1 字节表示8 个像素,1 表示全黑,0 表示全白;比如0b0101'0101
,或者0x55
,重复发送这个字节,就会在屏幕上显示4 组黑白相间的横线。如果要把0x55
显示成灰度0,只要给屏幕连续发送两字节0 就行了;要变成灰度3,那就连续发送两次0x55
,对应的像素值就是11
。如果要显示灰度1 和2,只要发送一次0x00
,一次0x55
,对应的像素值就是01
或10
,那么该如何控制发送的先后顺序呢?[doge]
我刚开始还打算用查表法,然后马上反应过来,二进制0b01
和0b10
本身就包含了这个顺序 。想先发0 后发0x55
,只需要把0b01
放在一个变量里作为控制标记,然后:
- 对
0b01
按位取反变成0b10
; 0x01 & 0b10
,计算得到0b10
的最低位是0;- 发送0;
0b10
右移一位;- 与
0x01
,计算得到最低位是1; - 发送
0x55
;
就这么简单,换成0b10
的话,第2 步计算出最低位是1,发送的序列就变成0x55, 0x00
。所以只需要给函数传入灰度值作为参数,然后用这个步骤就能转换出灰度序列。如果是16 级灰阶,那就把灰度值取反后循环右移4 次。
不过这个方法只能用于像素值有规律的这些屏幕,万一有某个辣鸡屏幕像素值是乱排的,比如0b00 是全白,0b01 是全黑,然后0b10 是浅灰,那这样的话就只能查表了。