OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4462|回复: 1

i2c总线

[复制链接]

22

主题

95

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
378
金钱
378
注册时间
2018-7-16
在线时间
58 小时
发表于 2018-9-24 14:09:06 | 显示全部楼层 |阅读模式
#include <reg52.h>
#include <INTRINS.H>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
sbit SCL = P2^1;
sbit SDA = P2^0;
sbit DS1302 = P2^4;
/*****************************************************************************
** 函数名称:Delay
** 功能描述:延时子程序
******************************************************************************/
void Delay(void)
{
        _nop_();
        _nop_();
        _nop_();
        _nop_();
       
}
/*****************************************************************************
** 函数名称:InitI2C
** 功能描述:配置模拟I2C的IO端口
** 可移植性:注意IO口需支持漏开输出
******************************************************************************/
void InitI2C(void)
{
         SDA = 1;
         SCL = 1;
}
/*****************************************************************************
** 函数名称:I2CStart
** 功能描述:发送I2C总线起始状态
** 输    入:无
** 输    出:无
** 全局变量:无
** 调用模块:Delay_us()
** 可移植性:直接移植
******************************************************************************/
void I2CStart(void)       //通过时序图知道
{
        SDA = 1;   
        Delay();      // 延时子程序
        SCL = 1;
        Delay();
        SDA = 0;
        Delay();
        SCL = 0;


}
/*****************************************************************************
** 函数名称:I2CStop
** 功能描述:发送I2C总线停止起始状态
** 输    入:无
** 输    出:无
** 全局变量:无
** 调用模块:Delay_us()
** 可移植性:直接移植
******************************************************************************/
void I2CStop(void)                  //这里我也知道
{
        SCL = 0;
    Delay();
        SDA = 0;
        Delay();
        SCL = 1;
        Delay();
        SDA = 1;
        Delay();


}
/*****************************************************************************
** 函数名称:I2CSend
** 功能描述:向I2C总线发送一个字节数据,并检测应答
** 输    入:待发送字节byte
** 输    出:无
** 全局变量:无
** 调用模块:Delay_us()
** 可移植性:直接移植
******************************************************************************/
void I2CSend(uint8 byte)
{
        uint8 mask;
        uint8 i;
        uint8 j;               //不知道这个j有啥用

        mask = 0x80;
        for(i = 0; i < 8; i++)     //这个for循环我能理解
        {
                SCL = 0;
                Delay();
                if((mask & byte) == 0)
                {
                        SDA = 0;
                }
                else
                {
                        SDA = 1;
                }
                mask >>= 1;
                Delay();
                SCL = 1;
                Delay();
        }
       
        SCL = 0;             //这里的的我就不能理解了  ,按照时序图应该是应答,可是和时序图对不上,请大佬解惑
        SDA = 1;
        Delay();
        SCL = 1;
        j = SDA;
        Delay();
        SCL = 0;
       
}

/*****************************************************************************
** 函数名称:I2CRead
** 功能描述:从I2C总线读取最后一个字节数据,并发送非应答位
** 输    入:无
** 输    出:接收到的字节byte
** 全局变量:无
** 调用模块:Delay_us()
** 可移植性:直接移植
******************************************************************************/
uint8 I2CRead(void)
{
        uint8 byte;
        uint8 i;

        byte = 0;
        for(i = 0; i < 8; i++)
        {
                SCL = 0;
                SDA = 1;
                Delay();
                SCL = 1;
                Delay();
                byte <<= 1;         
                if(SDA == 1)
                {
                        byte |= 0x01;
                }
                Delay();
        }
        SCL = 0;              //这里同上,不知道为何这样写
        SDA = 1;
        Delay();
        SCL = 1;
        Delay();
        SCL = 0;
       
        return byte;

}
/*****************************************************************************
** 函数名称:I2CReadAck
** 功能描述:从I2C总线读取一个字节数据,并发送应答
** 输    入:无
** 输    出:接收到的字节byte
** 全局变量:无
** 调用模块:Delay_us()
** 可移植性:直接移植
******************************************************************************/
uint8 I2CReadAck(void)               //不知道为什么 有这个读应答
{
        uint8 i;
        uint8 byte;
       
        byte = 0;
        for(i=0;i<8;i++)
        {
                SCL = 0;
                SDA = 1;
                Delay();
                SCL = 1;
                Delay();
                byte <<= 1;
                if(SDA==1) {byte |= 0x01;}
                Delay();
        }
        SCL = 0;
        Delay();
        SDA = 0;
        Delay();
        SCL = 1;
        Delay();
        SCL = 0;
       
        return byte;
}         
/*****************************************************************************
** 函数名称:read_eeprom
** 功能描述:读取EEPROM数据函数(可多片共存)
** 输    入:E2中目的地址addr
** 输    出:读取的数据
** 全局变量:无
** 调用模块:I2CStart(),I2CSend(),I2CStop()
******************************************************************************/
uint8 read_eeprom(uint8 addr)
{
        uint8 databyte;

        I2CStart();
        I2CSend(0xa0);
        I2CSend(addr);
        I2CStart();
        I2CSend(0xa1);
        databyte = I2CRead();
        I2CStop();

        return databyte;
       
}

