真值表是控制LCD显示指定内容必须的资料,开发者依据真值表,控制SEGy引脚、COMx引脚电平,显示指定符号。部分LCD显示内容由一组(COMx,SEGy)控制,其它则是需要多组(COMx,SEGy)控制。单组引脚控制时,通常使SEGi、COMj引脚为高电平,即可显示该符号,低电平时,该内容不显示。多组引脚控制时,依据显示的内容不同,(COMx1,SEGy1),(COMx2,SEGy2),...,(COMxn,SEGyn)组合也不同。
LCD控制原理
下面我先给出一张效果图,这是LCD所有字符同时显示时的效果。在控制LCD显示时,可以使用专用的LCD驱动芯片BL55080,这样MCU不用拿出多个引脚去控制Seg和COM引脚的电压,只需把相应的数据通过I2C协议发送给BL55080显示控制模组。如此一来,MCU可以空出更多的引脚,进行其他操作。

BL55080的典型应用示意图如下所示。"BL55080 内部集成了 LCD 驱动器所必需的所有功能电路。例如:LCD偏置电压发生器、LCD电压选择器、内部时钟(OSC =25.6KHz)、显示寄存器、段/背极输出电路、I2C串行接口、上电复位电路和显示控制电路。BL55080 有35个段输出SEG0--SEG34和8个背极输出COM0---COM7,它们和LCD 直接相连,当少于35个段输出应用时,不用的段可空出。BL55080采用1/8背极输出1/4 偏置电压显示方式。"这是BL55080芯片手册的原文,这里的背指的就是COM引脚,段指的就是SEG引脚。手册里面还提到VDD和VLCD引脚需要同时上电、同时掉电,且VDD的上升时间必须大于1ms。

真值表信息整理
下面的表格就是LCD屏幕对应的真值表,包含LCD显示字符的主要信息。只有下面的表格还不够,开发者还需要找到表格对应的符号显示的位置图。在COMx引脚和SEGx引脚一一对应的情况下,如果要控制屏幕显示"当前"二字,用户需要将S1对应的引脚设置为高电平。一个一个去对着表格,找对应字符所在的位置(COMx,SEGy对应的组合)实在是太费时间了,你绝对不会想这样做。幸好现在的AI工具准确率还凑合,你将字符表截图,使用AI工具将图片转成Excel,就可以使用Excel查找功能,就可以发现字符位置信息。


下图的Excel表是我使用AI工具转换出来的真值表。为了提高AI识别的准确率,我把LCD资料里面的字符表分成两次识别,并做适当修正。最后,在复制到Excel表的时候,通过复制 、转置功能,将表格变成竖向显示,并重新排序,得到方便用户处理的真值表。

单个显示区域控制
在Excel类型的真值表里,通过查找操作,用户可以很轻松的找到"当前" 对应的字符位置------第33行第1列。我之前是使用长度为34的无符号8位整型(UINT8)数组g_disBuf[]来控制引脚电平,g_disBuf[33] |= 0x80 ,即是将COM1,SEG33引脚设置为高电平,控制屏幕显示"当前"二字(注意:竖列,COM1~COM8的电平与UINT8数据的最高位到最低位bit数据对应,横行,我做的行号标识与要操作的数组元素的数据对应)。LCD厂商做的真值表,通常会将大部分字符放在相邻区域,方便开发者查找。但如果BL55080芯片引脚与LCD的引脚对应关系不友好,开发就需要自己调整行、列数据的显示顺序。之前的PCB设计师,工作经验丰富,引脚大多一一对应,给开发带来了很大帮助。处于某些原因,SEG21号引脚空了出来,所以g_disBuf[21]无需用户操作。
多个(数字)显示区域控制
单个显示元素的操作,开发者可以毫不费力的计算出对应的数据,那多个呢?例如,控制中间大数码管,最左边第一个数码管显示4,你还可以计算出来吗,如果把0~0xF对应的符号分别显示出来呢?这个时候我就不建议开发者自己计算,百密一疏,容易出错。我一开始就是这样做的,功倍事半,后来我就使用Excel公式自动计算对应的UINT8类型数据,并对数据进行格式化处理,方便构建数字显示数组。
控制中间大数码管,第一个数字区域显示"4",需要将3B、3C、3F、3G区域设置为高电平,其他区域低电平。由上面的Excel数据可知,字符"4"的显示需要使用两个数组元素,具体内容如下"g_disBuf[32] |= 0x6,g_disBuf[33] |= 0x6"。中间10个大数码管的显示规律可以分为两种,具体规律如下图所示。

