网友TestCode给了个老外的串口直接与I2C通讯的电路图,如下:
其中:
DTR控制串口窃电.
TX作为I2C的时钟信号SCL.
RTS作为PC侧SDA的数据输出.
DSR作为PC侧SDA的数据输入.
我有些愚笨,有些不明白...主要是TX的问题.
如果用Output()向串口发数据,实际是给I2C发时钟脉冲.
如发字符"U"(0x55),即在8位无校验1个停止位时,刚好是个方波信号.
即:S10101010P.其中S为起始位'0',P为停止为'1'.
也就是0101010101.即5个I2C的时钟周期.
但是在常规的编程时,TX和RX信号都是测试不了的,他们只能用函数
Output()和Input()函数操作.
这样虽然可以利用数据来发送I2C的时钟信号,那么怎样和在什么时候
发送或接收SDA上的数据呢???
难道在线程中根据给定的波特率即时间来捕捉TX信号上的跳变???
想了一天都没能想明白~~~脑子确实进水了...可是怎么也想不出来.
没办法,在TestCode给出图的瞬间,总觉得这样可能更合理些.
我的想法如下:
1.最关键的是如何测试TX的边沿.
我连了2个信号,CTS(可测试上升或下降的跳变)和RI(只能测出下降的跳变).
2.对TX的捕捉能力即时间是否跟上???
为此在不想搭上面的电路的情况下,做了下面电路的实验:
"自环"程序大概是这样的:
用Output("UU");发送I2C需要的10个SCL时钟信号.
在首个"U"的起始位"0"发出时,这是在CTS或RI上的RS232电平为10V左右.
CTS将会捕捉到comEvCTS事件.(但不能捕捉到comEvRing事件,画出它想在正规的电路上用)
在comEvCTS事件中,由于CTS为"1",所以这时控制RTS="1",导致RX线上为RS232电平10V左右
即RX收到RTS间接发来的起始位.依此类推,发完10个SCL时钟信号.
这时用Input()函数确实也收到了"数据"---"UU".即完成了软件的自环链接.
3.如何直接在RX上收到I2C的数据???
虽然发送"UU"可以得到很高的速率,但内部其中包含了2个停止位.
在真正的I2C数据通讯时,在SCL即TX的低电平(经过非门电路)是发送方放入数据的.
在SCL的高电平不允许SDA信号改变是告诉你接收方要取出数据的.
那么在硬件RS232电路内部是不会在那2个停止位上采样数据的,故"UU"组合不成立.
即2分频是不成立的.
故可采用:
8位无校验1个停止位的0x92,即
S0 1 00 1 00 1P S0 1 00 1 00 1P S0 1 00 1 00 1P
即发送3个0x92来产生9个I2C时钟(8位数据+ACK)
这样,起始位可在发送前拉低SDA简单的得到,
停止位和重复位可随便做到,如0x0f等.
也可用6位无校验1个停止位的0x26+0x3E,即
S0 11 00 1P S0 11 00 1P S0 11 00 1P S0 11 00 1P S0 11 00 1P...
这样写确实晕,不过0x26为字符"&",0x3e为字符">"
I2C时钟信号为"&&&&>"表示写7位地址+R/W+ACK的时钟序列.
若地址后带命令的停止位的完整的I2C时钟序列符为:
&&&&>&&&&&
从以上2个例子可以看出,要想用RX硬件读出数据,时钟序列中
都有"1P",即把停止位藏在一个高电平时钟后,这样就可以
"在停止位上从RX上采样到的数据"了~~~晕!!!
4.求助帮忙想想老外是如何"思想"的???
谢谢各位!!!
雁塔菜农 2007-7-7 01:59
用Input()实际是不好实现的.
因为RS232的停止位P=1.而I2C一侧可能发过来一个0.
这样Input()是不会读回来数据的.
例: PC端 S0000 1111P
I2C端 HLLLL LLLLL (H表示高电平,L表示低电平)
正确的是在P前I2C不能在发L了,即
PC端 S0000 1111P
I2C端 HLLLL LLLLH
但I2C规定了在SCL=1期间,SDA是不能改变的.
而从HLLLL LLLLH可以看出在一个时钟周期内可能需要跳变3次,这显然是通用的I2C协议不允许的.
故这个图即本问题看似简单,实际"充满了杀机"~~~
所以,用Input()直接读取RXD的数据是有困难的.