当前位置: 首页 > 工具软件 > i51 > 使用案例 >

在51单片机上实现I2C通信

温星华
2023-12-01

在51单片机上实现I2C通信

代码较复杂,跟着老师来都会比较混乱

#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char

sbit dula = P2^6;
sbit wela = P2^7;
sbit SCL = P2^1;
sbit SDA = P2^0;

void time0Init();
void display(uchar);
void delayms(uchar);
void delay5us();
void I2C_Stop();
void I2C_Start();
void I2CSendByte(uchar);

uchar count1,num;
uchar code SMGwei[] = {0xfe,0xfd,0xfb};
uchar code SMGduan[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
bit ACKflag;        //声明ACKflag 为字节变量
/*I2C通信初始化*/
void I2C_Start()        //起始信号
{
    SCL = 1;
    SDA = 1;
    delay5us();
    SDA = 0;
    delay5us();
}
void I2C_Stop()         //停止信号
{
    SCL = 0;
    SDA = 0;
    SCL = 1;
    delay5us();
    SDA = 1;
    delay5us();
}
/*I2C应答和非应答*/

//I2C主机读从机应答
bit ReadACK()
{
    SCL = 0;
    SCL = 1;
    delay5us();
    if(SDA)//非应答
    {
        SCL = 0;
        return (1);
    }
    else//应答
    {
        SCL = 0;
        return(0);
    }
}
//I2C主机发送应答
void sendACK(bit i)
{
    SCL = 0;
    if(i)
        SDA = 1;
    else
        SDA = 0;
    SCL = 1;
    delay5us();
    SCL = 0;
    SDA = 1;    //释放数据总线
}
void At24c02Write(uchar adress,DAT)
{
    I2C_Start();
    /*发送器件地址 + Write(0)*/
    I2CSendByte(0xA0 + 0);
    /*读是否应答*/
    if(ReadACK())   //若为1 从机没有应答
        ACKflag = 1;        //无应答
    else
        ACKflag = 0;        //应答

    /*写入首地址(放在256个容器中的哪一个)*/
    I2CSendByte(adress);
    /*读是否应答*/
    if(ReadACK())   //若为1 从机没有应答
        ACKflag = 1;        //无应答
    else
        ACKflag = 0;        //应答
    I2CSendByte(DAT);
    /*读是否应答*/
    if(ReadACK())   //若为1 从机没有应答
        ACKflag = 1;        //无应答
    else
        ACKflag = 0;        //应答
    I2C_Stop();

}
uchar I2cReadByte()
{
    uchar j,DAT;
    for(j = 0;j<8;j++)
    {
        DAT <<=1;
        SCL = 0;
        SCL = 1;
        if(SDA)
            DAT |= 0X01;
    }
    return (DAT);
}
uchar At24c02Read(uchar adress)
{
    uchar DAT;
    I2C_Start();
    /*发送器件地址 + Write(0)*/
    I2CSendByte(0xA0 + 0);
    /*读是否应答*/
    if(ReadACK())   //若为1 从机没有应答
        ACKflag = 1;        //无应答
    else
        ACKflag = 0;        //应答

    /*写入首地址(放在256个容器中的哪一个)*/
    I2CSendByte(adress);
    ReadACK();//不管应不应答
    I2C_Start();
    /*从机地址+1*/
    I2CSendByte(0xA0 + 1);
    if(ReadACK())   //若为1 从机没有应答
        ACKflag = 1;        //无应答
    else
        ACKflag = 0;        //应答
    DAT = I2cReadByte();      //读一字节
    sendACK(1);
    I2C_Stop();
    return (DAT);
}
void I2CSendByte(uchar DAT)      //发送一个字节
{
    uchar i;
    for(i = 0;i < 8; i++)
    {
        SCL = 0;        //拉低时钟线才能允许数据变化
        if(DAT & 0X80)
            SDA = 1;
        else
            SDA = 0;
        SCL = 1;
        DAT <<= 1;
    }
    SCL = 0;
    SDA = 1;//释放数据总线
}
/*数码管显示函数*/
void display(uchar num)
{
    static uchar wei;
    P0 = 0xff;
    wela = 1;
    P0 = SMGwei[wei];
    wela = 0;
    switch(wei)
    {
        case 0: dula = 1; P0 = SMGduan[num/100];    dula =0; break;
        case 1: dula = 1; P0 = SMGduan[num%100/10]; dula =0; break;
        case 2: dula = 1; P0 = SMGduan[num%10];     dula =0; break;
    }
    P0 =0xff;
    wei++;
    if(wei == 3)
    {
        wei = 0;
    }
}
/*time0定时器初始化函数*/
void time0Init()        //1MS
{
    TR0 = 1;
    TMOD |= 0X01;
    TH0 = 0x0F0;
    TL0 = 0x60;
    EA = 1;
    ET0 = 1;
}
/*time0定时器中断函数*/
void time0() interrupt 1
{
    TF0 = 0;
    TH0 = 0x0F0;
    TL0 = 0x60;
    display(num);
}
/*1.延时函数    2.延时5微秒函数*/
void delayms(uchar xms)
{
    uchar i,j;
    for(i=xms;i>0;i--)
        for(j=110;j>0;j--);
}
void delay5us()
{
    _nop_();    //延时5微妙
}
/*主函数*/
void main()
{
    time0Init();
    EA = 0;     //屏蔽中断
    At24c02Write(3,258);
		delayms(5);
    num = At24c02Read(3);
    if(!ACKflag)
    {
        P1 = 0;
    }
    else
    {
        P1 = 0xff;
    }//若应答则P1口上的全部灯亮
    EA = 1;     //开中断
    while(1);   //等待中断发生
}
 类似资料: