張錚,程和生,賴世勛
(安徽省煤炭科學研究院 監控技術中心,合肥 230001)
?
基于CanFestival和μC/OS-II的CANopen平臺構建*
張錚,程和生,賴世勛
(安徽省煤炭科學研究院 監控技術中心,合肥 230001)
基于開源的CANopen架構CanFestival和嵌入式實時系統μC/OS-II,提出了一種構建CANopen從站平臺的方法。詳細闡述CANopen協議棧的軟件結構設計,實現了μC/OS-II系統在MC9S12XF512上的移植,并將CANopen從站協議的狀態機封裝成任務后嵌入到μC/OS-II中運行。該硬件平臺采用單片機MC9S12XF512和高速CAN總線收發器TJA1040來實現。通信測試表明CANopen從站通信穩定,實現了DS301通信規范的功能。
CANopen協議;μC/OS-II;CanFestival
CanFestival作為一個開源的CANopen架構,實現了CANopen通信規范DS301的基本協議,并且在不斷升級[1]。本文結合CANopen開源協議棧CanFestival,分析CANopen的協議結構、對象字典和通信對象,實現了嵌入式操作系統μC/OS-II在Freescale微控制器MC9S12XF512上的移植;進一步修改CAN總線的底層驅動程序,將CANopen從站協議嵌入到μC/OS-II系統中,實現了一種CANopen從站平臺的方法。
CANopen通信以CAN總線為基礎,物理層遵循IS11898標準,數據鏈路層遵循CAN2.0標準,在應用層上CANopen協議定義了一系列規范來實現高層通信,主要分為CANopen通信規范和CANopen設備規范。CANopen的通信規范主要包括DS301,DS301定義CANopen設備之間的通信方式和行為規范,所有設備必須實現DS301。 CANopen的設備規范則定義了特定類型設備進入CAN總線的通信方式和功能。
CANopen設備模型分為三個部分[2,5],如圖1所示。通信接口實現CANopen四種通信對象的功能,來實現不同數據的收發,包括服務數據對象(SDO)、過程數據對象(PDO)、網絡管理對象(NMT)以及一些特殊功能對象(SYNC、TIME和EMCY)。

圖1 CANopen設備模型
CANopen設備最核心的部分是對象字典,它是一個有序的對象組,每個對象采用一個16位的索引值來尋址,同時為允許訪問數據結構中的單個元素,定義一個8位的子索引[7-8]。對象字典中的對象可以是輸入輸出信號、設備功能以及網絡變量。在應用程序中,CANopen主從站進行連接,通過SDO對CANopen設備對象字典進行配置,同時通過PDO進行實時數據的通信。
2.1 CAN總線通信硬件實現
CANopen平臺的構建使用飛思卡爾的芯片MC9S12XF512。CAN總線收發器采用TJA1040。如圖2所示,在CANH和CANL之間并聯兩個60 Ω的電阻并通過一個30 pF的小電容接地,從而濾除CAN總線上的高頻干擾。MSCAN控制器模塊上的TXD、RXD引腳與TJA1040的TXD、RXD相互連接,并通過TJA1040的CANH和CANL引腳接入到CAN總線網絡中。

圖2 CAN總線接口硬件電路
2.2 CANopen協議棧軟件設計
整個CANopen協議棧的軟件設計遵循模塊化的原則,并依據協議棧的分層結構按照以下三個相對獨立的部分來進行設計,包括操作系統及硬件驅動接口層、CAN-open 通信協議層以及設備行規應用層,如圖3所示。

