基于PIC24FJ256GB106读写ROM 24C1024时,读出数据总是不对
时间:10-02
整理:3721RD
点击:
基于PIC24FJ256GB106读写ROM 24C1024时,读出数据总是不对,哪位大牛给看看呀
读出数据一直都是0xffff,不知道问题出在哪里呀呀
#include <p24fxxxx.h>
void InitI2C(void);
void WaitMI2C(void);
void I2C_write(unsigned char data);
void I2C_BYTE_WRITE(unsigned char addhigh,unsigned char addmid,unsigned char addlow,unsigned char data);
unsigned char I2C_BYTE_READ(unsigned char addhigh,unsigned char addmid,unsigned char addlow);
void I2C_ACK_CHECK(void);
#define StartI2C() I2C1CONbits.SEN=1 //启动I2C
#define StopI2C() I2C1CONbits.PEN=1 //停止I2C
#define RstartI2C() I2C1CONbits.RSEN=1 //重新启动I2C
#define NACKI2C() I2C1CONbits.ACKDT=1;I2C1CONbits.ACKEN=1 //发送不应答信号
#define ACKI2C() I2C1CONbits.ACKDT=0;I2C1CONbits.ACKEN=1 //发送应答信号
#define RecI2C() I2C1CONbits.RCEN=1 //使能接收允许位
#define CMD_W24C01 0XA0
#define CMD_R24C01 0XA1
unsigned char I2C_Data; //读写24C01的数据暂存单元
unsigned char I2C_Addr; //读写24C01的地址暂存单元
unsigned char I2C_DATA_BACK; //写入24C01的数据备份单元
unsigned char I2C_STEP = 0; //调试变量,一旦I2C死机,监视执行到哪个步骤死机
void delay_ms(unsigned char count) //1ms延时
{
unsigned int i,j;
for(i = 0 ; i < count ; i++)
{
for(j = 0 ; j < 0x2eda; j++);
}
}
int main(void)
{
CLKdiv = 0; //CPU时钟为32MHZ,外设总线与CPU时钟一致
while(OSCCONbits.LOCK == 0); //等待PLL时钟稳定,如果上电后有重要IO要马上设置,此语句可挪到IO初使化后
_DISI = 1 ; //使能DISI指令,某些内建函数需要配合DISI指令操作
CM2CON = 0 ; //模拟比较器2关闭,RB0~3的比较器复用功能关闭
ODCB &= 0x0000 ; //RB0~3设置为正常的双向口,其它不变
AD1PCFGL |= 0xFFFF ;//AN0~3设置为数字口,其它不变
TRISB &= 0X0000 ; //TRISB低4位清0,置输出
//实验板L4~L1,默认分别对应RB3~0,全亮
InitI2C();
I2C_Addr = 0x66; //0到127之间有效
I2C_Data=0x49;
I2C_DATA_BACK = 0X49;
I2C_BYTE_WRITE(0x00,0x00,I2C_Addr,I2C_Data);
// I2C_ACK_CHECK(); //dsPIC30/PIC24可直接调用此函数后进行读,PIC32还得加延时(错误:执行该语句便进入死循环)
LATB=0x0002;
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
I2C_Data = 0;
I2C_Data = I2C_BYTE_READ(0x00,0x23,I2C_Addr); //如果读回来的即为写下去的0x49,读写都OK,
//如果读回来为0XFF,未必代表写失败。
LATB=I2C_Data&0X000F ; //LATB低4位送1,其它不变
while(1);
}
/*
函数功能:I2C初使化
入口参数:无
出口参数:无
调用说明:无
*/
void InitI2C(void)
{
_ODD9 = 1; //RD9/10设置OC功能打开
_ODD10 = 1; //
LATDbits.LATD9 = 1;
LATDbits.LATD10 = 1;
TRISDbits.TRISD9 = 1;
TRISDbits.TRISD10 = 1;
I2C1CON = 0X8000;
I2C1STAT = 0;
I2C1BRG = 159; //16mips,调整到接近100KHZ
}
/*
函数说明:通用的等待I2C各种动作完成函数
入口参数:无
出口参数:无
调用说明:无
*/
void WaitMI2C(void)
{
while(_MI2C1IF == 0); //判断MI2CIF以判定各种动作是否完成
Nop();
Nop();
_MI2C1IF = 0; //清标志位
}
void I2C_write(unsigned char data)
{
while (I2C1STATbits.TBF); //传输正在进行中,等待
I2C1TRN = data; //写入数据
}
void I2C_BYTE_WRITE(unsigned char addhigh,unsigned char addmid,unsigned char addlow,unsigned char data)
{
unsigned char temp_i2cdata,add;
StartI2C(); //1, 启动I2C
WaitMI2C(); //等待启动完成
add=CMD_W24C01|addhigh;
I2C_write(add); //2, 送入命令,
//地址+读写方式,地址为101 0000 ,写方式=0
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
I2C_write(addmid); //3,要操作24C1024的高地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(addlow); //3,要操作24C1024的地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(data); //4,要写入24C01的数据值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
StopI2C(); //5,发送停止信号
WaitMI2C(); //
//
}
unsigned char I2C_BYTE_READ(unsigned char addhigh,unsigned char addmid,unsigned char addlow)
{
unsigned char data;
unsigned char temp_i2cdata,add_w,add_r;
StartI2C(); //1, 启动I2C
WaitMI2C(); //等待启动完成
add_w=CMD_W24C01|addhigh;
I2C_write(add_w); //2, 送入命令,
//地址+读写方式,地址为101 0000 ,写方式=0
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
I2C_write(addmid); //3,要操作24C1024的高地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(addlow); //3,要操作24C1024的地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
RstartI2C(); //4,发送重启动信号
WaitMI2C();
add_r=CMD_R24C01|addhigh;
I2C_write(add_r); //5, 送入命令,
//地址+读写方式,地址为101 0000 ,读方式=1
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
RecI2C(); //6,使能接收
WaitMI2C();
data = I2C1RCV; //7,保存数据
NACKI2C(); //8,发送非应答信号,停止从发送方的发送
WaitMI2C();
StopI2C(); //9,发送停止信号
WaitMI2C();
return (data); //10,返回读到的数据
}
/*
函数功能;通过发读命令检测I2C总线是否空闲
入口参数:无
出口参数:无
调用说明:PIC24F/dsPIC30F上均可用,PIC32上还需配合延时函数
*/
void I2C_ACK_CHECK(void)
{
do
{
StartI2C();
WaitMI2C();
I2C_write(CMD_R24C01);
WaitMI2C();
StopI2C();
WaitMI2C();
LATB=I2C1STATbits.ACKSTAT&0X000F;
}
while(I2C1STATbits.ACKSTAT);
}
读出数据一直都是0xffff,不知道问题出在哪里呀呀
#include <p24fxxxx.h>
void InitI2C(void);
void WaitMI2C(void);
void I2C_write(unsigned char data);
void I2C_BYTE_WRITE(unsigned char addhigh,unsigned char addmid,unsigned char addlow,unsigned char data);
unsigned char I2C_BYTE_READ(unsigned char addhigh,unsigned char addmid,unsigned char addlow);
void I2C_ACK_CHECK(void);
#define StartI2C() I2C1CONbits.SEN=1 //启动I2C
#define StopI2C() I2C1CONbits.PEN=1 //停止I2C
#define RstartI2C() I2C1CONbits.RSEN=1 //重新启动I2C
#define NACKI2C() I2C1CONbits.ACKDT=1;I2C1CONbits.ACKEN=1 //发送不应答信号
#define ACKI2C() I2C1CONbits.ACKDT=0;I2C1CONbits.ACKEN=1 //发送应答信号
#define RecI2C() I2C1CONbits.RCEN=1 //使能接收允许位
#define CMD_W24C01 0XA0
#define CMD_R24C01 0XA1
unsigned char I2C_Data; //读写24C01的数据暂存单元
unsigned char I2C_Addr; //读写24C01的地址暂存单元
unsigned char I2C_DATA_BACK; //写入24C01的数据备份单元
unsigned char I2C_STEP = 0; //调试变量,一旦I2C死机,监视执行到哪个步骤死机
void delay_ms(unsigned char count) //1ms延时
{
unsigned int i,j;
for(i = 0 ; i < count ; i++)
{
for(j = 0 ; j < 0x2eda; j++);
}
}
int main(void)
{
CLKdiv = 0; //CPU时钟为32MHZ,外设总线与CPU时钟一致
while(OSCCONbits.LOCK == 0); //等待PLL时钟稳定,如果上电后有重要IO要马上设置,此语句可挪到IO初使化后
_DISI = 1 ; //使能DISI指令,某些内建函数需要配合DISI指令操作
CM2CON = 0 ; //模拟比较器2关闭,RB0~3的比较器复用功能关闭
ODCB &= 0x0000 ; //RB0~3设置为正常的双向口,其它不变
AD1PCFGL |= 0xFFFF ;//AN0~3设置为数字口,其它不变
TRISB &= 0X0000 ; //TRISB低4位清0,置输出
//实验板L4~L1,默认分别对应RB3~0,全亮
InitI2C();
I2C_Addr = 0x66; //0到127之间有效
I2C_Data=0x49;
I2C_DATA_BACK = 0X49;
I2C_BYTE_WRITE(0x00,0x00,I2C_Addr,I2C_Data);
// I2C_ACK_CHECK(); //dsPIC30/PIC24可直接调用此函数后进行读,PIC32还得加延时(错误:执行该语句便进入死循环)
LATB=0x0002;
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
I2C_Data = 0;
I2C_Data = I2C_BYTE_READ(0x00,0x23,I2C_Addr); //如果读回来的即为写下去的0x49,读写都OK,
//如果读回来为0XFF,未必代表写失败。
LATB=I2C_Data&0X000F ; //LATB低4位送1,其它不变
while(1);
}
/*
函数功能:I2C初使化
入口参数:无
出口参数:无
调用说明:无
*/
void InitI2C(void)
{
_ODD9 = 1; //RD9/10设置OC功能打开
_ODD10 = 1; //
LATDbits.LATD9 = 1;
LATDbits.LATD10 = 1;
TRISDbits.TRISD9 = 1;
TRISDbits.TRISD10 = 1;
I2C1CON = 0X8000;
I2C1STAT = 0;
I2C1BRG = 159; //16mips,调整到接近100KHZ
}
/*
函数说明:通用的等待I2C各种动作完成函数
入口参数:无
出口参数:无
调用说明:无
*/
void WaitMI2C(void)
{
while(_MI2C1IF == 0); //判断MI2CIF以判定各种动作是否完成
Nop();
Nop();
_MI2C1IF = 0; //清标志位
}
void I2C_write(unsigned char data)
{
while (I2C1STATbits.TBF); //传输正在进行中,等待
I2C1TRN = data; //写入数据
}
void I2C_BYTE_WRITE(unsigned char addhigh,unsigned char addmid,unsigned char addlow,unsigned char data)
{
unsigned char temp_i2cdata,add;
StartI2C(); //1, 启动I2C
WaitMI2C(); //等待启动完成
add=CMD_W24C01|addhigh;
I2C_write(add); //2, 送入命令,
//地址+读写方式,地址为101 0000 ,写方式=0
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
I2C_write(addmid); //3,要操作24C1024的高地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(addlow); //3,要操作24C1024的地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(data); //4,要写入24C01的数据值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
StopI2C(); //5,发送停止信号
WaitMI2C(); //
//
}
unsigned char I2C_BYTE_READ(unsigned char addhigh,unsigned char addmid,unsigned char addlow)
{
unsigned char data;
unsigned char temp_i2cdata,add_w,add_r;
StartI2C(); //1, 启动I2C
WaitMI2C(); //等待启动完成
add_w=CMD_W24C01|addhigh;
I2C_write(add_w); //2, 送入命令,
//地址+读写方式,地址为101 0000 ,写方式=0
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
I2C_write(addmid); //3,要操作24C1024的高地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
I2C_write(addlow); //3,要操作24C1024的地址值发送到I2C总线
WaitMI2C();
temp_i2cdata = I2C1RCV; //
RstartI2C(); //4,发送重启动信号
WaitMI2C();
add_r=CMD_R24C01|addhigh;
I2C_write(add_r); //5, 送入命令,
//地址+读写方式,地址为101 0000 ,读方式=1
WaitMI2C(); //等待写入完成
temp_i2cdata = I2C1RCV; //
RecI2C(); //6,使能接收
WaitMI2C();
data = I2C1RCV; //7,保存数据
NACKI2C(); //8,发送非应答信号,停止从发送方的发送
WaitMI2C();
StopI2C(); //9,发送停止信号
WaitMI2C();
return (data); //10,返回读到的数据
}
/*
函数功能;通过发读命令检测I2C总线是否空闲
入口参数:无
出口参数:无
调用说明:PIC24F/dsPIC30F上均可用,PIC32上还需配合延时函数
*/
void I2C_ACK_CHECK(void)
{
do
{
StartI2C();
WaitMI2C();
I2C_write(CMD_R24C01);
WaitMI2C();
StopI2C();
WaitMI2C();
LATB=I2C1STATbits.ACKSTAT&0X000F;
}
while(I2C1STATbits.ACKSTAT);
}
是不是单片机复位时可以保存,并且存储的数据存储正常。但是断电后保存的数据不正常。