基于红外传输的多点温度采集系统
今天分享的是基于红外通信的多点温度采集系统。先简单说一下要实现的功能:使用三个温度传感器采集三路温度信号,然后将采集的信号通过红外的方式发射出去,主机接收红外信号并解码,将温度信息在上位机上面显示出来。
今天我们主要讲解的是前面部分,也就是采集温度和红外传输,关于上位机的内容,需要单独花一篇来讲,将在下一篇里介绍。
本项目使用到的器件:ds18b20温度传感器,红外发射管和接收管,单片机(51和stm32都可以)。在本次实验中,因为单片机数量有限,所以采用了一个做主机,另外两个做从机,共三个单片机。Stm32采集两路温度信息,51采集第三路温度信息,然后在另一块51上面接收,当然,这个是比较随意的,只要搞清楚里面的核心原理,用什么单片机,采集几路信号,这些都不是问题。
好了,废话不多说,接下来我们逐一介绍几个部分。
一、温度采集部分
温度采集部分我们用的是常见的DS18B20芯片,DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
关于这块芯片详细的工作原理什么的,这里就不多介绍了,我们只需要关心怎么使用,怎么通过它来获取温度就好了。DS18B20在出厂时以配置为12位,读取温度时共读取16位,前5个位为符号位,当前5位为1时,读取的温度为负数;当前5位为0时,读取的温度为正数。温度为正时读取方法为:将16进制数转换成10进制即可。温度为负时读取方法为:将16进制取反后加1,再转换成10进制即可。例:0550H = +85 度,FC90H = -55 度。
1、接线
这块芯片的接线很简单,一个VCC,一个GND,一个dat数据线,这个数据线可以连上单片机任意的一个IO口。
2、控制方法
控制方法主要涉及到传感器的初始化工作,如何读取寄存器,如何写入寄存器,其他的也就没什么了。
a)初始化工作
(1) 先将数据线置高电平“1”。
(2) 延时(该时间要求的不是很严格,但是尽可能的短一点)
(3) 数据线拉到低电平“0”。
(4) 延时750微秒(该时间的时间范围可以从480到960微秒)。
(5) 数据线拉到高电平“1”。
(6) 延时等待(如果初始化成功则在15到60微秒时间之内产生一个由DS18B20所返回的低电平“0”。据该状态可以来确定它的存在,但是应注意不能无限的进行等待,不然会使程序进入死循环,所以要进行超时控制)。
(7) 若CPU读到了数据线上的低电平“0”后,还要做延时,其延时的时间从发出的高电平算起(第(5)步的时间算起)最少要480微秒。
(8) 将数据线再次拉高到高电平“1”后结束。
图一:初始化(复位)时序
简单的说就是主机首先发出一个480us~960us的低电平脉冲,然后释放总线变为高电平,并在随后的480us时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。若无低电平出现一直都是高电平说明总线上无器件应答。
做为从器件的DS18B20在一上电后就一直在检测总线上是否有480-960us的低电平出现,如果有,在总线转为高电平后等待15-60us后将总线电平拉低60us~240us做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。
b)写操作
(1) 数据线先置低电平“0”。
(2) 延时确定的时间为15微秒。
(3) 按从低位到高位的顺序发送字节(一次只发送一位)。
(4) 延时时间为45微秒。
(5) 将数据线拉到高电平。
(6) 重复上(1)到(6)的操作直到所有的字节全部发送完为止。
(7) 最后将数据线拉高。
图二:写时序
写时序包含了两种写时序:写0时序和写1时序。所有写时序至少需要60us,且每个写时序之间至少需要1us的恢复时间。
主机产生0时序:DQ line 拉低,延时60us,然后释放总线为高电平,延时2us。
主机产生1时序:DQ line 拉低,延时2us,然后释放总线为高电平,延时60us
做为从机的DS18B20则在检测到总线被拉底后等待15us然后从15us到60us开始对总线采样,在采样期内总线为高电平则为1,若采样期内总线为低电平则为0。
c)读操作
(1)将数据线拉高“1”。
(2)延时2微秒。
(3)将数据线拉低“0”。
(4)延时3微秒。
(5)将数据线拉高“1”。
(6)延时5微秒。
(7)读数据线的状态得到1个状态位,并进行数据处理。
(8)延时60微秒。
图三:读时序
单总线期间仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。
对于读数据时序也分为读0时序和读1时序。所有读时序至少需要60us才能完成,且2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线数据。典型的读时序过程为:主机输出低电平延时 2us,然后主机转入输入模式延时 12us,然后读取单总线当前的电平,然后延时 50us。
以上都是一些具体的操作,那么一个完整的操作流程是怎么样的呢?DS18B20的典型温度读取过程:
复位 → 发 SKIP ROM 命令(0XCC)→ 发开始转换命令(0X44) → 延时 → 复位 → 发送 SKIP ROM 命令(0XCC) → 发读存储器命令(0XBE)→ 连续读出两个字节数据(即温度) → 结束。
以上就是温度传感器的操作,总的来说,并不是很难,最重要的就是要注意它的时序问题,也就是说里面的延时必须是很准确的,如果延时不准确很可能导致芯片的初始化失败。其实红外也是对时间有比较严格的要求,所以,接下来我们就来介绍红外部分。
二、红外发射部分
红外分为发射和接收部分,这里先介绍一下红外发射。
通常红外发射为了提高抗干扰性能和降低电源消耗,红外遥控器常用载波的方式传送二进制编码,常用的载波频率为38kHz。也有一些遥控系统采用36kHz、40 kHz、56 kHz等,一般由发射端晶振的振荡频率来决定。所以,通常的红外遥控器是将遥控信号(二进制脉冲码)调制在38KHz的载波上,经缓冲放大后送至红外发光二极管,转化为红外信号发射出去的。
二进制脉冲码的形式有多种,其中最为常用的是NECProtocol 的 PWM码(脉冲宽度调制)和 Philips RC-5 Protocol 的 PPM码(脉冲位置调制码,脉冲串之间的时间间隔来实现信号调制)。如果要开发红外接收设备,一定要知道红外遥控器的编码方式和载波频率,我们才可以选取一体化红外接收头和制定解码方案。这里使用的是NEC协议。
NEC协议的特征如下:
1、 8 位地址和 8 位指令长度;
2、地址和命令 2 次传输(确保可靠性)
3、 PWM 脉冲位置调制,以发射红外载波的占空比代表“ 0”和“ 1”;
4、载波频率为 38Khz;
5、位时间为 1.125ms 或 2.25ms;
NEC码的位定义:
一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms( 560us脉冲+1680us低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)。而红外接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑 1 应该是 560us 低+1680us高,逻辑 0 应该是 560us 低+560us 高。所以可以通过计算高电平时间判断接收到的数据是0还是1。
NEC码位定义时序图如图
NEC遥控指令的数据格式为:引导码、地址码、地址反码、控制码、控制反码。引导码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。数据格式如下:
NEC码还规定了连发码(由9ms 低电平+2.5m 高电平+0.56ms低电平+97.94ms 高电平组成),如果在一帧数据发送完毕之后,红外遥控器按键仍然没有放开,则发射连发码,可以通过统计连发码的次数来标记按键按下的长短或次数。
以上是关于红外发射的具体说明,简单来说就是这样:
首先要发射一段引导码,这段引导码的作用就是告诉接收端这是一帧数据的开始,这段引导码在接收端看来是9ms的低电平加上4.5ms的高电平,然后再发射接下来的4个字节,这4个字节分别是地址码,地址反码,控制码,控制反码。地址码是用来区分不同的红外设备的,因为有可能会使用不同的红外设备来遥控,所以要有一个唯一的标志。控制码就是真正的数据部分,就是你想要发送什么数据,然后接收端收到这个数据之后就执行相应的操作。发送反码是为了增强可靠性,用于数据校验。
那么对于具体的发射来说,如果想要发射低电平,并不是直接输出低电平,而是输出一段脉冲,这段脉冲的频率是38khz,如果想要发射高电平,就直接输出高电平就好了,因为在接收端看来,收到脉冲就认为是低电平,否则就认为是高电平。最后就是要注意以下时间,不管是“1”还是“0”,低电平的时间都是一样的,靠高电平时间来区分0和1,不过这个是在接收时要重点考虑的。
那么,应该如何编写代码?
因为要产生一个固定频率的载波,所以采用定时器中断的方法,38khz频率对应的时间周期就是26us,半周期就是13us,也是就是说要设置一个定时器,每13us产生一次中断,然后在中断函数中翻转电平,产生脉冲,但因为有时候不是要产生脉冲,所以加上一个标志,用来控制是否产生脉冲。
首先是发射引导码,引导码由9ms的低电平加上4.5ms的高电平组成,所以,对于发射端来说,就是9ms的脉冲加上4.5ms高电平。定义一个变量,每次进入中断加1,然后在发射函数中使用while循环,将这个变量与另一个设置好的变量相比较,一直等到他们相等退出循环。代码如下:
中断服务函数:
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update))
{
led2=!led2;
count++;
if (flag==1)
{
OP=~OP;
}
else
{
OP = 0;
}
IR_OUT = OP;
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
发射函数(截取部分):
void SendIRdata(char p_irdata)
{
int i;
char irdata=p_irdata;
//发送9ms的起始码
endcount=t9000;
flag=1;
count=0;
do{}while(count<endcount);
对于其他的也是和发射引导码类似的操作,这里就不多说了。
它的关键就在于产生准确的延时,这样才能产生固定频率的脉冲,然后我们通过一个变量计数就可以来控制时间。
我们可以看一下使用逻辑分析仪捕捉到的波形:
前面那一段比较长的脉冲就是引导码中的低电平。
三、红外接收部分
这一部分就是在接收端对红外信号进行解码的操作了。解码无非就是从收到的波形里面读取出它到底是0还是1,或者说携带的信息是什么。
实际上,我们根据上面的逻辑分析仪的波形,甚至可以自己手动解码,当自己根据波形可以手动解码之后,就说明对原理比较清楚了,这时候就可以编写程序,让单片机来为我们高效的工作。
根据前面的分析,1是0.56ms的低电平加上1.68ms的高电平,0是0.56ms的低电平加上0.56ms的高电平,所以,区分0和1只和高电平时间有关。上面的波形跳过引导码之后,解码出来就是
1100 0000 , 0011 1111 , 1000 0100 , 0111 1011;
由于发射是从低位开始,所以左边是LSB,右边是MSB,所以第一个字节解码后其实是3,第二个字节是252,第三个字节是33,第四个字节是222。第三个字节才是用户的实际要发的有效数据,在这里是温度信息。
SendIRdata(temp,0x03,0xfc);
可以看到,解码后的数据就是原来发送的数据,说明我们数据传输是成功的。
上面是我们手动的依靠波形来解码,那么,如何编写程序来实现解码呢?
思路其实就是首先,要捕获引导码,因为引导码代表着一帧数据的开始,捕获完了引导码之后,就是正式的解码过程,无非就是判断是0还是1,而判断是0还是1的依据就是判断高电平的时间长度。
我们还是使用到了定时器资源,每隔一定时间进入中断。对于51单片机来说,可以用一个变量记录上一次管脚的电平状态,然后每次进入中断读取本次管脚的电平状态,如果上一次是1,这一次是0,就可以判断为产生了下降沿,反之就是上升沿。而对于stm32来说,带有输入捕获的功能,所以可以直接使用上升沿捕获计算时间长度。
因为要计算高电平的时间,所以采用捕获上升沿的方法,当捕获到上升沿的时候,开始计时,捕获到下降沿的时候,结束计时,根据计时的长度就知道是引导码,还是0,或者是1.
如果捕获到的第一个高电平的时间是4.5ms左右,则表示捕获到了引导码,接着判断下一次上升沿到来后的高电平时间,如果高电平时间太长或者太短,则表示接收的是干扰信号,应该舍弃这一帧数据。当捕获完了32位数据之后,告诉主程序已经捕获完了,这时主程序可以对数据进行判断或处理。
以下是接收时中断处理函数的流程图
至此,接收部分就完成了。
四、各模块间的整合
前面已经把温度采集,红外发射,红外接收做好了,现在就是要将这几部分整合在一起。
首先是要把温度采集得到的数据,提供给发射模块作为输入参数,然后在接收端观察数据的接收。
这里有一点是特别需要注意的,那就是在红外发射模块当中,使用到了一个定时器,这个定时器的定时时间是很短的,也就是说会频繁的进入中断,那么,将温度采集模块和红外发射模块结合的时候,就会因为频繁进入中断影响主程序的执行,使得温度传感器初始化失败,因为温度传感器对延时时间是有比较严格的要求的,本来是正常的延时时间,因为中断的打扰,延时时间明显加长,这就导致采集的温度是错误的。解决的方法就是在温度采集的时候,关闭定时器中断,等采集完温度之后再打开中断,这样就不会影响了。
整个项目最好使用模块化的编程思路,也就是每个模块都单独写一个.c文件,然后在头文件中声明,这样可以方便程序的移植。
我们可以暂时使用串口助手来观察接收的数据是否正常。
可以看到,接收端可以正常接收温度信息并显示。这里面有一个小细节,就是串口助手显示的是ASCII码值,也就是说,如果使用串口发送一个数字51,在串口助手上并不会显示51,而是显示3,具体的可以去查一下ASCII码表,因此,为了便于观察,应该先将要发送的数据进行转化和处理,这样才能在串口助手上正确显示要发送的信息。
五、总结
以上就是整个多点温度采集系统的讲解,另外,关于项目中的一些细节问题,在这里也一并总结一下:
1、温度传感器对时序要求还是挺严格的,所以要有比较准确的延时函数,对于stm32来说,可以使用SysTick定时器来产生延时,比较准确,而对于51来说,延时并不是那么好把控,有时候需要去实际测一下更好。
2、对于红外发射和接收来说,其实并没有那么多要求,上面所说的那些规则,只是大家约定的习惯而已,并没有一个标准,事实上,只要保证发射和接收相匹配,就能收到数据。而且对于接收端来说,在一个比较宽的频率范围内,收到的脉冲都将被认为是0,并没有要求一定是38khz,实测19khz也是正常接收。
3、巧妙的借助一些工具可以非常有利于我们对实验结果的分析。比如本次实验当中,逻辑分析仪就起了很重要的作用。刚开始的时候分析红外发射的时候,只需要借助keil软件里自带的逻辑分析仪就可以分析输出的管脚电平,当然这是理论计算得到的结果,与事实可能有一点点差别,但是差别不会太大。而在分析接收端的管脚电平的时候,就不得不使用真实的逻辑分析仪来观察了,这个没办法仿真。
4、将模块进行整合的时候,原本各个模块都能正常工作的,整合在一起却不能工作了,这时要分析它们之间是否有相互作用。比如在本次项目中的温度采集和发射模块,两个模块单独测量都是没有问题的,但是将温度采集后的数据送到发送端却出了问题,刚开始排查是否共用了什么资源,发现并没有,后来在经过大量实验之后发现这两部分确实都是正常的,那么只可能是一个对另一个产生了影响,后来终于发现原来是中断打扰了主程序的运行。
5、代码要养成及时备份的习惯,每写好一部分功能,就要保存起来,下次要修改或者添加功能的时候,先复制出一份出来,在复制的那一份上进行修改,这样可以防止把原来能用的程序修改坏了。
后台回复“温度采集系统”获取源码和资料!
![](https://jkboy.com/wp-content/uploads/2021/10/Pasted-11.png)