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