模拟I2C---从机
硬件平台:em78p153
一般IO模拟有2种方法:中断或查询。这里用的是查询的方式。查询IO口状态变化,主机SCK速率不能超过100Khz。
I2C协议中最重要的一点是I2C地址。这个地址有7位和10位两种形式。7位能够表示127个地址,而在实际使用中基本上不会挂载如此多的设置,所以很多设备的地址都采用7位,所以本文接下来的说明都是基于此。I2C还有一个很重要的概念,就是“主—从”。对于从设备来说,它是啥都不干的,更不会自动发送数据;而主设备,则是起到控制作用,一切都是从它开始。
*********
观看时序图总结几点:
1. 时序图都是共用一个时钟信号,注意时钟信号在上下图中的对应。
2. 时序图中有叉或者上升下降的如果是数据线的话表示数据有变化。菱形封闭的一段表示有效数据。
3. 数据需要一段时间稳定,一般在数据变化后,时钟的上升沿或者下降沿读入数据或者写入数据。
**********
由于这里是做从机,所以用主机读写从机来反推时序,可以去查看AT24C02的时序
做从机时,就要反过来根据时序逆推:采用方式IO口查询模式
作为从机要判断的事件有。
检测start->地址是否匹配->主机是要写,还是要读
写的情况下:发送ACK -->接收数据-->数据接收完毕发送nack或者等待主机停止-->主机stop
读的情况下:发送ACK-->发送数据-->等待主机ACK -->主机ACK后继续发送,主机NACK 停止发送,等待STOP-->主机STOP
MCU:8Mhz 内部IRC
程序代码
---代码经过测试,但这种容易阻塞读写不是很高效。这个只提供参考。
Date_0000: ;接受开始信号-------------------
MOV A,@0X03 ;0.25us 1个指令周期
IOW PORT5 ;sda输入模式
Date_0001:
;--------------------------------------------
JBS PORT5,SCL ;判断scl==1? 2个指令周期
JMP Date_0001 ;否,重新判断开始信号 1us 2个指令周期
JBS PORT5,SDA ;判断sda==1 1us
JMP Date_0001 ;
Date_0002:
JBC PORT5,SDA ;是,等待sda等于0 1us
JMP $-1 ;
JBS PORT5,SCL ;判断scl等于1吗
JMP Date_0000 ;否,重新判断开始信号 1us
地址:
Date_1000:
CLR REG0
MOV A,@8
MOV REG1,A ;赋值给yr1 1us
BC R3,0 ;清c进位标志位
Date_1100: ;接受指令---------------------------
JBC PORT5,SCL ;等待scl变0 1us
JMP $-1
;============================================
JBS PORT5,SCL ;等待scl变1
JMP $-1 ;在scl上升沿把sda作为数据输入 1us
;============================================
RLC REG0 ;左移一位把高位移出
JBC PORT5,SDA ;判断sda等于0 1us
BS REG0,0 ;等于1置位1
DJZ REG1 ;sda为0,判断yr1减1是否为0
JMP SID_1100 ;yr1不为0,接受下一位 1us
MOV A,REG0
XOR A,@0Xa0 ;判断数据是否为0xA0 3us
JBS R3,2
JMP Date_0000 ;不是重新接受开始信号
应答:
Date_1200:
MOV A,@0X01
;IOW PORT5 ;sda输出模式
JBC PORT5,SCL ;等到scl变0
JMP $-1
IOW PORT5
BC PORT5,SDA ;输出0
JBS PORT5,SCL ;等待scl变1
JMP $-1
JBC PORT5,SCL ;等待scl变0
JMP $-1
非应答:
Date_6500: ;非应答----从机 sda = 1
MOV A,@0X01
JBC PORT5,SCL ;等到scl变0
JMP $-1 ;
IOW PORT5 ;sda输出模式
BS PORT5,SDA
JBS PORT5,SCL ;等待scl变1
JMP $-1
JBC PORT5,SCL ;等待scl变0
JMP $-1
停止:
Date_7000: ;停止信号-------------
MOV A,@0X03
IOW PORT5
JBS PORT5,SCL ;判断scl是否为1
JMP Date_7000
JBC PORT5,SDA ;判断sda是否为0
JMP Date_7000
JBS PORT5,SDA ;等待sda变为1
JMP $-1
JBS PORT5,SCL ;SDA=1,判断scl是否为1
JMP Date_7000