标题:
单片机iic连续读取epprom出错的问题解决
[打印本页]
作者:
maowentao0416
时间:
2018-9-3 09:32
标题:
单片机iic连续读取epprom出错的问题解决
现象:单个读取字符正确,连续读取字符出错环境:stc89c52单片机 24C02的epprom
我的解决办法:
IIC_wirte 8bit时等待ack,如无ack,则stop-->start 重新发起信号,结果解决问题,下面贴出代码:
#include <reg52.h>
#include "intrins.h"
#include "type.h"
#include "i2c.h"
sbit SCL=P2^1;
sbit SDA=P2^0;
#define IIC_WRITE 0xA0
#define IIC_READ 0xA1
static void delay10Us(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函数名 : Delay10us()
* 函数功能 : 延时10us
* 输入 : 无
* 输出 : 无
*******************************************************************************/
/*
void Delay10us()
{
}
*/
/*******************************************************************************
* 函数名 : I2cStart()
* 函数功能 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
* 输入 : 无
* 输出 : 无
* 备注 : 起始之后SDA和SCL都为0
*******************************************************************************/
void I2cStart()
{
SCL=0;
delay10Us(1);
SDA=1;
SCL=1;
delay10Us(1);//建立时间是SDA保持时间>4.7us
SDA=0;
delay10Us(1);//保持时间是>4us
}
/*******************************************************************************
* 函数名 : I2cStop()
* 函数功能 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
* 输入 : 无
* 输出 : 无
* 备注 : 结束之后保持SDA和SCL都为1;表示总线空闲
*******************************************************************************/
void I2cStop()
{
SCL=0;
delay10Us(1);
SDA=0;
SCL=1;
delay10Us(1);
SDA=1;
delay10Us(1);
}
/*******************************************************************************
* 函数名 : 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。
SCL=0;
delay10Us(1);
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
SDA = dat>>7; //起始信号之后SCL=0,所以可以直接改变SDA信号
dat = dat<<1;
delay10Us(1);
SCL=1;
delay10Us(2);
SCL=0;
delay10Us(1);
}
SDA=1;
delay10Us(1);
SCL=1;
while(SDA)//等待应答,也就是等待从设备把SDA拉低
{
b++;
if(b>200) //如果超过2000us没有应答发送失败,或者为非应答,表示接收结束
{
return 0;
}
delay10Us(1);
}
return 1;
}
/*******************************************************************************
* 函数名 : I2cReadByte()
* 函数功能 : 使用I2c读取一个字节
* 输入 : 无
* 输出 : dat
* 备注 : 接收完一个字节SCL=0,SDA=1.
*******************************************************************************/
unsigned char I2cReadByte()
{
unsigned char a=0,dat=0;
SCL = 0;
delay10Us(1);
SDA=1; //起始和发送一个字节之后SCL都是0
delay10Us(1);
for(a=0;a<8;a++)//接收8个字节
{
SCL=1;
delay10Us(2);
dat<<=1;
dat|=SDA;
SCL=0;
delay10Us(1);
}
return dat;
}
/*******************************************************************************
* 函数名 : void At24c02Write(unsigned char addr,unsigned char dat)
* 函数功能 : 往24c02的一个地址写入一个数据
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void At24c02Write(unsigned char addr,unsigned char dat)
{
unsigned char ret;
again:
I2cStart();
ret = I2cSendByte(IIC_WRITE);//发送写器件地址
if(!ret){
I2cStop();
goto again;
}
ret = I2cSendByte(addr);//发送要写入内存地址
if(!ret){
I2cStop();
goto again;
}
ret = I2cSendByte(dat); //发送数据
if(!ret){
I2cStop();
goto again;
}
I2cStop();
}
/*******************************************************************************
* 函数名 : unsigned char At24c02Read(unsigned char addr)
* 函数功能 : 读取24c02的一个地址的一个数据
* 输入 : 无
* 输出 : 无
*******************************************************************************/
unsigned char At24c02Read(unsigned char addr)
{
unsigned char num;
unsigned char ret;
again:
I2cStart();
ret = I2cSendByte(IIC_WRITE); //发送器件写地址
if(!ret){
I2cStop();
goto again;
}
ret = I2cSendByte(addr); //发送要读取的地址
if(!ret){
I2cStop();
goto again;
}
I2cStart();
ret = I2cSendByte(IIC_READ); //发送读器件地址
if(!ret){
I2cStop();
goto again;
}
num=I2cReadByte(); //读取数据
NoAck();
I2cStop();
return num;
}
/*
非应答
*/
void NoAck(void)
{
SCL=0;
SDA=1;
delay10Us(1);
SCL=1;
delay10Us(2);
}
/*
应答信号
*/
void Ack(void)
{
SCL=0;
SDA=0;
delay10Us(1);
SCL=1;
delay10Us(2);
}
/*******************************************************************************
* 函数名 : unsigned char At24c02Read(unsigned char addr)
* 函数功能 : 读取24c02的一个地址的一个数据
* 输入 : 无
* 输出 : -1:error 0:success
*******************************************************************************/
void At24c02ReadBytes(unsigned char addr,unsigned char *dat,unsigned char n)
{
//unsigned char num = n;
unsigned char ret;
again:
I2cStart();
ret=I2cSendByte(0xa0); //发送写器件地址
if(!ret){
I2cStop();
goto again;
}
ret=I2cSendByte(addr); //发送要读取的地址
if(!ret){
I2cStop();
goto again;
}
I2cStart();
ret=I2cSendByte(0xa1); //发送读器件地址
if(!ret){
I2cStop();
goto again;
}
if(addr + n >256)
{
n = 256 - addr;
}
while(n--)
{
*dat = I2cReadByte(); //读取数据
if(n!=0) Ack();
dat++;
}
I2cStop();
//return num;
}
/*******************************************************************************
* 函数名 : unsigned char At24c02Read(unsigned char addr)
* 函数功能 : 读取24c02的一个地址的一个数据
* 输入 : 无
* 输出 : 无
*******************************************************************************/
/*******************************************************************************
* 函数名 : void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
* 函数功能 : 从地址addr开始,连续读取n个字符,读取字符放入dat中
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
dat[i]= At24c02Read(addr+i);
}
/*******************************************************************************
* 函数名 : void At24c02ReadBytes2(unsigned char addr,unsigned char *dat,unsigned char n)
* 函数功能 : 将dat中的字符写入addr开始的epprom中去,写入n个
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void At24c02WriteBytes(unsigned char addr,unsigned char *dat,unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
{
At24c02Write(addr+i,dat[i]);
}
}
复制代码
上诉代码的关键点在
I2cSendByte
这个方法有返回值,当I2cSendByte的返回值是1说明成功
1、在At24c02Write函数中利用goto语句来处理
写
出错;
2、At24c02Read 利用goto语句来处理地址写出错
3、At24c02ReadBytes 同上
总结:
1、在iic的连续read过程一定要有ACK
2、起始信号之后的器件地址写,存储器地址、器件地址读 这三个地址时,确保收到epprom发来的ack
单片机交流学习群:
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1