uip+freemodbus网络通信
前言:
TCP/IP協(xié)議通過uip協(xié)議棧來實現(xiàn),應(yīng)用層的modbus協(xié)議使用freemodbus來實現(xiàn),另外還需要一個網(wǎng)卡(筆者使用的是KSZ8851網(wǎng)卡控制器)來實現(xiàn)底層的數(shù)據(jù)傳輸(包括物理層、數(shù)據(jù)鏈路層)。
下面先介紹uip協(xié)議棧和freemodbus庫的使用,后續(xù)移植過程和測試結(jié)果再更新
一、uip協(xié)議棧
uIP協(xié)議棧去掉了完整的TCP/IP中不常用的功能,簡化了通訊流程,但保存了網(wǎng)絡(luò)通訊必須使用的協(xié)議,設(shè)計重點放在了IP/TCP/ICMP/UDP/ARP這些網(wǎng)絡(luò)層和傳輸層協(xié)議上,保證了其代碼的通用性和結(jié)構(gòu)的穩(wěn)定性。UIP提供的是封裝的策略。
由上往下逐步封裝用戶的數(shù)據(jù),如:
應(yīng)用層----------傳輸層--------網(wǎng)絡(luò)層------數(shù)據(jù)鏈路層-----物理層
應(yīng)用數(shù)據(jù)—TCP封裝頭部—IP封裝頭部-----mac封裝+尾部-----發(fā)送
uIP提供了三個函數(shù)到底層,既uip_init(), uip_input() 和uip_periodic(),同時還提供了許多函數(shù)與堆棧交互。當(dāng)設(shè)備驅(qū)動放一個輸入包到包緩存里(up_buf),系統(tǒng)將調(diào)用uip_input()函數(shù).函數(shù)將會處理這個包和需要時調(diào)用應(yīng)用程序。當(dāng)uip_input()返回,一個輸出包放在包緩存里。包的大小由全局變量uip_len約束。如果uip_len是0,則說明沒有包要發(fā)送。周期計時是用于驅(qū)動所有的uIP內(nèi)部時鐘事件。當(dāng)周期計時激發(fā),每一個TCP連接應(yīng)該調(diào)用uIP函數(shù)uip_periodic()。連接編號傳遞的是作為自變量給uip_periodic()函數(shù)的。類似于uip_input()函數(shù),當(dāng)uip_periodic()函數(shù)返回,輸出的IP包要放到包緩存里。任何的事物需要經(jīng)過一定的初始階段,在UIP協(xié)議里面通過uip_init()來初始化。
應(yīng)用程序作為單獨的模塊由用戶實現(xiàn),uIP協(xié)議棧提供一系列接口函數(shù)供用戶程序調(diào)用。用戶需要將應(yīng)用層入口程序作為接口提供給uIP協(xié)議棧,定義為宏UIP_APPCALL()。uIP在接受到底層傳來的數(shù)據(jù)包后,若需要送到上層應(yīng)用程序處理,它就調(diào)用UIP_APPCALL()。在uIP協(xié)議中有一個uip_buf緩沖用來接收和發(fā)送數(shù)據(jù)。
? 初始化 uIP 協(xié)議棧:uip_init()
? 處理輸入包:uip_input()
? 處理周期計時事件:uip_periodic()
? 開始監(jiān)聽端口:uip_listen()
? 連接到遠(yuǎn)程主機:uip_connect()
? 接收到連接請求:uip_connected()
? 主動關(guān)閉連接:uip_close()
? 連接被關(guān)閉:uip_closed()
? 發(fā)出去的數(shù)據(jù)被應(yīng)答:uip_acked()
? 在當(dāng)前連接發(fā)送數(shù)據(jù):uip_send()
? 在當(dāng)前連接上收到新的數(shù)據(jù):uip_newdata()
? 告訴對方要停止連接:uip_stop()
? 連接被意外終止:uip_aborted()
二、應(yīng)用層modbus協(xié)議(FreeModbus)
FreeModbus是針對通用的Modbus協(xié)議棧在嵌入式系統(tǒng)中應(yīng)用的一個實現(xiàn)。Modbus協(xié)議是一個在工業(yè)制造領(lǐng)域中得到廣泛應(yīng)用的一個網(wǎng)絡(luò)協(xié)議。一個Modbus通信協(xié)議棧包括兩層:定義了數(shù)據(jù)結(jié)構(gòu)和功能Modbus應(yīng)用協(xié)議和網(wǎng)絡(luò)層。目前版本的FreeModbus支持如下的功能碼:讀輸入寄存器 (0x04);讀保持寄存器 (0x03);寫單個寄存器 (0x06);寫多個寄存器 (0x10);讀/寫多個寄存器 (0x17);讀取線圈狀態(tài) (0x01);寫單個線圈 (0x05);寫多個線圈 (0x0F);讀輸入狀態(tài) (0x02);報告從機標(biāo)識 (0x11);
應(yīng)用Modbus TCP協(xié)議,當(dāng)準(zhǔn)備處理一個新數(shù)據(jù)幀的時候,移植層就必須首先向協(xié)議棧發(fā)送一個事件標(biāo)志。然后,協(xié)議棧調(diào)用一個返回值為接收到的Modbus TCP數(shù)據(jù)幀的函數(shù),并且開始處理這個數(shù)據(jù)幀。如果數(shù)據(jù)有效,則相應(yīng)的Modbus反饋幀將提供給移植層生成反饋幀。最后,該反饋被發(fā)送到客戶端。
FreeModbus必須首先調(diào)用初始化功能eMBInit()函數(shù)(使用modbus TCP模式時使用eMBTCPInit()函數(shù)),然后調(diào)用eMBEnable(),最后在循環(huán)體中調(diào)用eMBPoll()函數(shù)。
該函數(shù)主要設(shè)置偵聽的端口和對需要調(diào)用的函數(shù)指針進行復(fù)制:
pvMBFrameStartCur = eMBTCPStart;
pvMBFrameStopCur = eMBTCPStop;
peMBFrameReceiveCur = eMBTCPReceive;
peMBFrameSendCur = eMBTCPSend;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
eMBCurrentMode = MB_TCP;
eMBState = STATE_DISABLED;
右邊的函數(shù)如eMBTCPStart、eMBTCPStop等定義在mbtcp.c中
? 檢查modbus功能是否都被關(guān)閉,如果不是關(guān)閉(可能是沒有初始化或者已經(jīng)打開),就返回錯誤;
? 如果是disable狀態(tài),主要做兩件事:首先調(diào)用pvMBFrameStartCur,在eMBTCPInit()函數(shù)中指向了eMBTCPStart函數(shù);然后將eMB狀態(tài)改為使能狀態(tài),即初始化結(jié)束。
檢查是否有事件發(fā)送,如果有,則根據(jù)不太類型的事件響應(yīng):
? EV_READY事件,表示系統(tǒng)剛剛進入偵聽狀態(tài),則什么都不做;
? EV_FRAME_RECEIVED事件,表示接收到完整的幀,做兩件事情:調(diào)用peMBFrameReceiveCur()函數(shù),解析出地址、數(shù)據(jù)和長度;然后檢查地址,如果是廣播地址或本機地址(廣播地址表示從機接收,本機地址表示從機發(fā)送),就調(diào)用xMBPortEventPost( EV_EXECUTE ),將接收器的狀態(tài)更改為EV_EXECUTE;
? EV_EXECUTE事件,在函數(shù)列表中檢查,有沒有與命令字段相符合的函數(shù),若有則執(zhí)行響應(yīng)的函數(shù),否則返回非法功能碼;然后再次檢查地址,如果不等于廣播地址(即表示從機為發(fā)送狀態(tài)),則調(diào)用peMBFrameSendCur()函數(shù),開始發(fā)送數(shù)據(jù)包
? EV_FRAME_SENT事件,直接break(響應(yīng)寫進EV_EXECUTE事件中)
三、移植過程
先展示一下加入的uip協(xié)議棧和freemodbus庫在工程中的示例
運行的主函數(shù)
四、測試
局域網(wǎng)下板卡與路由器采用網(wǎng)線連接,PC端模擬上位機通過wifi接入局域網(wǎng),使用Modbus Poll模擬modbus主機,向從機發(fā)出查詢指令。
? 串口打印信息:初始化各模塊、建立連接、收到請求、關(guān)閉連接
? Wireshark抓包信息:TCP三次握手、keep-alive幀、modbus的收發(fā)。
? Modbus poll讀值:Modbus poll作為modbus主機能讀到從機對應(yīng)傳感器值的變化
? 串口打印信息
? Wireshark抓包信息
下圖中192.168.2.2是PC的ip地址,而192.168.2.10為板卡設(shè)置的ip地址。
? Modbus poll讀值
下圖中左邊一列為傳感器的名稱,右邊為讀取相應(yīng)傳感器的數(shù)據(jù)。
總結(jié)
以上是生活随笔為你收集整理的uip+freemodbus网络通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【笔记】研究生的早期科研之路(作者:中国
- 下一篇: 学习使用php的stripslashe(