I2C编程实例

来源:互联网 发布:东华软件 公安部 编辑:程序博客网 时间:2024/05/17 01:15

http://hi.baidu.com/%C3%F7%D4%C2%B7%E7%C8%CA/blog/item/fff4b01af80bd6b94bedbc0a.html

#include <reg52.h>        // 包含51单片机寄存器定义的头文件
#include <intrins.h>      //包含_nop_()函数定义的头文件
#define OP_READ 0xa1   // 器件地址以及读取操作,0xa1即为1010 0001B
#define OP_WRITE 0xa0   // 器件地址以及写入操作,0xa1即为1010 0000B
sbit SCL=P3^4;         //将串行时钟总线SCL位定义在为P3.4引脚
sbit SDA=P3^5;          //将串行数据总线SDA位定义在为P3.5引脚
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//定义共阳数码管显示字型码
unsigned char sec=0; //定义计数值,每过1秒,sec加1  
unsigned int count; //定时中断次数  
bit write=0; //写24C08的标志;
sbit shiwei=P2^6; //十位选通定义
sbit gewei=P2^7; //个位选通定义         
sbit K5=P3^2; //清0按键     
/*****************************************************
函数功能:延时1ms
***************************************************/
void delay1ms()
{
   unsigned char i,j;
for(i=0;i<10;i++)
   for(j=0;j<33;j++)
    ;  
}

/*****************************************************
函数功能:延时若干毫秒
入口参数:n
***************************************************/
void delaynms(unsigned char n)
{
   unsigned char i;
for(i=0;i<n;i++)
    delay1ms();
}
/***************************************************
函数功能:开始数据传送
***************************************************/
void start()
// 开始位
{
SDA = 1;    //SDA初始化为高电平“1”
   SCL = 1;    //开始数据传送时,要求SCL为高电平“1”
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
SDA = 0;    //SDA的下降沿被认为是开始信号
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
SCL = 0;    //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
}
/***************************************************
函数功能:结束数据传送
***************************************************/
void stop()// 停止位
{
SDA = 0;     //SDA初始化为低电平“0” _n
SCL = 1;     //结束数据传送时,要求SCL为高电平“1”
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
SDA = 1;    //SDA的上升沿被认为是结束信号
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
_nop_();     //等待一个机器周期
SDA=0;
SCL=0;
}
/***************************************************
函数功能:检测应答位
***************************************************/

bit Ask()                  //检测应答
{
      bit ack_bit;        //储存应答位
        SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,
                 //以让SDA线转由接收设备(AT24Cxx)控制
_nop_();        //等待一个机器周期
_nop_();        //等待一个机器周期
SCL = 1;       //根据上述规定,SCL应为高电平
_nop_();       //等待一个机器周期
_nop_();       //等待一个机器周期
_nop_();       //等待一个机器周期
_nop_();       //等待一个机器周期
_nop_();       //等待一个机器周期
ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节
                //若送高电平,表示没有接收到,传送异常 结束发送
SCL = 0;       //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
return ack_bit;    // 返回AT24Cxx应答位

}

/***************************************************
函数功能:从AT24Cxx读取数据
出口参数:x
***************************************************/
unsigned char ReadData()
// 从AT24Cxx移入数据到MCU
{
unsigned char i;
unsigned char x;   //储存从AT24Cxx中读出的数据
for(i = 0; i < 8; i++)
{
   SCL = 1;                //SCL置为高电平
   x<<=1;                  //将x中的各二进位向左移一位
   x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中
   SCL = 0;                        //在SCL的下降沿读出数据
}
return(x);                //将读取的数据返回
}
/***************************************************
函数功能:向AT24Cxx的当前地址写入数据
入口参数:y (储存待写入的数据)
***************************************************/
//在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0
void WriteCurrent(unsigned char y)
{
unsigned char i;
for(i = 0; i < 8; i++)   // 循环移入8个位
{
    SDA = (bit)(y&0x80);   //通过按位“与”运算将最高位数据送到S
                                    //因为传送时高位在前,低位在后
   _nop_();            //等待一个机器周期  
    SCL = 1;            //在SCL的上升沿将数据写入AT24Cxx     
   _nop_();            //等待一个机器周期
   _nop_();             //等待一个机器周期      
  
   SCL = 0;            //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲
   y <<= 1;           //将y中的各二进位向左移一位
              
}
}
/***************************************************
函数功能:向AT24Cxx中的指定地址写入数据
入口参数:add (储存指定的地址);dat(储存待写入的数据)
***************************************************/
void WriteSet(unsigned char add, unsigned char dat)
// 在指定地址addr处写入数据WriteCurrent
{
start();               //开始数据传递
WriteCurrent(OP_WRITE); //选择要操作的AT24Cxx芯片,并告知要对其写入数据
         Ask();
WriteCurrent(add);       //写入指定地址
Ask();
WriteCurrent(dat);       //向当前地址(上面指定的地址)写入数据
Ask();
stop();                //停止数据传递
delaynms(4);        //1个字节的写入周期为1ms, 最好延时1ms以上
}
/***************************************************
函数功能:从AT24Cxx中的当前地址读取数据
出口参数:x (储存读出的数据)
***************************************************/
unsigned char ReadCurrent()
{
unsigned char x;
start();               //开始数据传递
WriteCurrent(OP_READ);   //选择要操作的AT24Cxx芯片,并告知要读其数据
Ask();
x=ReadData();         //将读取的数据存入x
stop();                //停止数据传递
return x;              //返回读取的数据
}
/***************************************************
函数功能:从AT24Cxx中的指定地址读取数据
入口参数:set_addr
出口参数:x
***************************************************/
unsigned char ReadSet(unsigned char set_addr)
// 在指定地址读取
{
start();                      //开始数据传递
WriteCurrent(OP_WRITE);       //选择要操作的AT24Cxx芯片,并告知要对其写入数据
Ask();
WriteCurrent(set_addr);       //写入指定地址
Ask();
return(ReadCurrent());        //从指定地址读出数据并返回
}
/***********************************************************/
void LEDshow() //LED显示函数   
{

    P0=table[sec/10];
    shiwei=0;
delaynms(2);
shiwei=1;

P0=table[sec%10];
    gewei=0;
delaynms(2);
gewei=1;
}

/***********************************************************/
/***************************************************
函数功能:主函数
***************************************************/

void main(void)
{

TMOD=0x01; //定时器0工作在方式1
ET0=1;
    EA=1;
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //使定时器0.05秒中断一次
    SDA = 1;           // SDA=1,SCL=1,使主从设备处于空闲状态
SCL = 1;        
sec=ReadSet(2);//读出保存的数据赋于sec
TR0=1; //开始计时
   while(1)
   {
      LEDshow();
    if(write==1) //判断计时器是否计时一秒      
    {
    write=0; //清零
    WriteSet(2,sec); //在24c08的地址2中写入数据sec   
    }

    if(K5==0){
    delaynms(10);
    if(K5==0){
    sec=0;
    }
   }
   }
}


/**************************************************************/

void t0(void) interrupt 1 using 0 //定时中断服务函数  
{
TH0=(65536-50000)/256; //对TH0 TL0赋值
TL0=(65536-50000)%256; //重装计数初值
count++; //每过50ms tcnt加一    
if(count==20) //计满20次(1秒)时   
{
   count=0; //重新再计
   sec++;
   write=1; //1秒写一次24C08
   if(sec==100) //定时100秒,在从零开始计时
   {sec=0;}
}
}