51单片机在AT24C02读取数据的时候读不到
本帖最后由 djdgf4 于 2023-3-20 22:12 编辑写了一个按键控制led移位、存储和读取的程序,反复测试,读取P2的时候总是0x00,。AT24C02器件本身没问题,配置代码也没问题,因为开另一个使用24C02的工程的时候一切正常,可以存储读取
工程如下:
main.c:
#include <REGX52.H>
#include "Delay.h"
#include "AT24C02.h"
#include "key.h"
//#include "MatrixKey.h"
#define uchar unsigned char
#define StorageAddress 0xF1 //数据存储地址
#if 1
void main()
{
uchar KeyNum;
uchar LED_shift = 0;
P2 = ~0X01;
while (1)
{
KeyNum = key();
if(KeyNum == 1)//左移
{
Delay(5);
if (LED_shift >= 8)
{
LED_shift = 0;
}
P2 = ~(0x01 << ++LED_shift);
Delay(5);
}
if(KeyNum == 2)//右移
{
Delay(5);
if (LED_shift == 0)
{
LED_shift = 8;
}
P2 = ~(0x01 << --LED_shift);
Delay(5);
}
if (KeyNum == 3)
{
AT24C02_SendData(StorageAddress, P2);//把P2存入AT24C02
Delay(5);
}
if(KeyNum == 4)
{
P2 = AT24C02_ReceiveData(StorageAddress);//从AT24C02读取P2
}
}
}
#endif
AT24C02.C:
#include "I2C.h"
#define uchar unsigned char
#define SLAVE_ADDRESS 0XA0
/**
*@brief AT24C02写入一个字节
*@Param WordAddress 要写入字节的地址
*@param Data 要写入的数据
*@retva 无
*/
void AT24C02_SendData(uchar WordAddress, uchar Data)
{
I2C_Start();
I2C_SendByte(SLAVE_ADDRESS);
I2C_ReceiveACK();
I2C_SendByte(WordAddress);
I2C_ReceiveACK();
I2C_SendByte(Data);
I2C_ReceiveACK();
I2C_Stop();
}
/**
*@brief AT24C02读取一个字节
*@param WordAddress 要读出字节的地址
*@retva Data 读出的数据
*/
uchar AT24C02_ReceiveData(uchar WordAddress)
{
uchar Data;
I2C_Start();
I2C_SendByte(SLAVE_ADDRESS);
I2C_ReceiveACK();
I2C_SendByte(WordAddress);
I2C_ReceiveACK();
I2C_Start();
I2C_SendByte(SLAVE_ADDRESS | 0x01);
I2C_ReceiveACK();
Data = I2C_ReceiveByte();
I2C_SendACK(1);
I2C_Stop();
return Data;
}
I2C.c:
#include <REGX52.H>
sbit I2C_SDA = P2^0;
sbit I2C_SCL = P2^1;
#define uchar unsigned char
/*
*@brief I2C开始
*@param
*@retva
*/
void I2C_Start()
{
I2C_SCL = 0;
I2C_SDA = 1;
I2C_SCL = 1;
I2C_SDA = 0;
}
/*
*@brief I2C停止
*@param
*@retva
*/
void I2C_Stop()
{
I2C_SDA = 0;
I2C_SCL = 1;
I2C_SDA = 1;
}
/*
*@brief I2C发送一个字节
*@param Byte 要发送的字节
*@retva
*/
void I2C_SendByte(uchar Data)
{
uchar i;
I2C_SDA = 0; // 在接收前释放SDA
for (i = 0; i < 8; i++)
{
I2C_SCL = 0;
I2C_SDA = Data;
I2C_SCL = 1;
}
}
/*
*@brief I2C接受一个字节
*@param 无
*@retva Byte 接收到的字节数据
*/
uchar I2C_ReceiveByte()
{
uchar Data;
uchar i;
I2C_SDA = 0;
for (i = 0; i < 8; i++)
{
I2C_SCL = 0;
Data = I2C_SDA;
I2C_SCL = 1;
}
return Data;
}
/*
*@brief I2C发送应答
*@param ACKBit 应答位,0为应答,1为非应答
*@retva
*/
void I2C_SendACK(bit ACK_Sending)
{
I2C_SCL = 0;
I2C_SDA = ACK_Sending;
I2C_SCL = 1;
}
/*
*@brief I2C接受应答位
*@param 无
*@retva ACKBit 接收到的应答位
*/
uchar I2C_ReceiveACK()
{
bit ACK_Receiving;
I2C_SCL = 0;
ACK_Receiving = I2C_SDA;
I2C_SCL = 1;
return ACK_Receiving;
}
经过调试,发现在从写入AT24C02函数 AT24C02_SendData 出来的时候数据就错了,再仔细调试发现,在I2C_ReceiveByte函数结束的时候,data变成了0x00。
经过比对,发现整个I2C的具体实现都有~瑕疵~,重新改写I2c如下,烧录,完美解决。
#include <REGX52.H>
sbit I2C_SDA = P2^0;
sbit I2C_SCL = P2^1;
#define uchar unsigned char
/*
*@brief I2C开始
*@param
*@retva
*/
void I2C_Start()
{
I2C_SDA = 1;
I2C_SCL = 1;
I2C_SDA = 0;
I2C_SCL = 0;
}
/*
*@brief I2C停止
*@param
*@retva
*/
void I2C_Stop()
{
I2C_SDA = 0;
I2C_SCL = 1;
I2C_SDA = 1;
}
/*
*@brief I2C发送一个字节
*@param Byte 要发送的字节
*@retva
*/
void I2C_SendByte(uchar Data)
{
uchar i;
//I2C_SDA = 0; // 在接收前释放SDA,释放SDA,就是将IO置1
/*这句没有必要*/
for (i = 0; i < 8; i++)
{
I2C_SDA = Data & (0x80 >> i);
I2C_SCL = 1;
I2C_SCL = 0;
}
}
/*
*@brief I2C接受一个字节
*@param 无
*@retva Byte 接收到的字节数据
*/
uchar I2C_ReceiveByte()
{
uchar Data = 0;
uchar i;
I2C_SDA = 1;// 在接收前释放SDA
for (i = 0; i < 8; i++)
{
//Data = I2C_SDA;傻逼,写错了
I2C_SCL = 1;
if (I2C_SDA)
{
Data |= (0x80 >> i);
}
I2C_SCL = 0;
}
return Data;
}
/*
*@brief I2C发送应答
*@param ACKBit 应答位,0为应答,1为非应答
*@retva
*/
void I2C_SendACK(bit ACK_Sending)
{
//I2C_SCL = 0;这句没必要
I2C_SDA = ACK_Sending;
I2C_SCL = 1;
I2C_SCL = 0;
}
/*
*@brief I2C接受应答位
*@param 无
*@retva ACKBit 接收到的应答位
*/
uchar I2C_ReceiveACK()
{
bit ACK_Receiving;
I2C_SDA= 1;// 在接收前释放SDA
I2C_SCL = 1;
ACK_Receiving = I2C_SDA;
I2C_SCL = 0;
return ACK_Receiving;
}
> I2C总线释放SDA是将IO口置1的原因是:
>
> I2C总线的IO口是开漏或开集电极模式,即只能输出低电平或高阻态。
> 当IO口为高阻态时,SDA可以被其他设备拉高或拉低,即释放了对总线的控制权。
> SDA和SCL都为高电平时,表示总线空闲或结束信号。 换用其他io口试试呢 单独写给读取P2的程序看看,是不是P2口虚焊了 很厉害的样子还行吧 很厉害的样子还行吧 zhujue 发表于 2023-3-19 17:08
大佬这么牛,不顶不行啊,代码也很详尽。可以抄作业啦
代码已经改过来了
页:
[1]