摘 要: 介紹了以VC6.0為開(kāi)發(fā)平臺(tái),用無(wú)線(xiàn)單片機(jī)CC2530進(jìn)行多節(jié)點(diǎn)多參數(shù)的低功耗數(shù)據(jù)采集系統(tǒng)。下位機(jī)設(shè)計(jì)了可靈活擴(kuò)展的無(wú)線(xiàn)數(shù)據(jù)幀,并設(shè)計(jì)了采集控制命令,實(shí)現(xiàn)廣播模式和單目標(biāo)地址控制兩種功能。上位機(jī)利用CSerialPort類(lèi)對(duì)串口數(shù)據(jù)選擇性接收,提高了效率和穩(wěn)定性,可保存和識(shí)別隨機(jī)分配的節(jié)點(diǎn)地址,并改進(jìn)了CSerialPort類(lèi)可實(shí)現(xiàn)十六進(jìn)制數(shù)的發(fā)送。
關(guān)鍵詞: 無(wú)線(xiàn)傳感器網(wǎng)絡(luò);VC6.0;串口通信;CSerialPort類(lèi);數(shù)據(jù)幀
無(wú)線(xiàn)傳感器網(wǎng)絡(luò)是由部署在監(jiān)測(cè)區(qū)域內(nèi)部或附近的大量廉價(jià)、具有通信、感測(cè)及計(jì)算能力的微型器節(jié)點(diǎn)通過(guò)自組織構(gòu)成的“智能”測(cè)控網(wǎng)絡(luò)[1]。本系統(tǒng)下位機(jī)利用SHT11溫濕度傳感和美國(guó)TI公司的無(wú)線(xiàn)片上系統(tǒng)CC2530單片機(jī)構(gòu)成終端傳感器節(jié)點(diǎn),對(duì)溫室內(nèi)的溫度和相對(duì)濕度及終端傳感器片上電壓三個(gè)參數(shù)進(jìn)行實(shí)時(shí)測(cè)量,通過(guò)在環(huán)境內(nèi)布置多個(gè)測(cè)量節(jié)點(diǎn)來(lái)獲取現(xiàn)場(chǎng)信息。在眾多集成可視化開(kāi)發(fā)環(huán)境中,VisualC6.0是底層編程環(huán)境的最佳選擇,它提供了相當(dāng)齊備的類(lèi)和各種控件,編程界面友好。
1 系統(tǒng)下位機(jī)硬件組成
系統(tǒng)下位機(jī)硬件組成如圖1示,由I2C總線(xiàn)的SHT11數(shù)字溫濕度傳感器連接CC2530芯片的VDD/3的ADC通道,經(jīng)CC2530單片機(jī)采集處理后打包數(shù)據(jù)無(wú)線(xiàn)發(fā)送到與PC機(jī)連接的協(xié)調(diào)器節(jié)點(diǎn)。其中協(xié)調(diào)器節(jié)點(diǎn)與PC機(jī)通過(guò)串口轉(zhuǎn)USB線(xiàn)連接。
下位機(jī)使用TI公司SensorDemo例程在IAR7.5集成開(kāi)發(fā)環(huán)境下進(jìn)行二次開(kāi)發(fā),在應(yīng)用層對(duì)傳感器節(jié)點(diǎn)和協(xié)調(diào)器節(jié)點(diǎn)分別編寫(xiě)程序,協(xié)調(diào)器節(jié)點(diǎn)接收傳感器節(jié)點(diǎn)的數(shù)據(jù)以數(shù)據(jù)幀格式串行發(fā)送到PC機(jī)[2]。
2 下位機(jī)數(shù)據(jù)幀設(shè)計(jì)
下位機(jī)數(shù)據(jù)幀編程固定長(zhǎng)度為20 B的數(shù)據(jù),有些字節(jié)可變,有些字節(jié)是固定的。比如一個(gè)數(shù)據(jù)幀用十六進(jìn)制表示為:FE 0F 46 87 DE 65 02 00 09 00 1B 20 00 00 38 33 00 00 00 9E。其中:FE是幀頭字節(jié),46 87是雙字節(jié)數(shù)據(jù),低字節(jié)在前,標(biāo)識(shí)為8746為接收標(biāo)志;9E是前面19個(gè)字節(jié)的“異或”運(yùn)算值,為整個(gè)數(shù)據(jù)幀的CRC校驗(yàn)位,可變;0F是固定值,表示除了幀開(kāi)始和0F、46、87、9E 5個(gè)字節(jié)外的15個(gè)字節(jié)數(shù);DE65是傳感器節(jié)點(diǎn)16 bit地址號(hào)65DE,是隨著數(shù)據(jù)來(lái)自不同節(jié)點(diǎn)變化;0002、0009也是固定的字節(jié),表示數(shù)據(jù)包和有效數(shù)據(jù)位;1 B是節(jié)點(diǎn)溫度的整數(shù)部分,換算為十進(jìn)制值為26℃,可變;20是節(jié)點(diǎn)片上電壓值(乘10倍值),換算為十進(jìn)制值為3.2 V,可變;0000為父節(jié)點(diǎn)地址;38是節(jié)點(diǎn)相對(duì)濕度值,換算為十進(jìn)制值為56%,可變;33是節(jié)點(diǎn)溫度的小數(shù)部分,換算為十進(jìn)制值為(3×16+3)/256=0.199 2℃,可變;00 00 00是預(yù)留下來(lái)的3個(gè)字節(jié)給節(jié)點(diǎn)其他傳感器數(shù)據(jù)的傳送。
3 采集控制命令兩種模式實(shí)現(xiàn)
在傳感器節(jié)點(diǎn)C文件中添加命令輸入集合COLLECTOR_CMD_ID,協(xié)調(diào)器節(jié)點(diǎn)C 添加同樣的命令輸出集。為協(xié)調(diào)器節(jié)點(diǎn)設(shè)計(jì)3 B的串口數(shù)據(jù),前2個(gè)字節(jié)為目標(biāo)地址,第3個(gè)字節(jié)為采集控制命令,如設(shè)置80為停止采集,40為開(kāi)始采集命令。因?yàn)閰f(xié)調(diào)器地址是固定的0x0000十六進(jìn)制數(shù),其他傳感節(jié)點(diǎn)地址不可能是這個(gè)數(shù),所以當(dāng)發(fā)送前2個(gè)字節(jié)為0000時(shí),可將此作為向全體傳感器節(jié)點(diǎn)廣播的命令的判斷,如果是具體單個(gè)節(jié)點(diǎn)地址,則只有相應(yīng)節(jié)點(diǎn)接收控制命令,其中廣播命令發(fā)送的地址模式為0xFFFF。
4 上位機(jī)程序設(shè)計(jì)
4.1 CSerialPort類(lèi)加入程序
CSerialPort類(lèi)是remon spekreijse寫(xiě)的一個(gè)免費(fèi)的串口類(lèi),可在互聯(lián)網(wǎng)下載到其頭文件(h文件)和源程序(cpp文件),它可直接用于串口的讀寫(xiě)操作。首先建立一個(gè)基于窗口的MFC應(yīng)用程序,再將CSerialPort.h和CSerialPort.cpp兩個(gè)類(lèi)文件復(fù)制到工程文件夾中,并用project-add to project-files命令將上述兩個(gè)文件加入工程[3]。
因?yàn)镃SerialPort類(lèi)是第三方類(lèi),所以其串口消息響應(yīng)函數(shù)不能由VC的classwizd自動(dòng)生成,需通過(guò)手動(dòng)增加消息響應(yīng)函數(shù)的消息映射。在建立的窗口類(lèi)頭文件下添加以下代碼:
afx_msg LONG OnComm(WPARAM ch,LPARAM port);
在窗口類(lèi)ccp文件下進(jìn)行串口接收一個(gè)字符的響息映射,只要串口中有一個(gè)字節(jié)就觸發(fā)這個(gè)事件,代碼如下:
ON_MESSAGE(WM_COMM_RXCHAR,OnComm)
最初的CSerialPort類(lèi)的發(fā)送函數(shù)只有一種發(fā)送字符類(lèi)型WriteToPort( char* string)。而考慮到上位機(jī)對(duì)下位機(jī)控制命令都是十六進(jìn)制數(shù)傳送,且傳送數(shù)據(jù)的最終原理都是以二進(jìn)制數(shù)傳遞的,所以增加一種可按字節(jié)數(shù)發(fā)送的函數(shù)類(lèi)型WriteToPort(unsigned char*string,int n)。其中,string是發(fā)送的一個(gè)字節(jié)數(shù)據(jù),n是要發(fā)送的字節(jié)數(shù)。代碼如下:
void CSerialPort::WriteToPort(unsigned char*string,int n)
{
assert(m_hComm != 0);
memset(m_szWriteBuffer,0,sizeof(m_szWriteBuffer));
memcpy(m_szWriteBuffer,string,n);
m_nWriteSize=n;
//set event for write
SetEvent(m_hWriteEvent);
}
上位機(jī)軟件設(shè)計(jì)流程如圖2所示。
4.2 串口數(shù)據(jù)接收
對(duì)接收的數(shù)據(jù)進(jìn)行幀頭判斷,如果接收字節(jié)為FE則繼續(xù)接收,保存在無(wú)符號(hào)字符數(shù)組buf中,接收后面的字節(jié)保存在數(shù)組中,并對(duì)連續(xù)的18個(gè)字節(jié)進(jìn)行“異或”運(yùn)算。如果這個(gè)“異或”運(yùn)算值與第20個(gè)字節(jié)的值相等,表示這20個(gè)字節(jié)為一個(gè)有效數(shù)據(jù)串,然后再將其中的源節(jié)點(diǎn)地址提取出來(lái)并保存,再分別對(duì)其中的參數(shù)值進(jìn)行處理,根據(jù)節(jié)點(diǎn)地址寫(xiě)入VC表格控件中的相應(yīng)行。串口數(shù)據(jù)幀選擇性接收和多節(jié)點(diǎn)地址保存函數(shù)片段如下:
LONG CMYSerialPortDlg::OnComm(WPARAM ch,LPARAM port)
{ static char checksum=0; //校驗(yàn)和初值
static char checksum1=0; //校驗(yàn)和獲取值
static int count=0; //接收字符數(shù)
static unsigned char buf[21];
static unsigned char SAddrL[5];//源地址低字節(jié)
static unsigned char SAddrH[5];//源地址高字節(jié)
static int i=0; //源節(jié)點(diǎn)個(gè)數(shù)
if(ch= =0xFE)
{ count=0;
buf[count]=ch;
}
else
{count++;
buf[count]=ch;
if(count==1)
checksum=buf[count];
else if(count<19)
checksum^=buf[count];//ch
else if(count= =19)
{checksum1=buf[count];
if(checksum1= =checksum)
{ //源節(jié)點(diǎn)地址存放
if(i==0)
{SAddrL[0]=buf[4];SAddrH[0]=buf[5];i++;}
if(i==1)
{if((buf[4]==SAddrL[0])&&(buf[5]==SAddrH[0]));
else{i++;SAddrL[1]=buf[4];SAddrH[1]=buf[5];}
}
if(i==2)
… …
UpdateData(0);return 0;
}
4.3 串口命令的發(fā)送
在應(yīng)用程序的發(fā)送數(shù)據(jù)編輯框中輸入3 B的十六進(jìn)制數(shù)據(jù),而且要讓發(fā)送函數(shù)明白這是3 B的數(shù)據(jù),而不是默認(rèn)地把這些十六進(jìn)制數(shù)當(dāng)作6個(gè)單獨(dú)的字符來(lái)處理。在窗口CPP文件中加入“字符轉(zhuǎn)十六進(jìn)制數(shù)”的函數(shù)String2Hex(m_strSend,hexdata),其返回值為轉(zhuǎn)化后的十六進(jìn)制數(shù)的個(gè)數(shù),在此即是要發(fā)送的命令字節(jié)數(shù)(該函數(shù)原型來(lái)自參考文獻(xiàn)[4])。發(fā)送命令函數(shù)如下:
void CMYSerialPortDlg::OnSend()
{UpdateData(1); //更新參數(shù)數(shù)據(jù)
CByteArray hexdata;
int len=String2Hex(m_strSend,hexdata);
unsigned char *str;
str=(unsigned char*)malloc(sizeof(char)*len);
for(int j=0;j <len; j++)
{ str[j]=hexdata[j];
}
m_spSerialPort.WriteToPort(str,3);
//m_spSerialPort是在窗口中定義的CSerialPort類(lèi)成員變量
}
程序運(yùn)行結(jié)果如圖3示。
本文設(shè)計(jì)的無(wú)線(xiàn)傳感器網(wǎng)絡(luò)數(shù)據(jù)采集系統(tǒng)能夠?qū)崿F(xiàn)多節(jié)點(diǎn)多參數(shù)的數(shù)據(jù)實(shí)時(shí)采集,并對(duì)測(cè)量的數(shù)據(jù)進(jìn)行波形和表格顯示及存儲(chǔ)。設(shè)計(jì)的串口接收中斷程序可應(yīng)用到其他串口數(shù)據(jù)采集系統(tǒng)中,發(fā)送命令實(shí)現(xiàn)了對(duì)所有節(jié)點(diǎn)和個(gè)別節(jié)點(diǎn)采集過(guò)程的控制,在后期還運(yùn)用了計(jì)數(shù)求模的方法,可通過(guò)上位機(jī)發(fā)送改變除數(shù)來(lái)改變節(jié)點(diǎn)的采集時(shí)間間隔,整個(gè)程序可移植性強(qiáng)。
參考文獻(xiàn)
[1] 孫利民,李建中,陳渝,等.無(wú)線(xiàn)傳感器網(wǎng)絡(luò)[M].北京:清華大學(xué)出版社,2005.
[2] 深圳飛比電子科技公司.Z-STACK SensorDemo實(shí)驗(yàn). [EB/OL].[2011-10-13].http://wenku.baidu.com/view/dfe9d82ee2bd960590c6770c.html.
[3] 潘石柱,于仲安.VC實(shí)現(xiàn)串行通信的三種途徑[J].電子工程師.2002,28(9).
[4] 龔建偉.串口調(diào)試助手源程序及編程詳細(xì)過(guò)程.[EB/OL].(2001-06-20)[2010-12-21].http://hi.baidu.com/laoyang1018/ blog/item/641491ef565756fece1b3ecc.html.