实现温度的实时检测,并通过两个异步串口将数据发送至串口屏HMI和与蓝牙模块相连接的手机上。支持手机APP和串口屏进行实时的相关数据更改。单片机根据数据要求,当实时温度不在合理范围时,做出应激反应(表现在IO口的高低电平上)。
按照原理图或者按照自己的意图将相关模块焊接起来。由于电路十分简单,焊接应该非常的快!
这里有两部分代码要写,一个是单片机,一个是APP。
(由于程序较多也比较简单,就不copy,这里主要提供思路和经验)
首先要实现上诉的目标功能,我在摸索两天后,认为单片机在此处承担主要的数据处理、转换和存储功能。
程序构架
初始化所需要的功能
接着对实时的温度进行采样(驱动DS18B20模块)
这里有几点需要注意:
然后是数据处理和发送的算法设计
由于通讯设备是HMI串口屏和蓝牙,两个都有不同的通讯协议。所以在发送的时候需要注意,在这里可以设置两个通讯设备的优先级。这里提供一个思路:用一个if语句来决定单片机到底来执行那个设备的数据更改请求。
//判断语句决定了串口2的数据处理优先级高于串口1
if(text2) //如果串口2收到数据将进入此处
{
dispose(); //数据处理函数
text2 = 0;
}
else if(text1) //如果串口1收到数据将进入此处
{
dispose();
text1 = 0;
}
这里先介绍两个设备的通讯协议
单片机更改HMI串口屏的相关数据要根据具体调用的控件来看,例如我的:
我使用的是数字控件,所以单片机发送的格式应该是:
n0.val=更改的数据 ffffff (对应n0控件的内容变成更改的数据,后面跟的是指令结束的标识符,3个十六进制的FF)
具体的代码如下
SendString2("n1.val=");
SendData2((Min/10)+0x30);
SendData2((Min%10)+0x30);
SendData2(0xff);
SendData2(0xff);
SendData2(0xff);
(这里要注意,代码中 Min 是一个十进制数)
而单片机通过蓝牙和手机通讯的协议原本是非常简单的,就是直接的数据透传,但是本人在用E4A调试的时候发现,传到APP上的数据不能一次性发送,是间断性无规律性的发送,调试数据显示,一次10bit数据的传送,极可能被分为两次传送,这样的话,APP对数据处理的技巧性就显得尤为重要。(这样的情况可能是本人对E4A的掌握程度不足,希望有经验的良师益友帮忙指点)
在这里我调用了E4A的文本切割的功能,对接收到的数据进行多次判断,确保每一次数据接收的完整性。
由于APP不像HMI串口屏那样可以单一指定性的进行数据覆盖,所以在APP内需要增加判断所需覆盖的组件,在这里我选择在每次数据传送的时候以"W、S、X"作为数据开始传送的标志,并分别对应实时温度、温度上限、温度下限 的组件。为了应对APP接收数据的分包透传现象,我在每次数据包的最后提供了一个供APP参考的 数据结束符"$"。
当APP每次收到数据时都先进行判断是否为新的数据包,如果是的就暂时锁住数据包的更迭,并根据数据包的起始字符对相应组件进行数据覆盖并将其标志位置为高位,如果不是的就继续对上一个组件的数据覆盖。在最后有一个对数据包是否传送完毕有一个检测,如果检测到结束符"$",就将锁打开并置零相关组件标志位,使下一次的数据包可以被正常接收。
在处理完单片机对设备数据覆盖的问题后,我们来处理设备对单片机数据覆盖的问题。
由于单片机串口接收数据的格式比较统一,这大大的简化了我们在单片机处理数据上的程序,具体代码如下:
void dispose()
{
switch(date)
{
case 0x65:RT_o = 0 ;date = 0;break;
case 0x63:Min ++ ; date = 0;break;
case 0x64:Min -- ; date = 0;break;
case 0x61:Max ++ ; date = 0;break;
case 0x62:Max -- ; date = 0;break;
}
}
其中,Min Max RT 分别是实时温度、温度上限、温度下限 ,而 Min_o Max_o RT_o 则分别对应单片机所认可的值。
而想对其中的值进行操作,所需要发送的字符分别为 ‘a‘、’b‘、’c‘、’d‘,对应的ASCII码是 0X61 0X62 0X63 0X64,为了实现设备主动更新实时温度的应激动作,我添加了’e‘,对应ASCII码是 0X65,当设备向单片机发送相应字符时,单片机将认可的实时温度改为零度,这样会触发数据更迭函数。具体实现会在后面分析。
对于单片机对于设备数据的更迭,我起初是想每次循环都更迭一次。但是我发现这样的更迭方式既占用资源也不具备美感。于是我用了个if语句进行判别,当单片机内认可的值受到设备的调整时,才进行数据更迭并将其更迭的内容实时通讯给另一个设备。这样的好处不仅在于资源的节约,而且在于我所用的单片机并不支持双工通讯,如果单片机在无脑的更新无用数据,当你利用其他设备进行数据设置时,很可能会出现无效的现象。
实现代码如下:
if(Max_o != Max) //判断认可值是否被设备更改
{
SendString2("n0.val=");
SendData2((Max/10)+0x30);
SendData2((Max%10)+0x30);
SendData2(0xff);
SendData2(0xff);
SendData2(0xff);
SendData1('s');
SendData1((Max/10)+0x30);
SendData1((Max%10)+0x30);
SendData1('&');
Max_o = Max;
P00 = RT_o > Max_o ; //相应的应激反应
}
对于实时温度,我在APP上提供了下滑刷新的功能,HMI串口屏上提供了点击空白处刷新的功能。这是为了防止通讯设备在温度稳定后才接入单片机,造成数据无法正常更迭。最简单的方法就是将单片机认可的值直接串改,当18B20 的数据与认可值有出入时,单片机将自动更迭数据,并同步至通讯设备之上。
这里需要注意:
对于DS18B20的数据读取,不能暴力式的循环。暴力循环会导致设备更新数据的请求失真,所以在这里,我调用了单片机的一个定时器T0,用作控制温度读取的时间,我定在4秒读取一次。这样话,减少了请求失真的可能。(失真即指发给单片机的字符进行了不完整透传,导致单片机做出不可控的应激动作)
讲到这里,单片机的程序和部分APP的程序都已经讲解完毕!
由于使用的是E4A软件进行编写,难度并不是很大,这里主要记录下APP对于切屏的蓝牙连接的经验和总结。
对于主窗口,我的想法是提供一个蓝牙连接选择的列表,手动选择想要连接的蓝牙,并切屏去控制界面。第一次尝试时,我直接将窗口进行切换,发现这样切换会使得HC-05模块直接与APP断开连接。
我经过思索之后,认为问题出现在窗口之间的组件无法共存的原因,于是我在控制界面也添加了蓝牙组件,并企图调用之前连接的蓝牙地址。
于是我调用了E4A保存设置函数,其分类在易安卓核心类库中的读写设置类
调用方式简单粗暴,在列表的设备被手动点击到时,就将相应的地址存储到系统中等待调用,再实现切屏效果。但是问题再次出现,设备仍然无法连接,即使进行了初始化。
经过多次的探索,我找到了问题的所在,每次蓝牙设备连接之前都有前提条件,就是要先启动蓝牙组件的搜索功能!
于是我在控制窗口的完成事件中添加了蓝牙组件的初始化并启动了 蓝牙组件的搜索功能,果然蓝牙组件调用了之前保存了的地址并进行了连接,HC-05连接成功!
读取地址,用的仍然是读写设置类的 读取设置函数
加上之前讲述的数据处理方法,APP大致的模型就出来了!
由于每个人对该模型的应用环境不同,对中个的代码也需要进行不同程度的修改或者添加!这也是为什么我不将所有代码copy出来的原因。我认为共享的目的主要是思维和算法的交流,而非功能上的单向借鉴。欢迎朋友交流指点!
想要轻松阅读上诉文字,读者应具备一定的单片机基础、E4A的操作基础以及在脑海中对算法要有概念!
以上均为原创,仅供学习!爱好这方面的朋友可以加我的QQ:1602741063 进行交流!