51单片机 软件模拟IIC

10 篇文章 0 订阅
8 篇文章 2 订阅
 

/*==========================================================================

名称:IIC协议

内容:函数是采用软件延时的方法产生SCL脉冲,固对高晶振频率要作一定的修改

(本例是1us机器周期,即晶振频率要小于12MHZ)

============================================================================*/

#include <reg52.h>

#include "iic.h"

bit ack;

/*=================================================

启动总线

==================================================*/

void iic_start()

{

SDA = 1; //发送起始条件的数据信号

SCL = 1;

delay_us(1); //起始条件建立时间大于4.7us,延时

SDA = 0; //发送起始信号

delay_us(1); //起始条件锁定时间大于4μ

SCL = 0; //钳住I2C总线,准备发送或接收数据

}

/*=================================================

结束总线

==================================================*/

void iic_stop()

{

SDA = 0; //发送结束条件的数据信号

SCL = 1;

delay_us(1); //结束条件建立时间大于4μ

SDA = 1; //发送I2C总线结束信号

delay_us(1);

SCL = 0;

}

/*=====================================================================

发送一个字节数据

函数原型: bit iic_send_byte(unsigned char byte);

功能: 将数据byte发送出去,可以是地址,也可以是数据,发完后等待应答,并对

此状态位进行操作.(不应答或非应答都使ack=0 假)

发送数据正常,ack=1; ack=0表示被控器无应答或损坏。

======================================================================*/

bit iic_send_byte(unsigned char byte)

{

unsigned char i;

for(i = 0; i < 8; i++) //要传送的数据长度为8位

{

SDA = byte & 0x80; //判断发送位

SCL = 1; //置时钟线为高,通知被控器开始接收数据位

delay_us(1); //保证时钟高电平周期大于4μ

SCL = 0;

byte <<= 1;

}

SCL = 1;

SDA = 1; //8位发送完后释放数据线,准备接收应答位

delay_us(1);

if(0 == SDA) //判断是否接收到应答信号

{

ack = 1;

}

else

{

ack = 0;

}

SCL = 0;

return ack;

}

/*===================================================================================

接受一个字节数据

函数原型: unsigned char iic_receive_byte();

功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。

====================================================================================*/

unsigned char iic_receive_byte()

{

unsigned char i;

unsigned char a;

unsigned char temp = 0;

SDA = 1; //置数据线为输入方式

for(i = 0; i < 8; i++)

{

SCL = 0; //置时钟线为低,准备接收数据位

delay_us(1); //时钟低电平周期大于4.7us

SCL = 1; //置时钟线为高使数据线上数据有效

if(SDA)

{

a = 1;

}

else

{

a = 0;

}

temp |= (a << (7 - i)); //读数据位,接收的数据位放入retc中

delay_us(1);

}

SCL = 0;

return temp;

}

/*===============================================================

应答子函数

================================================================*/

void iic_ack()

{

SDA = 0;

SCL = 1;

delay_us(1); //时钟低电平周期大于4μ

SCL = 0; //清时钟线,钳住I2C总线以便继续接收

}

/*================================================================

非应答子函数

=================================================================*/

void iic_noack()

{

SDA = 1;

SCL = 1;

delay_us(1); //时钟低电平周期大于4μ

SCL = 0; //清时钟线,钳住I2C总线以便继续接收

}

/*===========================================================================================

向有子地址器件发送多字节数据函数

函数原型: bit iic_send_str(unsigned char sla, unsigned char suba, unsigned char *str, unsigned char len);

功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程。

从器件地址sla,子地址suba,发送内容是str指向的内容,发送len个字节。

如果返回1表示操作成功,否则操作有误。

注意:使用前必须已结束总线。

=============================================================================================*/

bit iic_send_str(unsigned char sla, unsigned char suba, unsigned char *str, unsigned char len)

{

unsigned char i;

iic_start(); //启动总线

iic_send_byte(sla); //发送器件地址

if(0 == ack)

{

return ERR;

}

iic_send_byte(suba); //发送器件子地址

if(0 == ack)

{

return ERR;

}

for(i = 0; i < len; i++)

{

iic_send_byte(*str); //发送数据

delay_us(1); //必须延时等待芯片内部自动处理数据完毕

if(0 == ack)

{

return ERR;

}

str++;

}

iic_stop(); //结束总线

return SUCC;

}

/*===========================================================================================

向有子地址器件读取多字节数据函数

函数原型: bit iic_receive_str(unsigned char sla, unsigned char suba, unsigned char *str, unsigned char len);

功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程。

从器件地址sla,子地址suba,读出的内容放入str指向的存储区,读len个字节。

如果返回1表示操作成功,否则操作有误。

注意:使用前必须已结束总线。

=============================================================================================*/

bit iic_receive_str(unsigned char sla, unsigned char suba, unsigned char *str, unsigned char len)

{

unsigned char i;

iic_start(); //启动总线

iic_send_byte(sla); //发送器件地址

if(0 == ack)

{

return ERR;

}

iic_send_byte(suba); //发送器件子地址

if(0 == ack)

{

return ERR;

}

iic_start();

iic_send_byte(sla + 1);

if(0 == ack)

{

return ERR;

}

for(i = 0; i < len - 1; i++)

{

*str = iic_receive_byte(); //发送数据

iic_ack(); //发送就答位

str++;

}

*str = iic_receive_byte();

iic_noack(); //发送非应位

iic_stop(); //结束总线

return SUCC;

}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值