标题:
基于蓝牙的遥控摄像车遥控通信设计
[打印本页]
作者:
不要加香菜
时间:
2017-8-1 10:20
标题:
基于蓝牙的遥控摄像车遥控通信设计
摘要: 针对多变环境摄像的环境,遥控摄像车多为无线遥控,也需要对环境有一定检测和处理。因此,遥控通信的复杂程度比较大。本文通过程序设计,依托蓝牙的数据传输完成对摄像车的控制及其他多种功能。
关键词:摄像车 遥控 蓝牙 通信
目的
编写通信程序,通过蓝牙所发送的数据控制摄像车的运行,并且返回车子运行时的参数和环境状态等参数到遥控器显示屏显示。
总体设计
通信设计分为硬件设计和软件设计两部分,硬件设计为蓝牙设计,这里我们采用已有模块使用;软件设计为通信程序设计和协议设计。
蓝牙设备
现有蓝牙模块的功能比较稳定,设计技术成熟。我们根据设计需求,选择要使用的蓝牙模块。通信时需要车子与遥控之间是双向通信,互相发送数据。因此,选择可以主从机一体化的蓝牙模块。所选蓝牙传输距离:视距10米 ,Flash存储容量:6-8Mbit,满足当前设计需求。蓝牙模块相应参数过多,这里不做详细介绍。
程序设计
通信设计主体在于通信协议的设计。之前介绍了遥控与车子之间是双向通信,且通信数据复杂繁多。通过用蓝牙发送简单数据来完成通信任务是不可能。蓝牙所传输数据在0-255之间,256个数据根本不能控制车子的各种精细动作和显示车子运行参数和环境数据。因此,要通过设计通信协议将数据进行扩充,加大通信数据的大小,实现复杂数据的传输。
初步构想,将数据拆分多个简单数据,依次发送。把复杂数据进行拆分,拆分为高低位,这样就可以把所发数据由256扩充到65536。在65536的数据大小传输能够分别完成摄像车的精细测量和操作(摄像头三维度角度调整、车子舵机精度角度调节、环境参数精度分辨)。
上面我们能够完成单一动作的高精度控制,但是需要控制或测量的对象不是一个,为此需要进一步设计通信程序,来完成全局的控制和测量。进一步设计,我们需要传输大量的数据,要想数据能过不出错的传输,就要对数据进行分类分批发送。
先将所有的数据分类编号,按发送顺序或发送频率排好序,按照序列进行编号并且做好记录注明。但是多数据传输时,传输连接不稳断开或数据输出跳变出错后,重连数据传输会导致数据接收解算出现错误,导致车子不受控制。因此,设计时考虑到上述问题,需要将数据进行打包处理,使得错误数据对程序应降到最小。采用现有一些通信协议模型,我们设计了如图1的程序流程,这样一个错误的数据只会影响一个参数的大小,并且在下一次相同参数数据传输过来时被刷新替代。
简述一下框图流程,我们把最大数据255作为数据报头,当接受255时,数据接收正式开始接收存储,之后依次会有数据类型、数据正负值、数据高低位的数据传输,最后接收完数据后进入数据整合程序,完成数据的还原,发给控制程序和相应程序运算使用。这个框架只是为了大数据量所开发的通用通信设计,我们实际最后整车所用的数据大体在30多个数据,我们可以将流程简化一步,将第二步数据类型和第三步数据正负值,整合在同一个数据内发送出去。这样系统在长周期内,控制频率更高了,控制性能指标提升了。
图1
实验过程
上面我们分析了理论设计思想,下面我们来用实践来一步步完善程序调试。
蓝牙连接调试
我们首先要连接蓝牙保证通讯媒介的正常使用。蓝牙调试主要有蓝牙命名、密码设定、工作频率设定、主从机设定等。这些相关设定我们通过AT指令来完成,设定蓝牙完成后,蓝牙能过正常连接在一起。再连接完成后,我们进行简单数据的传输,测试通信能正常完成。调试完成进入第二步。
数据接收调试
通过设计程序使得我们能控制此时发送数据的值,通过将发送数据显示在显示屏上,检查数值与我们发送的数据相同。数据是相互对传的,在接收进行简单计算返回数据,进行显示对比数据没有异常。要长时间通信,检测通讯数据在长期工作下不出现错误。完成测试后,进入下一步。
通信程序调试
编写完整的通信程序,依次测试每个数据的传输和解算整合,并将每个数据发送到显示屏,逐个检查没有出现错误传输或异常现象。在正常工作情况下完成测试后,进行异常工作测试。将通讯设备移到通讯的极限距离外一段时间,再拿回连接,记录设备重连后的接收数据,对比数据能够恢复正常通讯的数据。完成全部测试,证明程序设计没有错误,可以使用该程序进行工作。
总结
我们通过设计通信程序,对数据进行分类、拆分等手段,并依次发送数据。从而,利用小数据发送的蓝牙完成了大数据量的发送,完成对车子整体控制和相关环境因素的测量。
附录:部分程序代码
发送数据的选择程序第一段无降频处理
if(fangsongshunxu==0)
{
sci_int_send(sudu);
}
if(fangsongshunxu==1)
{
sci_int_send(zhuanxiang);
}
if(fangsongshunxu==2)
{
sci_int_send(sxtzuoyou);
}
if(fangsongshunxu==3)
{
sci_int_send(sxtfuyang);
}
if(fangsongshunxu==4)
{
sci_int_send(dangwei);
}
if(fangsongshunxu==5)
{
sci_int_send(sxtqijiang);
}
if(fangsongshunxu==6)
{
sci_int_send(canshutiaozheng);
canshutiaozheng=0;
}
if(fangsongshunxu==7)
{
sci_int_send(moshi);
}
if(fangsongshunxu==8)
{
sci_int_send(shuzhijiao);
}
fangsongshunxu=fangsongshunxu+1;
if(fangsongshunxu>8)
{
fangsongshunxu=0;
}
通过fangsong变量的值降低发送频率
if(fangsongshunxu==0&&fangsong==0)
{
sci_int_send(chejiao);
fangsong=1;
}
if(fangsongshunxu==1&&fangsong==0)
{
sci_int_send(gdzxp);
fangsong=1;
}
if(fangsongshunxu==2&&fangsong==0)
{
sci_int_send(gdzxd);
fangsong=1;
}
if(fangsongshunxu==3&&fangsong==0)
{
sci_int_send(gdsudu);
fangsong=1;
}
if(fangsongshunxu==4&&fangsong==0)
{
sci_int_send(jiaosuduyushe);
fangsong=1;
}
if(fangsongshunxu==5&&fangsong==0)
{
sci_int_send(G);
fangsong=1;
}
if(fangsongshunxu==6&&fangsong==0)
{
sci_int_send(zxzhongzhi);
fangsong=1;
}
if(fangsongshunxu==7&&fangsong==0)
{
sci_int_send(yutaizhongzhi);
fangsong=1;
}
if(fangsongshunxu==8&&fangsong==0)
{
sci_int_send(sxtfuyangzz);
fangsong=1;
}
if(fangsongshunxu==9&&fangsong==0)
{
sci_int_send(wendu);
fangsong=1;
}
if(fangsongshunxu>9)
{
fangsongshunxu=0;
}
//串口发送//
//---------------------------------------------------------------------
// 函数功能:UART0_Init初始化
// 形式参数: 无
// 函数返回值:无
//---------------------------------------------------------------------
void UART0_Init(void)
{
SCI0CR1 = 0x00;
SCI0CR2 = 0x2C; //接收中断使能,发送接收使能
SCI0BD = 0x2b; //波特率配置成115200
//When IREN = 0 then
//SCI baud rate = SCI bus clock / (16 x SBR[12:0])
}
//---------------------------------------------------------------------
// 函数功能:SCI0发送一个字节数据
// 形式参数: byte ch:发送的一个字节数据
// 函数返回值:无
//---------------------------------------------------------------------
void UART0_SendByte(byte ch)
{
while(!(SCI0SR1&0x80));
SCI0DRL = ch;
}
//---------------------------------------------------------------------
// 函数功能:SCI0发送字符串数据
// 形式参数: byte *pBuff 发送缓冲区
// int Length 发送字节的长度
// 函数返回值:无
//---------------------------------------------------------------------
void UART0_SendPacket(byte *pBuf,int pBuf_Length)
{
int i;
for(i=0;i<pBuf_Length;i++)
{
while(!(SCI0SR1&0x80));
SCI0DRL=*(pBuf+i);
}
}
//---------------------------------------------------------------------
// 函数功能:SCI0接受字符串数据
// 函数返回值:无符号
//---------------------------------------------------------------------
unsigned char SCI_0Read(void)
{
if(SCI0SR1_RDRF==1)
{
SCI1SR1_RDRF=1;
return SCI0DRL;
}
}
//---------------------------------------------------------------------
通信协议程序部分
拆分高低字节,将位数较高的数据化为两个低位数据
正负数判断和处理(中间部分括号内程序为数据类型选择)
//---------------------------------------------------------------------
void sci_int_send(int num)
{
unsigned char dath,datl;
if(num<0)
{
datl=(uchar)(~num&0x00ff);//拆低字节
dath=(uchar)(~num>>8);//拆高字节
while(!(SCI0SR1&0x80));
SCI0DRL=255;
if(fangsongshunxu==0)
{
while(!(SCI0SR1&0x80));
SCI0DRL=2;
}
if(fangsongshunxu==1)
{
while(!(SCI0SR1&0x80));
SCI0DRL=3;
}
if(fangsongshunxu==2)
{
while(!(SCI0SR1&0x80));
SCI0DRL=4;
}
if(fangsongshunxu==3)
{
while(!(SCI0SR1&0x80));
SCI0DRL=5;
}
if(fangsongshunxu==4)
{
while(!(SCI0SR1&0x80));
SCI0DRL=6;
}
if(fangsongshunxu==5)
{
while(!(SCI0SR1&0x80));
SCI0DRL=7;
}
if(fangsongshunxu==6)
{
while(!(SCI0SR1&0x80));
SCI0DRL=8;
}
if(fangsongshunxu==7)
{
while(!(SCI0SR1&0x80));
SCI0DRL=9;
}
if(fangsongshunxu==8)
{
while(!(SCI0SR1&0x80));
SCI0DRL=10;
}
while(!(SCI0SR1&0x80));
SCI0DRL=1;
while(!(SCI0SR1&0x80));
SCI0DRL=dath;
while(!(SCI0SR1&0x80));
SCI0DRL=datl;
}
else
{
datl=(uchar)(num&0x00ff);//拆低字节
dath=(uchar)(num>>8);//拆高字节
while(!(SCI0SR1&0x80));
SCI0DRL=255;
if(fangsongshunxu==0)
{
while(!(SCI0SR1&0x80));
SCI0DRL=2;
}
if(fangsongshunxu==1)
{
while(!(SCI0SR1&0x80));
SCI0DRL=3;
}
if(fangsongshunxu==2)
{
while(!(SCI0SR1&0x80));
SCI0DRL=4;
}
if(fangsongshunxu==3)
{
while(!(SCI0SR1&0x80));
SCI0DRL=5;
}
if(fangsongshunxu==4)
{
while(!(SCI0SR1&0x80));
SCI0DRL=6;
}
if(fangsongshunxu==5)
{
while(!(SCI0SR1&0x80));
SCI0DRL=7;
}
if(fangsongshunxu==6)
{
while(!(SCI0SR1&0x80));
SCI0DRL=8;
}
if(fangsongshunxu==7)
{
while(!(SCI0SR1&0x80));
SCI0DRL=9;
}
if(fangsongshunxu==8)
{
while(!(SCI0SR1&0x80));
SCI0DRL=10;
}
while(!(SCI0SR1&0x80));
SCI0DRL=0;
while(!(SCI0SR1&0x80));
SCI0DRL=dath;
while(!(SCI0SR1&0x80));
SCI0DRL=datl;
}
}
终端部分通信逆运算,算出各种数据的值
/*************************中断服务程序***************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 20 sci0(void)
{
if(SCI0SR1_RDRF==1)
{
SCI1SR1_RDRF=1;
shuju= SCI0DRL;
}
if(shuju==255&&zhunbei==0)
{
kaishi=1;
zhunbei=1;
}
if(kaishi==1)
{
if(shuju==2)
{
chezijiaodusj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==3)
{
gdzxpsj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==4)
{
gdzxdsj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==5)
{
sudupsj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==6)
{
suduisj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==7)
{
sududsj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==8)
{
zxzhongzhisj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==9)
{
yutaizhongzhisj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==10)
{
sxtfuyangzzsj=1;
zhengfu=1;
kaishi=0;
}
if(shuju==11)
{
wendusj=1;
zhengfu=1;
kaishi=0;
}
}
if(chezijiaodusj==1&&dushu==1)//车子角度
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
chezijiaodu=datah*256+datal;
if(zhengshu==1)
{
chezijiaodu=0-chezijiaodu;
}
zhenghe=0;
dushu=0;
zhunbei=0;
chezijiaodusj=0;
}
}
if(gdzxpsj==1&&dushu==1) //光电P
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
gdzxp=datah*256+datal;
if(zhengshu==1)
{
gdzxp=0-gdzxp;
}
zhenghe=0;
dushu=0;
zhunbei=0;
gdzxpsj=0;
}
}
if(gdzxdsj==1&&dushu==1) //光电D
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
gdzxd=datah*256+datal;
if(zhengshu==1)
{
gdzxd=0-gdzxd;
}
zhenghe=0;
dushu=0;
zhunbei=0;
gdzxdsj=0;
}
}
if(sudupsj==1&&dushu==1)//速度P
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
sudup=datah*256+datal;
if(zhengshu==1)
{
sudup=0-sudup;
}
zhenghe=0;
dushu=0;
zhunbei=0;
sudupsj=0;
}
}
if(suduisj==1&&dushu==1)//速度P
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
sudui=datah*256+datal;
if(zhengshu==1)
{
sudui=0-sudui;
}
zhenghe=0;
dushu=0;
zhunbei=0;
suduisj=0;
}
}
if(sududsj==1&&dushu==1)//速度P
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
sudud=datah*256+datal;
if(zhengshu==1)
{
sudud=0-sudud;
}
zhenghe=0;
dushu=0;
zhunbei=0;
sududsj=0;
}
}
if(zxzhongzhisj==1&&dushu==1) //转向中值
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
zxzhongzhi=datah*256+datal;
if(zhengshu==1)
{
zxzhongzhi=0-zxzhongzhi;
}
zhenghe=0;
dushu=0;
zhunbei=0;
zxzhongzhisj=0;
}
}
if(yutaizhongzhisj==1&&dushu==1)//云台中值
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
yutaizhongzhi=datah*256+datal;
if(zhengshu==1)
{
yutaizhongzhi=0-yutaizhongzhi;
}
zhenghe=0;
dushu=0;
zhunbei=0;
yutaizhongzhisj=0;
}
}
if(sxtfuyangzzsj==1&&dushu==1) //摄像头中值
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
sxtfuyangzz=datah*256+datal;
if(zhengshu==1)
{
sxtfuyangzz=0-sxtfuyangzz;
}
zhenghe=0;
dushu=0;
zhunbei=0;
sxtfuyangzzsj=0;
}
}
if(wendusj==1&&dushu==1)//温度
{
if(diyici==1)
{
datal=shuju;
diyici=0;
zhenghe=1;
}
if(diyici==0&&zhenghe==0)
{
datah=shuju;
diyici=1;
}
if(zhenghe==1)
{
wendu=datah*256+datal;
if(zhengshu==1)
{
wendu=0-wendu;
}
zhenghe=0;
dushu=0;
zhunbei=0;
wendusj=0;
}
}
if(shuju==0&&zhengfu==1)
{
zhengshu=0;
zhengfu=0;
dushu=1;
}
if(shuju==1&&zhengfu==1)
{
zhengshu=1;
zhengfu=0;
dushu=1;
}
}
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1