当前位置: 首页 > news >正文

IIC协议总结

1.基本理解

        iic通信协议:双线制串行通信协议,由时钟线SCL和数据线SDA构成.

        通信方式:主从模式,主设备发起通信,从设备响应通信

2.通信的基本步骤


    a.主设备发送一个开始信号,表示开始通信,即启动I2C  

        条件:SCL=1,SDA出现下降沿 
        IIC启动之后,SCL=1时,SDA的电平不允许有变化
                              SCL=0时,数据发送方才能在SDA上改变发送电平
    b.主设备发送一个从设备的地址和(读写位) 一般地址的长度是7bit,最后一个bit是读写指令,
        1是读(主机接收从机数据),0是写(主机发送数据到从机)
    C.仲裁机制和应答,从机只有收到自己的地址信息才会被唤醒,这个过程是以一个低电平的SDA脉冲应答,
        主机检测这个应答位,0是 1不是
    d.数据传输 确认目标后,主设备发送或者接收数据,数据传输在每个时钟周期的上升沿或者下降沿进行
    e.停止:SCL = 1,SDA出现上升沿
        注意:I2C外部需根据传输速率匹配上拉电阻,速率越高,上拉电阻越小,否则会影响时序;
                    I2C引脚作为输出时需是开漏输出,作为输入时需是浮空输入,不能匹配内部上拉或下拉电阻;
              

    3.软件模拟


    1.结构体定义总线的SDA和SCL两个引脚:用于控制两个引脚的输入输出

typedef struct{uint32_t SDA_RCC_APB2Periph;//SDA脚的时钟GPIO_TypeDef* SDA_Port;//SDA脚Portuint16_t SDA_Pin;//SDA脚Pinuint32_t SCL_RCC_APB2Periph;//SCL脚的时钟GPIO_TypeDef* SCL_Port;//SCL脚Portuint16_t SCL_Pin;//SCL脚Pin}sw_i2c_gpio_t;


     2.宏定义
      

#define I2C_USE_7BIT_ADDR //如果使用的从机地址是7Bit模式,则打开这个宏,否则注释掉这个宏#define I2C_DELAY                50 // I2C每个Bit之间的延时时间,延时越小I2C的速率越高#define SW_I2C_SCL_LOW          GPIO_ResetBits(gpio->SCL_Port,gpio->SCL_Pin) // I2C SCL脚输出0 地电平#define SW_I2C_SCL_HIGH         GPIO_SetBits(gpio->SCL_Port,gpio->SCL_Pin) // I2C SCL脚输出1 高电平#define SW_I2C_SDA_LOW          GPIO_ResetBits(gpio->SDA_Port,gpio->SDA_Pin) // I2C SDA脚输出0 低电平#define SW_I2C_SDA_HIGH         GPIO_SetBits(gpio->SDA_Port,gpio->SDA_Pin) // I2C SDA脚输出1 高电平#define SW_I2C_SDA_INPUT        sw_i2c_set_sda_input(gpio) // 将SDA脚方向设置为输入 #define SW_I2C_SDA_OUTPUT        sw_i2c_set_sda_output(gpio) // 将SDA脚方向设置为输出#define SW_I2C_SDA_STATUS        sw_i2c_sda_status(gpio) // 获取SDA脚输入电平状态  #define i2c_delay_us(a)            SystemDelayUs(a) // 延时


   3,其他准备函数
  

 SDA输入输出及状态/**************************************************************************
***                          读取SDA脚的状态                             ***
***************************************************************************/
static uint8_t sw_i2c_sda_status(sw_i2c_gpio_t *gpio)
{uint8_t sda_status;sda_status = GPIO_ReadInputDataBit(gpio->SDA_Port,gpio->SDA_Pin);    return sda_status?1:0;
}
/**************************************************************************
***                          设置SDA脚为输入                             ***
***************************************************************************/
static void sw_i2c_set_sda_input(sw_i2c_gpio_t *gpio)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = gpio->SDA_Pin;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init (gpio->SDA_Port, & GPIO_InitStructure );
}
/**************************************************************************
***                          设置SDA脚为输出                             ***
***************************************************************************/
static void sw_i2c_set_sda_output(sw_i2c_gpio_t *gpio)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = gpio->SDA_Pin;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;   //开漏输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init (gpio->SDA_Port, & GPIO_InitStructure );
}I2C启动static void sw_i2c_start(sw_i2c_gpio_t *gpio)
{// I2C 开始时序:SCL=1时,SDA由1变成0.SW_I2C_SDA_HIGH;         i2c_delay_us(I2C_DELAY);SW_I2C_SCL_HIGH;           i2c_delay_us(I2C_DELAY);SW_I2C_SDA_LOW;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);
}
I2C停止
static void sw_i2c_stop(sw_i2c_gpio_t *gpio)
{// I2C 开始时序:SCL=1时,SDA由0变成1.SW_I2C_SDA_LOW;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);SW_I2C_SDA_HIGH;
}等待数据接收方反馈
static uint8_t sw_i2c_wait_ack(sw_i2c_gpio_t *gpio)
{uint8_t sda_status;uint8_t wait_time=0;uint8_t ack_nack = 1;//先设置SDA脚为输入SW_I2C_SDA_INPUT;//等待SDA脚被从机拉低while(SW_I2C_SDA_STATUS){wait_time++;//如果等待时间过长,则退出等待if (wait_time>=200){ack_nack = 0;break;}}// SCL由0变为1,读入ACK状态// 如果此时SDA=0,则是ACK// 如果此时SDA=1,则是NACKi2c_delay_us(I2C_DELAY);SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);//再次将SCL=0,并且将SDA脚设置为输出SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);SW_I2C_SDA_OUTPUT;i2c_delay_us(I2C_DELAY);return ack_nack;
}发送ACK给数据发送方  应答信号
static void sw_i2c_send_ack(sw_i2c_gpio_t *gpio)
{// 发送ACK就是在SDA=0时,SCL由0变成1SW_I2C_SDA_LOW;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);
}发送NACK给数据发生方 非应答信号,表示接受没有成功
static void sw_i2c_send_nack(sw_i2c_gpio_t *gpio)
{// 发送NACK就是在SDA=1时,SCL由0变成1SW_I2C_SDA_HIGH;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);
}

