stm32 模拟I2C

目录

简介

I2C 物理层

协议层

①②:起始信号和结束信号

③ 应答和非应答信号

④数据有效性

⑤数据传输

⑥空闲状态


简介

I2C 物理层

        一个 I2C 总线两条线组成,一个双向串行数据线SDA用来表示数据,一个串行时钟线SCL用于数据收发同步

        “总线”指多个设备共用的信号线,在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机

        多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线

       每个连接到总线的设备(主、从机)都有一个独立的地址,主机可通过该地址来访问不同设备

        总线通过上拉电阻接到电源,当挂在I2C中某设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平

        具有三种传输模式:标准模式传输速率为 100kbit/s ,快速模式为 400kbit/s ,高速模式下可达3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模式,一般用快速模式
 

因为I²C协议比较简单,常常用GPIO来模拟I²C时序,这种方法称为模拟I²C。如果使用MCU的I²C控制器,设置好I²C控制器, I²C控制器就自动实现协议时序,这种方式称为硬件I²C。因为I²C设备的速率比较低,通常两种方式都可以,模拟I²C方便移植,硬件I²C工作效率相对较高

协议层

        协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环
节,这里主要讲起始、停止信号、发送、接收、应答、数据有效性、地址及数据

 ①②:起始信号和结束信号

        起始 (S) 和停止 (P) 信号是两种特殊的状态,表示开始通信和停止通信。当 SCL 线是高电平时 SDA 线从高电平向低电平切换,这个情况表示通讯的起始;当 SCL 是高电平时 SDA 线由低电平向高电平切换,表示通讯的停止。

/*起始信号: 初始SCL\SDA 为高,然后SDA\SCL由高拉低开始,H高L低*/
void i2c_start(void)
{
    SDA_H();
    delay();
    SCL_H();
    delay();
/*必须先拉低SDA再拉低SCL*/
    SDA_L();
    delay();
    SCL_L();
    delay();
}
/*停止信号:初始 SCL 为高,然后SDA由低拉高结束*/
void i2c_stop(void)
{
    SDA_L();
    delay();
    SCL_H();
    delay();
    SDA_H();
    delay();
}

③ 应答和非应答信号

        I²C每次传输的8位数据后需要从机反馈一个应答位,以确认从机是否正常接收了数据。应答信号为低电平时,规定为有效应答位(ACK 简称应答位);应答信号为高电平时,规定为非应答位(NACK)。当设备 (无论主从机) 接收到 I2C 传输的一个字节数据或地址后,若希望对方继
续发送数据,则需要向对方发送“应答 (ACK)”信号,发送方会继续发送下一个数据;若接收端
希望结束数据传输,则向对方发送“非应答 (NACK)”信号,发送方接收到该信号后会产生一个
停止信号,结束信号传输。

        在第 9 个时钟时,数据发送端会释放 SDA 的控制权,由数据接收端控制SDA,若 SDA 为高电平,表示非应答信号 (NACK),低电平表示应答信号 (ACK)

/*I2C发出应答/非应答信号*/
void i2c_ack(uint8_t AckBit)
{
    if(1 == AckBit)
        SDA_H();/*表示不应答*/
    else
        SDA_L();/*表示应答*/
    delay();
    SCL_H();/*读取应答*/
    delay();
    SCL_L();
    delay();
}

④数据有效性

        SDA为高电平表示“ 1”,低电平表示“0”;SCL为高电平时表示有效数据(读取SDA数据),为低电平时表示无效数据,等SDA会进行电平切换(可能是1可能是0),为下次数据表示做准备。

 ⑤数据传输

         在 SCL 串行时钟的配合下,在SDA 上逐位地串行传送每一位数据

        I2C 总线上的每个设备都有自己的独立地址,主机发起通讯时,通过 SDA 信号线发送设备地址来查找从机,设备地址一般是7 位的地址应用比较广泛。地址之后紧跟的一个数据位用来表示数据传输方向,数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据;发送完之后从机就会等待主机的应答信号。

/*发送一个字节,data: 要发送的数据*/
void send_byte( unsigned char data)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        if(data & (0x80 >> i))/*每次移位获取对应的数据位判断SDA是发0还是发1*/
        {
            SDA_H();/*拉高,发1*/
        }
        else{
            SDA_L();/*拉低,发0*/
        }
       
        SCL_H();/*读取数据*/
        delay();   
        SCL_L();
        delay();     
    }

}
/*I2C读出一个字节*/
unsigned char iic_read_byte(void)
{
    unsigned char i,data = 0x00;
    SDA_H();
    delay();
    for(i=0;i<8;i++)
    {
        SCL_H();/*拉高开始读取数据*/
        delay();
        /*使用库函数去读取SDA的GPIO引脚电平,通过返回值进入循环*/
        if(/*读取SDA的电平 == 1*/)
        {
            data |= (0x80 >> i);/*通过读取电平进行置1*/
        }/*如果是0就不用进入if语句,因为data初始位0000 0000,通过上面对对应的位置1即可*/
        SCL_L();/*等待读取数据*/
        dalay();
    }

    return data;
}
/*I2C等待从机的应答信号,应答信号SDA为低*/
uint8_t i2c_wait_ack(void)
{
    unsigned char  wait_time=0;
    /*发送完数据等待应答信号的状态*/
    SDA_H();/*释放SDA,让发送应答信号方控制*/
    delay();
    SCL_H();/*开始读出SDA*/
    delay();
    while(/*使用库函数去读取SDA的GPIO引脚电平,通过返回值进入循环*/)/*等待应答*/
    {
        /*如果读取引脚电平为高,即1,表示不应答*/
        wait_time++;/*等待时间*/
        if(wait_time > 250)
        {
            /*认为从机没有发送应答信号*/
            SCL_L();
            return 1;/*表示接收失败*/
        }
        
    }
    /*没进入循环,表示SDA拉低了,表示应答*/
    SCL_L();
    return 0;
}

⑥空闲状态

        IIC 总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值