在单片机开发中,如果时序关系不正确定的话,数据就不能正确的读写。因此,在程序中,如何正确的控制时序关系,就显得特别的重要。
先来看以下的两个例子:
1. DS1302时钟芯片,采用SPI总线;
2. 24C08存储芯片,采用I2C总线。
在对DS1302进行编程时,发现数码管只显示时间的奇数值,而偶数值则不显示。
检查了下程序,问题定位在读出数据与写入数据的函数,原函数具体如下:
uchar ReadDs1302()
{
uchar dat,i;
SCLK=1;
Delayus(2);
for(i=0;i<8;i++)
{
dat>>=1;
if(DATA==1)
{
dat|=0x80;
}
SCLK=1;
Delayus(2);
SCLK=0;
Delayus(2);
}
return da;
}
将上面红色字体的那行程序删除,或者改为:SCLK=0,再重新烧写后,数码管显示的时间正常。
而写入数据的函数如下:
void WriteDs1302(uchar dat)
{
uchar i;
SCLK=0;
Delayus(2);
for(i=0;i<8;i++)
{
DATA=dat&0x01;
Delayus(2);
SCLK=1;
Delayus(2);
SCLK=0;
dat>>=1;
Delayus(2);
}
}
若只将上面蓝色部分的程序改为:
if(i<7)
{
SCLK=0;
}
重新烧写进去后,数码管也能正确的显示。
以蓝色那行程序的修改,分析其原因:
先看下SPI总线的读操作时序,其为下降沿采样,如下图所示:
从时序图中,可看出,对于写数据,是在时钟的上升沿,而读数据,则是在时钟的下降沿。
程序修改前,在往DS1302中写入第八位数据后,时钟信号就变为低电平。此后,进入读阶段,在DS1302还没将数据送到SDA线上时,时钟就变为高电平,此时对应的SDA上的数据,还是为写入的数据1。
而程序修改后,即在SDA写入数据后,在第八位数据时,SCLK就不降为低电平了,一直保持为高电平,直到DS1302将数据送到SDA时,才变为低电平,在下降沿时对SDA上的数据进行采样。
即修改后的程序,在读写操作交替那个时钟,等到DS1302送数据到SDA线上后,才变为低电平,进行采样的。
对于24C08,其采用I2C总线技术,当程序烧写进入后,发现不能正常的工作。
问题定位在I2C结束信号函数,具体如下所示:
void Stop()
{
SCL=1;
SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}
上面红色两行程序的顺序对调下,则能正确的读写24C08芯片内部的数据。
分析其原因,则在于若执行Stop()这个函数之前时,若SDA上存在几个周期的高电平时,此时执行SCL=1;SDA=0,相当于多出了个I2C的开始信号,导致错误。
在实际中,总结了下以后几点,希望可以尽量避免时序操作错误:
1. 特别注意单字节读,写函数刚开始或结束时,时钟信号的高低电平;
2. 可确定1或者0为程序的默认电平。如对于DS1302的CLK,可以低电平;
3. 从节省功耗的角度出发,尽量保证默认电平功耗低。以I2C总线为例,因其有上拉电阻 的存在,故可保证默认电平为高;
4. 同样从功耗的角度出发,尽量保证各类信号少翻转;
5. 对于总线控制信号(如SPI总线的RST),一切信号都准备好之后,控制信号才开启。当总线要停止工作时,先将控制信号关断,再作其他信号的处理;
6. 当然,得时刻警惕信号的建立时间与保持时间。
当然,若在程序中查找不出问题时,可采用示波器,同时测量时钟与数据信号,判断时序是否正确。
上一篇:单片机C语言求平方根函数
下一篇:直流电机PWM调速程序
推荐阅读最新更新时间:2024-03-16 14:41