IIC通信

通信协议简述

  • 三条线:串行数据线(SDA)、串行时钟线(SCL),地线;

       IIC通信_第1张图片

  • 半双工 一问一答 ,主从模式,多设备模式
  • 总线协议:支持多个设备进行通信(多主多从)

IIC通信_第2张图片

  • 异步模式(串口):通信双方约定好波特率,然后各自按照自己时钟进行通信。

        好处:便捷;

        缺点:双方必须时钟精确,否则对不齐了。

  • 同步通信(IIC):由主机的时钟总线确定通信速率
  • 选择IIC原因:考虑小型传感器没有晶振提供精确的时钟基准

通信协议过程

在IIC总线上,每个从机都有其唯一的默认设备地址【这个设备地址由谁规定的呢?】。发送数据时采用广播形式,数据最开始带着从机地址,其他设备会选择性失聪。

IIC通信_第3张图片

IIC通信_第4张图片

1、通信开始前:

两总线电平处于拉高状态:

IIC通信_第5张图片

主机在时钟线上产生恒定的时钟脉冲

IIC通信_第6张图片

2、主机发起通信:

在时钟线某个高电平时数据线下拉;随机主机会在时钟线上产生一个恒定的时钟脉冲信号。

IIC通信_第7张图片IIC通信_第8张图片

3、数据发送过程:

接下来每一个时钟周期内,SDL上发送电平基本小规则

主机在低电平时钟时,设置数据;从机在高时钟时,读取数据。

IIC通信_第9张图片IIC通信_第10张图片

IIC通信_第11张图片
字节数据发送主要规则:

       每当发送器传输完一个字节(8 bit)的数据之后,发送端会等待一定的时间,等接收方的应答信号。接收端通过拉低SDA数据线,给发送端发送一个应答信号,以提醒发送端我这边已经接受完成,数据可以继续传输,接下来,发送端就可以继续发送数据了。如此反复,直到发送完所有数据。

IIC通信_第12张图片

即每一帧的数据传送与应答数据 共有9bit

总线寻址:

值得注意的是,IIC通信中,主机发送的第一个字节往往是某个从机在总线上的地址

IIC通信_第13张图片

IIC通信_第14张图片

数据读写方向:

IIC通信_第15张图片

IIC通信_第16张图片

参考来源:

IIC详解,包括原理、过程,最后一步步教你实现IIC_iic协议-CSDN博客

4、通信终止信号:

然后主机会在时钟线处于高电平时,将数据线拉高,通信终止信号。整段通信完成。

IIC通信_第17张图片

起始信号和终止信号都是由主机发送的。在起始信号产生之后,总线就处于被占用的状态,在终止信号产生之后,总线就处于空闲状态。

注意:每次数据传送总是由主机产生的终止信号来结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。

模拟IIC协议代码实现

代码实现-学习视频推荐

iic读取函数书写_哔哩哔哩_bilibiliiic读取函数书写, 视频播放量 2012、弹幕量 4、点赞数 57、投硬币枚数 17、收藏人数 62、转发人数 0, 视频作者 小远课堂, 作者简介 作者已关闭了评论提醒,相关视频:I2C时序图解讲解[上],IIC的代码不会写?,秒懂I2C时序图,IIC时序图讲解【中】,I2C入门第一节-I2C的基本工作原理,I2C写字节的基本流程,lcd1602看时序图写代码,I2C时序图讲解【下】,学完C语言,做不出小程序,做不出图形化界面,只有黑乎乎的窗口,自学编程的几点建议,7分钟看懂时序图,不懂你骂我,花了四个多小时画了人生第一块PCBicon-default.png?t=N7T8https://www.bilibili.com/video/BV1Vj411Z7qN/?spm_id_from=333.788&vd_source=f443c8140671d1c361aa817ad1193312代码更详细实现-博客推荐

【通信协议】IIC通信协议详解-CSDN博客IIC的基本介绍IIC总线的发展: 芯片间总线(Inter Interface Circuit,IIC),是应用广泛的芯片间串行扩展总线。目前世界上采用的IIC总线一共有两个规范,分别由荷兰飞利浦公司和日本索尼公司提出的,现在基本采用荷兰飞利浦的IIC总线的技术规范。IIC总线的优点:1、IIC总线优点中最主要的优点是其简单性(IIC只有两条信号线)和有效性(根据SCL线上的时钟线来判断)。带有IIC总线的接口的单片机都可直接与具有IIC总线接口的各种扩展器件..._iic通信协议https://blog.csdn.net/qq_53918631/article/details/124810934?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-124810934-blog-107078170.235%5Ev38%5Epc_relevant_anti_vip_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-124810934-blog-107078170.235%5Ev38%5Epc_relevant_anti_vip_base&utm_relevant_index=2

