modbus-tcp qt4-socket ---------micro2440 as device
生活随笔
收集整理的這篇文章主要介紹了
modbus-tcp qt4-socket ---------micro2440 as device
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
private:Ui::Widget *ui;QTcpServer *tcpServer;QTcpSocket *clientConnection ;QByteArray sendBuf;QByteArray receBuf;qint64 bytesRead ;//接收到的字節數 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)){ //監聽本地主機的6666端口,如果出錯就輸出錯誤信息,并關閉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();//我們獲取已經建立的連接的子套接字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監聽本地502端口。modbus之于502就像ftp之于21一樣。當有客戶端連接請求時激發newConnection()信號從而執行slots acceptConnection()。
2.在acceptConnection()里面應答連接,并建立readyRead()信號與 readData()槽函數的連接。readyRead信號在端口有數據到達時發射。
3.在readData ()函數里面讀取數據(一個modbus frame)。調用checkComm0Modbus()分析此幀。
4.modbus tcp的幀結構相比串口modbus rtu的前面多了6個字節modbus協議頭即mbap header,后面少了2個字節的crc,中間部分除了第一字節的node其余字節完全相同,都遵守modbus幀規范。
/***************************************************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 //服務器端(micro2440)回復幀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 //服務器端(micro2440)回復幀其中 00 06 00 00 00 06 ff 03 00 00 00 03 前6字節是mbap header: 00 事務處理標識符hi 06 事務處理標識符lo。一般主機每發送一個modbus幀,事務處理標識符+1 00 00 modbus協議標識符 必須為 00 00 00 信文長度hi 06 信文長度lo。指后續的字節數。 后面的字節屬于正文 ff modbus 節點地址,基于tcp/ip的modbus此地址無用。因為ip+port就可以唯一確定是哪個服務器 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字節是mbap header: 00 06 00 00 前4字節和客戶端發來的一樣。 00 信文長度hi 09 信文長度lo。指后續的字節數。 后面的字節屬于正文 ff modbus 節點地址。和客戶端發來的一樣。 03 function code。和客戶端發來的一樣。 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.還需要根據mosbus規范完善異常情況的控制。同一時間僅支持一個客戶連接請求。另一客戶請求時,會把請一個踢掉,而服務最新的這個客戶,可以使用多線程完善一下,使每個線程服務一個客戶連接。。
6.使用UartAssist測試
function code 01
function code 03
7.使用modscan32測試,
8.使用dasserver測試
安裝dasmbtcp,添加主題名 tcp2
在intouch中添加訪問名access_tcp2
建立io整型點,test1.注意item是400003.不是40003.
可以看到在為地址400003采集數據時,dasmbtcp發出的請求幀是 00 B3 00 00 00 06 FF 03 00 02 00 01 。最后6個字節中,03功能號。符合mb規范。
當更改這個變量例如改成9,如圖,的時候
dasmbtcp會發出請求幀,如下圖,
即01 42 00 00 00 09 FF 10 00 00 02 00 01 02 00 09 .最后9個字節中,0x10功能號。00 02 starting address。00 01 寄存器個數。02 后續字節數2個。00 09寫入值。
16 (10 Hex) Preset Multiple Registers
下面是0x10號功能請求幀的格式
服務器需要響應幀類似如下:
再實驗一個地址000006
很明顯,function code 01。
當我們試圖去置test2為off,如圖,的時候,
dasmbtcp會發出請求幀,如下圖,
是功能號0x0F
15 (0F Hex) Force Multiple Coils
由此確定:開發一個在支持wonderware dasmb 讀和寫的modbus設備,需要該設備實現01 02 03 04 0F 10功能號。而05 06置單線圈和單寄存器功能可以不要。因為wonderware dasmb置線圈和寄存器都是使用的0F 和10功能號,沒有用到05 06。
10不必開放,在intouch里面修改4xxxx的變量時(function code 03),dasmb 自動發出10請求幀。
0F不必開放,在intouch里面修改0xxxx的變量時(function code 01),dasmb 自動發出0F請求幀。
本例沒實現0x10號功能,所以改不了。按照mb規范加上這個功能很簡單的,自己動動腦子啦。
http://download.csdn.net/detail/songqqnew/3863154
轉載于:https://www.cnblogs.com/-song/archive/2011/11/27/3331916.html
總結
以上是生活随笔為你收集整理的modbus-tcp qt4-socket ---------micro2440 as device的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: modbus-rtu qt4-seria
- 下一篇: Jdom的SAXBuilder解析Str