一二百行代码产生的错误,不知不觉的改到了现在,不得不说,硬件的bug确实比软件难改,会让人怀疑是硬件问题还是软件问题。为了改AT24C02的错误,花了半小时复习了下,主要内容在下面。现在先说以下这次bug造成的原因,以及以后大家在学习51单片机中遇到错误该怎们办。
这次bug的形成原因是细节上的错误。
第一个比较明显的:就是终止信号的时候 应该是SCL在高电平的时候收到一个SDA的上升沿,这个时候为终止。这里错写为SCL为低电平的时候,SDA出现上升沿了。
第二个错误:这个改出来的时候我想死的心都有了。。。。,
#ifndef uint
define uint unsigned int
endif
这个没问题吧,再看下面
#ifndef uchar
define ucahr unsigned int
endif
如果不仔细看你绝对发现不了,这样的好错误
然后现在讲51中遇到错误该怎们办(个人学习见解,能力有限,如有错误,还请指出)
首先先不要怀疑硬件问题(我们用的别人做好的板子,硬件一般是过关的)
用别人的代码进行测试(如果行得通,那就是你代码的问题了,这个时候就要好好检查了)
才用硬件调试 这个应该是调试寄存器,难度可能有点大
使用串口进行调试(我用的就是这个方式,也是我目前推荐的对于我们萌萌哒硬件的同学,51调试器暂时还没入手尝试下,串口怎么用呢!简单的说就是打印变量。我这里已经做了下封装,等下把相关代码传到群里。由于时间仓促,写的有可能也有点bug,如有发现还请指出)
最后呢希望大家继续努力,路漫漫其修远兮,上下而求索!
SDA 数据总线
SCL 时钟总线
只有当SCL上的电平为低电平时SDA上的数据才能够变化,也就是说当SCL(时钟总线)上为高电平时SDA(数据总线)
上的数据必须保持稳定。
起始信号和终止信号由通信主机掌控,产生起始信号后通讯总线就处于被占用状态,知道出现终止信号产生,总线就处于空闲状态。
接收到字节后接收器将SCL(时钟总线)拉低,让主机处于等待状态,接受完一个字节后就释放SCL(时钟总线)让数据继续发送
两个一个进行寻地址,一个进行传送数据 关于中间的不应答情况,暂且不要考虑
操作时序 第一步发送一个起始信号,然后发送7位寻址1位方向位(1代表R receiver 接受数据,0代表t 就是发送数据) 从机应答,主机发送数据,从机应答,主机再次发送数据,从机应答或者不应答,这个时候主机进行停止。
我们逐一分析
起始信号:当SCL为高电平的时候,SDA上出现一个下降沿
SDA 1
SCL 1
SDA 0 //出现下降沿
SCL 0 //将SCL置为0 ,表示占用总线
终止信号:当SCL为高电平的时候,SDA上出现一个上升沿
SDA 0
SCL 1
SDA 1 //出现一个上升沿
//结束后,SCL为高电平总线空闲
应答:SCL为高的时候等待SDA发生下降沿跳变,此跳变由从机发出(更准确的来说是,再经过一个时钟周期,再从SDK读入一个数据)
SDA 1
SCL 1
等待SDA 0
非应答:SCL为高的时候等待SDA发生上升沿跳变,此跳变由从机发出(更准确的来说是,再经过一个时钟周期,再从SDK读入一个数据)
注意读数据过程
先写入
开始
地址
开始
地址
读取
AT24C02代码处
.#include “i2c.h”
.#include “usart.h”
/*********************************************************************
* 函数名 : Delay10us()
* 函数功能 : 延时10us
* 输入 : 无
* 输出 : 无
*********************************************************************/
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b–)
for(a=2;a>0;a–);
}
/*********************************************************************
* 函数名 : I2cStart()
* 函数功能 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
* 输入 : 无
* 输出 : 无
* 备注 : 起始之后SDA和SCL都为0
*********************************************************************/
void I2cStart()
{
SDA=1;
Delay10us();
SCL=1;
Delay10us();//建立时间是SDA保持时间>4.7us
SDA=0;
Delay10us();//保持时间是>4us
SCL=0;
Delay10us();
}
/*********************************************************************
* 函数名 : I2cStop()
* 函数功能 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
* 输入 : 无
* 输出 : 无
* 备注 : 结束之后保持SDA和SCL都为1;表示总线空闲
*********************************************************************/
void I2cStop()
{
SDA=0;
Delay10us();
SCL=1;
Delay10us();//建立时间大于4.7us
SDA=1;
Delay10us();
}
/*********************************************************************
* 函数名 : I2cSendByte(unsigned char dat)
* 函数功能 : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定
* 输入 : num
* 输出 : 0或1。发送成功返回1,发送失败返回0
* 备注 : 发送完一个字节SCL=0,SDA=1
*********************************************************************/
unsigned char I2cSendByte(unsigned char dat)
{
unsigned char a=0,b=0;//最大255,一个机器周期为1us,最大延时255us。
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA=dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat=dat<<1;
Delay10us();
SCL=1;
Delay10us();//建立时间>4.7us
SCL=0;
Delay10us();//时间大于4us
}
SDA=1;
Delay10us();
SCL=1;
while(SDA)//等待应答,也就是等待从设备把SDA拉低
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
SCL=0;
Delay10us();
return 0;
}
}
SCL=0;
Delay10us();
return 1;
}
/*********************************************************************
* 函数名 : I2cReadByte()
* 函数功能 : 使用I2c读取一个字节
* 输入 : 无
* 输出 : dat
* 备注 : 接收完一个字节SCL=0,SDA=1.
*********************************************************************/
unsigned char I2cReadByte()
{
unsigned char a=0,dat=0;
SDA=1; //起始和发送一个字节之后SCL都是0
Delay10us();
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
Delay10us();
dat<<=1;
dat|=SDA;
Delay10us();
SCL=0;
Delay10us();
}
return dat;
}
/*********************************************************************
* 函数名 : void At24c02Write(unsigned char addr,unsigned char dat)
* 函数功能 : 往24c02的一个地址写入一个数据
* 输入 : 无
* 输出 : 无
*********************************************************************/
void At24c02Write(unsigned char addr,unsigned char dat)
{
I2cStart();
I2cSendByte(0xa0);//发送写器件地址
I2cSendByte(addr);//发送要写入内存地址
I2cSendByte(dat); //发送数据
I2cStop();
}
/*********************************************************************
* 函数名 : unsigned char At24c02Read(unsigned char addr)
* 函数功能 : 读取24c02的一个地址的一个数据
* 输入 : 无
* 输出 : 无
*********************************************************************/
unsigned char At24c02Read(unsigned char addr)
{
unsigned char num;
I2cStart();
I2cSendByte(0xa0); //发送写器件地址
I2cSendByte(addr); //发送要读取的地址
I2cStart();
I2cSendByte(0xa1); //发送读器件地址
num=I2cReadByte(); //读取数据
I2cStop();
return num;
}
就到这里吧!低功耗蓝牙还没来得及封装,还有连接和通信也没进行总结!加油!