每个字符对应的具体数据我通过Excel公式计算,计算第一列数据(xA、xB、xC、xD对应显示区域)我使用的公式为"=DEC2HEX(F89*8+G89*4+H89*2+I89)",后续为了方便处理,我使用公式统一数据格式,所用公式为"=CONCAT(",0x0",T89)"。再将所需数据粘贴到浏览器网址输入框中,直接将多行数据变成一行。

使用过程中,我使用数组给g_disBuf[]元素赋值,TAB_MainDcd[][]二维数组元素,即我通过Excel处理得到的数据。使用该方式,可以提高开发效率,降低出错概率。
objectivec
/*******************************************************************************
功能描述: 解码主数据
输入参数: pBuff: 数据入口
num: 显示字符数
返回参数:
函数说明:
*******************************************************************************/
static const INT8U TAB_MainSeg[2][10] = //主数据段码(对应MCU内部SEG口)
{
{18, 16, 14, 12, 10, 24, 26, 28, 30, 32},
{17, 15, 13, 11, 9, 25, 27, 29, 31, 33} //右边第一个数码管->左边第一个数码管
};
static const INT8U TAB_MainDcd[4][16] = //主数据解码(即MCU内部SEG口的数据LCDBUF[])
{
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, b, C, d, E, F
{0x0F,0x06,0x0D,0x0F,0x06,0x0B,0x0B,0x0E,0x0F,0x0F,0x0E,0x03,0x09,0x07,0x09,0x08},
{0x0A,0x00,0x06,0x04,0x0C,0x0C,0x0E,0x00,0x0E,0x0C,0x0E,0x0E,0x0A,0x06,0x0E,0x0E},
{0x0F,0x06,0x0D,0x0F,0x06,0x0B,0x0B,0x0E,0x0F,0x0F,0x0E,0x03,0x09,0x07,0x09,0x08},
{0x05,0x00,0x03,0x02,0x06,0x06,0x07,0x00,0x07,0x06,0x07,0x07,0x05,0x03,0x07,0x07}
};
void Decode_MainLine(const INT8U *pBuff, INT8U num)
{
INT8U i, j;
if ((num != 0) && (num <= 10)) //入口参数检查
{
for (i=0; i<num; i++)
{
j = i/2; //舍掉小数部分
if (i < 6)
{
if ((i & 0x01) == 0x00)
{
g_DispBuf[TAB_MainSeg[0][i]] = TAB_MainDcd[0][(pBuff[j] & 0x0F)];
g_DispBuf[TAB_MainSeg[1][i]] = TAB_MainDcd[1][(pBuff[j] & 0x0F)];
}
else
{
g_DispBuf[TAB_MainSeg[0][i]] = TAB_MainDcd[0][(pBuff[j] >> 4)];
g_DispBuf[TAB_MainSeg[1][i]] = TAB_MainDcd[1][(pBuff[j] >> 4)];
}
}
else
{
if ((i & 0x01) == 0x00)
{
g_DispBuf[TAB_MainSeg[0][i]] = TAB_MainDcd[2][(pBuff[j] & 0x0F)];
g_DispBuf[TAB_MainSeg[1][i]] = TAB_MainDcd[3][(pBuff[j] & 0x0F)];
}
else
{
g_DispBuf[TAB_MainSeg[0][i]] = TAB_MainDcd[2][(pBuff[j] >> 4)];
g_DispBuf[TAB_MainSeg[1][i]] = TAB_MainDcd[3][(pBuff[j] >> 4)];
}
}
}
}
}