搜索
bottom↓
回复: 65

发一个IO模拟I2C从机的代码吧

  [复制链接]

出0入0汤圆

发表于 2014-5-11 15:41:54 | 显示全部楼层 |阅读模式
本帖最后由 xiaob135 于 2014-5-11 16:22 编辑

今天下了一天雨,无聊写点代码吧。
发现网上都是io口模拟i2c主机的代码,很少有模拟i2c从机的。所以写一个贡献出来。对于学习i2c的时序还是挺有帮助的。
需要两个带中断的io口,必须支持上升沿和下降沿中断。


typedef enum
{
                I2C_SLAVE_IDLE,
                I2C_SLAVE_ADD,//write iic add
                I2C_SLAVE_REG,//write the register add
                I2C_SLAVE_WRITE,//master write and slave read
                I2C_SLAVE_READ,//master read and slave write
                I2C_SLAVE_BUSY
}e_I2C_SLAVE_MODE;

static e_I2C_SLAVE_MODE                i2c_slave_mode = I2C_SLAVE_IDLE;
static unsigned char I2C_DATA_TEMP = 0;
static unsigned char i2c_slave_reg_p = 0;//the register add
static unsigned char i2c_slave_data_p = 0;//


void i2c_slave_scl_h( void )
{
        I2C_SDA_INT_EN();
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_ADD:
                case I2C_SLAVE_REG:
                case I2C_SLAVE_WRITE:
                        I2C_DATA_TEMP <<= 1;
                        if( I2C_SDA_IN() )
                                I2C_DATA_TEMP ++;
                        i2c_slave_data_p++;
                        break;               
                default:break;
        }
}

void i2c_slave_scl_l( void )
{
        I2C_SDA_INT_DIS();
       
        if( i2c_slave_data_p > 8 )
        {
                i2c_slave_data_p = 0;
                I2C_SDA_H();//end ack;
                return;
        }
       
        I2C_SCL_L();//slow the i2c speed
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_ADD:
                        if( i2c_slave_data_p == 8 )
                        {
                                        if( I2C_DATA_TEMP >> 1 == I2C_ADD )
                                        {
                                                I2C_SDA_L();//ack
                                                if( I2C_DATA_TEMP & 0x01 )//read
                                                {
                                                        i2c_slave_mode = I2C_SLAVE_READ;
                                                }
                                                else
                                                        i2c_slave_mode = I2C_SLAVE_REG;//write regster add
                                        }
                                        else
                                                i2c_slave_mode = I2C_SLAVE_BUSY;//nack
                        }
                        break;
                case I2C_SLAVE_REG:
                        if( i2c_slave_data_p == 8 )
                        {
                                        I2C_SDA_L();//ack
                                        i2c_slave_reg_p = I2C_DATA_TEMP;
                                        i2c_slave_mode = I2C_SLAVE_WRITE;
                        }
                        break;
                case I2C_SLAVE_WRITE:
                        if( i2c_slave_data_p == 8 )
                        {//
                                        if( I2C_SLAVE_WRITE_BYTE( i2c_slave_reg_p++, I2C_DATA_TEMP ) )
                                        {
                                                        I2C_SDA_L();
                                        }
                                        else
                                        {
                                                        i2c_slave_mode = I2C_SLAVE_BUSY;
                                        }
                        }
                        break;
                case I2C_SLAVE_READ:
                        if( i2c_slave_data_p < 8 )
                        {
                                        if( I2C_DATA_TEMP & 0x80 )//output a bit
                                                I2C_SDA_H();
                                        else
                                                I2C_SDA_L();               
                                        I2C_DATA_TEMP <<= 1;
                                        i2c_slave_data_p++;
                        }
                        else if( i2c_slave_data_p == 8 )
                        {
                                        if( I2C_SLAVE_READ_BYTE(i2c_slave_reg_p++, &I2C_DATA_TEMP) )
                                        {
                                                        I2C_SDA_L();
                                        }
                                        else
                                        {
                                                        i2c_slave_mode = I2C_SLAVE_BUSY;
                                        }
                        }
                        break;
                        default:break;
        }
        I2C_SCL_H();
}

void i2c_slave_sda_h( void )
{
                if( I2C_SCL_IN() )
                {
                        I2C_SCL_INT_DIS();
                        i2c_slave_mode = I2C_SLAVE_IDLE;
                }
}