/*****************************************************************************
** 函数名称:write_eeprom
** 功能描述:读取EEPROM数据函数(可多片共存)
** 输    入:E2中目的地址addr
** 输    出:读取的数据
** 全局变量:无
** 调用模块:I2CStart(),I2CSend(),I2CStop()
******************************************************************************/
void write_eeprom(uint8 addr, uint8 databyte)
{
        I2CStart();
        I2CSend(0xa0);
        I2CSend(addr);
        I2CSend(databyte);
        I2CStop();

}

void UART_init(void)
{
        SCON = 0x50;
        TMOD = 0x20;
        TH1  = 0xFD;
        TL1  = 0xFD;
        TR1  = 1;
//        ES   = 1;
//        EA   = 1;
}
void UART_send_byte(uint8 dat)
{
        SBUF = dat;
        while(!TI);
        TI = 0;
}
/*****************************************************************************
** 函数名称:主函数main
** 功能描述:读写EEPROM
** 输    入:
** 输    出:
******************************************************************************/
main()
{
        uint8 addr = 0x00, databyte = 0xe4;
        uint8 c = 0;
        uint16 i;
        DS1302 = 0;
        UART_init();
        InitI2C();
        while(1)
        {
                write_eeprom(addr, databyte);
                for(i = 0; i < 1000; i++)
                {
                        Delay();
                }
                c = read_eeprom(addr);
                UART_send_byte(c);
                addr++;
                databyte++;
                if(addr == 0xff) {addr = 0;}
                if(databyte == 0xff) {databyte = 0;}
                for(i = 0; i < 1000; i++)
                {
                        Delay();
                }
         }
       
               
}


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

71

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
478
金钱
478
注册时间
2018-10-7
在线时间
66 小时
发表于 2018-10-31 09:17:08 | 显示全部楼层
这里是我整理写的一份IIC通信的函数,解释都标记的很清楚,如果你没看明白,就照着IIC通信的时序图看就应该明白了
#include <reg52.h>
#include <iic.h>

sbit IIC_SDA=P2^6;        //声明IIC总线的数据线接在单片机的P2.6端口。
sbit IIC_SCL=P2^7;        //声明IIC总线的时钟线接在单片机的P2.5端口。