圖3 CANopen協議棧軟件結構
2.2.1 操作系統及硬件驅動接口層
底層提供操作系統與CAN總線驅動接口,操作系統接口使得CANopen協議棧可以嵌入到不同的系統中,實現任務的調度。CAN總線驅動接口處理CAN總線的數據幀信息,獲得其中的有效數據進行存儲并提供給上層通信對象使用。基于MC9S12XF512芯片的CAN總線驅動程序主要包括CAN總線控制器初始化函數、CAN總線報文發送程序、CAN總線報文接收程序以及中斷函數的設置,其中初始化的內容包括CAN總線波特率、濾波器的設置,CAN總線控制器時鐘的選擇。CAN總線驅動中定義結構體Message來存儲CAN總線的信息幀:
typedef struct{
SHORT_CAN cob-id;
UNS8 rtr;
UNS8 len;
UNS8 data[8];
}Message
其中 32位的cob_id表示CAN幀ID值,兼容CAN2.0A/B;rtr表示是否為遠程幀,0為數據幀,1為遠程幀;len代表數據的長度,對應CAN總線幀里DLC的數值;8字節數組data存儲CAN總線有效數據。 CAN總線驅動接口將CAN總線底層驅動的收發程序封裝在對應于CanFestival的f_can_send和f_can_receive函數當中,二者分別讀寫CAN總線收發程序的緩沖區,獲取其中CAN總線數據cob_id、rtr、len、data的數值并存入到結構體Message中。通過這種方式,在運行高層協議時,CANopen通信對象不需要關心底層驅動的實現過程及執行環境,從而將CANopen通信協議層和底層驅動分隔開來,便于移植。
2.2.2 CANopen通信協議層
CANopen通信協議層實現協議4種通信對象的功能,每個設備獨立擁有一個對象字典,它作為通信對象與上層應用程序的接口,存放著設備的配置參數和過程參數,設備之間配置參數的通信通過SDO以客戶機/服務器的方式來實現。SDO提供基于請求和應答的點對點通信,允許大于8字節的數據采用分段或分塊的方式傳輸。過程參數的通信通過PDO采用生產者/消費者方式來實現,數據從一個生產者傳到一個或者多個消費者,且數據長度在8字節以內。PDO在對象字典中通過通信參數規定該PDO所使用的cob-id、傳輸類型、抑制時間等參數,通過映射參數設置映射到PDO中的對象字典里的具體對象。時間標記、同步、應急等預定義的報文則可以提高網絡利用率,NMT用來實現節點狀態的轉移和錯誤的控制。它采用主從結構,主節點對從節點進行狀態管理和節點保護,每個CANopen從節點以狀態機的方式接受主節點NMT對其狀態的切換。