void i2c_slave_sda_l( void )
{
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_IDLE:
                        if( I2C_SCL_IN() )
                        {
                                I2C_SCL_INT_EN();
                                i2c_slave_mode = I2C_SLAVE_ADD;
                                i2c_slave_data_p = 0;
                        }
                        break;
                default:break;
        }
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-11 15:57:28 | 显示全部楼层
nice  mark

出0入0汤圆

发表于 2014-5-11 16:28:47 | 显示全部楼层
I2C从机, 在何处应用较多?

出0入0汤圆

 楼主| 发表于 2014-5-11 16:32:08 | 显示全部楼层
qiushui_007 发表于 2014-5-11 16:28
I2C从机, 在何处应用较多?

单片机做从机的时候,或者两个单片机互相通信的时候。串口是字符型的通信,i2c是数据块型的通信,更方便一些。

出0入0汤圆

发表于 2014-5-11 16:40:44 | 显示全部楼层
不错,赞一个。

出0入0汤圆

发表于 2014-5-11 21:50:27 | 显示全部楼层
这思路不错啊!

出0入0汤圆

发表于 2014-5-11 21:58:16 | 显示全部楼层
谢谢分享,看上去很好。先收藏了

出0入0汤圆

发表于 2014-5-11 23:46:59 来自手机 | 显示全部楼层
太好了,对我正好有用!

出100入101汤圆

发表于 2014-5-12 06:10:50 | 显示全部楼层
xiaob135 发表于 2014-5-11 16:32
单片机做从机的时候,或者两个单片机互相通信的时候。串口是字符型的通信,i2c是数据块型的通信,更方便 ...

串口是字符型的通信,i2c是数据块型的通信,这个如何理解?

出0入0汤圆

发表于 2014-5-12 08:45:16 | 显示全部楼层
我记得以前学习51单片机的时候,就是模拟的,让人很不爽的就是i2c的时序了,当时是第一次接触,头晕,

出0入0汤圆

发表于 2014-5-12 09:16:46 | 显示全部楼层
这命名方式看得头大

出0入0汤圆

 楼主| 发表于 2014-5-12 09:18:15 | 显示全部楼层
