I2C协议的科学化学习方法

[复制链接]
 楼主| gaoyang9992006 发表于 2023-5-25 22:37 | 显示全部楼层 |阅读模式
I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在集成电路(IC)之间进行短距离数据传输。它是由Philips(现在的NXP半导体)在上世纪80年代开发的,并成为一种广泛应用的通信协议。

I2C协议主要用于连接微控制器、传感器、存储器和其他外围设备,以实现简单而可靠的通信。它使用两根信号线:串行数据线(SDA)和串行时钟线(SCL)。通过这两根线,多个设备可以同时连接到同一条总线上。
以下是I2C协议的一些关键特点:
  • 简单和双向:I2C使用主从结构,其中一个设备充当主设备,负责控制通信的时序和协调数据传输,其他设备则充当从设备,按照主设备的指示进行操作。双向通信意味着数据可以在主设备和从设备之间双向传输。
  • 地址寻址:每个从设备在总线上都有一个唯一的7位或10位地址,用于主设备选择要与之通信的从设备。7位地址模式支持最多128个从设备,10位地址模式支持最多1024个从设备。
  • 速度可变:I2C协议支持多种传输速率,通常有标准模式(100 kbit/s)、快速模式(400 kbit/s)和高速模式(3.4 Mbit/s)。速率的选择由主设备决定,所有从设备都必须支持所选择的速率。
  • 起始和停止条件:通信的开始由主设备发出起始条件(Start),而结束由主设备发出停止条件(Stop)。起始条件和停止条件的产生使得每个通信传输都有明确的开始和结束,确保数据的完整性。
  • 硬件传输:I2C协议通过改变SDA和SCL线上的电压来传输数据。SDA线上的数据传输是基于时钟信号的变化,而SCL线上的时钟信号由主设备生成。

I2C协议在许多应用中得到广泛应用,特别是在连接微控制器和外围设备的场景中。它提供了一种简单可靠的通信方式,具有较低的成本和较少的引脚需求。由于其流行和广泛支持,许多芯片和模块都集成了I2C接口,使得设备之间的互联变得更加简单和灵活。
接下来用实例说明实现方式
  1. /**********************************************
  2. //IIC Start
  3. 时钟信号在高电平状态时候在数据线产生一个下降沿
  4. **********************************************/
  5. void IIC_Start()
  6. {
  7.         OLED_SCLK_Set() ;
  8.         OLED_SDIN_Set();
  9.         OLED_SDIN_Clr();
  10. }

  11. /**********************************************
  12. //IIC Stop
  13. 时钟信号在高电平状态时候在数据线产生一个上升沿
  14. **********************************************/
  15. void IIC_Stop()
  16. {
  17.         OLED_SCLK_Set();
  18.         OLED_SDIN_Clr();
  19.         OLED_SDIN_Set();       
  20. }
  21. //这里就是跳过这个时钟周期,没有去读数据位有没有回来应答信号。
  22. void IIC_Wait_Ack()
  23. {
  24.         OLED_SCLK_Set();
  25.         OLED_SCLK_Clr();
  26. }
  27. /**********************************************
  28. // IIC Write byte
  29. 在时钟线为低电平的时候在数据线发送数据位,高位在前
  30. 在完成数据发送后要保持数据线为低电平
  31. **********************************************/

  32. void Write_IIC_Byte(unsigned char IIC_Byte)
  33. {
  34.         unsigned char i;
  35.         unsigned char m,da;
  36.         da=IIC_Byte;

  37.         for(i=0;i<8;i++)               
  38.         {
  39.                 m=da;
  40.                 OLED_SCLK_Clr();
  41.                 m=m&0x80;
  42.                
  43.                 if(m==0x80)
  44.                         OLED_SDIN_Set();
  45.                 else
  46.                         OLED_SDIN_Clr();

  47.                 da=da<<1;

  48.                 OLED_SCLK_Set();
  49.                 }
  50.         OLED_SCLK_Clr();
  51. }
  52. /**********************************************
  53. // IIC Write Command
  54. 开始信号
  55. 前8位为:写7位地址,高位在前,并跟随1个读写位0,表示写入:0111 100 0
  56. 第9位应答,这里就是跳过一个时钟信号(拉高时钟,拉低时钟)
  57. 接下已一个字节发送0x00表示后面要写命令
  58. 接下来应答位,这里就是跳过一个时钟信号(拉高时钟,拉低时钟)
  59. 后面开始写入的数据作为命令,即将命令字节装载到这个发送字节的函数里发送出去
  60. 然后又是一个应答位,跳过一个时钟信号
  61. 之后发送停止指令。
  62. **********************************************/
  63. void Write_IIC_Command(unsigned char IIC_Command)
  64. {
  65.         IIC_Start();
  66.         Write_IIC_Byte(0x78);            //Slave address,SA0=0
  67.         IIC_Wait_Ack();       
  68.         Write_IIC_Byte(0x00);                        //write command
  69.         IIC_Wait_Ack();       
  70.         Write_IIC_Byte(IIC_Command);
  71.         IIC_Wait_Ack();       
  72.         IIC_Stop();
  73. }
  74. /**********************************************
  75. // IIC Write Data
  76. 开始信号
  77. 前八位为:写7位地址,高位在前,并跟随1个读写位0,表示写入:0111 100 0
  78. 第9位应答,这里就是跳过一个时钟信号(拉高时钟,拉低时钟)
  79. 接下已一个字节发送0x40表示后面要写的是数据
  80. 接下来应答位,这里就是跳过一个时钟信号(拉高时钟,拉低时钟)
  81. 后面开始写入的数据作为数据,即将数据字节装载到这个发送字节的函数里发送出去
  82. 然后又是一个应答位,跳过一个时钟信号
  83. 之后发送停止指令。
  84. **********************************************/
  85. void Write_IIC_Data(unsigned char IIC_Data)
  86. {
  87.         IIC_Start();
  88.         Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0
  89.         IIC_Wait_Ack();       
  90.         Write_IIC_Byte(0x40);                        //write data
  91.         IIC_Wait_Ack();       
  92.         Write_IIC_Byte(IIC_Data);
  93.         IIC_Wait_Ack();       
  94.         IIC_Stop();
  95. }




 楼主| gaoyang9992006 发表于 2023-5-26 21:29 | 显示全部楼层