//void delay(unsigned int t)
//{//延时函数
//    while(t){t--;};                    //延时循环计数
//}
//-------------------------------------------------------------------
void delay_IIC(void)   
{//IIC总线限速延时函数。
//该函数是空函数,延时4个机器周期。
        ;
        ;
}
//-------------------------------------------------------------------
void IIC_Init(void)
{//IIC总线初始化函数
    IIC_SDA=1;//释放IIC总线的数据线。
    IIC_SCL=1;//释放IIC总线的时钟线。
}
//-------------------------------------------------------------------
void IIC_start(void)
{//IIC总线产生起始信号函数  
     IIC_SDA=1;//拉高数据线
         IIC_SCL=1;//拉高时钟线
         delay_IIC();
         IIC_SDA=0;//在时钟线为高电平时,拉低数据线,产生起始信号。
         delay_IIC();
   IIC_SCL=0;//拉低时钟线
}
//-------------------------------------------------------------------
void IIC_stop(void)
{//IIC总线产生停止信号函数
    IIC_SDA=0;//拉低数据线
    delay_IIC();
    IIC_SCL=1;//拉高时钟线。
    delay_IIC();
    IIC_SDA=1;//时钟时线为高电平时,拉高数据线,产生停止信号。
    delay_IIC();
}
//-------------------------------------------------------------------
bit IIC_Tack(void)
{//接收应答信号函数
    bit ack;//定义一个位变量,来暂存应答状态。
    IIC_SDA=1;//释放数据总线,准备接收应答信号。
    delay_IIC();
    IIC_SCL=1;//拉高时钟线。
    delay_IIC();
    ack=IIC_SDA;//读取应答信号的状态。
    delay_IIC();
    IIC_SCL=0;//拉低时钟线。
    delay_IIC();
    return ack;//返回应答信号的状态,0表示应答,1表示非应答。
}
//-------------------------------------------------------------------
void IIC_write_byte(unsigned char Data)
{//向IIC总线写入一个字节的数据函数
        unsigned char i;
         for(i=0;i<8;i++)//有8位数据
        {
                        IIC_SDA=Data&0x80;//写最高位的数据
                        delay_IIC();
                        IIC_SCL=1; //拉高时钟线,将数写入到设备中。
                        delay_IIC();
                        IIC_SCL=0;//拉低时钟线,允许改变数据线的状态
                        delay_IIC();
                        Data=Data<<1;//数据左移一位,把次高位放在最高位,为写入次高位做准备
        }
}
//-------------------------------------------------------------------
unsigned char IIC_read_byte()
{//从IIC总线读取一个字节的数据函数
    unsigned char i;
    unsigned char Data;       //定义一个缓冲寄存器。
    for(i=0;i<8;i++)//有8位数据
    {
        IIC_SCL=1;//拉高时钟线,为读取下一位数据做准备。
        delay_IIC();
        Data=Data<<1;//将缓冲字节的数据左移一位,准备读取数据。
        delay_IIC();
        
        if(IIC_SDA)//如果数据线为高平电平。
            Data=Data|0x1;//则给缓冲字节的最低位写1。
        IIC_SCL=0;//拉低时钟线,为读取下一位数据做准备。
        delay_IIC();
    }
    return Data;//返回读取的一个字节数据。
}
void IIC_single_byte_write(unsigned char Daddr,unsigned char Waddr,unsigned char Data)
{//向任意地址写入一个字节数据函数
    IIC_start();//产生起始信号
    IIC_write_byte(Daddr);//写入设备地址(写)
    IIC_Tack();//等待设备的应答
    IIC_write_byte(Waddr);//写入要操作的单元地址。
    IIC_Tack();//等待设备的应答。
    IIC_write_byte(Data);//写入数据。
    IIC_Tack();//等待设备的应答。
    IIC_stop();//产生停止符号。
}
//-------------------------------------------------------------------
unsigned char IIC_single_byte_read(unsigned char Daddr,unsigned char Waddr)
{//从任意地址读取一个字节数据函数
    unsigned char Data;//定义一个缓冲寄存器。

    IIC_start();//产生起始信号
    IIC_write_byte(Daddr);//写入设备地址(写)
    IIC_Tack();//等待设备的应答
    IIC_write_byte(Waddr);//写入要操作的单元地址。
    IIC_Tack();//等待设备的应答。
   
    IIC_start();//产生起始信号
    IIC_write_byte(Daddr+1);//写入设备地址(读)。
    IIC_Tack();//等待设备的应答。
    Data=IIC_read_byte();//写入数据。
    IIC_stop();//产生停止符号。
    //-------------------返回读取的数据--------------------
    return Data;//返回读取的一个字节数据。
}
/*
*********************************************************************************************************
*   函 数 名: i2c_Ack
*   功能说明: CPU产生一个ACK信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
    SDA = 0;//响应
    i2c_Delay();
    SCL = 1;
    i2c_Delay();
    SCL = 0;
    i2c_Delay();   //在SCL为高电平期间SDA都为0即产生一个应答信号
    SDA = 1;       //释放总线
    i2c_Delay();
}

/*
*********************************************************************************************************
*   函 数 名: i2c_NAck
*   功能说明: CPU产生1个NACK信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
     SDA = 1;
     i2c_Delay();
     SCL = 1;
     i2c_Delay();
     SCL = 0;
     i2c_Delay();   //在SCL为高电平期间SDA都为1即产生一个非应答信号
}
/*
*********************************************************************************************************
*   函 数 名: i2c_SendByte
*   功能说明: CPU向I2C总线设备发送8bit数据
*   形    参:  _ucByte : 等待发送的字节
*   返 回 值: 无
*********************************************************************************************************
*/
/******
void i2c_SendByte(unsigned char _ucByte)
{
     unsigned char i;     //其实信号开始后SCL是被拉低的
     for(i = 0; i < 8; i++)
     {
        if(_ucByte & 0x80)
            SDA = 1;
        else
            SDA = 0;
        SCL = 1;
        i2c_Delay();
        SCL = 0;      //SCL等于0的时候写数据
        if(i == 7)    //最后一次时释放总线
        {
            SDA = 1;
        }
        _ucByte<<=1;  //左移一位
        i2c_Delay();
     }
}

/*
*********************************************************************************************************
*   函 数 名: i2c_ReadByte
*   功能说明: CPU从I2C总线设备读取8bit数据
*   形    参:  无
*   返 回 值: 读到的数据
*********************************************************************************************************
*/
/***unsigned char i2c_ReadByte(void)
{
     unsigned char i;
     unsigned char value = 0;
     for(i = 0; i < 8; i++)
     {
        value<<=1;
        SCL = 1;  //稳定状态的时候读数据
        if(SDA == 1)
            value++;
        SCL = 0;  //允许数据变化
        i2c_Delay();
     }

     return value;
}
****/
/*
*********************************************************************************************************
*   函 数 名: i2c_WaitAck
*   功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
*   形    参:  无
*   返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
unsigned char i2c_WaitAck(void)
{
     unsigned char re; //应答信号等于0则应答正确,等于1则没有应答
     SDA = 1;          //释放总线,能让对方拉低
     i2c_Delay();
     SCL = 1;          //此时刻开始,数据保持应答状态稳定
     i2c_Delay();
     if(SDA == 1)
     {
        re = 1;        //没有应答
     }
     else
     {
        re = 0;        //应答正确                                                                                                                                                                           
     }
     SCL = 0;
     i2c_Delay();

     return re;
}
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 17:16

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表