craigtao 发表于 2014-5-12 08:45
我记得以前学习51单片机的时候,就是模拟的,让人很不爽的就是i2c的时序了,当时是第一次接触,头晕,{:lol ...

你当时用的肯定是i2c的主模式。主模式和从模式的程序结构是完全不一样的。

出100入101汤圆

发表于 2014-5-12 09:18:44 | 显示全部楼层
串口是字符型的通信,i2c是数据块型的通信,这个如何理解?

出0入0汤圆

 楼主| 发表于 2014-5-12 09:21:07 | 显示全部楼层
fengyunyu 发表于 2014-5-12 06:10
串口是字符型的通信,i2c是数据块型的通信,这个如何理解?

就是说从应用层的角度来讲,串口是一个字节一个字节的传送,需要自己编写一个通信协议。
i2c每次读取、写入都是先写地址,再写数据。这样应用层就可以直接进行数据交流,而不需要自己再写通信协议。

出0入0汤圆

发表于 2014-5-12 12:20:14 | 显示全部楼层
思路不错,MARK!

出0入0汤圆

发表于 2014-5-12 13:13:36 | 显示全部楼层
哦,是嘛。那看来这个是个不错的资料啊,。谢谢共享

出0入0汤圆

 楼主| 发表于 2014-5-13 13:21:18 | 显示全部楼层
BUG修正版。在单片机上实际测试通过。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2014-5-13 13:35:25 | 显示全部楼层
不错。用在什么单片机上,主频多少,有没有测试过主机SCK最高速率多少?
去年做过一个产品,51单片机,处理起来很费时。最后没办法,检测到起始位后,关闭中断,直接用nop的方式来延时,直到通信结束退出。
主机SCK速率不能超过30K。

出0入0汤圆

发表于 2014-6-18 16:35:42 | 显示全部楼层
先顶了,楼主能不能发个应用方面的程序看看

出0入0汤圆

发表于 2014-6-20 16:30:27 | 显示全部楼层
楼主测试过吗,有实际使用过吗?

出0入0汤圆

发表于 2014-7-19 09:45:41 | 显示全部楼层
很实用的程序,谢谢分享。

出0入0汤圆

发表于 2015-7-28 17:51:52 | 显示全部楼层
看着驱动很整洁,但是不知道怎么应用

出0入0汤圆

发表于 2015-7-29 09:32:53 | 显示全部楼层
不错,谢谢

出0入0汤圆

发表于 2015-7-29 11:29:36 | 显示全部楼层
这么说主从机都可以不用带硬件IIC了么?完全软件化的IIC。可以自己弄和软件协议创造一个新的更实用的接口。

出0入0汤圆

发表于 2015-10-12 16:23:55 | 显示全部楼层
好东西,先mark一下!

出0入0汤圆

发表于 2015-12-16 07:08:16 | 显示全部楼层
楼主你好,我将你的代码移植到STM32L051K6上,发现配置为开漏输出和中断后,获取的I2C电平被衰减了,去掉上升沿下降沿触发后,I2C电平又恢复了,不知曾经遇到过这样的问题没有?

出0入0汤圆

发表于 2016-2-17 13:55:00 | 显示全部楼层
正需要这个,感谢楼主分析,先分析一下

出0入0汤圆

发表于 2016-3-14 09:51:02 | 显示全部楼层
谢谢楼主的分享,但是没怎看懂,不知道楼主是怎么实现24lcxx中的:未收到停止位,又接收到一个起始位的情况。

出0入0汤圆

发表于 2016-3-14 12:30:51 | 显示全部楼层
IO模拟I2C从机

出0入0汤圆

发表于 2016-3-14 14:32:03 | 显示全部楼层
模拟从机还没见过

出0入0汤圆

发表于 2016-3-15 15:05:44 | 显示全部楼层
谢谢分享,看上去很好。

出0入0汤圆

发表于 2016-3-15 15:42:20 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2016-3-24 10:03:46 | 显示全部楼层
        /* Connect EXTI Line2 to PA2 pin */

出0入0汤圆

发表于 2016-3-24 10:06:47 | 显示全部楼层
        /* Connect EXTI Line2 to PA2 pin */        /* Connect EXTI Line3 to PA3 pin */  你好,PA2,和PA3接口应该连接到哪里呢,连接主机SCL,SDA口么?看你代码,应该是PA6,PA7这2个脚连接主机的SCL和SDA,代码如下,                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 ;                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                 GPIO_Init(GPIOA, &GPIO_InitStructure);                                  I2C_SCL_H();                 I2C_SDA_H();。

出0入0汤圆

发表于 2016-3-24 10:07:14 | 显示全部楼层
        /* Connect EXTI Line2 to PA2 pin */        /* Connect EXTI Line3 to PA3 pin */  你好,PA2,和PA3接口应该连接到哪里呢,连接主机SCL,SDA口么?看你代码,应该是PA6,PA7这2个脚连接主机的SCL和SDA,代码如下,                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 ;                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                 GPIO_Init(GPIOA, &GPIO_InitStructure);                                  I2C_SCL_H();                 I2C_SDA_H();

出0入0汤圆

发表于 2016-5-10 11:29:21 | 显示全部楼层
楼主公德无量啊,之前我都从没有用过模拟从机,看了楼主的代码后觉得很棒。决定要试试了。

出0入0汤圆

发表于 2016-5-10 18:39:44 | 显示全部楼层
make!make!

出0入0汤圆

发表于 2016-5-10 19:03:46 | 显示全部楼层
这个必须顶一下,MAKE!

出0入0汤圆

发表于 2016-5-14 16:20:23 | 显示全部楼层
mark 。。学习

出0入0汤圆

发表于 2016-9-2 10:57:02 | 显示全部楼层
谢谢分享,用到一个触摸芯片程序中,用来输出按键状态数据.

出0入0汤圆

发表于 2016-9-2 18:21:09 | 显示全部楼层
很不错哦,测试看看

出0入0汤圆

发表于 2016-9-21 20:58:24 | 显示全部楼层
不错收藏了。

出0入0汤圆

发表于 2017-1-19 21:02:41 | 显示全部楼层
请问楼主,这个设置为从机,另外一个单片机设置为主机与他通讯,是否可以读取他的内容了?

出0入0汤圆

发表于 2017-1-20 15:09:07 | 显示全部楼层
楼主这个是32bit的是吗?

出0入9汤圆

发表于 2017-1-20 15:24:23 | 显示全部楼层
这个不错,其实需要用到iic从机的时候建议还是用带从机模式的MCU,例如LPC812之类的芯片,操作比较简单。

出0入0汤圆

发表于 2017-1-20 15:27:17 来自手机 | 显示全部楼层
IIC 单片机做从设备,软件模拟需要配合中断脚

出0入0汤圆

发表于 2018-3-28 14:20:32 | 显示全部楼层
shangyu60104 发表于 2016-9-2 18:21
很不错哦,测试看看

哥们,这个i2c从机程序怎么用啊

出0入0汤圆

发表于 2018-3-28 14:30:51 | 显示全部楼层
yufanyufan77 发表于 2018-3-28 14:20
哥们,这个i2c从机程序怎么用啊

现在很多单片机带硬件I2C,建议还是硬件I2C的MCU。

出0入0汤圆

发表于 2018-3-28 21:44:54 | 显示全部楼层
很不错的,学习下、

出0入0汤圆

发表于 2018-5-7 15:25:14 | 显示全部楼层
正好要用到 谢谢LZ 的奉献

出0入53汤圆

发表于 2019-9-20 11:29:31 | 显示全部楼层
liufabing 发表于 2016-9-2 10:57
谢谢分享,用到一个触摸芯片程序中,用来输出按键状态数据.

楼上的模拟iic 从搞定了吗?

出0入53汤圆

发表于 2019-9-20 11:31:05 | 显示全部楼层
tanguicaicai 发表于 2018-5-7 15:25
正好要用到 谢谢LZ 的奉献

楼上的在项目中开始应用了?

出0入0汤圆

发表于 2019-9-20 19:16:23 | 显示全部楼层
zhcj66 发表于 2019-9-20 11:29
楼上的模拟iic 从搞定了吗?

只是作了样品,没有量产.
程序是参考楼主的.

出0入53汤圆

发表于 2019-9-21 08:53:40 | 显示全部楼层
liufabing 发表于 2019-9-20 19:16
只是作了样品,没有量产.
程序是参考楼主的.

最后有没有调通,我有点看不懂楼主的程序

出0入0汤圆

发表于 2019-9-21 09:05:16 | 显示全部楼层
zhcj66 发表于 2019-9-21 08:53
最后有没有调通,我有点看不懂楼主的程序

调通了,不过我那个是汇编,更难看懂.

出0入53汤圆

发表于 2019-9-21 10:29:13 | 显示全部楼层
liufabing 发表于 2019-9-21 09:05
调通了,不过我那个是汇编,更难看懂.

c的没有做过?  有没有听说谁用iic从 用到项目中稳定工作的?

汇编从模式的iic

  1. ;/*------------------------------------------------------------------*/
  2. ;/* --- STC MCU International Limited -------------------------------*/
  3. ;/* --- STC 1T Series MCU Simulate I2C Slave Demo -------------------*/
  4. ;/* --- Mobile: (86)13922805190 -------------------------------------*/
  5. ;/* --- Fax: 86-755-82944243 ----------------------------------------*/
  6. ;/* --- Tel: 86-755-82948412 ----------------------------------------*/
  7. ;/* --- Web: www.STCMCU.com -----------------------------------------*/
  8. ;/* If you want to use the program or the program referenced in the  */
  9. ;/* article, please specify in which data and procedures from STC    */
  10. ;/*------------------------------------------------------------------*/

  11. SCL BIT P1.0
  12. SDA BIT P1.1

  13. ;----------------------------

  14.         ORG 0

  15. RESET:
  16.     SETB SCL
  17.     SETB SDA
  18.    
  19.     CALL I2C_WAITSTART  ;等待起始信号
  20.     CALL I2C_RXBYTE     ;接收地址数据
  21.     CLR C
  22.     CALL I2C_TXACK      ;回应ACK
  23.     SETB C              ;读/写 IDATA[80H - FFH]
  24.     RRC A               ;读/写位->C
  25.     MOV R0,A            ;地址送入R0
  26.     JC READDATA         ;C=1(读) C=0(写)
  27. WRITEDATA:
  28.     CALL I2C_RXBYTE     ;接收数据
  29.     MOV @R0,A           ;写入IDATA
  30.     INC R0              ;地址+1
  31.     CLR C
  32.     CALL I2C_TXACK      ;回应ACK
  33.     CALL I2C_WAITSTOP   ;等待停止信号
  34.     JMP RESET
  35.    
  36. READDATA:
  37.     MOV A,@R0
  38.     INC R0
  39.     CALL I2C_TXBYTE     ;发送IDATA数据
  40.     CALL I2C_RXACK      ;接收ACK
  41.     CALL I2C_WAITSTOP   ;等待停止信号
  42.     JMP RESET

  43. ;----------------------------
  44. ;等待起始信号
  45. ;----------------------------
  46. I2C_WAITSTART:
  47.     JNB SCL,$       ;等待时钟->高
  48.     JB SDA,$        ;等待数据线下降沿
  49.     JB SCL,$        ;等待时钟->低
  50.     RET

  51. ;----------------------------
  52. ;等待结束信号
  53. ;----------------------------
  54. I2C_WAITSTOP:
  55.     JNB SCL,$       ;等待时钟->高
  56.     JNB SDA,$       ;等待数据线上升沿
  57.     RET

  58. ;----------------------------
  59. ;发送ACK/NAK信号
  60. ;----------------------------
  61. I2C_TXACK:
  62.     MOV SDA,C       ;送ACK数据
  63.     JNB SCL,$       ;等待时钟->高
  64.     JB SCL,$        ;等待时钟->低
  65.     SETB SDA        ;发送完成
  66.     RET

  67. ;----------------------------
  68. ;接收ACK/NAK信号
  69. ;----------------------------
  70. I2C_RXACK:
  71.     SETB SDA        ;准备读数据
  72.     JNB SCL,$       ;等待时钟->高
  73.     MOV C,SDA       ;读取ACK信号
  74.     JB SCL,$        ;等待时钟->低
  75.     RET

  76. ;----------------------------
  77. ;接收一字节数据
  78. ;----------------------------
  79. I2C_RXBYTE:
  80.     MOV R7,#8       ;8位计数
  81. RXNEXT:
  82.     JNB SCL,$       ;等待时钟->高
  83.     MOV C,SDA       ;读取数据口
  84.     RLC A           ;保存数据
  85.     JB SCL,$        ;等待时钟->低
  86.     DJNZ R7,RXNEXT  ;收下一位
  87.     RET

  88. ;----------------------------
  89. ;发送一字节数据
  90. ;----------------------------
  91. I2C_TXBYTE:
  92.     MOV R7,#8       ;8位计数
  93. TXNEXT:
  94.     RLC A           ;移出数据位
  95.     MOV SDA,C       ;数据送数据口
  96.     JNB SCL,$       ;等待时钟->高
  97.     JB SCL,$        ;等待时钟->低
  98.     DJNZ R7,TXNEXT  ;送下一位
  99.     RET

  100. ;----------------------------

  101.         END
复制代码

出0入0汤圆

发表于 2019-10-17 16:42:43 | 显示全部楼层
zhcj66 发表于 2019-9-21 08:53
最后有没有调通,我有点看不懂楼主的程序

楼主的程序是有bug的,但楼主说验证通过了的,我就很纳闷了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-10-17 16:54:36 | 显示全部楼层
zhcj66 发表于 2019-9-21 10:29
c的没有做过?  有没有听说谁用iic从 用到项目中稳定工作的?

汇编从模式的iic

STC这个DEMO一直在死等,难道不干其他事情吗

出0入0汤圆

发表于 2019-10-19 00:24:11 来自手机 | 显示全部楼层
io模拟i2c从机

出0入0汤圆

发表于 2019-10-19 20:33:03 | 显示全部楼层
楼主 我在尝试不用中断 使用定时器的方式来实现 目前还未调通 不知道可不可行

出0入300汤圆

发表于 2019-10-21 06:26:44 来自手机 | 显示全部楼层
这个帖子让我很深刻,其中的关键词是楼主开贴的第一句。从此以后的很多年,我要写代码一定要等到天降大雨

出0入0汤圆

发表于 2019-12-22 21:12:35 | 显示全部楼层
在scl的下降沿中断中,开头的  I2C_SCL_L();//slow the i2c speed  和结尾的 I2C_SCL_H()是干嘛的,sck的速率不是主机决定的吗。

出0入0汤圆

发表于 2019-12-23 03:14:59 | 显示全部楼层
这已超过五年以上的老帖又给挖出土了!呵呵~

出0入0汤圆

发表于 2021-3-25 14:48:29 | 显示全部楼层
mark!!!!!!

出0入0汤圆

发表于 2022-5-19 11:15:19 | 显示全部楼层
io模拟i2c从机

出0入0汤圆

发表于 2022-11-4 09:39:06 | 显示全部楼层
楼主能否发个完整的例程上来,这个实在看不懂了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 05:10

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表