头文件

myiic.h

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h"  

//IO方向设置
//CRH,CRL 端口输入输出模式寄存器。CRH为8-15引脚,CRL为0-7引脚
#define SDA_IN()  {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=8<<12;}//PC11引脚为上拉/下拉输入
#define SDA_OUT() {GPIOC->CRH&=0XFFFF0FFF;GPIOC->CRH|=3<<12;}//PC11为推挽输出

//IO操作函数    
#define IIC_SCL    PCout(12) //SCL
#define IIC_SDA    PCout(11) //SDA    
#define READ_SDA   PCin(11)  //输入SDA

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口                
void IIC_Start(void);                //发送IIC开始信号
void IIC_Stop(void);                  //发送IIC停止信号
void IIC_Send_Byte(u8 txd);            //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);                 //IIC等待ACK信号
void IIC_Ack(void);                    //IIC发送ACK信号
void IIC_NAck(void);                //IIC不发送ACK信号

//一下两个函数实际并未被定义
void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);      
#endif

.c文件

#include "myiic.h"
#include "delay.h"


//初始化IIC
//硬件I2C必须开漏输出
//模拟I2C则为推挽输出(方便输出高低电平?)
void IIC_Init(void)
{                         
    GPIO_InitTypeDef GPIO_InitStructure;
    //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
    RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOC, ENABLE );    
       
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
 
    IIC_SCL=1;//PCout(12)
    IIC_SDA=1;//PCout(11)

}
//产生IIC起始信号
//SCL为高时,SDA拉低,准备开始传数据。(记得再拉低SCL,这个是为什么?)
//SCL为高时,SDA拉高,结束传输数据。
//传输数据时,SCL为高时数据有效
void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA=1;     //SDA = 1,SCL = 1 空闲状态       
    IIC_SCL=1;
    delay_us(4);
     IIC_SDA=0;//START:when CLK is high,DATA change form high to low
    delay_us(4);
    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}      
//产生IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();//sda线输出
    IIC_SCL=0;
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     delay_us(4);
    IIC_SCL=1;
    IIC_SDA=1;//发送I2C总线结束信号
    delay_us(4);                                   
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;delay_us(1);       
    IIC_SCL=1;delay_us(1);     //设置数据有效
    while(READ_SDA)//READ_SDA为0时表示接收到应答
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0;//时钟输出0        
    return 0;  
}
//产生ACK应答
void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}
//不产生ACK应答            
void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}                                          
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答              
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
    SDA_OUT();         
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;//先发高位
        txd<<=1;       
        delay_us(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;    
        delay_us(2);
    }    
}         
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0;
        delay_us(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
        delay_us(1);
    }                    
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}
————————————————
版权声明:本文为CSDN博主「碑 一」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dedell/article/details/96628955

模拟IIC应用实战:

stm32无人机:利用上面基础模拟IIC代码把数据从mpu6050传感器数据读取出来(未完成)

*stm32 HAL库 实现和使用IIC总线*

#include "stm32xxxxx.h"
#include "stm32xxxxx_hal.h"
 
I2C_HandleTypeDef hi2c1;
 
void SystemClock_Config()
{
  // 配置系统时钟
  // ...
}
 
void GPIO_Configuration()
{
  // 配置GPIO引脚
  // ...
}
 
void I2C_Configuration()
{
  // 配置I2C外设
  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x00303D5B; // 根据具体系统时钟和I2C时钟频率调整这个值
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
 
  // 初始化I2C外设
  HAL_I2C_Init(&hi2c1);
}
 
