modbus-tcp qt4-socket ---------micro2440 as device
生活随笔
收集整理的這篇文章主要介紹了
modbus-tcp qt4-socket ---------micro2440 as device
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
private:Ui::Widget *ui;QTcpServer *tcpServer;QTcpSocket *clientConnection ;QByteArray sendBuf;QByteArray receBuf;qint64 bytesRead ;//接收到的字節(jié)數(shù) public:/*****for modbus function*******/void checkComm0Modbus(void);void readCoil(void) ;void forceSingleCoil(void);void readRegisters();void presetSingleRegister(void);uint16 getCoilVal(uint16 addr,uint16 *tempData);uint16 setCoilVal(uint16 addr,uint16 tempData);uint16 getRegisterVal(uint16 addr,uint16 *tempData);uint16 setRegisterVal(uint16 addr,uint16 tempData)?? ?;/******************************/ Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);tcpServer = new QTcpServer(this);//if(!tcpServer->listen(QHostAddress::LocalHost,6666))if(!tcpServer->listen(QHostAddress("192.168.1.230"),502)){ //監(jiān)聽本地主機(jī)的6666端口,如果出錯就輸出錯誤信息,并關(guān)閉qDebug() << tcpServer->errorString();close();}connect(tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection())); }Widget::~Widget() {delete ui; } void Widget::acceptConnection()//response the sever's connection request-- {clientConnection = tcpServer->nextPendingConnection();//我們獲取已經(jīng)建立的連接的子套接字connect(clientConnection,SIGNAL(disconnected()),clientConnection,SLOT(deleteLater()));connect(clientConnection,SIGNAL(readyRead()),this,SLOT(readData()));connect(clientConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));ui->statusLabel->setText("already constuct clientConnection");}void Widget::readData(void)//when the readyRead signal is emit,this slots function is excuted {bytesRead=clientConnection->bytesAvailable();if(bytesRead>=8){DEBUG_BYSONG<<bytesRead;receBuf = clientConnection->readAll();DEBUG_BYSONG<<receBuf.toHex().toUpper();checkComm0Modbus();//to parse mbclientConnection->write(sendBuf);bytesRead=0;} }說明:
1.micro2440監(jiān)聽本地502端口。modbus之于502就像ftp之于21一樣。當(dāng)有客戶端連接請求時激發(fā)newConnection()信號從而執(zhí)行slots acceptConnection()。
2.在acceptConnection()里面應(yīng)答連接,并建立readyRead()信號與 readData()槽函數(shù)的連接。readyRead信號在端口有數(shù)據(jù)到達(dá)時發(fā)射。
3.在readData ()函數(shù)里面讀取數(shù)據(jù)(一個modbus frame)。調(diào)用checkComm0Modbus()分析此幀。
4.modbus tcp的幀結(jié)構(gòu)相比串口modbus rtu的前面多了6個字節(jié)modbus協(xié)議頭即mbap header,后面少了2個字節(jié)的crc,中間部分除了第一字節(jié)的node其余字節(jié)完全相同,都遵守modbus幀規(guī)范。
/***************************************************implement modbus function**************************/void Widget::checkComm0Modbus(void) {uint16 tempData=0;sendBuf.resize(0);sendBuf[0]=receBuf[0];sendBuf[1]=receBuf[1];sendBuf[2]=receBuf[2];sendBuf[3]=receBuf[3];//receBuf[0];////receBuf[1];////receBuf[2];//00//receBuf[3];//00//receBuf[4];//length mb hi byte//receBuf[5];//length mb lo byte 6//receBuf[6];//ff//receBuf[7];//function code//receBuf[8];//address hi byte//receBuf[9];//address lo byte//receBuf[10];//length hi byte//receBuf[11];//length lo byte//sendBuf[0];//**//sendBuf[1];//**//sendBuf[2];//**//sendBuf[3];//**//sendBuf[4];//length mb hi byte//sendBuf[5];//length mb lo byte 11//sendBuf[6];//**//sendBuf[7];//**//sendBuf[8];//length below 8//sendBuf[9];//data1 hi byte//sendBuf[10];//data1 lo byte//sendBuf[11];//data2 hi byte//sendBuf[12];//data2 lo byte//sendBuf[13];//data3 hi byte//sendBuf[14];//data3 lo byte//sendBuf[15];//data4 hi byte//sendBuf[16];//data4 lo byteif(bytesRead >= 12){if(receBuf[0]==receBuf[0]){//if(crcData == receBuf[7]+(receBuf[6]<<8)){if(receBuf[7] == (char)1){readCoil();}else if(receBuf[7] == (char)2){readCoil();}else if(receBuf[7] == (char)3){readRegisters();}else if(receBuf[7] == (char)4){readRegisters();}else if(receBuf[7] == (char)5){forceSingleCoil();}else if(receBuf[7] == (char)6){presetSingleRegister();}}}}}void Widget::readCoil(void) {DEBUG_BYSONG<<"readCoil"; /* 10 00 00 00 00 06 ff 02 00 00 00 03? //客戶端(pc)請求幀。 10 00 00 00 00 04 FF 02 01 01 //服務(wù)器端(micro2440)回復(fù)幀10 00 00 00 00 06 ff 02 00 00 00 03 10 00 00 00 00 06 mbap header ff 地址 02 功能號 00 00 start address 00 03 length10 00 00 00 00 04 FF 02 01 01 10 00 00 00 00 04 mbap header ff 地址 02 功能號 01 length of the follows 01 data即0000 0001b.所以adress0:1 address1:0 address2:0 */uint8 addr;uint8 tempAddr;uint16 byteCount;uint16 bitCount;uint16 crcData;uint8 position;uint8 i,k;//uint8 result;uint16 tempData;uint8 temp;uint8 exit = 0;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;bitCount = (receBuf[4+6]<<8) + receBuf[5+6];bitCount &= 0xff;byteCount = bitCount / 8;if(bitCount%8 != 0)byteCount++;for(k=0;k<byteCount;k++){position = k + 3 + 6;sendBuf[position] = 0;temp=0;for(i=0;i<8;i++){getCoilVal(tempAddr,&tempData);temp|=tempData << i;sendBuf[position] =temp;tempAddr++;if(tempAddr >= addr+bitCount){exit = 1;break;}}if(exit == 1)break;}sendBuf[4]=(byteCount+(char)3)>>8;//length mb hi bytesendBuf[5]=(byteCount+(char)3) & 0xff;//length mb lo byte 11sendBuf[0+6] = receBuf[6];sendBuf[1+6] = receBuf[7];sendBuf[2+6] = byteCount;}//void readCoil(void)void Widget::readRegisters(void) { /* 00 06 00 00 00 06 ff 03 00 00 00 03 //客戶端(pc)請求幀。 00 06 00 00 00 09 FF 03 06 00 00 00 01 00 02 //服務(wù)器端(micro2440)回復(fù)幀其中 00 06 00 00 00 06 ff 03 00 00 00 03 前6字節(jié)是mbap header: 00 事務(wù)處理標(biāo)識符hi 06 事務(wù)處理標(biāo)識符lo。一般主機(jī)每發(fā)送一個modbus幀,事務(wù)處理標(biāo)識符+1 00 00 modbus協(xié)議標(biāo)識符 必須為 00 00 00 信文長度hi 06 信文長度lo。指后續(xù)的字節(jié)數(shù)。 后面的字節(jié)屬于正文 ff modbus 節(jié)點地址,基于tcp/ip的modbus此地址無用。因為ip+port就可以唯一確定是哪個服務(wù)器 03 function code 00 start address hi 00 start address lo 00 length hi 03 length lo00 06 00 00 00 09 FF 03 06 00 00 00 01 00 02 前6字節(jié)是mbap header: 00 06 00 00 前4字節(jié)和客戶端發(fā)來的一樣。 00 信文長度hi 09 信文長度lo。指后續(xù)的字節(jié)數(shù)。 后面的字節(jié)屬于正文 ff modbus 節(jié)點地址。和客戶端發(fā)來的一樣。 03 function code。和客戶端發(fā)來的一樣。 06 length of the follows 00 00 data1 00 01 data2 00 02 data3 */DEBUG_BYSONG<<"readRegisters";uint8 addr;uint8 tempAddr;uint16 crcData;uint16 readCount;uint16 byteCount;uint16 i;uint16 tempData = 0;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;readCount = (receBuf[4+6]<<8) + receBuf[5+6];if (readCount>166) readCount=166;/constraint the quantitiesbyteCount = readCount * 2;for(i=0;i<byteCount;i+=2,tempAddr++){getRegisterVal(tempAddr,&tempData);sendBuf[i+3+6] = tempData >> 8;sendBuf[i+4+6] = tempData & 0xff;}sendBuf[4]=(byteCount+(char)3)>>8;//length mb hi bytesendBuf[5]=(byteCount+(char)3) & 0xff;//length mb lo byte 11sendBuf[0+6] = receBuf[6];sendBuf[1+6] = receBuf[7];sendBuf[2+6] = byteCount;// sendBuf[byteCount+6]='\0';}//void readRegisters(void)void Widget::forceSingleCoil(void) { /* 00 06 00 00 00 06 ff 05 00 03 FF 00 //client send mb frame。server response with the same 00 06 00 00 00 06 smap header ff modbus node address.useless 05 function code 00 03 start address ff 00 stand for 1。if clr 0,will be 00 00*/uint8 addr;uint8 tempAddr;uint16 tempData=0xabcd;uint8 onOff;uint8 i;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;//°????è????±????·onOff = (receBuf[4+6]<<8) + receBuf[5+6];if(onOff == 0xff00){ //?è??ONtempData = 1;}else if(onOff == 0x0000){ //?è??OFFtempData = 0;}if (tempData==1 || tempData==0){setCoilVal(tempAddr,tempData);for(i=0;i<bytesRead;i++){sendBuf[i] = receBuf[i];}}}//void forceSingleCoil(void)void Widget::presetSingleRegister(void) { /* 00 06 00 00 00 06 ff 06 00 03 FF 00 //client send mb frame。server response with the same 00 06 00 00 00 06 smap header ff modbus node address.useless 06 function code 00 03 start address 12 66 the data to write into the address above */uint8 addr;uint8 tempAddr;uint16 crcData;uint16 tempData;int i;addr = (receBuf[2+6]<<8) + receBuf[3+6];tempAddr = addr & 0xff;//°????è????±????·tempData = (receBuf[4+6]<<8) + receBuf[5+6];setRegisterVal(tempAddr,tempData);for(i=0;i<bytesRead;i++){sendBuf[i] = receBuf[i];}}
5.this is? the most? simple demo which implements the modbus tcp protocol.還需要根據(jù)mosbus規(guī)范完善異常情況的控制。同一時間僅支持一個客戶連接請求。另一客戶請求時,會把請一個踢掉,而服務(wù)最新的這個客戶,可以使用多線程完善一下,使每個線程服務(wù)一個客戶連接。。
6.使用UartAssist測試
function code 01
function code 03
7.使用modscan32測試,
8.使用dasserver測試
安裝dasmbtcp,添加主題名 tcp2
在intouch中添加訪問名access_tcp2
建立io整型點,test1.注意item是400003.不是40003.
可以看到在為地址400003采集數(shù)據(jù)時,dasmbtcp發(fā)出的請求幀是 00 B3 00 00 00 06 FF 03 00 02 00 01 。最后6個字節(jié)中,03功能號。符合mb規(guī)范。
當(dāng)更改這個變量例如改成9,如圖,的時候
dasmbtcp會發(fā)出請求幀,如下圖,
即01 42 00 00 00 09 FF 10 00 00 02 00 01 02 00 09 .最后9個字節(jié)中,0x10功能號。00 02 starting address。00 01 寄存器個數(shù)。02 后續(xù)字節(jié)數(shù)2個。00 09寫入值。
16 (10 Hex) Preset Multiple Registers
下面是0x10號功能請求幀的格式
服務(wù)器需要響應(yīng)幀類似如下:
再實驗一個地址000006
很明顯,function code 01。
當(dāng)我們試圖去置test2為off,如圖,的時候,
dasmbtcp會發(fā)出請求幀,如下圖,
是功能號0x0F
15 (0F Hex) Force Multiple Coils
由此確定:開發(fā)一個在支持wonderware dasmb 讀和寫的modbus設(shè)備,需要該設(shè)備實現(xiàn)01 02 03 04 0F 10功能號。而05 06置單線圈和單寄存器功能可以不要。因為wonderware dasmb置線圈和寄存器都是使用的0F 和10功能號,沒有用到05 06。
10不必開放,在intouch里面修改4xxxx的變量時(function code 03),dasmb 自動發(fā)出10請求幀。
0F不必開放,在intouch里面修改0xxxx的變量時(function code 01),dasmb 自動發(fā)出0F請求幀。
本例沒實現(xiàn)0x10號功能,所以改不了。按照mb規(guī)范加上這個功能很簡單的,自己動動腦子啦。
http://download.csdn.net/detail/songqqnew/3863154
轉(zhuǎn)載于:https://www.cnblogs.com/-song/archive/2011/11/27/3331916.html
總結(jié)
以上是生活随笔為你收集整理的modbus-tcp qt4-socket ---------micro2440 as device的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: modbus-rtu qt4-seria
- 下一篇: Jdom的SAXBuilder解析Str