|
摘要: 針對(duì)多變環(huán)境攝像的環(huán)境,遙控?cái)z像車多為無線遙控,也需要對(duì)環(huán)境有一定檢測(cè)和處理。因此,遙控通信的復(fù)雜程度比較大。本文通過程序設(shè)計(jì),依托藍(lán)牙的數(shù)據(jù)傳輸完成對(duì)攝像車的控制及其他多種功能。
關(guān)鍵詞:攝像車 遙控 藍(lán)牙 通信
目的
編寫通信程序,通過藍(lán)牙所發(fā)送的數(shù)據(jù)控制攝像車的運(yùn)行,并且返回車子運(yùn)行時(shí)的參數(shù)和環(huán)境狀態(tài)等參數(shù)到遙控器顯示屏顯示。
總體設(shè)計(jì)
通信設(shè)計(jì)分為硬件設(shè)計(jì)和軟件設(shè)計(jì)兩部分,硬件設(shè)計(jì)為藍(lán)牙設(shè)計(jì),這里我們采用已有模塊使用;軟件設(shè)計(jì)為通信程序設(shè)計(jì)和協(xié)議設(shè)計(jì)。
藍(lán)牙設(shè)備
現(xiàn)有藍(lán)牙模塊的功能比較穩(wěn)定,設(shè)計(jì)技術(shù)成熟。我們根據(jù)設(shè)計(jì)需求,選擇要使用的藍(lán)牙模塊。通信時(shí)需要車子與遙控之間是雙向通信,互相發(fā)送數(shù)據(jù)。因此,選擇可以主從機(jī)一體化的藍(lán)牙模塊。所選藍(lán)牙傳輸距離:視距10米 ,F(xiàn)lash存儲(chǔ)容量:6-8Mbit,滿足當(dāng)前設(shè)計(jì)需求。藍(lán)牙模塊相應(yīng)參數(shù)過多,這里不做詳細(xì)介紹。
程序設(shè)計(jì)
通信設(shè)計(jì)主體在于通信協(xié)議的設(shè)計(jì)。之前介紹了遙控與車子之間是雙向通信,且通信數(shù)據(jù)復(fù)雜繁多。通過用藍(lán)牙發(fā)送簡(jiǎn)單數(shù)據(jù)來完成通信任務(wù)是不可能。藍(lán)牙所傳輸數(shù)據(jù)在0-255之間,256個(gè)數(shù)據(jù)根本不能控制車子的各種精細(xì)動(dòng)作和顯示車子運(yùn)行參數(shù)和環(huán)境數(shù)據(jù)。因此,要通過設(shè)計(jì)通信協(xié)議將數(shù)據(jù)進(jìn)行擴(kuò)充,加大通信數(shù)據(jù)的大小,實(shí)現(xiàn)復(fù)雜數(shù)據(jù)的傳輸。
初步構(gòu)想,將數(shù)據(jù)拆分多個(gè)簡(jiǎn)單數(shù)據(jù),依次發(fā)送。把復(fù)雜數(shù)據(jù)進(jìn)行拆分,拆分為高低位,這樣就可以把所發(fā)數(shù)據(jù)由256擴(kuò)充到65536。在65536的數(shù)據(jù)大小傳輸能夠分別完成攝像車的精細(xì)測(cè)量和操作(攝像頭三維度角度調(diào)整、車子舵機(jī)精度角度調(diào)節(jié)、環(huán)境參數(shù)精度分辨)。
上面我們能夠完成單一動(dòng)作的高精度控制,但是需要控制或測(cè)量的對(duì)象不是一個(gè),為此需要進(jìn)一步設(shè)計(jì)通信程序,來完成全局的控制和測(cè)量。進(jìn)一步設(shè)計(jì),我們需要傳輸大量的數(shù)據(jù),要想數(shù)據(jù)能過不出錯(cuò)的傳輸,就要對(duì)數(shù)據(jù)進(jìn)行分類分批發(fā)送。
先將所有的數(shù)據(jù)分類編號(hào),按發(fā)送順序或發(fā)送頻率排好序,按照序列進(jìn)行編號(hào)并且做好記錄注明。但是多數(shù)據(jù)傳輸時(shí),傳輸連接不穩(wěn)斷開或數(shù)據(jù)輸出跳變出錯(cuò)后,重連數(shù)據(jù)傳輸會(huì)導(dǎo)致數(shù)據(jù)接收解算出現(xiàn)錯(cuò)誤,導(dǎo)致車子不受控制。因此,設(shè)計(jì)時(shí)考慮到上述問題,需要將數(shù)據(jù)進(jìn)行打包處理,使得錯(cuò)誤數(shù)據(jù)對(duì)程序應(yīng)降到最小。采用現(xiàn)有一些通信協(xié)議模型,我們?cè)O(shè)計(jì)了如圖1的程序流程,這樣一個(gè)錯(cuò)誤的數(shù)據(jù)只會(huì)影響一個(gè)參數(shù)的大小,并且在下一次相同參數(shù)數(shù)據(jù)傳輸過來時(shí)被刷新替代。
簡(jiǎn)述一下框圖流程,我們把最大數(shù)據(jù)255作為數(shù)據(jù)報(bào)頭,當(dāng)接受255時(shí),數(shù)據(jù)接收正式開始接收存儲(chǔ),之后依次會(huì)有數(shù)據(jù)類型、數(shù)據(jù)正負(fù)值、數(shù)據(jù)高低位的數(shù)據(jù)傳輸,最后接收完數(shù)據(jù)后進(jìn)入數(shù)據(jù)整合程序,完成數(shù)據(jù)的還原,發(fā)給控制程序和相應(yīng)程序運(yùn)算使用。這個(gè)框架只是為了大數(shù)據(jù)量所開發(fā)的通用通信設(shè)計(jì),我們實(shí)際最后整車所用的數(shù)據(jù)大體在30多個(gè)數(shù)據(jù),我們可以將流程簡(jiǎn)化一步,將第二步數(shù)據(jù)類型和第三步數(shù)據(jù)正負(fù)值,整合在同一個(gè)數(shù)據(jù)內(nèi)發(fā)送出去。這樣系統(tǒng)在長(zhǎng)周期內(nèi),控制頻率更高了,控制性能指標(biāo)提升了。
圖1
實(shí)驗(yàn)過程
上面我們分析了理論設(shè)計(jì)思想,下面我們來用實(shí)踐來一步步完善程序調(diào)試。
藍(lán)牙連接調(diào)試
我們首先要連接藍(lán)牙保證通訊媒介的正常使用。藍(lán)牙調(diào)試主要有藍(lán)牙命名、密碼設(shè)定、工作頻率設(shè)定、主從機(jī)設(shè)定等。這些相關(guān)設(shè)定我們通過AT指令來完成,設(shè)定藍(lán)牙完成后,藍(lán)牙能過正常連接在一起。再連接完成后,我們進(jìn)行簡(jiǎn)單數(shù)據(jù)的傳輸,測(cè)試通信能正常完成。調(diào)試完成進(jìn)入第二步。
數(shù)據(jù)接收調(diào)試
通過設(shè)計(jì)程序使得我們能控制此時(shí)發(fā)送數(shù)據(jù)的值,通過將發(fā)送數(shù)據(jù)顯示在顯示屏上,檢查數(shù)值與我們發(fā)送的數(shù)據(jù)相同。數(shù)據(jù)是相互對(duì)傳的,在接收進(jìn)行簡(jiǎn)單計(jì)算返回?cái)?shù)據(jù),進(jìn)行顯示對(duì)比數(shù)據(jù)沒有異常。要長(zhǎng)時(shí)間通信,檢測(cè)通訊數(shù)據(jù)在長(zhǎng)期工作下不出現(xiàn)錯(cuò)誤。完成測(cè)試后,進(jìn)入下一步。
通信程序調(diào)試
編寫完整的通信程序,依次測(cè)試每個(gè)數(shù)據(jù)的傳輸和解算整合,并將每個(gè)數(shù)據(jù)發(fā)送到顯示屏,逐個(gè)檢查沒有出現(xiàn)錯(cuò)誤傳輸或異常現(xiàn)象。在正常工作情況下完成測(cè)試后,進(jìn)行異常工作測(cè)試。將通訊設(shè)備移到通訊的極限距離外一段時(shí)間,再拿回連接,記錄設(shè)備重連后的接收數(shù)據(jù),對(duì)比數(shù)據(jù)能夠恢復(fù)正常通訊的數(shù)據(jù)。完成全部測(cè)試,證明程序設(shè)計(jì)沒有錯(cuò)誤,可以使用該程序進(jìn)行工作。
總結(jié)
我們通過設(shè)計(jì)通信程序,對(duì)數(shù)據(jù)進(jìn)行分類、拆分等手段,并依次發(fā)送數(shù)據(jù)。從而,利用小數(shù)據(jù)發(fā)送的藍(lán)牙完成了大數(shù)據(jù)量的發(fā)送,完成對(duì)車子整體控制和相關(guān)環(huán)境因素的測(cè)量。
附錄:部分程序代碼
發(fā)送數(shù)據(jù)的選擇程序第一段無降頻處理
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變量的值降低發(fā)送頻率
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;
}
//串口發(fā)送//
//---------------------------------------------------------------------
// 函數(shù)功能:UART0_Init初始化
// 形式參數(shù): 無
// 函數(shù)返回值:無
//---------------------------------------------------------------------
void UART0_Init(void)
{
SCI0CR1 = 0x00;
SCI0CR2 = 0x2C; //接收中斷使能,發(fā)送接收使能
SCI0BD = 0x2b; //波特率配置成115200
//When IREN = 0 then
//SCI baud rate = SCI bus clock / (16 x SBR[12:0])
}
//---------------------------------------------------------------------
// 函數(shù)功能:SCI0發(fā)送一個(gè)字節(jié)數(shù)據(jù)
// 形式參數(shù): byte ch:發(fā)送的一個(gè)字節(jié)數(shù)據(jù)
// 函數(shù)返回值:無
//---------------------------------------------------------------------
void UART0_SendByte(byte ch)
{
while(!(SCI0SR1&0x80));
SCI0DRL = ch;
}
//---------------------------------------------------------------------
// 函數(shù)功能:SCI0發(fā)送字符串?dāng)?shù)據(jù)
// 形式參數(shù): byte *pBuff 發(fā)送緩沖區(qū)
// int Length 發(fā)送字節(jié)的長(zhǎng)度
// 函數(shù)返回值:無
//---------------------------------------------------------------------
void UART0_SendPacket(byte *pBuf,int pBuf_Length)
{
int i;
for(i=0;i<pBuf_Length;i++)
{
while(!(SCI0SR1&0x80));
SCI0DRL=*(pBuf+i);
}
}
//---------------------------------------------------------------------
// 函數(shù)功能:SCI0接受字符串?dāng)?shù)據(jù)
// 函數(shù)返回值:無符號(hào)
//---------------------------------------------------------------------
unsigned char SCI_0Read(void)
{
if(SCI0SR1_RDRF==1)
{
SCI1SR1_RDRF=1;
return SCI0DRL;
}
}
//---------------------------------------------------------------------
通信協(xié)議程序部分
拆分高低字節(jié),將位數(shù)較高的數(shù)據(jù)化為兩個(gè)低位數(shù)據(jù)
正負(fù)數(shù)判斷和處理(中間部分括號(hào)內(nèi)程序?yàn)閿?shù)據(jù)類型選擇)
//---------------------------------------------------------------------
void sci_int_send(int num)
{
unsigned char dath,datl;
if(num<0)
{
datl=(uchar)(~num&0x00ff);//拆低字節(jié)
dath=(uchar)(~num>>8);//拆高字節(jié)
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);//拆低字節(jié)
dath=(uchar)(num>>8);//拆高字節(jié)
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;
}
}
終端部分通信逆運(yùn)算,算出各種數(shù)據(jù)的值
/*************************中斷服務(wù)程序***************************/
#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) //轉(zhuǎn)向中值
{
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)//云臺(tái)中值
{
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;
}
}
|
|