新浪博客

使用GPIO模拟I2C总线进行通信

2013-10-13 15:42阅读:
I2C是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。I2C是总线结构,1个Master,1个或多个Slave,各Slave设备以7位地址区分,地址后面再跟1位读写位,表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址,此时每个设备有读、写两个地址,高7位地址其实是相同的。
I2C数据格式如下:
无数据:SCL=1,SDA=1;
开始位(Start):当SCL=1时,SDA由1向0跳变;
停止位(Stop):当SCL=1时,SDA由0向1跳变;
数据位:当SCL由0向1跳变时,由发送方控制SDA,此时SDA为有效数据,不可随意改变SDA;
当SCL保持为0时,SDA上的数据可随意改变;
地址位:定义同数据位,但只由Master发给Slave;
应答位(ACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=0;
否应答位(NACK):当发送方传送完8位时,发送方释放SDA,由接收方控制SDA,且SDA=1。
当数据为单字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,停止位。
当数据为一串字节传送时,格式为:
开始位,8位地址位(含1位读写位),应答,8位数据,应答,8位数据,应答,……,8位数据,应答,停止位。
需要注意的是:
1,SCL一直由Master控制,SDA依照数据传送的方向,读数据时由Slave控制SDA,写数据时由Master控制SDA。当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反。
2,开始位“Start”和停止位“Stop”,只能由Master来发出。
3,地址的8位传送完毕后,成功配置地址的Slave设备必须发送“ACK”。否则否则一定时间之后Master视为超时,将放弃数据传送,发送“Stop”。
4,当写数据的时候,Master每发送完8个数据位,Slave设备如果还有空间接受下一个字节应该回答“ACK”,Slave设备如果没有空间接受更多的字
节应该回答“NACK”,Master当收到“NACK”或者一定时间之后没收到任何数据将视为超时,此时Master放弃数据传送,发送“Stop”。
5,当读数据的时候,Slave设备每发送完8个数据位,如果Master希望继续读下一个字节,Master应该回答“ACK”以提示Slave准备下一个数据,如果Master不希望读取更多字节,Master应该回答“NACK”以提示Slave设备准备接收Stop信号。
6,当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。
在实际应用中,并没有强制规定数据接收方必须对于发送的8位数据做出回应,尤其是在Master和Slave端都是用GPIO软件模拟的方法来实现的情况下,编程者可以事先约定数据传送的长度,slave不检查NACK,有时可以起到减少系统开销的效果。但是如果slave方是硬件i2c要求一定要标准的NACK,master方是GPIO软件模拟i2c并没有正确的发送NACK,就会出现“slave收不到stop”导致i2c挂死。


下面给出了模拟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. int i2c_start()
  6. {
  7. //初始化GPIO口
  8. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
  9. set_gpio_direction (SCL, OUTP); //设置SCL方向为输出
  10. set_gpio_value(SDA, 1); //设置SDA为高电平
  11. set_gpio_value(SCL, 1); //设置SCL为高电平
  12. delay(); //延时
  13. //起始条件
  14. set_gpio_value(SDA, 0); //SCL为高电平时,SDA由高变低
  15. delay();
  16. }
  17. void i2c_stop()
  18. {
  19. set_gpio_value(SCL, 1);
  20. set_gpio_direction(SDA, OUTP);
  21. set_gpio_value(SDA, 0);
  22. delay();
  23. set_gpio_value(SDA, 1); //SCL高电平时,SDA由低变高
  24. }
  25. unsigned char i2c_read_ack()
  26. {
  27. unsigned char r;
  28. set_gpio_direction(SDA, INP); //设置SDA方向为输入
  29. set_gpio_value(SCL,0); // SCL变低
  30. r = get_gpio_value(SDA); //读取ACK信号
  31. delay();
  32. set_gpio_value(SCL,1); // SCL变高
  33. delay();
  34. return r;
  35. }
  36. int i2c_send_ack()
  37. {
  38. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
  39. set_gpio_value(SCL,0); // SCL变低
  40. set_gpio_value(SDA, 0); //发出ACK信号
  41. delay();
  42. set_gpio_value(SCL,1); // SCL变高
  43. delay();
  44. }
  45. void i2c_write_byte(unsigned char b)
  46. {
  47. int i;
  48. set_gpio_direction(SDA, OUTP); //设置SDA方向为输出
  49. for (i=7; i>=0; i--) {
  50. set_gpio_value(SCL, 0); // SCL变低
  51. delay();
  52. set_gpio_value(SDA, b & (1<</SPAN><</SPAN>i)); //从高位到低位依次准备数据进行发送
  53. set_gpio_value(SCL, 1); // SCL变高
  54. delay();
  55. }
  56. i2c_read_ack(); //检查目标设备的ACK信号
  57. }
  58. unsigned char i2c_read_byte()
  59. {
  60. int i;
  61. unsigned char r = 0;
  62. set_gpio_direction(SDA, INP); //设置SDA方向为输入
  63. for (i=7; i>=0; i--) {
  64. set_gpio_value(SCL, 0); // SCL变低
  65. delay();
  66. r = (r <</SPAN><</SPAN>1) | get_gpio_value(SDA); //从高位到低位依次准备数据进行读取
  67. set_gpio_value(SCL, 1); // SCL变高
  68. delay();
  69. }
  70. i2c_send_ack(); //向目标设备发送ACK信号
  71. return r;
  72. }
  73. void i2c_read(unsigned char addr, unsigned char* buf, int len)
  74. {
  75. int i;
  76. unsigned char t;
  77. i2c_start(); //起始条件,开始数据通信
  78. //发送地址和数据读写方向
  79. t = (addr <</SPAN><</SPAN> 1) | 1; //低位为1,表示读数据
  80. i2c_write_byte(t);
  81. //读入数据
  82. for (i=0; i<</SPAN>len; i++)
  83. buf[i] = i2c_read_byte();
  84. i2c_stop(); //终止条件,结束数据通信
  85. }
  86. void i2c_write (unsigned char addr, unsigned char* buf, int len)
  87. {
  88. int i;
  89. unsigned char t;
  90. i2c_start(); //起始条件,开始数据通信
  91. //发送地址和数据读写方向
  92. t = (addr <</SPAN><</SPAN> 1) | 0; //低位为0,表示写数据
  93. i2c_write_byte(t);
  94. //写入数据
  95. for (i=0; i<</SPAN>len; i++)
  96. i2c_write_byte(buf[i]);
  97. i2c_stop(); //终止条件,结束数据通信
  98. }
在上面的代码中,i2c_read和i2c_write这两个函数可以实现GPIO接口对I2C总线的模拟读写。
--------------------------------------------------------------------------------------------------
不是完整的代码,仅仅提供模拟操作部分供大家参考。

[cpp] view plaincopyprint?
  1. #define DELAY 1
  2. #define SCL 89
  3. #define SDA 20
  4. #define RST 19
  5. #define IRQ 108
  6. void i2c_start(void)
  7. {
  8. gpio_direction_output(SDA, 1);
  9. gpio_direction_output(SCL, 1);
  10. udelay(DELAY);
  11. gpio_set_value(SDA, 0);
  12. udelay(DELAY);
  13. gpio_set_value(SCL, 0);
  14. udelay(DELAY);
  15. }
  16. void i2c_stop(void)
  17. {
  18. gpio_set_value(SCL, 0);
  19. gpio_set_value(SDA, 0);
  20. udelay(DELAY);
  21. gpio_set_value(SCL, 1);
  22. udelay(DELAY);
  23. gpio_set_value(SDA, 1);
  24. udelay(DELAY);
  25. }
  26. void i2c_send_ack(u8 ack)
  27. {
  28. if(ack)
  29. gpio_direction_output(SDA, 1);
  30. else
  31. gpio_direction_output(SDA, 0);
  32. udelay(DELAY);
  33. gpio_set_value(SCL, 1);
  34. udelay(DELAY);
  35. gpio_set_value(SCL, 0);
  36. udelay(DELAY);
  37. }
  38. u8 i2c_receive_ack(void)
  39. {
  40. u8 rc = 0;
  41. gpio_direction_input(SDA);
  42. gpio_set_value(SCL, 1);
  43. udelay(DELAY);
  44. if(gpio_get_value(SDA)) {
  45. rc = 1;
  46. }
  47. gpio_set_value(SCL, 0);
  48. gpio_direction_output(SDA, 1);
  49. return rc;
  50. }
  51. u8 i2c_send_byte(u8 send_byte)
  52. {
  53. u8 rc = 0;
  54. u8 out_mask = 0x80;
  55. u8 value;
  56. u8 count = 8;
  57. while(count > 0) {
  58. value = ((send_byte & out_mask) ? 1 : 0);
  59. if (value == 1) {
  60. gpio_set_value(SDA, 1);
  61. }
  62. else {
  63. gpio_set_value(SDA, 0);
  64. }
  65. udelay(DELAY);
  66. gpio_set_value(SCL, 1);
  67. udelay(DELAY);
  68. gpio_set_value(SCL, 0);
  69. udelay(DELAY);
  70. out_mask >>= 1;
  71. count--;
  72. }
  73. gpio_set_value(SDA, 1);
  74. rc = i2c_receive_ack();
  75. return rc;
  76. }
  77. void i2c_read_byte(u8 *buffer, u8 ack)
  78. {
  79. u8 count = 0x08;
  80. u8 data = 0x00;
  81. u8 temp = 0;
  82. gpio_direction_input(SDA);
  83. while(count > 0) {
  84. gpio_set_value(SCL, 1);
  85. udelay(DELAY);
  86. temp = gpio_get_value(SDA);
  87. data <<= 1;
  88. if (temp)
  89. data |= 0x01;
  90. gpio_set_value(SCL, 0);
  91. udelay(DELAY);
  92. count--;
  93. }
  94. i2c_send_ack(ack);//0 = ACK 1 = NACK
  95. *buffer = data;
  96. }
  97. //向client的某个寄存器写入多个字节,len是要写入的数据的长度
  98. u8 i2c_write(u8 device_id, u8 reg_address, u8* data, u8 len)
  99. {
  100. u8 rc = 0;
  101. u8 i;
  102. i2c_start();
  103. rc |= i2c_send_byte( (device_id << 1) | 0x00 );
  104. rc |= i2c_send_byte(reg_address);
  105. if(data==NULL ||0==len) {
  106. i2c_stop();
  107. return rc;
  108. }
  109. for(i=0; i<len; i++) {
  110. rc |= i2c_send_byte(*data);
  111. data++;
  112. }
  113. i2c_stop();
  114. if(rc) {
  115. printk('ERROR! ssd2531_i2c_write failed/n');
  116. }
  117. return rc;
  118. }
  119. //从某个register中读取len个字节放在长度为len的缓冲区buffer中
  120. u8 i2c_read(u8 device_id, u8 reg_address, u8 *buffer, u8 len)
  121. {
  122. u8 rc = 0;
  123. u8 i;
  124. i2c_start();
  125. rc |= i2c_send_byte( (device_id << 1) | 0x00 );
  126. rc |= i2c_send_byte(reg_address);
  127. i2c_start();//restart I2C
  128. rc |= i2c_send_byte( (device_id << 1) | 0x01 );
  129. for(i=0;i<len;i++) {
  130. i2c_read_byte(buffer++, !(len-i-1));// !(len-i-1) 这个用来保证在读到每个字节后发送一个ACK并能在最后一个字节读完后发送一个NACK
  131. }
  132. i2c_stop();
  133. if(rc) {
  134. printk('ERROR! ssd2531_i2c_read failed/n');
  135. return rc;
  136. }
  137. return rc;
  138. }

我的更多文章

下载客户端阅读体验更佳

APP专享