相信大家在初次接触到单片机的时候,会发现有很多种类的外围设备。如温湿度传感器、时钟芯片、陀螺仪等等。在面对这么多种类型的设备时,很多人都会有种无从下手的感觉。并且一开始也并不知道单片机是怎么把传感器的数据读出来, 也不知道怎么去驱动设备。下面就给大家说说这些接口。
一.单总线
1、采用单总线的设备有非常具有代表性的温度传感器DS18B20以及温湿度传感器DHT11。顾以名思义单总线即只有单根信号线,该线即传输数据也传输时钟,并且数据传输也为双向。此处与spi、i2c以及串口不同。采用这种形式可以节省io口,并且简单。
我们通过DHT11的时序来讲讲单总线的机制以及编程方法。
①总线空闲时,总保持高电平。
②总线都先由主机拉低一段时间(需让从机能够检测到起始信号)在拉高,等待从机响应。
③从机发送低电平响应信号,从机拉高总线电平,表示准备输出
④从机发送信号,主机读取从机信号。
⑤结束后,继续保持总线为高电平
下图为单片机与DHT11通讯过程图
2、接下来是从机如何表示每bit,信号1与信号0的表示。
在DHT11中,每一bit数据都先以50us的低电平开始,高电平的时间长短来确定该数据位为1或0。
信号0的表示方法如下图,开始以50us的低电平,26-28us的高电平组合表示信号0.
信号1的表示如下图所示。同样以50us的低电平开始,70us的高电平组合表示信号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、程序部分
- sbit DHTbus=P1^0;
- void readBus(void)
- {
- u8 i;
- for(i=0;i<8;i++)
- {
- U8FLAG=2;
- while((!DHTbus)&&U8FLAG++);
- Delay_10us();
- Delay_10us();
- Delay_10us();
- U8temp=0;
- if(DHTbus)U8temp=1;
- U8FLAG=2;
- while((DHTbus)&&U8FLAG++);
- //超时则跳出for循环
- if(U8FLAG==1)break;
- //判断数据位是0还是1
- // 如果高电平高过预定0高电平值则数据位为 1
- U8busdata<<=1;
- U8busdata|=U8temp; //0
- }
- }
- void DHT11(void)
- {
- //主机拉低18ms
- DHTbus=0;
- Delay(180);
- DHTbus=1;
- //总线由上拉电阻拉高 主机延时20us
- Delay_10us();
- Delay_10us();
- Delay_10us();
- Delay_10us();
- //主机设为输入 判断从机响应信号
- DHTbus=1;
- //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
- if(!DHTbus) //T !
- {
- U8FLAG=2;
- //判断从机是否发出 80us 的低电平响应信号是否结束
- while((!P2_0)&&U8FLAG++);
- U8FLAG=2;
- //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
- while((P2_0)&&U8FLAG++);
- //数据接收状态
- readBus();
- U8RH_data_H_temp=U8busdata;
- readBus();
- U8RH_data_L_temp=U8busdata;
- readBus();
- U8T_data_H_temp=U8busdata;
- readBus();
- U8T_data_L_temp=U8busdata;
- readBus();
- U8checkdata_temp=U8busdata;
- DHTbus=1; //释放总线
- //数据校验
- U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
- if(U8temp==U8checkdata_temp)
- {
- U8RH_data_H=U8RH_data_H_temp;
- U8RH_data_L=U8RH_data_L_temp;
- U8T_data_H=U8T_data_H_temp;
- U8T_data_L=U8T_data_L_temp;
- U8checkdata=U8checkdata_temp;
- }
- }
- }
由于DHT11对延时有要求,所以单片机的延时函数需要大致计算一下时间,确保每次延时都能在DHT11的规定范围内。
印象中有挺多学弟学习51时,在初次使用DHT11的时候,拿到官方或者别人写好的例程就往单片机里面烧写,发现确实能够得到数据,以为这样就大功告成。
没曾想之后的项目中使用了功能更加齐全的12C5a60s2,同样的例程烧写到单片机里面时,发现程序没有用了。绞尽脑汁都觉得是单片机或者DHT11出了问题。
但其实主要还是没有弄清楚DHT11的时序,以及单片机的延时。在实际测试中,相同的以下程序
- void Delay(U16 j)
- {
- u8 i;
- for(;j>0;j--)
- {
- for(i=0;i<27;i++);
- }
- }
STC89C52RC与STC12C5A60S2要相差很多,用示波器测出的结果大致为12C5A要比89C52RC快上3-5倍。这也就导致了在普通51单片机上面能正常运行,但是换上12C5A就毫无作用的原因了。
注:文章转自电子芯客吧,感觉本篇文章对单总线、IIC、SPI接口的讲解很详实,在菠菜园为大家分享一下。