好久没更新了,进度如下:
1、RTC芯片DS3232的驱动问题已经弄明白是怎么回事,琢磨了很久,后来无意中发现如果使用内置的6M RC晶振时,通讯就没问题,原来是MCU在使用外置的22.1184Mhz晶振时,指令的执行行速度太快,由于是用软件模拟I2C协议的序,结果速度太快而导致时序不符合要求而通讯失败失败,后来在相关指令后面加NOP或加入重复指令适当延时,问题解决了。
2、PS2键盘开始工作,设计PS2键盘的硬件接口电路时,数据手册上说PS2键盘是使用+5V,因此我设计时供给PS2键盘的电源也是+5V,这带来了一个问题:MCU为3.3V电压版,IO口允许的最高电压为3.8V,而PS2键盘使用5V电源,它的IO输出是5V,如果MCU跟PS2键盘直接连接的话,很可能会烧坏MCU。这种情况的解决通常有三种方法:
————使用专用的IO口电平转换芯片,MAXIM和国半都有不少这种匹配IO口电平的芯片,这种方法成本高,电路也复杂,但最稳妥,而且支持双向通讯。
————使用限流电阻,就是在3.3V和5V两个IO口间直接串入一个电阻限流来防止低压的部件烧坏,这种方法最不稳妥,但电路最简单,成本最低,也支持双向通讯,麻烦的地方是需要做很多试验得出一个比较合适的电阻值才能比较稳妥,通常的电阻值都要1K以上。
————使用快速二极管,利用二极管的导通和反相截止特性,在3.3V和5V之间逆向接入二极管,这种方法也非常稳妥,成本低,电路简单,唯一的缺点是只能单向通讯。
我设计时没考虑清楚,认为只需要MCU接收PS2键盘发过来的信号就行,不需要发送信号给PS2键盘,因此采用了二极管的接法,结果写驱动时发现,MCU固然能接收到PS2键盘发过来的键码,但无法对键盘进行设置,也无法实现numlock、caps lock的亮灯,因为只能单向通讯-_-!(以前以为NUMLOCK灯的亮起是键盘自己处理的,就是只要按下NUMLOCK键盘就能亮起NUMLOCK灯,现在才发现原来必需CPU进行处理,当NUMLOCK键按下时,键盘会把NUMLOCK键的键码发送给CPU,CPU处理后,发送点亮NUMLOCK灯的命令给键盘,键盘接到命令后再执行把灯点亮的动作)为了测试全面的功能,我把二极管拆了,换上1K的电阻,现在可以发送命令给键盘来实现相关功能了。
3、32K SRAM可以工作了,这部分的难度出乎我意料,之前的没有考虑完全加上经验不足带来相当大的麻烦,折腾了我几乎两星期的时间。
首先,设计时我是选用双MCU共享SRAM内存的结构,这就决定了我选用的MCU不能使用ALE脚来驱动SRAM,因为两片MCU的复位动作肯定有先后之分,哪怕是非常微小的时间差异,启动后,两块MCU的ALE信号肯定会不合拍,不合拍的ALE信号是无法驱动SRAM的。于是我只能使用IO口模拟读写时序来驱动SRAM,因此选用了无ALE/WR/RD功能的STC12LE5412,它的执行速度比通常的MCU要快得多,可以弥补由于使用软件时序读写SRAM而带来的速度下降。
于是噩梦开始,首先用软件时序读写SRAM非常麻烦,想一下,每一个要访问的变量都必须调用一段子程序才能访问,譬如一行普通的uchar a=0x11;代码,我必须自己安排变量a的物理存储地址,然后调用SRAM的读写子程序来把0x11的值写入,也就是说,我几乎需要自己用汇编写一个专门的编译器或者翻译器来完成代码的转换,这工作难度无与伦比的高,折腾了好几天,简直是要精神崩溃准备放弃SRAM了,但放弃SRAM就意味着几乎整个设计的失败。因为无论是USB的驱动还是MMC卡的驱动,都需要1K以上字节的内存,STC12LE5412只有总共才512个字节的内存,没有扩展的内存的话,是无法完成USB驱动和MMC驱动的,而没有了USB驱动和MMC驱动,MP3模块的驱动就失去意义,因为没有存储文件,MP3模块也放不出声音来。
异常绝望的时候,突然无意中看到keil C51的xram bank功能,这功能是让51核的MCU支持大于64K的SRAM内存,因为传统的51核MCU,使用MOVX @DPTR来间接访问外置的SRAM,DPTR是16位的寄存器,它仅能表示从0x0000到0xffff的内存范围,也就是64K,而xram bank功能就是通过额外的IO口或者特殊的分页寄存器,加上用户自己编写的分页驱动,把大于64K的内存地址重新换算到DPTR来访问,譬如举例如下:
如果系统里使用了芯片621024(128K SRAM),你可以把多余的一个IO口用来连接621024的最高地址口A16,把这片128K分成两个64K的页,当A16=0时,MOVX @DPTR访问到的是第一页,而A16=1时,MOVX @DPTR访问的是第二页,只要修改xbanking.A51文件,在里面加入A16的设定代码和MOVX @DPTR的相关代码,就可以在工程里添加上xbanking.A51一起编译,同时可以把变量定义为far的存储类型来保存进SRAM里做处理。
我的SRAM只有32K,远没达到需要分页的需要,这分页的技术对我没用,但我看中的是这个功能:只要把变量定义为far类型,编译器就会自动把变量的访问通过调用xbanking.A51里代码来访问,也就是说,我只要把SRAM的驱动写入xbanking.A51,以后要把变量保存进SRAM时,定义成far类型就可以透明访问了。Aha,that is god damn great!于是把keil自带的几个xbanking使用范例都琢磨了一番,终于明白xbanking是怎样处理的了。经过反复调试,终于凑出一个可以正常工作的xbanking.A51。搞好了这个xbanking后,我现在就不需要为每个变量反复思考调用访问子程序了,只要我把变量定义成far存储类型,编译器会自动帮我链接好相关的访问子程序,也就是说xbank写好后,原先uchar a=0x11现在也只需一句 uchar far a=0x11就ok,至于a分配到什么地址或者如何调用子程序,不用我再伤脑筋,编译器会替我处理好,非常透明的使用方法。测试SRAM读写没问题后,不禁再次感叹keil C51的强大功能。
本来以为SRAM的读写到此完满成功,没想到跟着问题又开始来了。设计硬件连接时,我没有考虑清楚,把SPI口的IO口复用为SRAM的高位地址,结果在驱动MMC卡时,通过SPI口从MMC卡读出一个字节数据,然后保存到SRAM(因为MCU只有512字节的内存,其他一些变量的占用,剩余内存远不够512字节,而MMC每次读取需要连续读512个字节,因此不可能把MMC读到的内存存放到MCU的内部内存,必须保存到SRAM里去),结果调试时发现,从MMC卡读取到的内存是正确的,但保存到SRAM后,内容都变了,开始以为是xbanking里的SRAM驱动还没写好,调试了很多天,最后发现,是由于SPI口复用为SRAM的高位地址,结果从SPI口读取了数据后,再保存到SRAM时,由于SPI口电平造成高位地址的不确定,保存到SRAM时就保存到别的不确定的地址上了。一开始想到的解决方法是软件处理SRAM读写时禁止MMC卡,后来测试是不可能的,因为MMC卡一旦禁止,重新使用时就必须重新初始化MMC卡,不可能每次读一个字节都初始化一次MMC卡。想了很久,最后还是没办法,只好改硬件了,我把电路板上跟SPI口有关的几根IO口和SRAM的连接线都用小刀割断(免得干涉SRAM的高地址位),由于实在没有多余的IO口来驱动SRAM的高位,只好把那些空出来的SRAM高位地址线短接到GROUND,SRAM只能缩水使用了。按这样的修改方法,32K的SRAM仅能使用其中的2K,亏死了-_-!不过,2K虽然少了点,但好歹能对付绝大部分使用需求了。修改后经过测试,对MMC卡的读写非常成功,各个扇区的内容可以完整读出,保存进SRAM,要处理时就对SRAM里的数据进行处理。
4、MMC卡的驱动完成,MMC卡有两种访问协议,一种是使用SPI协议,另一种是MMC卡的专用协议,使用SPI口协议读写速度相对较慢,但兼容性好,譬如可以兼容SD卡(SD卡同样支持SPI协议),我使用了SPI协议,因为我选用的STC12LE5412具有快速的硬件SPI口,使用SPI协议通讯时,我只要把要发送的内容填入SPDR寄存器,SPI口就会自动启动把数据按照SPI协议发送给MMC卡,然后MMC卡把数据同样发回给MCU,MCU把收到的数据保存到SPDR里,使用非常方便。驱动MMC卡时没有遇上多大的麻烦,毕竟网上有关MMC卡的驱动资料和范例都很多,对照资料和范例,很容易弄明白。
5、FAT文件驱动基本完成,FAT驱动网上也有很多范例,但没有C51及针对MMC卡的,参考了范例和调试后,终于把网上找到的为AVR单片机写的MMC_FAT驱动移植到C51,初步测试非常成功,支持FAT16及FAT32,支持1G MMC卡(手头上没有2G MMC,没做测试),支持MMC卡上文件的读出(没有编写文件写入部分的代码,不打算支持,感觉不需要,程序空间不够,能省则省),推测MP3文件的读取播放应该没问题了。非常简洁和有效率的FAT驱动,连SRAM、MMC卡驱动全部编译后才5K大小,我对此非常满意。
6、USB驱动失败。设计时没查清楚,原来CH374芯片用官方提供的lib库驱动U盘时,每次读写至少需要一个扇区,有可能是512字节,或1K,或更大,视U盘的特性而定。因此驱动对SRAM的需求比较大,虽然已经实现了SRAM的透明使用,但问题时官方提供的lib库并不支持xbanking,因此也就不能支持我的SRAM。自己实现USB协议难度太大,再没其他办法就只能放弃了U盘支持。打算跟芯片供应商联系,把我的xbanking.A51提供给他,让他帮忙重新编译一个支持xbanking的lib库来使用。虽然USB驱动失败,但我也做了一些基本测试。譬如检测U盘的插入、拔出等,CH374的使用还是比较简单,如果这次设计的SRAM硬件不是这么怪异的接法(必须使用xbanking),用官方的lib库实现U盘读写非常容易。
接下去应该实现MP3模块的播放了,难度应该不大,因为无论是官方的数据手册还是google到的相关资料,都非常非常详细,基本上都看明白了,就差动手调试了。
再下一步是写显示屏驱动,还有两个MCU协调(到目前为止,我都还没启动第二块MCU,以上所做的所有调试都是在一块MCU上),还有把各种驱动模块整合起来……
路漫漫其修远兮……