GPIO模拟I2C总线进行通信

I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段、数据传输阶段和终止阶段。

1. 起始阶段

在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平。如果此时主机需要发起新的通信请求,那么需要首先通过SDA和SCL发出起始标志。当SCL为高电平时,SDA电平从高变低,这一变化表示完成了通信的起始条件。

在起始条件和数据通信之间,通常会有延时要求,具体的指标会在设备厂商的规格说明书中给出。

2. 数据传输阶段

I2C总线的数据通信是以字节(8位)作为基本单位在SDA上进行串行传输的。一个字节的传输需要9个时钟周期。其中,字节中每一位的传输都需要一个时钟周期,当新的SCL到来时,SCL为低电平,此时数据发送方根据当前传输的数据位控制SDA的电平信号。如果传输的数据位为"1",就将SDA电平拉高;如果传输的数据位为"0",就将SDA的电平拉低。当SDA上的数据准备好之后,SCL由低变高,此时数据接收方将会在下一次SCL信号变低之前完成数据的接收。当8位数据发送完成后,数据接收方需要一个时钟周期以使用SDA发送ACK信号,表明数据是否接收成功。当ACK信号为"0"时,说明接收成功;为"1"时,说明接收失败。每个字节的传输都是由高位(MSB)到低位(LSB)依次进行传输。

I2C总线协议中规定,数据通信的第一个字节必须由主机发出,内容为此次通信的目标设备地址和数据通信的方向(读/写)。在这个字节中,第1~7位为目标设备地址,第0位为通信方向,当第0位为"1"时表示读,即后续的数据由目标设备发出主机进行接收;当第0位为"0"时表示写,即后续的数据由主机发出目标设备进行接收。在数据通信过程中,总是由数据接收方发出ACK信号。

3. 终止阶段

当主机完成数据通信,并终止本次传输时会发出终止信号。当SCL 是高电平时,SDA电平由低变高,这个变化意味着传输终止。

下面给出了模拟I2C总线进行读写的伪代码,用以说明如何使用GPIO实现I2C通信:

 
  1. #define SDA 254 //定义SDA所对应的GPIO接口编号

  2. #define SCL 255 //定义SCL所对应的GPIO接口编号

  3. #define OUTP 1 //表示GPIO接口方向为输出

  4. #define INP 0 //表示GPIO接口方向为输入

  5. /* I2C起始条件 */

  6. int i2c_start()

  7. {

  8. //初始化GPIO口

  9. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出

  10. set_gpio_direction (SCL, OUTP); //设置SCL方向为输出

  11. set_gpio_value(SDA, 1); //设置SDA为高电平

  12. set_gpio_value(SCL, 1); //设置SCL为高电平

  13. delay(); //延时

  14. //起始条件

  15. set_gpio_value(SDA, 0); //SCL为高电平时,SDA由高变低

  16. delay();

  17. }

  18. /* I2C终止条件 */

  19. void i2c_stop()

  20. {

  21. set_gpio_value(SCL, 1);

  22. set_gpio_direction(SDA, OUTP);

  23. set_gpio_value(SDA, 0);

  24. delay();

  25. set_gpio_value(SDA, 1); //SCL高电平时,SDA由低变高

  26. }

  27. /*

  28. I2C读取ACK信号(写数据时使用)

  29. 返回值 :0表示ACK信号有效;非0表示ACK信号无效

  30. */

  31. unsigned char i2c_read_ack()

  32. {

  33. unsigned char r;

  34. set_gpio_direction(SDA, INP); //设置SDA方向为输入

  35. set_gpio_value(SCL,0); // SCL变低

  36. r = get_gpio_value(SDA); //读取ACK信号

  37. delay();

  38. set_gpio_value(SCL,1); // SCL变高

  39. delay();

  40. return r;

  41. }

  42. /* I2C发出ACK信号(读数据时使用) */

  43. int i2c_send_ack()

  44. {

  45. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出

  46. set_gpio_value(SCL,0); // SCL变低

  47. set_gpio_value(SDA, 0); //发出ACK信号

  48. delay();

  49. set_gpio_value(SCL,1); // SCL变高

  50. delay();

  51. }

  52. /* I2C字节写 */

  53. void i2c_write_byte(unsigned char b)

  54. {

  55. int i;

  56. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出

  57. for (i=7; i>=0; i--) {

  58. set_gpio_value(SCL, 0); // SCL变低

  59. delay();

  60. set_gpio_value(SDA, b & (1<<i)); //从高位到低位依次准备数据进行发送

  61. set_gpio_value(SCL, 1); // SCL变高

  62. delay();

  63. }

  64. i2c_read_ack(); //检查目标设备的ACK信号

  65. }

  66. /* I2C字节读 */

  67. unsigned char i2c_read_byte()

  68. {

  69. int i;

  70. unsigned char r = 0;

  71. set_gpio_direction(SDA, INP); //设置SDA方向为输入

  72. for (i=7; i>=0; i--) {

  73. set_gpio_value(SCL, 0); // SCL变低

  74. delay();

  75. r = (r <<1) | get_gpio_value(SDA); //从高位到低位依次准备数据进行读取

  76. set_gpio_value(SCL, 1); // SCL变高

  77. delay();

  78. }

  79. i2c_send_ack(); //向目标设备发送ACK信号

  80. return r;

  81. }

  82. /*

  83. I2C读操作

  84. addr:目标设备地址

  85. buf:读缓冲区

  86. len:读入字节的长度

  87. */

  88. void i2c_read(unsigned char addr, unsigned char* buf, int len)

  89. {

  90. int i;

  91. unsigned char t;

  92. i2c_start(); //起始条件,开始数据通信

  93. //发送地址和数据读写方向

  94. t = (addr << 1) | 1; //低位为1,表示读数据 (addr)&fe

  95. i2c_write_byte(t);

  96. //读入数据

  97. for (i=0; i<len; i++)

  98. buf[i] = i2c_read_byte();

  99. i2c_stop(); //终止条件,结束数据通信

  100. }

  101. /*

  102. I2C写操作

  103. addr:目标设备地址

  104. buf:写缓冲区

  105. len:写入字节的长度

  106. */

  107. void i2c_write (unsigned char addr, unsigned char* buf, int len)

  108. {

  109. int i;

  110. unsigned char t;

  111. i2c_start(); //起始条件,开始数据通信

  112. //发送地址和数据读写方向

  113. t = (addr << 1) | 0; //低位为0,表示写数据 (addr)|1

  114. i2c_write_byte(t);

  115. //写入数据

  116. for (i=0; i<len; i++)

  117. i2c_write_byte(buf[i]);

  118. i2c_stop(); //终止条件,结束数据通信

  119. }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值