int main(void)
{
  uint8_t sendData[] = {0x01, 0x02, 0x03};
  uint8_t receiveData[3];
 
  // 初始化系统时钟
  SystemClock_Config();
 
  // 配置GPIO引脚
  GPIO_Configuration();
 
  // 配置I2C外设
  I2C_Configuration();
 
  // 发送数据
  HAL_I2C_Master_Transmit(&hi2c1, DeviceAddress, sendData, sizeof(sendData), HAL_MAX_DELAY);
 
  // 延时等待数据发送完成
  HAL_Delay(1); // 根据实际情况调整延时时间
 
  // 接收数据
  HAL_I2C_Master_Receive(&hi2c1, DeviceAddress, receiveData, sizeof(receiveData), HAL_MAX_DELAY);
 
  while (1)
  {
    // 主程序逻辑
  }
}

参考:

【物联网】I2C(IIC)通信协议详解与应用_iic通信_嵌入式小白—小黑的博客-CSDN博客

【通信协议】IIC通信协议详解-CSDN博客IIC的基本介绍IIC总线的发展: 芯片间总线(Inter Interface Circuit,IIC),是应用广泛的芯片间串行扩展总线。目前世界上采用的IIC总线一共有两个规范,分别由荷兰飞利浦公司和日本索尼公司提出的,现在基本采用荷兰飞利浦的IIC总线的技术规范。IIC总线的优点:1、IIC总线优点中最主要的优点是其简单性(IIC只有两条信号线)和有效性(根据SCL线上的时钟线来判断)。带有IIC总线的接口的单片机都可直接与具有IIC总线接口的各种扩展器件..._iic通信协议https://blog.csdn.net/qq_53918631/article/details/124810934?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-124810934-blog-107078170.235%5Ev38%5Epc_relevant_anti_vip_base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~Rate-1-124810934-blog-107078170.235%5Ev38%5Epc_relevant_anti_vip_base&utm_relevant_index=2

案例:利用IIC从单片机读取温湿度显示到电脑

数据显示到电脑上:

前几节用到的串口以及串口调试助手 - 从单片机发送数据到pc上,显示出来

IIC写驱动

项目架构

IIC通信_第18张图片

IIC通信_第19张图片

直接看“传感器数据手册”

IIC通信_第20张图片

重点关注:设备从机地址 0X71

IIC通信_第21张图片

【STM32入门教程-2023】第12集 IIC通信与温湿度传感器AHT20(DHT20)_哔哩哔哩_bilibili本期视频我们一起来了解一下如何使用STM32的IIC通信, 获取你房间的温度与湿度~------------------------------------------------------------------------------学习套件获取: https://b23.tv/sblUuvI 或者直接某宝搜索"keysking stm32", 认准店铺"波特律, 视频播放量 24904、弹幕量 140、点赞数 1026、投硬币枚数 605、收藏人数 1354、转发人数 109, 视频作者 keysking, 作者简介 立志做最好最简洁最易懂的教程!!!,相关视频:【STM32入门教程-2023】第14集 如何在OLED屏幕上挥毫,STM32物联网入门30步--STM32CubeMX+HAL库 CubeIde蓝牙 WIFI ESP8266 嵌入式物联网开发教学 基于F103 30集全,STM32入门100步→100集系统化STM32入门方案=STM32F103+KEIL标准库+C语言基础+代码逐行分析+独家教学PPT+人机界面开发全过程,【STM32入门教程-2023】第13集 IIC的中断与DMA以及状态机编程,【洋桃电子】STM32入门F4:F407+CubeMX+HAL库(CubeIDE)+蓝牙 WIFI ESP8266+原创例程+独家PPT图表(更新中),【STM32入门教程-2023】应该是全B站最好的STM32教程了,5分钟看懂!串口RS232 RS485最本质的区别!,电路里为什么要摆这两个电容?,【洋桃电子】洋桃补习班(为0基础的初学者补足基础知识)STM32入门100步系列视频,10行代码,就能让你真正理解DMA!你用的可能很少,但是在单片机中非常重要!icon-default.png?t=N7T8https://www.bilibili.com/video/BV1QN411D7ak/?spm_id_from=333.788&vd_source=f443c8140671d1c361aa817ad1193312

从面试角度看IIC的提问点:

1、为什么选择IIC通信,和SPI UART 的区别,哪个更快?

2、IIC最大速率

3、IIC协议,帧格式,收发数据的时序流程

4、介绍一下IIC

5、调试IIC过程中遇到的问题

6、iic寻址,主机从机如何对接的

你可能感兴趣的:(stm32基础,单片机,嵌入式硬件)