本文為ProfiNet介紹文章《嵌入式環(huán)境 實現(xiàn)ProfiNet/PN工業(yè)以太網(wǎng)》的應(yīng)用實例,使用ESM7000+ETA104+UR205PN
如圖1,將ETA104V5和UR205PN,以及EM7000核心板,安裝至SBC884底板
圖1
如圖2,連接編程電腦,交換機(jī),組態(tài)用PC,及SBC884板卡系統(tǒng)。
圖2,系統(tǒng)組成
將GSD壓縮文件解壓并放置到任意目錄中,目錄中有如下三個文件
打開博圖,并在菜單欄中,通過“選項->管理通用站點描述文件”進(jìn)入gsd管理。
選擇第一步GSD文件的解壓路徑,并勾選文件,安裝。
完成后,可以在博圖的硬件目錄中,“其他現(xiàn)場設(shè)備-> PROFINETIO -> I/O-> UreateAutomatic -> VARIABLE I/O ->前端模塊”中找到新添加的設(shè)備。
首先新建一個博圖項目,然后在拓?fù)湟晥D中,添加PLC,交換機(jī),和PN模塊。我這里選擇的PLC是1211C。而模塊的位置如下圖:
將PLC和UR205PN模塊連接起來。
然后轉(zhuǎn)到網(wǎng)絡(luò)視圖中,添加他們的連接關(guān)系,如圖:
接著雙擊UR205PN模塊,進(jìn)入設(shè)備視圖,并在設(shè)備插槽中,添加4個數(shù)據(jù)交換模塊
設(shè)備插槽中插入數(shù)據(jù)交換模塊,數(shù)據(jù)交換模塊中插入數(shù)據(jù)對象。數(shù)據(jù)對象可以從“1/2/4字節(jié)輸入”或者“1/2/4字節(jié)輸出”中選擇。
接下來分別為每個數(shù)據(jù)模塊添加數(shù)據(jù)對象,如下:
分別是1個1字節(jié)輸入(兩路DI輸入),1個1字節(jié)輸出(對應(yīng)一路繼電器輸出),兩個2字節(jié)輸入(對應(yīng)4-20MA輸入)。
這里添加的四個模塊,對應(yīng)的是ETA104模塊的輸入輸出通路。其對應(yīng)關(guān)系如下:
ETA104 | UR205PN | 信息備注 |
PKW module_1 | PKW問詢式通信通道 | |
1路繼電器輸出 | inpupt 1 byte(bit0) | 繼電器0=數(shù)據(jù)位0 |
2路空觸頭輸入 | Output 1byte(bit0 ,bit1) | 輸入0= 數(shù)據(jù)位0 輸入1= 數(shù)據(jù)位1 |
電流輸入1 | Input 2 byte | 16位電流輸入值 |
電流輸入2 | Input 2 byte | 16位電流輸入值 |
為模塊添加變量。
首先我們要找到UR205PN各模塊的數(shù)據(jù)地址。
在博圖的設(shè)備視圖中選擇UR205PN模塊,并點擊各模塊,即可查看模塊數(shù)據(jù)在PLC中的位置.例如下圖展示的是PKW模塊的示意圖:
上圖中,說明PKW模塊的輸入,是從PLC數(shù)據(jù)地址68到75,共8個字節(jié)。PKW模塊的輸出,是從64到71,共8個字節(jié)。
以此類推,可以找到所有數(shù)據(jù)的地址.本例中數(shù)據(jù)地址如下表
數(shù)據(jù)模塊 | 輸入地址 | 輸出地址 |
PKW | 68-75 | 64-71 |
DI :Input 1 byte | 76 | -- |
Do:Output 1byte | -- | 72 |
AI0:Input 2 byte | 77,78 | -- |
AI1:Input 2 byte | 79,80 | -- |
根據(jù)數(shù)據(jù)表,我們在PLC中建立如下變量表:
建立項目的強(qiáng)制列表,該表用于設(shè)置輸出值。
建立項目的監(jiān)視表,該表用于讀取輸入值。
數(shù)據(jù)變量分為兩個區(qū)域:PKW 和 周期通信。 周期通信比較好理解,就是每次通信都會交換的周期數(shù)據(jù),也是我們在插槽中插入的模塊數(shù)據(jù):如DI,DO,AI,AO。
PKW_開頭的數(shù)據(jù)對象,則屬于PKW訪問過程。該訪問基于一問一答,過程和定義如下:
所以,PLC如果要發(fā)起PKW通信,需要如下步驟:
1. PKW_RW_req 設(shè)為“0:讀” 或者 “1:寫”
2. PKW_INDEX_req 設(shè)為需要訪問的數(shù)據(jù)索引
3. PKW_VALUE_req 如果為寫操作,這里需要輸入寫入的值
4. PKW_COUNT_req 自增1,以表明是新的PKW訪問,觸發(fā)PN操作
當(dāng)接收數(shù)據(jù)時:
1. 等待PKW_COUNT_rsp與PKW_COUNT_req一致
2. 對比回應(yīng)的INDEX是否等于請求INDEX
3. 若是讀取操作的回應(yīng)幀,則獲取PKW_VALUE_rsp
完成后將組態(tài)編譯并下載到PLC。
本案例使用的嵌入式編譯開發(fā)環(huán)境式如下:
操作系統(tǒng) | WIN11 64位 |
虛擬機(jī)操作系統(tǒng) | WSL+Ubuntu-20.04 |
開發(fā)環(huán)境 | VSCODE WSL 遠(yuǎn)程連接 |
C編譯鏈接 | arm-poky-linux-gnueabi-gcc |
其搭建過程可參考如下文檔:《VSCODE嵌入式編譯環(huán)境搭建》
PC連接嵌入式板的過程,參考英創(chuàng)工控板使用說明。
解壓縮案例代碼:test_DIO_pn.rar。
通過VSCODE ,WSL方式遠(yuǎn)程打開該項目。
項目的文件組成如下圖所示:
對應(yīng)用層而言,通信都是建立在周期數(shù)據(jù)交換幀上。其內(nèi)部劃分為兩個功能區(qū):PKW,和周期通信區(qū)。這兩個功能區(qū)在周期通信幀中,他們的位置如下:
這兩個功能區(qū),對應(yīng)了嵌入式內(nèi)的兩種通信對象:PKW索引訪問對象和周期通信訪問對象。
PKW: 數(shù)據(jù)以<索引-值>的方式存放在嵌入式端,用戶可以為某個參數(shù)指明特定的索引號,PLC通過問答方式,訪問該索引。這種方式適用于交換時間不敏感的數(shù)據(jù)。例如一些參數(shù)。其通信幀定義如下:、
周期通信對象:數(shù)據(jù)每個通信周期都會交換一次,適合時間敏感的通信對象,往往都是一些輸入輸出值,如DI,DO,AI,AO等。其在幀中定義如下:
在案例中,用戶代碼區(qū)域主要有以下代碼段需要維護(hù):
1. 周期通信模塊定義
uint8_t UMList[4]={ //模塊類型 模塊數(shù)據(jù)存儲區(qū) MODULE_1BYTE_INPUT, //1個字節(jié)的DI輸入 MODULE_1BYTE_OUTPUT, //1個字節(jié)的DO輸出 MODULE_2BYTE_INPUT, //16位AI輸入 MODULE_2BYTE_INPUT //16位AI輸出 };
用戶通過該數(shù)組定義周期通信模塊的數(shù)量和類型。本案例中,模塊如下表:
模塊序號 | 模塊類型 | 模塊描述 | 對應(yīng)數(shù)據(jù)對象 |
0 | MODULE_1BYTE_INPUT | 一個字節(jié)的輸入模塊 | BIT0 = DI0 BIT1 = DI1 |
1 | MODULE_1BYTE_OUTPUT | 一個字節(jié)的輸處模塊 | BIT0=DO0 |
2 | MODULE_2BYTE_INPUT | 兩個字節(jié)的輸入 | 4-20MA輸入1 |
3 | MODULE_2BYTE_INPUT | 兩個字節(jié)的輸入 | 4-20MA輸入2 |
我們目前支持的模塊類型有:
#define MODULE_1BYTE_INPUT 0X01 //1字節(jié)輸入 #define MODULE_2BYTE_INPUT 0X02 //2字節(jié)輸入 #define MODULE_4BYTE_INPUT 0X04 //4字節(jié)輸入 #define MODULE_1BYTE_OUTPUT 0X81 //1字節(jié)輸出 #define MODULE_2BYTE_OUTPUT 0X82 //2字節(jié)輸出 #define MODULE_4BYTE_OUTPUT 0X84 //4字節(jié)輸出
(注意這里的輸出是以PLC為主站視角,從PLC到嵌入式為輸出;從嵌入式到PLC為輸入。)
2. PKW索引訪問區(qū)域模塊定義
sPKWNode UPKWList[]= { {0x0001,PKW_R|PKW_W,0}, //索引為1的可讀寫寄存器 {0x0012,PKW_R,0}, //索引為8001H的只讀寄存器 {0x8002,PKW_W,0} //索引為8002H的只寫寄存器 };
3. 周期通信回調(diào)函數(shù)user_Oncycle
當(dāng)周期通信發(fā)生時,會調(diào)用該回調(diào)函數(shù),用戶在這里將需要傳輸?shù)闹担cPN上的通信值做交換。
例如在本案例中,回調(diào)函數(shù)如下:
//切換大小端 //pDes 指向切換后的結(jié)果存儲區(qū) //pSrc 來源 //SIZE 數(shù)據(jù)字節(jié)長度 void sw_bigsmall(uint8_t *pDes, uint8_t *pSrc, uint8_t size) { uint8_t *pD; uint8_t *pS; for(int i=0;i<size;i++) { pD = pDes+i; pS = pSrc+size-1-i; *pD = *pS; } } //用戶在該函數(shù)中,交換模塊和外部設(shè)備之間的數(shù)據(jù) void user_Oncycle(sPNModule *pModule, int modulecount) { uint8_t *src8; uint8_t *des8; //這里處理周期數(shù)據(jù) if(pModule[0].moduletype == MODULE_1BYTE_INPUT)//確保模塊類型正確 { *pModule[0].pmoduleBuff = ETA105_DI ; } if(pModule[1].moduletype == MODULE_1BYTE_OUTPUT)//確保模塊類型正確 ETA105_DO = *(pModule[1].pmoduleBuff) ; if(pModule[2].moduletype == MODULE_2BYTE_INPUT)//確保模塊類型正確 sw_bigsmall((pModule[2].pmoduleBuff),(uint8_t*)&(ETA105_AI[0]),2); if(pModule[3].moduletype == MODULE_2BYTE_INPUT)//確保模塊類型正確 sw_bigsmall((pModule[3].pmoduleBuff),(uint8_t*)&(ETA105_AI[1]),2); }
4. PKW讀索引回調(diào)函數(shù)user_onReadIndex
當(dāng)PKW中有新的讀取請求時,會執(zhí)行該回調(diào)函數(shù)。用戶在次函數(shù)對該索引數(shù)據(jù)賦值并執(zhí)行一些自定義操作。本案例中程序如下
void user_onReadIndex(sPKWNode *pNode) { uint8_t *src8; uint8_t *des8; if(pNode == NULL) return ; switch(pNode->index) { case 0x0001: //這里添加讀0001索引對象時的程序 break; case 0x0012: //這里添加讀0012索引對象時的程序 假定是波特率 //這里注意從小端切換成大端 sw_bigsmall((uint8_t*)&(pNode->value),(uint8_t*)&(m_Serial.baudrate),4); break; case 0x8002: //0x8002不可讀,不操作 break; } }
5 .PKW寫操作回調(diào)函數(shù)
當(dāng)有PKW寫請求時,系統(tǒng)調(diào)用該回調(diào)函數(shù),用戶在此函數(shù)中,將PLC傳輸來得值寫入,并執(zhí)行相應(yīng)得自定義操作。
//用戶定義的寫縮影回調(diào)函數(shù) void user_onWriteIndex(sPKWNode *pNode) { if(pNode == NULL) return ; switch(pNode->index) { case 0x0001: // break; case 0x0012: //該對象只讀,不操作 break; case 0x8002: // break; } }
入口:
m_Serial.CDC_ACM_number =0; //初始化通信對象 m_Serial.baudrate = 115200; m_Serial.oncycle = user_Oncycle; //注冊回調(diào)函數(shù) m_Serial.onPKWRead = user_onReadIndex; m_Serial.onPKWWrite = user_onWriteIndex; m_Serial.startPN(); //創(chuàng)建PN工作線程
退出處理:
m_Serial.stopPN( );
本項目為英創(chuàng)公司與第三方公司合作項目。ProfiNet專業(yè)技術(shù)支持可以聯(lián)系:
電子郵件 99@ureate.com
電話 028-85550280-815
成都英創(chuàng)信息技術(shù)有限公司 028-8618 0660