注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小明砸乱弹琴

一个工程师的日常

 
 
 

日志

 
 
关于我

喜欢哲学、几何学、心理学、物理学、音乐、简单的文字及一切有趣的事物。热爱幻想,追求思想和学术自由,热衷简单平凡的生活和发现美好的事物。

网易考拉推荐
 
 

用I/O口模拟总线时序  

2014-08-25 16:27:02|  分类: 通信协议 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在做总线通信过程中,我们很少会用到这样方法,一般在我们选择MCU的时候都会带有你所需要的通信接口。但是,对于一些简单的通信应该用的场合,一 般在一些传感器的数据通信过程中,传感器厂商会将通信协议做一些改变,这些通信协议也没有一个标准的协议规定。以至于传感器的兼容性很差,甚至有时候找不 到能够与其通信的MCU,这个时候有一种方法就是用I/O口来模拟通信总线(由于I/O速度的限制一般只适用于低速的通信总线)的时序。之前,用I2C通信做一个温湿度测量的工程,本篇文章就以一个例子来看看如何用I/O口对总线时序进行模拟。

我们平时计算机常用的RS232/485工作在异步工作状态时是有严格的数据时钟限制,也就是我们所说的波特率,通信的两个设备有相同的波特率才能正确的通信。对于同步通信一般没有严格的时间限制,总线通过高低电平来分辨数据是"0"还是"1",有两个关键的时刻:上升沿,下降沿。它 是用过上升沿和下降沿的时刻来读写数据的,也就是说这样的话通信频率不是固定的,因为通信的设备"数"的是上升沿和下降沿的数目,然后读写数据线上的数 据。笔者做过实验,将I2C通信的频率降到了10Hz左右,这样用示波器能够很好的捕捉到每一个时钟,通信的结果也是正确的。

好了,直接来看案例吧。

通常我们的I2C的通信时序应该如下图所示,在时钟线拉高的情况下,将数据线拉低就会产生一个启动信号。但是传感器SHT的启动信号却是一个数据线拉低后,时钟线产生一个脉冲,而后再将数据线拉高,这样做的好处是在一定程度上确保了总线正确的启动,但是几乎与之匹配的MCU。这个时候就需要通过I/O模拟的方式来与SHT11完成通信。

#define IIC_SCL RC0 //I2C时钟线

#define IIC_SDA RC1 //I2C线

#define IIC_SCL_DIR TRISC0 //I2C时钟线传输方向

#define IIC_SDA_DIR TRISC1 //I2C线传输方向

#define PORT_INPUT 1

#define PORT_OUTPUT 0

#define IIC_SCL_HIGH() IIC_SCL_DIR = PORT_INPUT //时钟线拉高

#define IIC_SCL_LOW() IIC_SCL_DIR = PORT_OUTPUT;IIC_SCL=0//时钟线拉低

#define IIC_SDA_HIGH() IIC_SDA_DIR = PORT_INPUT //数据线拉高

#define IIC_SDA_LOW() IIC_SDA_DIR = PORT_OUTPUT;IIC_SDA=0//数据线拉低

 

/***************

*SHT11启动时序

***************/

void SHT_START(void)

{

IIC_SCL_HIGH();

IIC_SDA_HIGH();

delay_us(5);

IIC_SDA_LOW();

delay_us(5);

IIC_SCL_LOW();

delay_us(5);

IIC_SCL_HIGH();

delay_us(5);

IIC_SDA_HIGH();

delay_us(5);

IIC_SCL_LOW();

}

 

/***************

*SHT11发送数据时序

***************/

void SHT_SEND(uchar data)

{uchar i,data1;

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

{

data1=data<<i;

if(!(data1&0x80))

IIC_SDA_LOW();

if(data1&0x80)

IIC_SDA_HIGH();

IIC_SCL_LOW();        //写完1位数据将时钟线拉低,等待发送

delay_us(5);

IIC_SCL_HIGH();        //时钟线上升沿,发送1位数据

delay_us(5);         //等待1位数据发送完成

}

IIC_SCL_LOW();

IIC_SDA_HIGH();        //8位数据发送完成,数据线拉高,等待SLAVE器件响应

delay_us(5);

IIC_SCL_HIGH();        //时钟线拉高,产生上升沿读取数据线是否SLAVE器件有响应

//while(IIC_SDA==1);

delay_us(5);

IIC_SCL_LOW();

IIC_SDA_HIGH();        //数据线拉高,时钟线拉低,等待转换完成

}

/***************

*SHT11接收数据时序

***************/

uint SHT_REC(void)

{

uint i;

uint REC1=0,REC0=0,REC=0;

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

{

IIC_SCL_HIGH();        //转换完成,SLAVE器件将数据线拉低,时钟线产生上升沿读取高8位数据

REC1=(REC1<<1)+IIC_SDA;

delay_us(5);

IIC_SCL_LOW(); //将时钟线拉低,等待下一个上升沿的到来

delay_us(5);

}

SHT_ASK();     //8位数据接收完毕,发送应答信号

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

{

IIC_SCL_HIGH();        //转换完成,SLAVE器件将数据线拉低,时钟线产生上升沿读取低8位数据

REC0=(REC0<<1)+IIC_SDA;

delay_us(5);

IIC_SCL_LOW();

delay_us(5);

}

SHT_STOP();        //8位数据接收完毕,结束        

REC=(REC1<<8)+REC0;

return REC;

}

/***************

*SHT11应答时序

***************/

void SHT_ASK(void)

{

IIC_SCL_LOW();

IIC_SDA_LOW();        //数据线拉低

delay_us(5);

IIC_SCL_HIGH();        //时钟线拉高才生应答信号

delay_us(5);

IIC_SDA_HIGH();

IIC_SCL_LOW();

delay_us(5);

}

/***************

*SHT11停止时序

***************/

void SHT_STOP(void)

{

IIC_SDA_HIGH();

IIC_SCL_LOW();

delay_us(5);

IIC_SCL_HIGH();

delay_us(5);

IIC_SDA_HIGH();

IIC_SCL_LOW();

}

  评论这张
 
阅读(153)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017