圖4 報文處理
根據CANopen預定義連接集的描述,cob-id的高4位是用來區分不同通信對象的功能碼[2],報文接收到以后,通過判斷高4位功能碼來區分所接收到的通信對象,并通過一個指向函數的指針來調用相應的函數對報文進行處理,如圖4所示,通過接收中斷,CAN總線信息寫入到接收緩沖區后調用f_can_receive函數,將CAN總線幀中的有效數據存入Message結構體,而后通過ReceiveHandler函數讀取cob-id高4位功能碼,并根據不同的功能碼最終切換至4種通信對象的報文處理函數。
2.2.3 對象字典的建立
協議棧軟件的頂層主要包括對象字典的建立和訪問以及其他一些應用包括節點反饋、網絡的設置等。由于CANopen對象字典采用主索引和子索引結構,二者形成天然的二維數組結構,因此協議棧對象字典的實現是基于數組和數組的變型。主索引和子索引不同的數組下標在內存中就代表索引數據距離對象字典首地址的偏移量,通過該偏移量,便可以訪問到對象字典中的數據。一個對象的信息應該包括索引、子索引、數據、數據類型和訪問類型。這里通過定義兩個結構體來表示主索引和子索引:
typedef struct td_subindex{
enum e_accessAttribute bAccessType;
UNS8 bDataType;
UNS8 size;
void* pObject;
} subindex;
typedef struct td_indextable{
subindex* pSubindex;
UNS8 bSubCount;
} indextable;
其中bAccessType表示數據的訪問類型,分為只讀、只寫和可讀寫,bDataType表示數據類型,指針*pObject指向所包含的數據,通過結構體indextable來定義主索引,其中bSubCount表示此索引下子索引的數目。以對象字典中索引為1001H的錯誤寄存器為例,其對象字典定義為:
UNS8 OBJNAME = 0x0;
subindex Index1001[] ={
{ RO, uint8, sizeof(UNS8), (void*)&OBJNAME }
};
3.1 μC/OS-II在MC9S12XF512上的移植
為了使μC/OS-II系統內核能在某一特定的微控制器上運行,必須對與處理器相關的代碼進行修改。MC9S12XF512單片機有512 KB的片內FLASH和 32 KB RAM[3],可以在占有資源相對較少的條件下,運行操作系統的實時內核。集成的開發環境CodeWarrior可以進行程序的編譯、下載以及調試,提高了工作效率。由于μC/OS-II系統具有較強的可移植性,其移植工作主要是修改與處理器相關的代碼,包括OS_CPU.H、OS_CPU_C.C和OS_CPU_A.ASM[4],因為CodeWarrior支持C語言與匯編語言的混合編程,所以可將后兩個文件合成一個OS_CPU_C.C文件,以下從與移植相關的聲明和函數兩方面進行代碼的修改。
3.1.1 修改與移植相關的聲明
在OS_CPU.H中定義了與編譯器有關的數據類型、開關中斷宏、堆棧的生長方向以及任務切換宏。在MC9S12中堆棧是按字節進行操作,因此定義堆棧數據類型OS_STK為8位[6]。MC9S12處理器的堆棧是由高地址向低地址增長的,所以常量OS_STK_GROWTH設置為1。任務切換宏OS_TASK_SW()是在μC/OS-II從低優先級任務切換到最高優先級任務時被調用的,OS_TASK_SW()通過模擬一次中斷過程,在中斷返回的時候進行任務切換。MC9S12提供了軟中斷源和陷阱中斷源,這兩個中斷源都可以使得處理器的寄存器狀態保存到將被掛起任務的堆棧中。由于芯片中不存在監控程序,所以利用MC9S12XF512提供的軟中斷指令SWI來定義OS_TASK_SW(),并將其中斷服務程序的入口點指向OSCtxSw()。
3.1.2 修改與處理器相關的函數
(1) 任務切換函數
任務級任務切換函數OSCtxSw()的任務是將當前的CPU的狀態保存到正在運行任務的堆棧中,然后將堆棧指針保存到任務控制塊中,之后運行OSTaskSwHook()鉤子函數,而后將任務控制變量OSTCBCur和OSPrioCur的值更改為即將要運行的任務的屬性,從任務控制塊中得到將要運行任務的堆棧指針賦給SP寄存器,最后運行中斷返回指令。對于中斷級任務切換函數,由于中斷服務函數已經將CPU寄存器和中斷發生前正運行的任務堆棧指針保存過,因此OSIntCtxSw()即是OSCtxSw()在調用鉤子函數的后半部分。在MC9S12中,當中斷發生時芯片會將CPU寄存器推入堆棧,但是不會包括頁面管理寄存器,因此需要用匯編語言加入其入棧和出棧的操作:
ldaa PPAGE
psha //PPAGE入棧
pula
staa PPAGE //PPAGE出棧
(2) 任務堆棧初始化函數
任務堆棧初始化函數OSTaskStkInit()在創建任務的時候調用,用來在任務堆棧中按照一定順序初始化任務最初的數據。在MC9S12XF512芯片中,根據數據存放的順序,從高到低位對opt參數、PC寄存器、Y寄存器、X寄存器、D寄存器、CCR寄存器和PPAGE寄存器進行初始化,并最后返回堆棧指針所指向的地址。其中PC的值設置為任務的入口地址并存放兩次,第一個值是建立擴展任務所需的; D的值初始化為參數pdata的值用來傳遞任務參數;PPAGE則是用來存儲頁面寄存器的值。
(3) 時鐘節拍中斷服務函數
和其他中斷服務程序一樣,首先OSTickISR()在被中斷任務堆棧中保存CPU的值,然后調用OSIntEnter(),使得中斷嵌套層數全局變量OSIntNesting加1。隨后通過調用OSTimeTick(),遍歷任務控制鏈表中的所有任務控制塊,把各自用來存放延時時限的OSTCBDly變量減1,若其計數值為0,則表明該任務進入就緒狀態,最后調用OSIntExit()標志著時鐘節拍中斷服務子程序的結束。本次移植中時鐘節拍由硬件產生,必須設置好實時時鐘的控制寄存器,使得MC9S12芯片在產生相應中斷后,調用處理程序。實時時鐘控制寄存器設置如下:
RTICTL=0x49; //每秒產生100次中斷
CRGINT|=0x80; //使能中斷
μC/OS-II系統經過上述修改后在MC9S12芯片中運行起來。μC/OS-II的引入使得系統開發的效率得以提高,編寫程序時,只要將相關的功能封裝成任務,并根據任務的輕重緩急設定優先級,啟動多任務環境后,由μC/OS-II來管理這些任務。
3.2 μC/OS-II系統中嵌入CANopen
狀態機作為CANopen協議整個操作流程的核心,其從站狀態機定義了4個基本狀態:初始化、預操作、操作和停止,如圖3所示。執行過程中,從站上電復位后由初始化狀態跳轉到預操作狀態,等待主站控制命令的到來;主站是狀態機的控制者,從站待命后,主站發送命令切換各個從站的狀態,從而在各個狀態下完成操作。為將CANopen協議嵌入到μC/OS-II中,需要將狀態機封裝成一個任務:
void CANopenTask(void *pdata){
e_nodeState lastState=unknown_state;
pdata=pdata;
while(1){
switch(getState()){
case Initialisation:
……
case Pre_operational:
……
case Operational:
……
case Stopped:
……
}
}
}
在主函數中,操作系統完成初始化、創建任務和啟動任務的過程,通過OSTaskCreate()函數創建封裝好的CANopen從站任務,最后通過OSStart()函數,啟動操作系統,運行任務。
實驗中將μC/OS-II上運行的CANopen從站與主節點連接,按照以下流程進行通信實驗。在系統上電完成初始化后,從節點首先向主節點發送Boot-up報文,通知主節點已進入Pre_operational狀態。從節點處于Pre_operational狀態時,接收來自主節點的SDO報文對其對象字典進行配置。當從節點接收到主節點的NMT報文后,從節點進入operational狀態,此時主節點和從節點通過PDO進行實時數據的交互。在operational狀態下,將從節點的TPDO1~3映射到主節點的RPDO1~3,以時間觸發和事件觸發方式分別進行PDO傳送。通信實驗表明平臺能夠完成DS301通信規范所定義的網絡管理、PDO和SDO報文收發以及同步報文發送等功能。