新写的总结代码,强化了应答响应
  1. /*
  2. I2C Start
  3. 起始信号:时钟信号在高电平状态时候,数据线产生一个下降沿表示开始信号
  4. */
  5. void I2C_Start()
  6. {
  7.         IO_SCL_SET_H();
  8.        
  9.         IO_SDA_SET_H();
  10.         IO_SDA_SET_L();       
  11. }

  12. /*
  13. I2C Stop
  14. 停止信号:时钟信号在高电平状态时候,数据线产生一个上升沿表示停止
  15. */
  16. void I2C_Stop()
  17. {
  18.         IO_SCL_SET_H();
  19.        
  20.         IO_SDA_SET_L();
  21.         IO_SDA_SET_H();       
  22. }

  23. /*
  24. I2C ACK/NACK
  25. 应答信号:第九个时钟周期的时钟高电平时候读取SDA数据,如果SDA此时为0,则表示应答,如果为1则表示非应答。
  26. */
  27. void I2C_ACK()
  28. {
  29.         IO_SDA_SET_H();
  30.        
  31.         IO_SCL_SET_H();
  32.         if(Get_IO_SDA()==0)
  33.         IO_SCL_SET_L();
  34.         else
  35.         while(Get_IO_SDA()==1);
  36.         IO_SCL_SET_L();
  37. }

  38. /*
  39. I2C 上发送一个字节数据
  40. 发送字节:发送字节是时钟信号的低电平时候修改数据,。
  41. */
  42. void Write_I2C_Byte(unsigned char I2C_Byte)
  43. {
  44.         unsigned char i;
  45.        
  46.         for(i=0;i<8;i++)
  47.         {
  48.                 IO_SCL_SET_L();
  49.                
  50.                 if((I2C_Byte<<i)&0x80)
  51.                         IO_SDA_SET_H();
  52.                 else
  53.                         IO_SDA_SET_L();
  54.                
  55.                 IO_SCL_SET_H();               
  56.         }
  57.         IO_SCL_SET_L();
  58. }
  59. /*
  60. add:7位地址;
  61. rwbit:读写位,1表示读,0表示写
  62. dat:数据字节
  63. 命令或数据:1表示发送的字节是数据,0表示发送的字节是命令
  64.        
  65. */
  66. void OLED_WR_Byte(unsigned char dat,unsigned char cmd)
  67. {
  68.         I2C_Start();
  69.         Write_I2C_Byte(0x78);
  70.         I2C_ACK();
  71.         if(cmd)
  72.                 Write_I2C_Byte(0x40);
  73.         else
  74.                 Write_I2C_Byte(0x00);
  75.         I2C_ACK();
  76.         Write_I2C_Byte(dat);
  77.         I2C_ACK();       
  78.         I2C_Stop();
  79. }
个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2045

主题

16350

帖子

222

粉丝
快速回复 在线客服 返回列表 返回顶部