单总线、IIC、SPI接口详解(一)

相信大家在初次接触到单片机的时候,会发现有很多种类的外围设备。如温湿度传感器、时钟芯片、陀螺仪等等。在面对这么多种类型的设备时,很多人都会有种无从下手的感觉。并且一开始也并不知道单片机是怎么把传感器的数据读出来, 也不知道怎么去驱动设备。下面就给大家说说这些接口。

一.单总线

1、采用单总线的设备有非常具有代表性的温度传感器DS18B20以及温湿度传感器DHT11。顾以名思义单总线即只有单根信号线,该线即传输数据也传输时钟,并且数据传输也为双向。此处与spi、i2c以及串口不同。采用这种形式可以节省io口,并且简单。

我们通过DHT11的时序来讲讲单总线的机制以及编程方法。

①总线空闲时,总保持高电平。

②总线都先由主机拉低一段时间(需让从机能够检测到起始信号)在拉高,等待从机响应。

③从机发送低电平响应信号,从机拉高总线电平,表示准备输出

④从机发送信号,主机读取从机信号。

⑤结束后,继续保持总线为高电平

下图为单片机与DHT11通讯过程图

单片机与DHT11通讯过程图

2、接下来是从机如何表示每bit,信号1与信号0的表示。

在DHT11中,每一bit数据都先以50us的低电平开始,高电平的时间长短来确定该数据位为1或0。

信号0的表示方法如下图,开始以50us的低电平,26-28us的高电平组合表示信号0.

信号0与1的表示

信号1的表示如下图所示。同样以50us的低电平开始,70us的高电平组合表示信号1.

信号0与1的表示

3、DHT11的数据,共计40bits。由湿度整数部分8bit+湿度小数部分8bit+温度整数部分8bit+温度小数部分8bit+校验8bit(和校验)。

两点注意:①目前小数部分为0,所以只有整数部分有效  ②其他很多传感器采用高8bit+低8bit再除以100表示温湿度与此处不同)

示例: 0011 0001             0000 0000           0001 0110           0000 0000         0100 0111

湿度整数部分       湿度小数部分       温度整数部分       温度小数部分         和校验

00110001=31H=49%

00010110=16H=22℃

01000111=47H=71    和校验正确,代表数据正确可靠。即温度22℃,湿度49%。

4、程序部分

  1. sbit DHTbus=P1^0;
  2. void  readBus(void)
  3.       {
  4.     u8 i;
  5.         for(i=0;i<8;i++)
  6.         {
  7.            U8FLAG=2;
  8.         while((!DHTbus)&&U8FLAG++);
  9.         Delay_10us();
  10.         Delay_10us();
  11.         Delay_10us();
  12.         U8temp=0;
  13.         if(DHTbus)U8temp=1;
  14.         U8FLAG=2;
  15.         while((DHTbus)&&U8FLAG++);
  16.         //超时则跳出for循环          
  17.         if(U8FLAG==1)break;
  18.         //判断数据位是0还是1                   
  19.         // 如果高电平高过预定0高电平值则数据位为 1             
  20.         U8busdata<<=1;
  21.           U8busdata|=U8temp;        //0
  22.          }
  23.     }
  24. void DHT11(void)
  25.     {
  26.        //主机拉低18ms 
  27.         DHTbus=0;
  28.        Delay(180);
  29.        DHTbus=1;
  30.        //总线由上拉电阻拉高 主机延时20us
  31.        Delay_10us();
  32.        Delay_10us();
  33.        Delay_10us();
  34.        Delay_10us();
  35.        //主机设为输入 判断从机响应信号 
  36.        DHTbus=1;
  37.        //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行      
  38.        if(!DHTbus)         //T !      
  39.        {
  40.        U8FLAG=2;
  41.        //判断从机是否发出 80us 的低电平响应信号是否结束     
  42.        while((!P2_0)&&U8FLAG++);
  43.        U8FLAG=2;
  44.        //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
  45.        while((P2_0)&&U8FLAG++);
  46.        //数据接收状态         
  47.        readBus();
  48.        U8RH_data_H_temp=U8busdata;
  49.        readBus();
  50.        U8RH_data_L_temp=U8busdata;
  51.        readBus();
  52.        U8T_data_H_temp=U8busdata;
  53.        readBus();
  54.        U8T_data_L_temp=U8busdata;
  55.        readBus();
  56.        U8checkdata_temp=U8busdata;
  57.        DHTbus=1; //释放总线
  58.             //数据校验      
  59.        U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
  60.        if(U8temp==U8checkdata_temp)
  61.        {
  62.              U8RH_data_H=U8RH_data_H_temp;
  63.              U8RH_data_L=U8RH_data_L_temp;
  64.           U8T_data_H=U8T_data_H_temp;
  65.              U8T_data_L=U8T_data_L_temp;
  66.              U8checkdata=U8checkdata_temp;
  67.        }
  68. }
  69. }

由于DHT11对延时有要求,所以单片机的延时函数需要大致计算一下时间,确保每次延时都能在DHT11的规定范围内。

印象中有挺多学弟学习51时,在初次使用DHT11的时候,拿到官方或者别人写好的例程就往单片机里面烧写,发现确实能够得到数据,以为这样就大功告成。

没曾想之后的项目中使用了功能更加齐全的12C5a60s2,同样的例程烧写到单片机里面时,发现程序没有用了。绞尽脑汁都觉得是单片机或者DHT11出了问题。

但其实主要还是没有弄清楚DHT11的时序,以及单片机的延时。在实际测试中,相同的以下程序

  1. void Delay(U16 j)
  2.      {
  3.      u8 i;
  4.         for(;j>0;j--)
  5.          {
  6.  for(i=0;i<27;i++);
  7.        }
  8.      }

STC89C52RC与STC12C5A60S2要相差很多,用示波器测出的结果大致为12C5A要比89C52RC快上3-5倍。这也就导致了在普通51单片机上面能正常运行,但是换上12C5A就毫无作用的原因了。

 

注:文章转自电子芯客吧,感觉本篇文章对单总线、IIC、SPI接口的讲解很详实,在菠菜园为大家分享一下。

  • 版权声明: 本文源自 电子芯客吧, 于5年前,由整理发表,共 3096字。
  • 原文链接:点此查看原文
你想把广告放到这里吗?

发表评论

您必须 登录 才能发表留言!