str[3] = (unsigned char)ack + ‘0’;

str[4] = ‘’;

LcdShowStr(8, 0, str); //显示到液晶上

while (1);

}

/* 产生总线起始信号 */

void I2CStart(){

I2C_SDA = 1; //首先确保 SDA、SCL 都是高电平

I2C_SCL = 1;

I2CDelay();

I2C_SDA = 0; //先拉低 SDA

I2CDelay();

I2C_SCL = 0; //再拉低 SCL

}

/* 产生总线停止信号 */

void I2CStop(){

I2C_SCL = 0; //首先确保 SDA、SCL 都是低电平

I2C_SDA = 0;

I2CDelay();

I2C_SCL = 1; //先拉高 SCL

I2CDelay();

I2C_SDA = 1; //再拉高 SDA

I2CDelay();

}

/* I2C 总线写操作,dat-待写入字节,返回值-从机应答位的值 */

bit I2CWrite(unsigned char dat){

bit ack; //用于暂存应答位的值

unsigned char mask; //用于探测字节内某一位值的掩码变量

for (mask=0x80; mask!=0; mask》》=1){ //从高位到低位依次进行

if ((mask&dat) == 0){ //该位的值输出到 SDA 上

I2C_SDA = 0;

}else{

I2C_SDA = 1;

}

I2CDelay();

}

I2C_SCL = 1; //拉高 SCL

I2CDelay();

I2C_SCL = 0; //再拉低 SCL,完成一个位周期

I2C_SDA = 1; //8 位数据发送完后,主机释放 SDA,以检测从机应答

I2CDelay();

I2C_SCL = 1; //拉高 SCL

ack = I2C_SDA; //读取此时的 SDA 值,即为从机的应答值

I2CDelay();

I2C_SCL = 0; //再拉低 SCL 完成应答位,并保持住总线

return ack; //返回从机应答值

}

/* I2C 寻址函数,即检查地址为 addr 的器件是否存在,返回值-从器件应答值 */

bit I2CAddressing(unsigned char addr){

bit ack;

I2CStart(); //产生起始位,即启动一次总线操作

//器件地址需左移一位,因寻址命令的最低位

//为读写位,用于表示之后的操作是读或写

ack = I2CWrite(addr《《1);

I2CStop(); //不需进行后续读写,而直接停止本次总线操作

return ack;

}

我们把这个程序在 KST-51开发板上运行完毕,会在液晶上边显示出来我们预想的结果,主机发送一个存在的从机地址,从机会回复一个应答位,即应答位为 0;主机如果发送一个不存在的从机地址,就没有从机应答,即应答位为 1。

前面的章节中已经提到利用库函数_nop_()可以进行精确延时,一个_nop_()的时间就是一个机器周期,这个库函数包含在 intrins.h 这个文件中,如果要使用这个库函数,只需要在程序最开始,和包含 reg52.h 一样,include之后,程序中就可以使用这个库函数了。

还有一点要提一下,I2C通信分为低速模式 100kbit/s、快速模式 400kbit/s 和高速模式3.4Mbit/s。因为所有的 I2C 器件都支持低速,但却未必支持另外两种速度,所以作为通用的I2C 程序我们选择 100k 这个速率来实现,也就是说实际程序产生的时序必须小于等于 100k的时序参数,很明显也就是要求 SCL 的高低电平持续时间都不短于 5us,因此我们在时序函数中通过插入 I2CDelay()这个总线延时函数(它实际上就是 4 个 NOP 指令,用 define 在文件开头做了定义),加上改变 SCL 值语句本身占用的至少一个周期,来达到这个速度限制。如果以后需要提高速度,那么只需要减小这里的总线延时时间即可。

  • UC3846控制芯片工作原理控制图 逆变焊机原理与用途
  • 数字万用表电阻档测试二极管正反向没有阻值(使用万用表测量二极管的正向电阻,为什么各档)
  • 学单片机需要学数电模电吗(学单片机要先学数电模电吗)
  • 电工怎么选择适合自己用的万用表(电工初学者买什么样的万用表好)
  • 单片机需要同时运行多个任务怎么办(单片机怎么同时执行多个任务)
  • 电机保护的方案取决于负载的机械特性
  • 绝缘电阻表正负搭接不复零位是怎么回事
  • 短路怎么用万用表查