一、问题背景
昨天写一个开发板的库,写到LCD部分,遇到了几个问题。
相关电路如上图,左上角为单片机,通过硬件SPI连接74HC595,片选信号由74HC138产生,8位并行输出串联两个470欧8P4R排阻后连接到一组排针和LCD接口上。
1602的LCD一共16根引脚,其中数据有11根,把LCD连接到595上是迫不得已,单片机没有那么多IO口。这是一个不好的设计,但我已经焊接完了才发现问题。
问题有两个:
其一,595只能串行输入并行输出,但LCD模块有一个读取指令,检测LCD是否忙,并且这是一个必要的操作,然而单片机不能直接读取;
其二,我在每次写操作前都等待LCD进入空闲状态,但LCD只显示大约一半的字符,而且不固定。
二、解决方案
第一个问题,我规定用户要连接一根线,在初始化时作为参数传入:
void lcd_init(pin_t _exout7);
第二个问题,我在每次读取之前把74HC595输出置为高电平,然后就正常工作了:
exout_write(1 << 7); // LCD module is weak in pulling up
现在回想起来,第二个问题与解决方案之间的联系有些微妙。
三、解决过程
作为一块开发板,板上的许多net都引出了排针,可以用杜邦线连接起来。正好,595输出是在串联电阻后才接到LCD上的,两个输出不会冲突,并且这个net是有引出的,同时单片机也引出了GPIO,于是第一个问题的解决方案就很显而易见了——连起来。相应地程序中也要调用这个GPIO上的读取操作。
而第二个问题的解决就颇费周折。在单片机可以读取LCD忙状态以后,我在程序中每次写入前等待LCD进入空闲,理应能正常工作,然而并没有。
我先尝试加入延时,在写入过程中加入多个1ms延时,发现可以正常工作。然后我试着消除尽可能多的延时,并降低延时长度,发现只要LCD的E引脚的上升沿之前有10000次for循环延时就行,反之则不行。这种延时的解决方案远不能让我满意。
在E引脚的上升沿同时,LCD读取引脚电平并开始执行操作,在此之前一定要有延时。一个可能性是信号传输有延迟,但这里需要的最小延时有亚毫秒级,排除。另一个可能性就是忙状态电平读取错误,把表示忙状态的高电平读成了低电平。
之前在解决第一个问题的过程中,利用了595和LCD之间的电阻,它的存在让两个输出不冲突。但是这个电阻只有470欧,如果两端一个高电平一个低电平,会有10mA的电流,对于74HC595等CMOS IC,这个电流让电压偏离理想值不会超过1V,但是对别的IC就不一定了。
一个4引脚的RGB LED灯有共阴和共阳两种连接方式,我曾疑惑为什么要有两种,查阅资料后得知,比较老的IC,比如51,是使用TTL工艺制造的,端口sink电流能力强而source电流的能力弱,所以如果要用引脚驱动LED,一般会把正极接到VCC,串联电阻后接到引脚上,对于RGB的来说就是用共阳了。
下面两张图分别是TI的74HC00和74LS00的datasheet的截图,分析数据可以得出,前者输出低电平能力稍强,还是比较对称的,而后者明显不对称。
在这个问题中,LCD模块输出的source电流能力很弱,在5V电源下,当595输出低,LCD输出高时,后者端口上电压为1.1V;当595输出高,LCD输出低时,后者端口上电压也是1.1V;两个电压都会被单片机判定为低电平。
分析至此,就不难得出解决方案了——在读取之前把595的输出置为高电平,然后就能正确地读到LCD的输出了。
四、思考
这是一个不难的问题,我也顺利解决了,但是解决问题的思路与过程还是让我挺有收获的。
如果我在画原理图之前认真读datasheet,就会知道LCD也有读取的操作,就不会有后面的问题了。所以,以后做开发的过程中,要认真读datasheet;表面上看起来只有输出属性的设备也可能需要输入,不要因为一个设备是输出设备就把它挂在纯输出口上。
如果我在画原理图时把LCD直接与单片机相连接,也不会有后面的问题。而在这块开发板上,595连接了数码管、LCD与排针3种设备,这种复用方式是不好的,应该尽量避免;宁愿多加几个IC,或者换一个IO更多的单片机,虽然成本高了,但时间也省下来了。
在开发板上放这块595的最初目的,是为了给用户学习时序,学会根据datasheet来写程序,想着初学者也就会玩玩LED,为了方便用户就加上了排阻,就算输出要用作别的,串联的电阻也人畜无害。后来才把数码管和LCD一起连接上去。而LCD没有直接连接595输出而是连接电阻的原因,也只是为了方便布线。没想到最后歪打正着,串联的电阻帮了大忙。也许以后设计的时候应该多考虑一下串联电阻,反正几分钱的电阻四舍五入一下就是不要钱,但没准就有大用处。
最后,也是最重要的一点,电子电路的知识都是融会贯通的。即使是细枝末节、无关紧要的,或是已经obsolete的知识,也可能成为解决某个问题的关键。如果不曾了解共阳和共阴背后的原因,对于一个一直使用CMOS工艺制造的单片机的开发者来说,怎么会从LCD不接收指令一路联想到是TTL驱动能力的问题呢?没准到现在都没解决问题吧!