发一个IO模拟I2C从机的代码吧
本帖最后由 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;
}
}
nicemark I2C从机, 在何处应用较多? qiushui_007 发表于 2014-5-11 16:28
I2C从机, 在何处应用较多?
单片机做从机的时候,或者两个单片机互相通信的时候。串口是字符型的通信,i2c是数据块型的通信,更方便一些。 不错,赞一个。 这思路不错啊! 谢谢分享,看上去很好。先收藏了 太好了,对我正好有用! xiaob135 发表于 2014-5-11 16:32
单片机做从机的时候,或者两个单片机互相通信的时候。串口是字符型的通信,i2c是数据块型的通信,更方便 ...
串口是字符型的通信,i2c是数据块型的通信,这个如何理解? 我记得以前学习51单片机的时候,就是模拟的,让人很不爽的就是i2c的时序了,当时是第一次接触,头晕,{:lol:} 这命名方式看得头大 craigtao 发表于 2014-5-12 08:45
我记得以前学习51单片机的时候,就是模拟的,让人很不爽的就是i2c的时序了,当时是第一次接触,头晕,{:lol ...
你当时用的肯定是i2c的主模式。主模式和从模式的程序结构是完全不一样的。 串口是字符型的通信,i2c是数据块型的通信,这个如何理解? fengyunyu 发表于 2014-5-12 06:10
串口是字符型的通信,i2c是数据块型的通信,这个如何理解?
就是说从应用层的角度来讲,串口是一个字节一个字节的传送,需要自己编写一个通信协议。
i2c每次读取、写入都是先写地址,再写数据。这样应用层就可以直接进行数据交流,而不需要自己再写通信协议。 思路不错,MARK! 哦,是嘛。那看来这个是个不错的资料啊,。谢谢共享 BUG修正版。在单片机上实际测试通过。 不错。用在什么单片机上,主频多少,有没有测试过主机SCK最高速率多少?
去年做过一个产品,51单片机,处理起来很费时。最后没办法,检测到起始位后,关闭中断,直接用nop的方式来延时,直到通信结束退出。
主机SCK速率不能超过30K。 先顶了,楼主能不能发个应用方面的程序看看 楼主测试过吗,有实际使用过吗?
很实用的程序,谢谢分享。 看着驱动很整洁,但是不知道怎么应用{:sweat:} 不错,谢谢 这么说主从机都可以不用带硬件IIC了么?完全软件化的IIC。可以自己弄和软件协议创造一个新的更实用的接口。 好东西,先mark一下!{:titter:} 楼主你好,我将你的代码移植到STM32L051K6上,发现配置为开漏输出和中断后,获取的I2C电平被衰减了,去掉上升沿下降沿触发后,I2C电平又恢复了,不知曾经遇到过这样的问题没有? 正需要这个,感谢楼主分析,先分析一下 谢谢楼主的分享,但是没怎看懂,不知道楼主是怎么实现24lcxx中的:未收到停止位,又接收到一个起始位的情况。 IO模拟I2C从机 模拟从机还没见过 谢谢分享,看上去很好。 谢谢分享! /* Connect EXTI Line2 to PA2 pin */ /* 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();。 /* 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(); {:handshake:}楼主公德无量啊,之前我都从没有用过模拟从机,看了楼主的代码后觉得很棒。决定要试试了。 make!make! 这个必须顶一下,MAKE! mark 。。学习
谢谢分享,用到一个触摸芯片程序中,用来输出按键状态数据. 很不错哦,测试看看 不错收藏了。 请问楼主,这个设置为从机,另外一个单片机设置为主机与他通讯,是否可以读取他的内容了? 楼主这个是32bit的是吗? 这个不错,其实需要用到iic从机的时候建议还是用带从机模式的MCU,例如LPC812之类的芯片,操作比较简单。 IIC 单片机做从设备,软件模拟需要配合中断脚 shangyu60104 发表于 2016-9-2 18:21
很不错哦,测试看看
哥们,这个i2c从机程序怎么用啊 yufanyufan77 发表于 2018-3-28 14:20
哥们,这个i2c从机程序怎么用啊
现在很多单片机带硬件I2C,建议还是硬件I2C的MCU。 很不错的,学习下、 正好要用到 谢谢LZ 的奉献 liufabing 发表于 2016-9-2 10:57
谢谢分享,用到一个触摸芯片程序中,用来输出按键状态数据.
楼上的模拟iic 从搞定了吗? tanguicaicai 发表于 2018-5-7 15:25
正好要用到 谢谢LZ 的奉献
楼上的在项目中开始应用了? zhcj66 发表于 2019-9-20 11:29
楼上的模拟iic 从搞定了吗?
只是作了样品,没有量产.
程序是参考楼主的. liufabing 发表于 2019-9-20 19:16
只是作了样品,没有量产.
程序是参考楼主的.
最后有没有调通,我有点看不懂楼主的程序 zhcj66 发表于 2019-9-21 08:53
最后有没有调通,我有点看不懂楼主的程序
调通了,不过我那个是汇编,更难看懂. liufabing 发表于 2019-9-21 09:05
调通了,不过我那个是汇编,更难看懂.
c的没有做过?有没有听说谁用iic从 用到项目中稳定工作的?
汇编从模式的iic
;/*------------------------------------------------------------------*/
;/* --- STC MCU International Limited -------------------------------*/
;/* --- STC 1T Series MCU Simulate I2C Slave Demo -------------------*/
;/* --- Mobile: (86)13922805190 -------------------------------------*/
;/* --- Fax: 86-755-82944243 ----------------------------------------*/
;/* --- Tel: 86-755-82948412 ----------------------------------------*/
;/* --- Web: www.STCMCU.com -----------------------------------------*/
;/* If you want to use the program or the program referenced in the*/
;/* article, please specify in which data and procedures from STC */
;/*------------------------------------------------------------------*/
SCL BIT P1.0
SDA BIT P1.1
;----------------------------
ORG 0
RESET:
SETB SCL
SETB SDA
CALL I2C_WAITSTART;等待起始信号
CALL I2C_RXBYTE ;接收地址数据
CLR C
CALL I2C_TXACK ;回应ACK
SETB C ;读/写 IDATA
RRC A ;读/写位->C
MOV R0,A ;地址送入R0
JC READDATA ;C=1(读) C=0(写)
WRITEDATA:
CALL I2C_RXBYTE ;接收数据
MOV @R0,A ;写入IDATA
INC R0 ;地址+1
CLR C
CALL I2C_TXACK ;回应ACK
CALL I2C_WAITSTOP ;等待停止信号
JMP RESET
READDATA:
MOV A,@R0
INC R0
CALL I2C_TXBYTE ;发送IDATA数据
CALL I2C_RXACK ;接收ACK
CALL I2C_WAITSTOP ;等待停止信号
JMP RESET
;----------------------------
;等待起始信号
;----------------------------
I2C_WAITSTART:
JNB SCL,$ ;等待时钟->高
JB SDA,$ ;等待数据线下降沿
JB SCL,$ ;等待时钟->低
RET
;----------------------------
;等待结束信号
;----------------------------
I2C_WAITSTOP:
JNB SCL,$ ;等待时钟->高
JNB SDA,$ ;等待数据线上升沿
RET
;----------------------------
;发送ACK/NAK信号
;----------------------------
I2C_TXACK:
MOV SDA,C ;送ACK数据
JNB SCL,$ ;等待时钟->高
JB SCL,$ ;等待时钟->低
SETB SDA ;发送完成
RET
;----------------------------
;接收ACK/NAK信号
;----------------------------
I2C_RXACK:
SETB SDA ;准备读数据
JNB SCL,$ ;等待时钟->高
MOV C,SDA ;读取ACK信号
JB SCL,$ ;等待时钟->低
RET
;----------------------------
;接收一字节数据
;----------------------------
I2C_RXBYTE:
MOV R7,#8 ;8位计数
RXNEXT:
JNB SCL,$ ;等待时钟->高
MOV C,SDA ;读取数据口
RLC A ;保存数据
JB SCL,$ ;等待时钟->低
DJNZ R7,RXNEXT;收下一位
RET
;----------------------------
;发送一字节数据
;----------------------------
I2C_TXBYTE:
MOV R7,#8 ;8位计数
TXNEXT:
RLC A ;移出数据位
MOV SDA,C ;数据送数据口
JNB SCL,$ ;等待时钟->高
JB SCL,$ ;等待时钟->低
DJNZ R7,TXNEXT;送下一位
RET
;----------------------------
END
zhcj66 发表于 2019-9-21 08:53
最后有没有调通,我有点看不懂楼主的程序
楼主的程序是有bug的,但楼主说验证通过了的,我就很纳闷了。{:lol:}
zhcj66 发表于 2019-9-21 10:29
c的没有做过?有没有听说谁用iic从 用到项目中稳定工作的?
汇编从模式的iic
STC这个DEMO一直在死等,难道不干其他事情吗 io模拟i2c从机 楼主 我在尝试不用中断 使用定时器的方式来实现 目前还未调通 不知道可不可行 这个帖子让我很深刻,其中的关键词是楼主开贴的第一句。从此以后的很多年,我要写代码一定要等到天降大雨 在scl的下降沿中断中,开头的I2C_SCL_L();//slow the i2c speed和结尾的 I2C_SCL_H()是干嘛的,sck的速率不是主机决定的吗。 这已超过五年以上的老帖又给挖出土了!呵呵~
mark!!!!!! io模拟i2c从机 楼主能否发个完整的例程上来,这个实在看不懂了。
页:
[1]