/*******************************************************************
AT24C64的读写程序
********************************************************************/
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
#define uint unsigned int
#define _Nop() _nop_() /*定义空指令*/
sbit SDA=P1^0; /*模拟I2C数据传送位*/
sbit SCL=P1^1; /*模拟I2C时钟控制位*/
bit ack; /*应答标志位*/
uint one_minute;
bit timer0_flag;
/************************
名称:mDelay
功能:延时
输入参数:j
输出参数:无
**************************/
void mDelay(unsigned char j)//A normal delay
{
unsigned int i;
for(;j>0;j--)
{
for(i=0;i<125;i++)
{;}
}
}
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
SDA=1; /*发送起始条件的数据信号*/
_Nop();
SCL=1;
_Nop(); /*起始条件建立时间大于4.7us,延时*/
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; /*发送起始信号*/
_Nop(); /* 起始条件锁定时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; /*钳住I2C总线,准备发送或接收数据 */
_Nop();
_Nop();
}
/*******************************************************************
结束总线函数
函数原型: void Stop_I2c();
功能: 结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{
SDA=0; /*发送结束条件的数据信号*/
_Nop(); /*发送结束条件的时钟信号*/
SCL=1; /*结束条件建立时间大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; /*发送I2C总线结束信号*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
字节数据发送函数
函数原型: void SendByte(uchar c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void SendByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/
else SDA=0;
_Nop();
SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
_Nop();
_Nop(); /*保证时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
else ack=1; /*判断是否接收到应答信号*/
SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字节数据接收函数
函数原型: uchar RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数应答从机。
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
retc=0;
SDA=1; /*置数据线为输入方式*/
for(BitCnt=0;BitCnt<8;BitCnt++)
{
_Nop();
SCL=0; /*置时钟线为低,准备接收数据位*/
_Nop();
_Nop(); /*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=1; /*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
应答子函数
函数原型: void Ack_I2c(bit a);
功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(bit a)
{
if(a==0)SDA=0; /*在此发出应答或非应答信号 */
else SDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop(); /*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();
}
/************************
名称:AT24C64_W
功能:写器件
输入参数:*mcu_address,uint AT24C64_address,uint count
输出参数:无
**************************/
void AT24C64_W(uchar *mcu_address,uint AT24C64_address,uint count)
{
while(count--)
{
Start_I2c();
SendByte(0xa0);
Ack_I2c(0);
SendByte(AT24C64_address/256);
SendByte(AT24C64_address%256);
Ack_I2c(0);
SendByte(*mcu_address);
Ack_I2c(0);
Stop_I2c();
mDelay(10); // waiting for write cycle to be completed
mcu_address++;
AT24C64_address++;
}
}
/************************
名称:AT24C64_R
功能:读器件
输入参数:*mcu_address,uint AT24C64_address,uint count
输出参数:无
**************************/
void AT24C64_R(uchar *mcu_address,uint AT24C64_address,uint count)
{
while(count--)
{
Start_I2c();
SendByte(0xa0);
//Ack_I2c(0);
SendByte(AT24C64_address/256);
SendByte(AT24C64_address%256);
//Ack_I2c(0);
Start_I2c();
SendByte(0xa1);
//Ack_I2c(0);
*mcu_address=RcvByte();
Ack_I2c(1);
Stop_I2c();
mcu_address++;
AT24C64_address++;
}
}
void PC_init()
{
TMOD=0x01; //定时方式1
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1; //开总中断
ET0=1; //定时器中断0
TR0=1; //启动定时器工作
}
void timer0(void) interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
one_minute++;
if(one_minute==100)
{
timer0_flag=1;
}
}
void main()
{
uchar Number[8]={1,0,1,0,1,0,1,0};
unsigned char i=0;
PC_init();
AT24C64_W(Number,0x0058,8);//写入4个数据
mDelay(2000);
Number[0]=0;//将现有的数据清0
Number[1]=0;
Number[2]=0;
Number[3]=0;
AT24C64_R(Number,0x0058,8);//从存储器读出存入的数据*/
mDelay(2000);
while(1)
{
P2=Number;//将这4个数据从P1口显示出来
if(timer0_flag)
{
one_minute=0;
i++;
if(i==8)
i=0;
timer0_flag=0;
}
}
}
哪位大侠帮忙看看这个程序,单步执行可以,但是一起的话就不行了
你“一起”当然不行了。你写的时候,要检测等待应答,你必须手动模拟一个应答,才能过去,否则就停在那儿。
我在调试的时候,都是先把检测应答注释掉,到写片子时候再加上。
欢迎光临 (http://www.51hei.com/bbs/) | Powered by Discuz! X3.1 |