EEPROM的操作与DS1302数字时钟

因为昨天已经开始看EEPROM的文档了,今天就想按照文档中的试验一下,存数据进去掉电不会消失。至于DS1302芯片,是因为中午饭后搞定了EEPROM,所以就决定再做一个实验。总体来说不难,关键是有几个地方掉坑了……

注:因为本无产阶级买不起示波器,所以这里的图是凭借实验加上想象来画的……

EEPROM用的芯片是AT24C02,有256字节的存储空间。根据文档,它有8个腿,A0 A1 A2是用于识别设备的,这样多个这样的芯片可以共享一个总线IO。因为这板子上就一个这种芯片,就直接把A0 A1 A2全部接地了(都是低电平),于是这块芯片在板子上的设备ID就是0。Vcc连电源,SDA按照板子的手册,是连在P33上的,SCL是连在P32上的。通过P33和P32来和它通信。SDA跑信号的,SCL用于同步的。

EEPROM的SCL是用来同步的,我本来以为它每变化一次电平就可以通过SDA发送或接收一个信号,但是结果当然是失败的……它不是这么用的。仔细看说明以后得知,是SCL变为高电平的期间,SDA用于发送或者接受数据。例如要发送1,就把SDA弄成高电平,然后往SCL输出一个脉冲(先变高电平然后变回来)。发送0方法相同,把SDA弄成低电平,然后往SCL输出一个脉冲。接收的话,先把SDA置为高电平,然后往SCL送一个脉冲信号,在此过程中检查SDA是不是变成低电平了,检查过程是在脉冲之中,又要考虑它的反应速度所以在脉冲中偏后的位置似乎会比较好。如果变成低电平,那么说明收到的是0;否则说明收到的是1。这一系列芯片能接受的速度最低的似乎只有100KHz,我就按照这个100KHz来搞,慢是慢一点毕竟是实验。

它的使用手册上定义,SCL高电平的时候SDA的信号要求是稳定的,信号改变只能在低电平的时间内改变。于是要留下足够多的时间给AT24C02去反应,因为它速度只有100KHz。

我只用到了它的指定地址单个字节读取和指定地址单个字节写入功能。对于往指定地址写一个字节,过程是:(A代表单片机主动(输出),P代表单片机被动(输入))

START(A) –> 设备编号(A) –> ACK(P) –> 地址(A) –> ACK(P) –> 数据(A) –> ACK –> STOP

其中START的定义是,保持SCL高电平的同时,SDA从高电平变到低电平。STOP的定义是,保持SCL高电平的同时,SDA从低电平变到高电平。ACK的定义是,SDA变为低电平(就是对方发了一个0过来)。这里面有个应该说常识性问题我不知道的呢还是什么的,因为我之前不知道引脚用作输入的话要预先设置为高电平……(汗)

于是先定义两个函数,用于输出1和输出0。然后用这两个函数组成发送/接收一个字节的功能,因为上述设备编号、地址、数据都是8位,正好一个字节。

测试的时候,能收到ACK大致就可以认为大功告成了……

然后是读取,比写入更复杂不少。

START(A) –> 设备编号(A) –> ACK(P) –> 地址(A) –> ACK(P) –> START(A) –> 设备编号(A) –> ACK(P) –> DATA(P) –> STOP

其中前半部分和写入类似,不过到要发数据的时候变成发一个START过去,以及最后拿完数据不需要ACK(A)。

关于里面那个设备编号,它的前4位固定是1010,然后是A0 A1 A2引脚决定的编号,我这边是三个0。最后一位代表请求类型,是要读取还是写入。前者用1后者用0。比如这个情况我要写入,那么这个“设备编号”就是10100000。至于地址,就是0~255一共256个字节,AT24C02的容量也就这么256字节而已。数据就是一个字节的数据。注意的是发送过程中,所有字节都是“最高位优先(MSF)”的。比如要发送0x30,那么实际发送的比特流是 00110000。

实验是不难。关键是我之前掉坑了……就是端口用于输入的话要先设置为高电平的坑囧。

 

因为这个实验中午饭后就成功了,于是下午就决定研究一下DS1302数字时钟芯片。这个芯片的通信甚至比上面那个更简单,但是也是因为坑……啊啊一大堆坑(死目

它的通信和AT24C02有点不太一样,AT24C02不是上来直接给它发送数据就成了吗?DS1302不行,要先把CE引脚设为高电平,才能给它发请求……

还有,关于通信的时候它也是一个引脚同步一个引脚信号,但是关于同步信号的处理有一点不同。虽然发送数据的时候确实也是在脉冲中发的,但是从它接收数据的时候,是在脉冲之后接收,而不是脉冲之中……而且官方文档中没发现它能以多块的频率工作,于是也不知道到底应该以什么样的速度发送才好,就胡乱设了一个delay(胡乱……)。另外和AT24C02不同,DS1302芯片对数据的处理是“最小位优先(LSF)”的。比如要发送0x30,实际发送的比特流是 00001100。每个请求是一个字节,每个数据也是一个字节,操纵它就是给CE高电平,发送一个字节的请求,然后根据请求是读或者是写,来发送或者接收一个字节,完了取消CE的高电平即可。

这里面又遇到一个坑,就是发送请求完毕之后,如果是读取请求,这个时候不是应该接收数据吗?然后我刚才是不是有说过,从它接收数据是在低电平的时候?没错,问题就在这里……第一个要接收的比特在你发送完请求的最后一个比特之后,SCLK设为低电平之后,马上就开始返回了!而不是等到你给SCLK下一个脉冲。我一开始写的程序没考虑到这个,发完最后一个比特的请求数据、SCLK变回低电平之后,给了它一个脉冲才开始接收下一个数据,然后就是发现每两秒屏幕上的数字才会变一次,而且变得很诡异(因为少了最后一位!)。这坑搞了我好一阵子……另一个卡了半死的地方就是CE的高电平,没给它设高电平就开始操作得有来有去,怪不得它不鸟我 ._.

读取秒的时候,保持CE高电平,数据口和时钟口的信号:

发表评论