4.主设备接受和发送字节 

static void sw_i2c_write_byte(sw_i2c_gpio_t *gpio,uint8_t aByte)
{uint8_t i;for (i=0;i<8;i++){//先将SCL拉低;SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);//然后在SDA输出数据if(aByte&0x80){SW_I2C_SDA_HIGH;}else{SW_I2C_SDA_LOW;}i2c_delay_us(I2C_DELAY);//最后将SCL拉高,在SCL上升沿写入数据SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);aByte = aByte<<1;//数据位移}//写完一个字节只后要将SCL拉低SW_I2C_SCL_LOW;i2c_delay_us(I2C_DELAY);
}主设备从从设备读取字节
static uint8_t sw_i2c_read_byte(sw_i2c_gpio_t *gpio)
{uint8_t i,aByte;//先将SDA脚设置为输入SW_I2C_SDA_INPUT;for (i=0;i<8;i++){//数据位移aByte = aByte << 1;//延时等待SDA数据稳定i2c_delay_us(I2C_DELAY);//SCL=1,锁定SDA数据SW_I2C_SCL_HIGH;i2c_delay_us(I2C_DELAY);//读取SDA状态if(SW_I2C_SDA_STATUS){aByte |= 0x01;}//SCL=0,解除锁定SW_I2C_SCL_LOW;}//读完一个字节,将SDA重新设置为输出SW_I2C_SDA_OUTPUT;return aByte;
}

相关文章:

  • 【MySQL】深入解析 Buffer Pool 缓冲池
  • 用 TVMC 编译和优化模型(2)
  • vue3输入单号和张数,自动生成连号的单号
  • 初阶数据结构之---栈和队列(C语言)
  • 【04】C语言括号匹配问题
  • WebServer -- 注册登录
  • Spring Cloud Gateway-系统保护Sentinel集成
  • 什么是区块链粉尘攻击?
  • 【Spring连载】使用Spring Data访问 MongoDB----对象映射之属性转换器
  • 如何打印 springboot 框架中 接收请求的日志
  • 爬虫的一些小技巧总结
  • C++:模版初阶 | STL简介
  • 【Mybatis】快速入门 基本使用 第一期
  • 【JS】解构赋值注意点,解构赋值报错
  • 【微信小程序开发】常用方法封装工具类utils.js
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • JAVA_NIO系列——Channel和Buffer详解
  • PHP 小技巧
  • SQLServer插入数据
  • ubuntu 下nginx安装 并支持https协议
  • 将 Measurements 和 Units 应用到物理学
  • 七牛云假注销小指南
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 小程序01:wepy框架整合iview webapp UI
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 正则学习笔记
  • 7行Python代码的人脸识别
  • const的用法,特别是用在函数前面与后面的区别
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #{}和${}的区别是什么 -- java面试
  • #LLM入门|Prompt#3.3_存储_Memory
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (007)XHTML文档之标题——h1~h6
  • (分布式缓存)Redis分片集群
  • (分类)KNN算法- 参数调优
  • (五)Python 垃圾回收机制
  • .NET Core WebAPI中封装Swagger配置
  • .NET Framework杂记
  • .net Stream篇(六)
  • .Net Winform开发笔记(一)
  • .net 反编译_.net反编译的相关问题
  • .NET 分布式技术比较
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .net分布式压力测试工具(Beetle.DT)
  • .NET学习教程二——.net基础定义+VS常用设置
  • @Autowired注解的实现原理
  • @FeignClient注解,fallback和fallbackFactory
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • @基于大模型的旅游路线推荐方案
  • [ web基础篇 ] Burp Suite 爆破 Basic 认证密码
  • [BZOJ 3282] Tree 【LCT】