流量計(jì)檢定裝置中流量變化的自動控制
流量計(jì)生產(chǎn)廠家在生產(chǎn)儀表和校驗(yàn)儀表的時候就需要對這些儀表的參數(shù)進(jìn)行檢定,確定儀表的性質(zhì)并提供給使用者相應(yīng)的參數(shù)以便于使用。確定儀表參數(shù)有很多種方法,在實(shí)流檢定方法中檢測裝置必須提供相應(yīng)儀表流量范圍內(nèi)的幾個檢測點(diǎn)的流量。下面就闡述一下檢測裝置的幾個檢測點(diǎn)流量變化的實(shí)現(xiàn)。
1 工程要求及實(shí)現(xiàn)方法
工程中提供信號采集器、標(biāo)準(zhǔn)表、相應(yīng)口徑管道、變頻器和風(fēng)機(jī)等設(shè)備。為了實(shí)現(xiàn)對整個標(biāo)定過程的全自動的控制, 我們利用VC++通信控件MSComm編制上位機(jī)軟件對變頻器進(jìn)行控制,變頻器再對風(fēng)機(jī)進(jìn)行頻率控制,從而控制風(fēng)機(jī)的輸出功率達(dá)到氣體流量的變化。
2 系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
在本系統(tǒng)中硬件連接是從計(jì)算機(jī)的RS-232接口通過RS-232/485轉(zhuǎn)換器連接到變頻器。系統(tǒng)采用的是ABB公司的ACS400變頻器,在VC++編制通訊軟件的時候通訊協(xié)議嚴(yán)格按照ACS400變頻器的通訊協(xié)議進(jìn)行編寫。系統(tǒng)硬件連接圖如下:
實(shí)現(xiàn)流量自動控制的思路有兩種,一是給出流量的控制信號,經(jīng)過變頻器動作之后,再由實(shí)際的流量傳感器獲得流量值傳給主控計(jì)算機(jī),由主控計(jì)算機(jī)進(jìn)行比較運(yùn)算得出進(jìn)一步的調(diào)整信號再發(fā)給變頻器,變頻器動作后流量進(jìn)一步接近設(shè)定值;這樣特定算法反復(fù)幾次后便達(dá)到設(shè)定值(如圖1)。二是通過實(shí)際試驗(yàn)得出的準(zhǔn)確經(jīng)驗(yàn)值,設(shè)定到計(jì)算機(jī)里面,通過經(jīng)驗(yàn)值進(jìn)行控制也會達(dá)到預(yù)期目的。在這里采用第二種方法,由于通過經(jīng)驗(yàn)值的方法,控制方式簡單,實(shí)現(xiàn)速度快,完全滿足工程要求的控制精度。
2.1 MSComm控件[1]
VC++編寫串口通訊的方法很多,其中利用MSComm(Microsoft Communications Contro1)控件編程非常簡單方便,它是微軟公司開發(fā)的專用通信控件,封裝了串口的所有功能,我們只用其中主要的通信功能就能完成工程需要。
2.2 串口設(shè)置
定義串口控件的對象為m_com。
設(shè)置變頻器通信格式:
通信設(shè)置:2400,n,8,2
波特率:2400;無奇偶校驗(yàn)位; 8個數(shù)據(jù)位,2個停止位
幀的包裝格式:起始位1+數(shù)據(jù)位8+停止位2=11位
串口初始化為:
if(m_com.GetPortOpen())//如果串口打開則關(guān)閉
m_com.SetPortOpen(FALSE);
m_com.SetCommPort(1);//選擇COM1
m_com.SetInBufferSize(1024);
//設(shè)置輸人緩沖區(qū)的大小1024Bytes
m_com.SetOutBufferSize(1024);
//設(shè)置輸人緩沖區(qū)的大小1024Bytes
m_com.SetRThreshold(1);
//表示有一個字符引發(fā)一個事件
m_com.SetInputMode(1);
//表示為二進(jìn)制輸入
m_com.SetSettings("2400,n,8,2");
if(!m_com.GetPortOpen())
//打開串口
m_com.SetPortOpen(TRUE);
m_ReceiveData="";
//接收通信數(shù)據(jù)的緩沖變量清零
2.3 發(fā)送數(shù)據(jù)
在發(fā)送命令的時候嚴(yán)格按照變頻器的協(xié)議進(jìn)行編制;由于通常發(fā)送命令都是按照字符串的形式發(fā)送但是該控件的發(fā)送是VARIANT類型,所以應(yīng)用關(guān)鍵是解決VARIANT與字符串之間的轉(zhuǎn)換問題,包括我們在串口響應(yīng)得到的數(shù)據(jù)的關(guān)鍵也是如此,詳見2.4節(jié)。下面的函數(shù)會說明字符串到VARIANT的轉(zhuǎn)換過程。
變頻器通訊數(shù)據(jù)包格式為:
開始 | 地址域 | 功能域 | 數(shù)據(jù)域 | CRC校驗(yàn) | 結(jié)束 |
8位 | 8位 | n*8位 | 16位 | ||
×× | ×× | ××……×× | ×××× |
開始:忽略。
結(jié)束:忽略。
地址域:0~247,0是廣播式的傳播,正常傳遞的時候返回值也會在地址域?qū)懮献约旱恼咎枴?BR> 功能域:0x03讀操作,Ox06寫操作,響應(yīng)返回如果正常則值相同否則返回0x83且在數(shù)據(jù)域說明原因。
數(shù)據(jù)域:具體操作值。
CRC校驗(yàn):CRC域位于信息的最后,低字節(jié)在前,高字節(jié)居后。在傳送信息的時候最后發(fā)送低字節(jié)。
把需要發(fā)送的命令以字符串的形式賦給m_SendData程序如下:
CByteArrav hexdata;//十六進(jìn)制的數(shù)據(jù)
b_String2Hex(m_SendData,hexdata);
//把字符串轉(zhuǎn)化成十六進(jìn)制并添加上CRC校驗(yàn)位
m_com.SetOutput(COleVariant(hexdata));
//發(fā)送數(shù)據(jù)
//功能:把字符串轉(zhuǎn)化成十六進(jìn)制并添加上CRC校驗(yàn)位
int CQBView:: b_String2Hex(CString str,
CByteArray &senddata)
{
int hexdata,lowhexdata;
int hexdatalen=0;
int len=str.GetLength();
BYTE a[200];
BYTE A,B;
WORD C,D;
A=0xFF;
B=0xFF;
CString yang;
CString shan;
senddata.SetSize(1en/2+8);
for(int i=0;i<len;)
{
char lstr,hstr=str[i];
if(hstr=='')
{
i++;continue;
}
i++;
if(i>=len)
break;
lstr=str[i];
hexdata=ConvertHexChar(hstr);
//該函數(shù)是把字符轉(zhuǎn)成十六進(jìn)制
lowhexdata=ConvertHexChar(1str);
if((hexdata==16)||(1owhexdata==16))
break;
else
hexdata=hexdata*16+lowhexdata;
i++;
a[hexdatalen]=hexdata;
hexdatalen++:
}
//CRC_16校驗(yàn)的算法
for(i=0;i<hexdatlen;i++)
{
B=B^a[i];
C=A*256+B;
for(int j=0;j<8;j++)
}
D=C&Ox0001;
C=C≥1;
if(D)C=C^0xA001;
}
A=C/256:
B=C%256;
}
a[i]=B;
a[i+1]=A;
hexdatalen=hexdatalen+2;
for(i=0;i<hexdatalen;i++)
{
senddata[i]=(char)a[i];/* */
shan.Format("%.2x",a[i]);
yang+=shan;
}
yang.MakeUpper();
senddata.SetSize(hexdatalen);
return hexdatalen;
}
2.4 接收數(shù)據(jù)處理
接收數(shù)據(jù)要用到串口響應(yīng)的函數(shù)OnOnCommMscomm1(),該函數(shù)時刻響應(yīng)串口的動作,真正從緩沖區(qū)中得到正確數(shù)據(jù),有兩個難點(diǎn):一是解決VARIANT轉(zhuǎn)換為字符串類型,二是解決過濾掉不正確的信息。第一個問題的解決方式比較固定,如下例程,過程是VARIANT轉(zhuǎn)換為ColeSafeArray型變量再轉(zhuǎn)換為BYTE型數(shù)組再到CString型變量;而第二個問題的解決方式比較麻煩,因?yàn)槊總€字符都會引起OnOnCommMscomm1()的響應(yīng),所以一串完整的信息,往往要執(zhí)行很多次OnOnCommMscomml()事件,如果在該函數(shù)中進(jìn)行處理數(shù)據(jù),那么不固定很難操控并且處理完的數(shù)據(jù)緩沖變量必須清空。所以為了解決這一問題筆者設(shè)了一個定時器,當(dāng)信息串的第一個字符引起響應(yīng)的時候設(shè)置定時器并用一個標(biāo)志封住防止重復(fù)設(shè)置定時器,這樣設(shè)置一個很短的一個時間后在數(shù)據(jù)緩沖變量中累計(jì)的就是一個完整的信息串。為了驗(yàn)證該信息串的正確性可以驗(yàn)證該CRC校驗(yàn)位,但是在這里為了方便理解,在定時函數(shù)中判斷該長度就夠了,判斷正確后再按照通信協(xié)議進(jìn)行提取并處理信息。同時在定時器的函數(shù)里銷毀定時器并且解除對設(shè)置定時器的封存,為接收下一信息串作準(zhǔn)備。
例程如下:
void CQBView:: OnOnCommMscomml()//串口響應(yīng)函數(shù)
{
// TODO: Add your control notification handler code here
//功能:把接收來的數(shù)據(jù)轉(zhuǎn)換成字符串的形式
VARIANT m_input1; ColeSafeArray m_input2;LONG length, i;
BYTE data [1024];CString str;
if(m_com.GetCommEvent()== 2)
//響應(yīng)事件為2
{
m_input1=m_com.GetInput();
//讀取緩沖區(qū)內(nèi)的數(shù)據(jù)
m_input2=m_input1;
//將VARIANT型變量轉(zhuǎn)換為ColeSafeArrav型變量
length=m_input2.GetOneDimSize();
//確定數(shù)據(jù)長度
for(i=0;i<length;i++)
//將數(shù)據(jù)轉(zhuǎn)換為BYTE型數(shù)組
m_input2.GetElement(&i,data+i);
for(i=0;i<length;i++)
//將數(shù)組轉(zhuǎn)換為CString型變量
{
char a=* (char*)(data+i);
str.Format("%02x",a);
str=str.Right(2);//取最后三位
m_ReceiveData+=str;
}
m_ReceiveData.MakeUpper();//變大寫
{
if(b_yangweishan)
{
SetTimer(1,100,NULL);//延時讀取
b_yangweishan=FALSE;
//保證一串信息響應(yīng)一次
}
}
void CQBView::OnTimer(UINT nlDEvent)
//定時函數(shù)
{
// TODO: Add your message handler code here and/or call default
KillTimer(1);//銷毀定時器
b_yangweishan=TRUE;//解除封鎖
if(m_ReceiveData.GetLength()==12)
//簡單驗(yàn)證
{
//工作區(qū)開始
Operationl(m_ReceiveData);
//提取數(shù)據(jù)
Operation2();//計(jì)算操作1
Operation3();//計(jì)算操作2
Show();//數(shù)據(jù)顯示
//工作區(qū)結(jié)束
m_ReceiveData.Empty();//數(shù)據(jù)緩沖
變量清空
}
else//不正確的信息
{
m_ReceiveData.Empty();
}
}
3 應(yīng)用總結(jié)
根據(jù)不同的通信形式和通信協(xié)議通過串口進(jìn)行數(shù)據(jù)通信,形式大都很類似,上面與變頻器的通信的方法完全可以衍生到PC機(jī)與單片機(jī)、PLC、Modem等智能設(shè)備的通信。對于MSComm控件的屬性還很多,在這里只提到幾項(xiàng)主要的設(shè)置,對串口的操作MSComm完全可以勝任,而且屏蔽掉了底層函數(shù)的編寫為程序員省了很多時間,且該控件并不局限于CFormView和CDialog類里面應(yīng)用,它完全可以在一般的框架里面應(yīng)用,只是把綁定方式復(fù)雜些。筆者利用MSComm控件開發(fā)的全自動式標(biāo)準(zhǔn)表法氣體流量標(biāo)定系統(tǒng)運(yùn)行穩(wěn)定可靠,并且整體的性價比比較好,在標(biāo)定過程當(dāng)中相對時間短、運(yùn)行成本低,對生產(chǎn)效率和效益起到很大的積極作用。
參考文獻(xiàn)
[1]李現(xiàn)勇.Visual C++串口通信技術(shù)與工程實(shí)踐[M .北京:人民郵電出版社,2002