[1] Francis Dupin CanFestival v2.03 Manual [OL]. [2013-07]. http:// www. canfestival.org.
[2] CiA Draft Standard 301 Version 4.02, CANopen Application Layer and Communication Profile,2002.
[3] Freescale Semiconductor Inc. MC9S12XF512 Reference Manual Rev.1.19,2010.
[4] Labrosse J J.嵌入式實時操作系統μC/OS-II[M].2版.邵貝貝,譯.北京:北京航空航天大學出版社,2003:278-283.
[5] Xu Zhe, Dong Shifeng. The Design and Implementation of a CANopen Slave Stack for Powertrain Controller in Hybrid Electric Vehicle [C]//International Conference on Intelligent Computation Technology and Automation,May 11-12, 2010:755-758.
[6] 孫同景,陳桂友. Freescale 9S12十六位單片機原理與嵌入式開發技術[M].北京:機械工業出版社,2008:389-391.
[7] 陶維青,劉寧,余淼,等.基于DSP與CAN總線技術的饋線監控終端開發[J].合肥工業大學學報:自然科學版,2008,31(7):1016-1019.
[8] 孫樹文,楊建武,張慧慧,等.基于CANopen協議的分布式控制系統I/O從站設計[J].計算機測量與控制,2007,15(12):1705-1707.

Zhang Zheng,Cheng Hesheng,Lai Shixun
(Monitoring Technology Center, Anhui Province Coal Science Research Institute, Hefei 230001,China)
This paper presents a method for using MC9S12XF512 chip to construct a CANopen slave station based on μC/OS-II system and CanFestival open source stack, and illustrates the software design of CANopen protocol stack, the transplantation of μC/OS-II and the process of embedding CANopen slave stack to μC/OS-II. The communication test shows that the slave station realized the function of DS301 standard.
CANopen protocol;μC/OS-II;CanFestival
TP336
A
珍
2013-07-15)