版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第三章將μC/OS-Ⅱ移植到UP-Star實(shí)驗(yàn)板上
3.1μC/OS-ⅡLED實(shí)例
3.2μC/OS-Ⅱ移植
3.3μC/OS-Ⅱ串口通信實(shí)例
3.4本章小結(jié)
在第二章工程ex2_3的基礎(chǔ)上,通過(guò)編寫(xiě)和添加μC/OS-Ⅱ移植文件和內(nèi)核文件,進(jìn)一步介紹μC/OS-Ⅱ的兩個(gè)實(shí)例。借助這兩個(gè)實(shí)例,深入說(shuō)明μC/OS-Ⅱ移植到UP-Star實(shí)驗(yàn)板上的方法。通常應(yīng)該在介紹了μC/OS-Ⅱ內(nèi)核之后再介紹μC/OS-Ⅱ的移植,這樣更方便讀者理解移植所需要做的工作。本書(shū)先介紹μC/OS-Ⅱ移植再介紹μC/OS-Ⅱ內(nèi)核,是因?yàn)橐浦拨藽/OS-Ⅱ所做的工作與S3C2410A芯片硬件密切相關(guān),只要對(duì)UP-Star實(shí)驗(yàn)板和S3C2410A芯片比較熟悉,即使不了解μC/OS-Ⅱ,也可以學(xué)習(xí)移植;同時(shí),移植完成后,后續(xù)各章節(jié)實(shí)例均可基于這個(gè)移植,在UP-Star實(shí)驗(yàn)板上運(yùn)行。本書(shū)是以實(shí)例帶動(dòng)講解的方法編寫(xiě),所以需選擇先介紹μC/OS-Ⅱ的移植。讀者也可以先去閱讀第四章,再返回來(lái)閱讀本章。本章介紹的移植參考“μC/OS-ⅡandARMProcessorsApplicationNote(AN-1014)”文檔,基于μC/OS-ⅡV2.86,如果讀者用于其他μC/OS-Ⅱ的版本,需做一定的修改。
下面首先介紹一個(gè)基于UP-Star實(shí)驗(yàn)板的μC/OS-Ⅱ?qū)嵗?,即LED閃爍實(shí)例;然后再介紹μC/OS-Ⅱ移植需要做的工作。在第2.3節(jié)工程ex2_3的基礎(chǔ)上新建工程ex3_1,存儲(chǔ)目錄為D:\ZYUCOSII\ex3_1(此時(shí)的工程ex3_1與工程ex2_3完全相同,僅是工程名改為ex3_1),如圖3-1所示。
盡管是從工程ex2_3過(guò)渡到工程ex3_1,但事實(shí)上,讀者將會(huì)發(fā)現(xiàn),工程ex3_1將做很多重大的修改(以至于和圖3-1所示的工程ex3_1最初版本相比完全兩樣),以達(dá)到本節(jié)的程序設(shè)計(jì)目的。3.1μC/OS-ⅡLED實(shí)例圖3-1工程ex3_1的最初版本3.1.1實(shí)例ex3_1
為了清晰地說(shuō)明實(shí)例ex3_1的創(chuàng)建過(guò)程,下面逐步介紹。
S1.在圖3-1的工作區(qū)中,移除“user”分組下的所有文件,刪除“asm”分組,添加“ports”分組和“ucosii”分組,如圖3-2所示。圖3-2工程ex3_1的工作區(qū)分組從圖3-2可以看出,工程ex3_1僅保留了工程ex2_3的設(shè)置(即“Project?|?Options…”菜單項(xiàng)彈出窗口的內(nèi)容),但實(shí)際的程序設(shè)計(jì)中會(huì)用到工程ex2_3已編寫(xiě)的代碼。
S2.到目錄D:\ZYUCOSII\ex3_1下,刪除User子目錄下的所有文件,刪除子目錄ASM,然后新建子目錄ports和ucosii,將μC/OS-ⅡV2.86版軟件,即第1.2節(jié)提到的壓縮文件Micrium-μCos-Ⅱ-V286.ZIP解壓后的目錄Micrium-uCOS-II-V286\Micrium\SOFTWARE\μCOS-Ⅱ\Source下的14個(gè)文件拷貝到ucosii子目錄下,其中的文件os_cfg_r.h和os_dbg_r.c移動(dòng)到ports目錄下,并把文件名中的“_r”去掉。此時(shí)的目錄D:\ZYUCOSII\ex3_1如圖3-3所示。從網(wǎng)站下載AN-1014.ZIP文件,在網(wǎng)站的“Support|ApplicationNotes”鏈接中,是關(guān)于“μC/OS-ⅡforARMProcessorsWorksinARMorThumbmode”的。將AN-1014.ZIP壓縮文件中的IAR子目錄下的os_cpu.h、os_cpu_a.asm和os_cpu_c.c三個(gè)文件拷貝到圖3-3中的ports文件夾中。
現(xiàn)在可以檢查一下圖3-3中各個(gè)文件夾下的內(nèi)容,在ports文件夾下有5個(gè)文件,依次為os_cfg.h、os_cpu.h、os_cpu_a.asm、os_cpu_c.c和os_dbg.c;在ucosii文件夾下有12個(gè)文件,依次為os_core.c、os_flag.c、os_mbox.c、ox_mem.c、os_mutex.c、ox_q.c、os_sem.c、os_task.c、os_time.c、os_tmr.c、ucos_ii.c和ucos_ii.h;user文件夾下沒(méi)有文件,現(xiàn)在,新建一個(gè)空文本文件,更名為app_cfg.h。在程序設(shè)計(jì)過(guò)程中,盡可能地不去修改ucosii文件夾下的文件。圖3-3目錄D:\ZYUCOSII\ex3_1下的文件夾
S3.回到圖3-2,向工作區(qū)中添加文件,即向ucosii分組中添加D:\ZYUCOSII\ex3_1\ucosii\ucos_ii.c文件,向ports分組中添加D:\ZYUCOSII\ex3_1\ports目錄下的os_cpu_a.s、os_cpu_c.c和os_dbg.c3個(gè)文件。新建3個(gè)文件,即includes.h、app.h和app.c文件,這3個(gè)文件均保存到D:\ZYUCOSII\ex3_1\User目錄下,并把a(bǔ)pp.c文件添加到工作區(qū)的user分組下。其中app.h文件內(nèi)容為空,includes.h文件和app.c文件的內(nèi)容如下:includes.h文件的內(nèi)容:
1/*FileName:includes.h
2**Byzhnyong@21
3**@2009-4-4
4**CopyrightReserved
5*/
6
7#include"stdio.h"
8#include"string.h"
9
10#include"..\\ucosii\\ucos_ii.h"
11
12#include"app.h"app.c文件的內(nèi)容:
1/*FileName:app.c
2**Byzhnyong@21
3**@2009-4-4
4**MainRoutine
5**CopyrightReserved
6*/7
8#include“includes.h”
9
10voidmain(void)
11{
12OSInit();
13
14OSStart();
15}
這里主程序文件即為app.c文件,相當(dāng)于工程ex2_3中的zyMain.c的作用。至此,D:\ZYUCOSII\ex3_1\User目錄下有4個(gè)文件,即app.c、app.h、app_cfg.h和includes.h。其中app_cfg.h文件添加如下代碼:
S4.將目錄D:\ZYUCOSII\ex3_1\下所有文件的屬性修改為可讀可寫(xiě),即去掉“只讀”屬性。
S5.這時(shí)編譯工程ex3_1,即點(diǎn)擊菜單“Project|RebuildAll”,會(huì)出現(xiàn)多處“不能打開(kāi)文件錯(cuò)誤”,依次修改以下代碼:
(1)?ucos_ii.h第44行,由“#include<app_cfg.h>”改為“#include".\\user\\app_cfg.h"”;
(2)?ucos_ii.h第45行,由“#include<os_cfg.h>”改為“#include"..\\ports\\os_cfg.h"”;
(3)?ucos_ii.h第46行,由“#include<os_cpu.h>”改為“#include"..\\ports\\os_cpu.h"”;
(4)?os_cpu_c.c第24行,由“#include<ucos_ii.h>”改為“#include"..\\ucosii\\ucos_ii.h"”;
(5)?os_dbg.c第24行,由“#include<ucos_ii.h>”改為“#include"..\\ucosii\\ucos_ii.h"”;
(6)?ucos_ii.c第24行,由“#include<ucos_ii.h>”改為“#include"ucos_ii.h"”;
(7)?ucos_ii.c第28行,由“#include<os_core.c>”改為“#include"os_core.c"”;
(8)?ucos_ii.c第28行,由“#include<os_flag.c>”改為“#include"os_flag.c"”;
(9)?ucos_ii.c第28行,由“#include<os_mbox.c>”改為“#include"os_mbox.c"”;
(10)?ucos_ii.c第28行,由“#include<os_mem.c>”改為“#include"os_mem.c"”;
(11)?ucos_ii.c第28行,由“#include<os_mutex.c>”改為“#include"os_mutex.c"”;
(12)?ucos_ii.c第28行,由“#include<os_q.c>”改為“#include"os_q.c"”;
(13)?ucos_ii.c第28行,由“#include<os_sem.c>”改為“#include"os_sem.c"”;
(14)?ucos_ii.c第28行,由“#include<os_task.c>”改為“#include"os_task.c"”;
(15)?ucos_ii.c第28行,由“#include<os_time.c>”改為“#include"os_time.c"”;
(16)?ucos_ii.c第28行,由“#include<os_tmr.c>”改為“#include"os_tmr.c"”;
(17)?os_tmr.c第25行,由“#include<ucos_ii.h>”改為“#include"ucos_ii.h"”。
S6.新建文件bsp.h和bsp.c,保存在D:\ZYUCOSII\ex3_1\
ports目錄下,將bsp.c文件添加到工作區(qū)ports分組下,在includes.h文件末尾添加一條語(yǔ)句“#include"..\\ports\\bsp.h"”。其中,bsp.h文件內(nèi)容為空,bsp.c文件的內(nèi)容如下:1/*FileName:bsp.c
2**Byzhnyong@21
3**@2009-4-4
4**CopyrightReserved
5*/
6
7#include"..\\user\\includes.h"
8
9voidOS_CPU_ExceptHndlr(INT32Uexcept_type){}
10
11voidApp_TaskSwHook(void){}
1213voidApp_TaskCreateHook(OS_TCB*ptcb){}
14
15voidApp_TCBInitHook(OS_TCB*ptcb){}
16
17voidApp_TaskStatHook(void){}
18
19voidApp_TaskIdleHook(void){}
20
21voidApp_TaskDelHook(OS_TCB*ptcb){}
22
23voidApp_TimeTickHook(void){}現(xiàn)在編譯鏈接工程ex3_1,將正常編譯通過(guò),沒(méi)有任何警告和錯(cuò)誤,但實(shí)際的移植工作才剛剛開(kāi)始。
S7.新建文件startup.s,保存在目錄D:\ZYUCOSII\ex3_1\
ports下,并將該文件添加到工作區(qū)ports分組下,該文件實(shí)現(xiàn)S3C2410上電復(fù)位后的芯片初始化工作,其代碼如下:
S8.進(jìn)入到os_cpu_c.c文件的OSInitHookBegin函數(shù)中,即文件代碼的第136行,原始語(yǔ)句為“*pstk=(OS_STK)0;”,估計(jì)此處是軟件作者J.J.Labrosse先生的失誤,此處應(yīng)改為“*pstk++=(OS_STK)0;”。然后,在第147行和148行間插入一個(gè)函數(shù)調(diào)用語(yǔ)句,即在第147行處回車(chē),添加語(yǔ)句“myInitHookBegin()”,這個(gè)函數(shù)是作者自定義的系統(tǒng)初始化函數(shù)。接著,在app_cfg.h的末尾添加語(yǔ)句“voidmyInitHookBegin(void);//MyInitCodefuncprototype”。最后,在bsp.c文件的末尾添加如下代碼:注意:上述代碼在bsp.c中的實(shí)際行號(hào)是從第25行開(kāi)始的。myInitLED函數(shù)用于初始化LED燈,myInitTimer4用于初始化定時(shí)器4,定時(shí)器4用作μC/OS-Ⅱ時(shí)鐘節(jié)拍,定時(shí)中斷產(chǎn)生頻率為100Hz。
編寫(xiě)bsp.h文件的代碼如下:
S9.編寫(xiě)定時(shí)器4中斷入口和處理函數(shù),修改bsp.c文件中的OS_CPU_ExceptHndlr函數(shù)內(nèi)容如下:
1voidOS_CPU_ExceptHndlr(INT32Uexcept_type)
2{
3switch(except_type)
4{
5case6: //IRQInterrupt
6switch(INTOFFSET) //INTOFFSETissub-intentryNo.
7{18break;
19default:
20break;
21}
22}同時(shí),在bsp.h中添加如下代碼:
1//InterruptController
2//---------------------------------------------------------
3//InterruptRequestStatus
4//InterruptModeControl
5//InterruptMaskControl
6//IRQPriorityControl
7//InterruptRequestStatus
8//InterruotRequestSourceOffset
9//SubSourcePending上述代碼可位于bsp.h的末尾或“//FunctionPrototype”注釋行前面(實(shí)際上,這些代碼可位于文件中的任意位置)。
S10.新建文件appfun.c,保存在目錄D:\ZYUCOSII\
ex3_1\User下,并將該文件添加到工作區(qū)user分組下,該文件用于存放用戶編寫(xiě)的各種功能函數(shù),目前主要是關(guān)于LED燈點(diǎn)亮和熄滅的函數(shù),編寫(xiě)該文件內(nèi)容如下:編寫(xiě)app.h文件的代碼如下:
S11.修改app.c文件的內(nèi)容,創(chuàng)建一個(gè)任務(wù),用于控制LED燈的閃爍,其完整代碼如下:
1/*FileName:app.c
2**Byzhnyong@21
3**@2009-4-4
4**MainRoutine
5**CopyrightReserved
6*/
7
8#include“includes.h”
9
10voidmain(void)
11{
12OSInit();
13OSTaskCreate(AppTaskStart,(void*)0,&AppTaskStartStk
[TASK_STK_SIZE-1],0);
14OSStart();
15}目前,app.h的完整代碼如下:
1/*FileName:app.h
2**Byzhnyong@21
3**@2009-4-4
4**CopyrightReserved
5*/
6
7#ifdefMY_APP_GLOBALS
8#defineMY_APP文件appfun.c的完整代碼如下:
1/*FileName:appfun.c
2**Byzhnyong@21
3**@2009-4-4
4**CopyrightReserved
5*/
6
7#defineMY_APP_GLOBALS
8#include"includes.h"
9
S12.編譯鏈接工程ex3_1,在線仿真可以看到LED1和LED2間隔1秒交替點(diǎn)亮閃爍。最后的工程ex3_1如圖3-4所示。圖3-4移植完成后的工程ex3_1至此,工程ex3_1完成了,同時(shí)也完成了μC/OS-Ⅱ的移植,此時(shí),目錄D:\ZYUCOSII\ex3_1下的子目錄及其文件和圖3-3一樣,子目錄user下有文件app.c、app.h、app_cfg.h、appfun.c和includes.h,這些文件均需要自己編寫(xiě);子目錄ports下有文件bsp.c、bsp.h、os_cfg.h、os_cpu.h、os_cpu_
a.asm、os_cpu_c.c、os_dbg.c和startup.s,其中,只有bsp.c、bsp.h和startup.s文件需自己編寫(xiě);子目錄ucosii下為12個(gè)μC/OS-Ⅱ內(nèi)核文件,即os_core.c、os_flag.c、os_mbox.c、ox_mem.c、os_mutex.c、ox_q.c、os_sem.c、os_task.c、os_time.c、os_tmr.c、ucos_ii.c和ucos_ii.h,這些文件均不需要自己編寫(xiě)。通過(guò)對(duì)比工程ex3_1和工程ex2_3可知,兩個(gè)工程中需要自己編寫(xiě)的代碼數(shù)量是差不多的,但是工程ex3_1上加載了μC/OS-Ⅱ操作系統(tǒng)。
μC/OS-Ⅱ原作者J.J.Labrosse指出移植μC/OS-Ⅱ是件輕松的事情,主要是因?yàn)棣藽/OS-Ⅱ本身的設(shè)計(jì)就考慮了移植,即移植的大部分工作原作者都給出來(lái)了。
Labrosse認(rèn)為移植μC/OS-Ⅱ需要花費(fèi)幾個(gè)小時(shí)至一周的時(shí)間不等,視編程人員對(duì)ARM芯片結(jié)構(gòu)的熟悉程度。通過(guò)上述關(guān)于μC/OS-ⅡV2.86的移植,筆者也有同樣的觀點(diǎn),如果讀者自己研究移植代碼,將會(huì)發(fā)現(xiàn),移植μC/OS-Ⅱ工作的大部分時(shí)間都花在了閱讀“μC/OS-ⅡandARMProcessorsApplicationNote(AN-1014)”英文文檔上,一定意義上,編程人員的英文水平?jīng)Q定了他的移植水平。從現(xiàn)在開(kāi)始,我們將開(kāi)始基于μC/OS-Ⅱ嵌入式操作系統(tǒng)的面向任務(wù)程序設(shè)計(jì)工作,在調(diào)試這類(lèi)程序時(shí),借助μC/OS-Ⅱ的調(diào)試插件C-SPY更為直觀一些。在圖3-4中,點(diǎn)擊“Project|Options”菜單,進(jìn)入如圖3-5所示的界面,選中“Debugger|Plugins”下的“μC/OS-Ⅱ”一項(xiàng),點(diǎn)擊“OK”按鈕保存。然后回到圖3-4中,點(diǎn)擊“Project|DownloadandDebug”菜單進(jìn)入如圖3-6所示的調(diào)試環(huán)境界面,這時(shí)菜單欄中有一項(xiàng)為“μC/OS-Ⅱ”,點(diǎn)擊該菜單項(xiàng)下的“TaskList”子菜單,將彈出任務(wù)一欄,如圖3-6所示。圖3-5設(shè)置μC/OS-Ⅱ調(diào)試插件圖3-6工程ex3_1顯示任務(wù)信息的調(diào)試窗口從圖3-6中可以看出,工程ex3_1中包含4個(gè)任務(wù),其中優(yōu)先級(jí)為0的任務(wù)為我們自己創(chuàng)建的任務(wù),因?yàn)闆](méi)有命名,所以“Name”一欄為“?”;還有3個(gè)系統(tǒng)任務(wù),即μC/OS-ⅡTmr、μC/OS-ⅡStat和μC/OS-ⅡIdle,優(yōu)先級(jí)分別為10、62和63。
下面首先從整體上解釋一下實(shí)例ex3_1,重點(diǎn)介紹為了移植μC/OS-Ⅱ我們所做的工作,然后,第3.2節(jié)將進(jìn)一步介紹移植μC/OS-Ⅱ所需要做的工作,即摘錄“μC/OS-ⅡandARMProcessorsApplicationNote(AN-1014)”文檔中的一些內(nèi)容。3.1.2實(shí)例ex3_1注解
第3.1.1節(jié)實(shí)現(xiàn)了實(shí)例ex3_1及其功能,這里介紹這個(gè)實(shí)例是如何工作的。仿真(或系統(tǒng)上電之后)時(shí),程序首先從startup.s開(kāi)始執(zhí)行,實(shí)際上是從0x0地址開(kāi)始執(zhí)行的(這里也暴露出了IAREWARM軟件的一個(gè)小缺點(diǎn),好像快速中斷與普通中斷標(biāo)號(hào)在反匯編窗口中沒(méi)有區(qū)分,但是這點(diǎn)對(duì)程序執(zhí)行毫無(wú)影響)。startup.s文件完成S3C2410A芯片的一些初始化工
作,例如,關(guān)閉看門(mén)狗的復(fù)位功能和中斷功能(這里暫時(shí)關(guān)閉了,以后會(huì)開(kāi)啟這個(gè)功能,喂狗的時(shí)間周期小于10秒。注意看門(mén)狗定時(shí)器的定時(shí)功能依然工作);設(shè)置CPU時(shí)鐘工作頻率為192MHz(即FCLK的頻率為192MHz,PCLK為48MHz);設(shè)置存儲(chǔ)器管理器,將外部32MB的SDRAM配置在區(qū)塊6上;設(shè)置各種工作模式的堆棧指針;最后,將程序跳轉(zhuǎn)到C語(yǔ)言的主程序入口main。
startup.s的代碼均為匯編語(yǔ)言,不過(guò)這個(gè)代碼相對(duì)于《ARM原理與C程序設(shè)計(jì)》附錄四的啟動(dòng)代碼來(lái)說(shuō),是非常簡(jiǎn)單的。讀者還可以去閱讀“ARMIARAssemblerReferenceGuide”英文文檔來(lái)進(jìn)一步學(xué)習(xí)EWARM下的匯編指示符表示方法,這個(gè)文檔位于EWARM安裝目錄的一個(gè)doc子目錄下。接著,程序指針進(jìn)入到app.c文件,開(kāi)始執(zhí)行OSInit()函數(shù),通過(guò)單步執(zhí)行將發(fā)現(xiàn),OSInit將首先調(diào)用函數(shù)OSInitHookBegin,再單步進(jìn)入到OSInitHookBegin,可見(jiàn)我們自己定義的初始化函數(shù)myInitHookBegin就位于其中。即通過(guò)執(zhí)行myInitHookBegin函數(shù)就實(shí)現(xiàn)了系統(tǒng)的初始化,單步進(jìn)入myInitHookBegin函數(shù),里面的代碼用于初始化系統(tǒng)異常向量表(這是μC/OS-Ⅱ移植要求必須做的),初始化LED顯示和定時(shí)器4,這里將定時(shí)器4設(shè)置減計(jì)數(shù)到0的頻率為100Hz,也就是說(shuō),如果定時(shí)器4開(kāi)中斷后,其產(chǎn)生中斷信號(hào)的頻率為100Hz,就是用作μC/OS-Ⅱ的時(shí)鐘節(jié)拍頻率。然后,主程序文件app.c執(zhí)行完OSInit后,執(zhí)行OSTaskCreate創(chuàng)建一個(gè)任務(wù),這個(gè)任務(wù)的代碼位于appfun.c中,用于LED閃爍;接著,執(zhí)行OSStart函數(shù),單步進(jìn)入OSStart函數(shù)后,可見(jiàn)該函數(shù)的內(nèi)容如下:第一次執(zhí)行OSStart時(shí),變量OSRunning為OS_FALSE
(μC/OS-ⅡV2.86中真用OS_TRUE表示,假用OS_FALSE表示),所以會(huì)執(zhí)行第4~8行代碼,進(jìn)行任務(wù)調(diào)度,并執(zhí)行優(yōu)先級(jí)最高的任務(wù)。在執(zhí)行完OSStartHighRdy函數(shù)后,將開(kāi)放所有中斷,并且工作在管理(SVC)模式下(事實(shí)上,工程ex3_1幾乎總是工作在SVC模式下,除了極少數(shù)語(yǔ)句會(huì)工作在常規(guī)中斷(IRQ)模式下外)?,F(xiàn)在,IRQ中斷開(kāi)放了,同時(shí),μC/OS-Ⅱ會(huì)發(fā)現(xiàn)我們定義的任務(wù)AppTaskStart,并進(jìn)入其代碼中運(yùn)行(位于appfun.c中),函數(shù)AppTaskStart將首先打開(kāi)定時(shí)器4中斷,然后再進(jìn)入死循環(huán)中(所有任務(wù)都是死循環(huán)執(zhí)行的,不會(huì)返回)。為了清楚地說(shuō)明具體的執(zhí)行路線,下面列出AppTaskStart任務(wù)中的死循環(huán)代碼:
1while(1)
2{
3LEDon(1);
4OSTimeDlyHMSM(0,0,1,0);
5LEDon(2);
6OSTimeDly(100);
7}任務(wù)AppTaskStart進(jìn)入死循環(huán)后,首先執(zhí)行LEDon(1)(此處不妨假設(shè)定時(shí)器4中斷還沒(méi)有來(lái)到),使LED1號(hào)燈點(diǎn)亮;然后,執(zhí)行OSTimeDlyHMSM(0,0,1,0),這是一個(gè)μC/OS-Ⅱ延時(shí)函數(shù),進(jìn)入這個(gè)函數(shù)后,實(shí)際上μC/OS-Ⅱ?qū)⑶袚Q到一個(gè)名為“μC/OS-ⅡIdle”的空閑任務(wù);空閑任務(wù)每隔0.01秒會(huì)收到定時(shí)器4中斷,進(jìn)行任務(wù)調(diào)度;當(dāng)OSTimeDlyHMSM(0,0,1,0)延時(shí)滿1秒(實(shí)際上任務(wù)AppTaskStart的延時(shí)計(jì)數(shù)達(dá)到1秒)后,任務(wù)會(huì)由空閑任務(wù)調(diào)度到AppTaskStart任務(wù),程序指針回到LEDon(2)語(yǔ)句執(zhí)行,關(guān)閉LED1號(hào)燈,點(diǎn)亮LED2號(hào)燈;然后,又進(jìn)入到OSTimeDly(100)語(yǔ)句執(zhí)行,循環(huán)以上過(guò)程。函數(shù)OSTimeDlyHMSM(0,0,1,0)為延時(shí)函數(shù),四個(gè)參數(shù)的含義為時(shí)、分、秒、毫秒,由于定時(shí)器4的中斷頻率為100Hz,所以,最小的延時(shí)為10ms(它也有最大延時(shí)限制,但一般程序中不會(huì)越過(guò)這個(gè)最大限制)。而函數(shù)OSTimeDly用得更多一些,只有一個(gè)參量,表示延時(shí)時(shí)鐘節(jié)拍數(shù),如果時(shí)鐘節(jié)拍頻率為100Hz,則OSTimeDly(100)剛好延時(shí)1秒,與函數(shù)OSTimeDlyHMSM(0,0,1,0)的功能完全相同。
讀者可能會(huì)對(duì)上述介紹有些迷茫,相信在學(xué)習(xí)完第四章后,將會(huì)完全理解上述過(guò)程。畢竟,本章的主要目的在于移植μC/OS-ⅡV2.86,而不是詳細(xì)介紹其任務(wù)調(diào)度過(guò)程。
J.J.Labrosse先生編寫(xiě)的“μC/OS-ⅡandARMProcessorsApplicationNote,AN-1014Rev.F”移植文檔有56頁(yè),關(guān)于μC/OS-Ⅱ的移植工作介紹得非常細(xì)致全面,是移植μC/OS-Ⅱ必讀的參考資料。本節(jié)除摘錄了其中一些主要內(nèi)容外,還結(jié)合第3.1節(jié)進(jìn)行了必要的補(bǔ)充。3.2μC/OS-Ⅱ移植由第3.1節(jié)知,工程ex3_1的文件結(jié)構(gòu)如圖3-7所示。除了底層硬件UP-Star外,軟件部分可以分為四部分,即用戶編寫(xiě)的應(yīng)用程序、μC/OS-Ⅱ內(nèi)核文件、μC/OS-Ⅱ移植文件和BSP(BoardSupportPackage)板級(jí)支持包文件。圖3-7顯示了各個(gè)部分之間的關(guān)系:移植文件屏蔽了硬件的具體操作細(xì)節(jié),為μC/OS-Ⅱ內(nèi)核文件服務(wù);μC/OS-Ⅱ內(nèi)核文件管理著系統(tǒng)的所有資源,為應(yīng)用程序服務(wù);當(dāng)應(yīng)用程序需要直接訪問(wèn)底層硬件時(shí),可借助于BSP文件。圖3-7工程ex3_1文件結(jié)構(gòu)工程ex3_1中移植相關(guān)的文件保存在D:\ZYUCOSII\ex3_1\
ports中(其中也包含了BSP板級(jí)支持包文件),這個(gè)目錄下有8個(gè)文件,如圖3-8所示。習(xí)慣上也可把BSP文件bsp.h和bsp.c歸類(lèi)為移植文件。圖3-8中,bsp.h文件主要是宏定義一些S3C2410A芯片外設(shè)寄存器地址和自定義函數(shù)聲明;startup.s文件為啟動(dòng)代碼文件,用于初始化CPU時(shí)鐘和存儲(chǔ)器配置等,并跳轉(zhuǎn)到C語(yǔ)言入口地址;os_dbg.c文件主要為μC/OS-Ⅱ及其配置提供在線調(diào)試信息;os_cfg.h文件為μC/OS-Ⅱ定義配置常量。其中,bsp.h和startup.s文件內(nèi)容的說(shuō)明可參閱第3.1節(jié)。os_cfg.h文件內(nèi)容將在第五章的5.7節(jié)介紹。下面重點(diǎn)介紹其余四個(gè)文件的內(nèi)容,即os_cpu.h、os_cpu_c.c、os_cpu_a.asm和bsp.c文件。圖3-8工程ex3_1中的移植文件3.2.1os_cpu.h文件
os_cpu.h文件有241行代碼,限于篇幅,這里不給出完整的代碼了,第3.1節(jié)介紹了獲得該文件代碼的方法。移植μC/OS-Ⅱ時(shí),需要考慮不同的編譯器可能對(duì)數(shù)據(jù)類(lèi)型的定義不盡相同。例如,在EWARM中,short為16位有符號(hào)整型,而int為32位有符號(hào)整型。為了適應(yīng)不同的編譯系統(tǒng),移植人員需要查看編譯器關(guān)于基本數(shù)據(jù)類(lèi)型的定義,在EWARM中,可以作如下的自定義數(shù)據(jù)類(lèi)型:這樣,如果定義無(wú)符號(hào)16位整型數(shù),使用類(lèi)型INT16U即可。注意上述代碼的第11行和12行,第11行定義了類(lèi)型OS_STK,專(zhuān)門(mén)用于定義堆棧;第12行定義了類(lèi)型OS_CPU_SR,專(zhuān)門(mén)用于定義CPSR寄存器變量,用于臨時(shí)保存CPSR的值。這兩行自定義類(lèi)型的主要目的在于增強(qiáng)程序的可讀性。程序中那些執(zhí)行過(guò)程中不能被中斷的代碼,稱(chēng)為Critical代碼段,常被譯為臨界(段)代碼,本書(shū)采用這一譯法。因?yàn)檫@類(lèi)代碼往往用于設(shè)置硬件寄存器或初始化外設(shè),實(shí)際上是表示硬件狀態(tài)切換的代碼,有一種狀態(tài)“邊界”臨時(shí)轉(zhuǎn)換的含義,故譯為“臨界段”比較合適。臨界段代碼中中斷是關(guān)閉的,所以臨界段代碼一般比較短小,進(jìn)入臨界段前需要關(guān)閉中斷;離開(kāi)臨界段后要恢復(fù)CPSR寄存器的狀態(tài)。μC/OS-Ⅱ在os_cpu.h中宏定義了兩個(gè)函數(shù),分別用于關(guān)閉中斷和恢復(fù)CPSR寄存器狀態(tài),其代碼如下:
μC/OS-Ⅱ有三種中斷管理的方法,一般使用方法3,即上述第1行代碼中宏定義OS_CRITICAL_METHOD為3;第15~16行代碼為宏函數(shù),即調(diào)用OS_CPU_SR_Save()函數(shù)保存當(dāng)前CPSR寄存器的值,并關(guān)閉中斷;調(diào)用OS_CPU_SR_
Restore(cpu_sr)函數(shù)恢復(fù)CPSR的值,注意這里是“恢復(fù)”,如果原來(lái)的中斷是關(guān)閉的,則調(diào)用OS_CPU_SR_Restore后,中斷仍然是關(guān)閉的,即不能用OS_EXIT_CRITICAL來(lái)開(kāi)中斷!如果OS_CPU_INT_DIS_MEAS_EN大于0,還將調(diào)用第9行和第11行的兩個(gè)函數(shù),對(duì)中斷關(guān)閉期間進(jìn)行計(jì)數(shù),用于統(tǒng)計(jì)中斷關(guān)閉的時(shí)長(zhǎng)。第8行和第10行末尾的“\”是續(xù)行符,表示其下的一行代碼和當(dāng)前行代碼是同一行代碼。
在os_cpu_a.asm中可以找到如下代碼:上述代碼的解釋為:第1行定義標(biāo)號(hào)OS_CPU_SR_Save,即函數(shù)名;第2行將CPSR的值保存到R0寄存器,R0的值為函數(shù)的返回值;第3行,R0的值與OS_CPU_ARM_CONTROL
_INT_DIS常量(值為0xC0)取或,送入R1寄存器,此時(shí)R1的第7位和第6位為1;第4行將R1的值寫(xiě)入CPSR的控制域,即CPSR的第7位和第6位寫(xiě)為1;第5行跳轉(zhuǎn)。同理,第8行定義標(biāo)號(hào)OS_CPU_SR_Restore,即函數(shù)名;第9行將R0的值寫(xiě)入CPSR寄存器的控制位域,此處R0為全局參數(shù),即函數(shù)OS_CPU_SR_Restore的參數(shù);第10行跳轉(zhuǎn)。
S3C2410A芯片封裝ARM920T核,其堆棧增長(zhǎng)方向?yàn)橛蓛?nèi)存高地址向低地址,故在os_cpu.h中定義:
#defineOS_STK_GROWTH1/*StackgrowsfromHIGHtoLOWmemoryonARM*/
任務(wù)級(jí)的切換調(diào)用宏函數(shù)OS_TASK_SW(),這個(gè)宏函數(shù)位于os_cpu.h中:
#defineOS_TASK_SW()OSCtxSw()
用戶需要編寫(xiě)的異常處理函數(shù)也位于os_cpu.h中,即
voidOS_CPU_ExceptHndlr(INT32Uexcept_type);
os_cpu.h中的其他代碼請(qǐng)讀者自己閱讀,這里不再說(shuō)明。這個(gè)文件在移植時(shí)不需要做任何修改!3.2.2os_cpu_c.c文件
os_cpu_c.c文件第24行改為“#include"..\\ucosii\\ucos_ii.h"”,即添加包括文件路徑。該文件主要用于實(shí)現(xiàn)一些“鉤子”函數(shù),即OSInitHookBegin()、OSInitHookEnd()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskIdleHook()、OSTaskStatHook()、OSTaskStkInit()、OSTaskSwHook()、OSTCBInitHook()和OSTimeTickHook()函數(shù)。之所以稱(chēng)之為鉤子函數(shù),是由于這個(gè)函數(shù)放置在相應(yīng)的函數(shù)中調(diào)用,用于擴(kuò)充調(diào)用它們的函數(shù)的功能,就像一個(gè)鉤子一樣掛在那里,這些函數(shù)大部分可以為空函數(shù)。例如,OSInitHookBegin函數(shù)位于OSInit函數(shù)開(kāi)頭,即進(jìn)入OSInit函數(shù)后,首先執(zhí)行OSInitHookBegin函數(shù),而我們自定義的系統(tǒng)初始化函數(shù)就位于OSInitHookBegin函數(shù)中,如下:上述代碼的第24行為我們自定義的系統(tǒng)初始化函數(shù)。其中第12行代碼原文中沒(méi)有“++”,是筆者添上去的,估計(jì)是J.J.Labrosse先生的失誤,盡管這里“++”意義不是很大。第15行至19行代碼為定義異常堆棧首地址。在μC/OS-ⅡV2.86中要求所有異常模式下的堆棧共用一個(gè),其大小為OS_CPU_
EXCEPT_STK_SIZE,定義在文件os_cpu.h或app_cfg.h中。全部的10個(gè)鉤子函數(shù)中,只有OSTaskStkInit函數(shù)是必須編寫(xiě)的。每個(gè)任務(wù)都是一個(gè)死循環(huán),任務(wù)創(chuàng)建后就保存在內(nèi)存中了,任務(wù)被“調(diào)用”的含義嚴(yán)格意義上講是返回到某個(gè)任務(wù)去執(zhí)行!這個(gè)概念很重要,這是μC/OS-Ⅱ嵌入式操作系統(tǒng)下函數(shù)調(diào)用與普通芯片級(jí)程序下函數(shù)調(diào)用的不同之處。因此任務(wù)被“調(diào)用”執(zhí)行時(shí),即程序指針從某個(gè)任務(wù)返回到該任務(wù)時(shí),要做一系列的出棧操作,即恢復(fù)該任務(wù)的執(zhí)行環(huán)境。但事實(shí)上,任務(wù)被創(chuàng)建時(shí)并沒(méi)有執(zhí)行任務(wù),當(dāng)然也不會(huì)有入棧操作,所以,必須在OSTaskStkInit函數(shù)中進(jìn)行模擬的入棧操作,即讓任務(wù)創(chuàng)建時(shí)看起來(lái)有一個(gè)入棧的過(guò)程。在任務(wù)創(chuàng)建時(shí)首先會(huì)調(diào)用OSTaskStkInit函數(shù),目的就是完成任務(wù)的入棧操作,并且這個(gè)入棧操作與OSStartHighRdy(位于os_cpu_a.asm中)出棧操作必須對(duì)應(yīng)!這里OSTaskStkInit函數(shù)的代碼如下所示:再?gòu)?qiáng)調(diào)一下,每個(gè)任務(wù)都是一個(gè)死循環(huán)函數(shù),一個(gè)任務(wù)被“調(diào)用”執(zhí)行時(shí),實(shí)際上是返回到那個(gè)任務(wù)去執(zhí)行,而不是調(diào)用那個(gè)任務(wù)!返回一個(gè)任務(wù)去執(zhí)行,應(yīng)首先恢復(fù)這個(gè)任務(wù)的執(zhí)行環(huán)境,即執(zhí)行一個(gè)出棧操作。任務(wù)在創(chuàng)建時(shí)必須調(diào)用OSTaskStkInit函數(shù)“制造”一個(gè)入棧操作,即與返回到任務(wù)時(shí)的出棧操作完全相反的操作。而這個(gè)入棧操作意義不大,只有任務(wù)的入口地址和參數(shù)有效,即上述代碼的第10行和第24行,其余行的入棧操作只是對(duì)應(yīng)出棧過(guò)程而已,入棧的數(shù)值可以隨意選取。第26或27行很重要,根據(jù)ARM工作模式或Thumb工作模式設(shè)定入棧的CPSR的值(當(dāng)出棧時(shí)這個(gè)值用于恢復(fù)CPSR的值,從而開(kāi)放中斷)。
os_cpu_c.c文件在移植時(shí),除了前述在OSInitHookBegin中添加自定義的初始化函數(shù)myInitHookBegin外,其余內(nèi)容不需要修改。用戶添加鉤子功能時(shí),不需要直接在os_cpu_c.c的各個(gè)鉤子函數(shù)中添加代碼,而只需要在各鉤子函數(shù)中調(diào)用的“應(yīng)用鉤子函數(shù)”中添加代碼即可。例如:程序設(shè)計(jì)人員不需要直接在OSTaskCreateHook中添加代碼,而只需要在App_TaskCreateHook(上述代碼的第21行)函數(shù)中添加代碼,而這個(gè)App_TaskCreateHook函數(shù)一般放在bsp.c或其他用戶編寫(xiě)的程序文件中。這樣做的好處在于保持μC/OS-Ⅱ內(nèi)核代碼和移植代碼的完整性,不同的用戶使用時(shí),可清楚地劃分哪些是自己添加的代碼,哪些是μC/OS-Ⅱ的代碼,當(dāng)程序出現(xiàn)調(diào)試或運(yùn)行錯(cuò)誤時(shí),可以集中精力從自己添加的代碼中尋找錯(cuò)誤。各個(gè)鉤子函數(shù)中調(diào)用的“應(yīng)用鉤子函數(shù)”為:OSTaskCreateHook調(diào)用App_TaskCreateHook,在μC/OS-Ⅱ調(diào)用OSTaskCreate或OSTaskCreateExt創(chuàng)建一個(gè)任務(wù)時(shí)調(diào)用該函數(shù),用戶可以在此添加特殊功能的移植代碼;OSTaskDelHook調(diào)用App_TaskDelHook,在刪除一個(gè)任務(wù)(使任務(wù)處于休眠態(tài))時(shí)調(diào)用該函數(shù);OSTaskIdleHook調(diào)用App_TaskIdleHook,μC/OS-Ⅱ進(jìn)入空閑狀態(tài)時(shí)調(diào)用該函數(shù),一般地,可在該函數(shù)中添加使CPU工作于低功耗狀態(tài)的代碼;
OSTaskStatHook調(diào)用App_TaskStatHook,統(tǒng)計(jì)任務(wù)中調(diào)用該函數(shù);OSTaskSwHook調(diào)用App_TaskSwHook,任務(wù)級(jí)切換時(shí)調(diào)用該函數(shù);OSTCBInitHook調(diào)用App_TCBInitHook,在OS_TCBInit函數(shù)創(chuàng)建了TCB后,調(diào)用該函數(shù);OSTimeTickHook調(diào)用App_TimeTickHook,在每個(gè)時(shí)鐘節(jié)拍都會(huì)調(diào)用該函數(shù)。每個(gè)鉤子函數(shù)的調(diào)用位置很重要,后續(xù)章節(jié)中還會(huì)介紹。此外,讀者可去查看μC/OS-Ⅱ源代碼,以便了解到鉤子函數(shù)更準(zhǔn)確詳細(xì)的調(diào)用位置。3.2.3os_cpu_a.asm文件
os_cpu_a.asm文件有843行代碼,在學(xué)習(xí)《ARM原理與C程序設(shè)計(jì)》一書(shū)后,幾乎可以讀懂全部代碼。我們認(rèn)為,讀懂這個(gè)文件的全部代碼是有必要的,這些代碼中包含了對(duì)異常處理的一個(gè)精湛的方法,可以讓讀者收獲很大;而且,這些代碼寫(xiě)得相當(dāng)出色和專(zhuān)業(yè),是學(xué)習(xí)匯編語(yǔ)言的典范例子。
這里只講述OSStartHighRdy函數(shù),其余內(nèi)容讀者在學(xué)習(xí)完第四章后,再去自行研究。
為了介紹的方便,把OSStartHighRdy函數(shù)的內(nèi)容羅列如下:上述代碼中,第1行為標(biāo)號(hào),也用作C函數(shù)名;第3行設(shè)置CPSR的值,進(jìn)入SVC模式,關(guān)閉普通中斷和快速中斷;第5~7行,調(diào)用函數(shù)OSTaskSwHook,調(diào)用的方法為首先將保存了OSTaskSwHook跳轉(zhuǎn)地址的地址存入R0寄存器,將PC的當(dāng)前值保存到LR中,跳轉(zhuǎn)到R0地址處,此時(shí)的R0處為一個(gè)跳轉(zhuǎn)地址,于是進(jìn)入到OSTaskSwHook執(zhí)行;第9~11行依次為_(kāi)OS_Running的值保存到R0中,R1的值賦為1,將R1的值即1寫(xiě)入到_OS_Running地址處,而_OS_Runing地址處的值定義為OSRunning,所以,這幾句執(zhí)行的結(jié)果為OSRunning賦為1(即真);在os_cpu_a.asm的第822行,有語(yǔ)句“_OS_TCBHighRdy:DC32OSTCBHighRdy”,第14~16行依次為將_OS_
TCBHighRdy的值寫(xiě)入R0中,再將_OS_TCBHighRdy地址處的值寫(xiě)入R0中,最后,以_OS_TCBHighRdy地址處的值為地址,將該地址里存儲(chǔ)的值寫(xiě)入SP中,即堆棧指針指向新的TCB堆棧(參考第四章);第18行將CPSR出棧,出棧的值賦給SPSR,第18行與第21行聯(lián)合完成了對(duì)第3.2.2節(jié)OSTaskStkInit中入棧后堆棧的出棧操作(假設(shè)屬于同一個(gè)任務(wù)的調(diào)用)。上述內(nèi)容在學(xué)習(xí)了第四章后再去理解將更加容易一些。此外,os_cpu_a.asm中的OSCtxSw和OSIntCtxSw也是極為重要的代碼段,需要認(rèn)真學(xué)習(xí)。3.2.4bsp.c文件
bsp.c文件屬于BSP(板級(jí)支持包)文件,廣義上,也可以視為移植文件,因?yàn)棣藽/OS-Ⅱ內(nèi)核文件的正常運(yùn)作也需要這個(gè)文件中的部分函數(shù)。從第3.1.1節(jié)中可以找到這個(gè)文件完整的代碼,這里僅需要介紹第3.1.1節(jié)第S9步中提到的一些代碼,為方便起見(jiàn),將這些代碼羅列如下:14
15break;
16default:
17break;
18}
19break;
20default:
21break;
22}
23}上述函數(shù)OS_CPU_ExceptHndlr是用戶需要編寫(xiě)的中斷處理函數(shù)。第3行判斷參數(shù)except_type的值,如果為6,表示為IRQ普通中斷。這時(shí)在第6行進(jìn)一步判斷INTOFFSET的值,如果為14,表示為定時(shí)器4的中斷,此時(shí)在第9行調(diào)用OSTimeTick函數(shù)進(jìn)入系統(tǒng)時(shí)鐘節(jié)拍處理,這個(gè)函數(shù)是非常重要的,如果節(jié)拍太慢,系統(tǒng)的實(shí)時(shí)性會(huì)變差;如果節(jié)拍太快,系統(tǒng)的負(fù)擔(dān)加重,一般設(shè)為10~100Hz。第11~13行與定時(shí)器4的中斷處理相關(guān),參見(jiàn)《ARM原理與C程序設(shè)計(jì)》第170頁(yè)或“S3C2410AUser’sManual”第14章。當(dāng)定時(shí)器4中斷發(fā)生后,os_cup_a.asm中的異常處理函數(shù)將會(huì)觸發(fā)OS_CPU_ExceptHndlr函數(shù),進(jìn)一步調(diào)用OSTimeTick函數(shù),進(jìn)入系統(tǒng)節(jié)拍處理。
至此,讀者應(yīng)回到第3.1節(jié)反復(fù)運(yùn)行工程ex3_1,多設(shè)置一些斷點(diǎn),或把時(shí)鐘節(jié)拍加長(zhǎng)到10秒以上單步運(yùn)行(筆者在初次學(xué)習(xí)μC/OS-Ⅱ移植時(shí),曾把時(shí)鐘節(jié)拍延長(zhǎng)到19.08845秒),以體會(huì)移植代碼是如何工作的。本節(jié)在第3.1節(jié)工程ex3_1的基礎(chǔ)上,添加串口通信功能,生成工程ex3_2。在工程ex3_2中的AppTaskStart任務(wù)中,再新建3個(gè)任務(wù),即AppTaskOne、AppTaskTwo和AppTaskThree。其中,AppTaskOne每隔一秒點(diǎn)亮LED1燈一次;AppTaskTwo每隔2秒點(diǎn)亮LED2燈一次;AppTaskThree每隔4秒點(diǎn)亮LED3燈一次。當(dāng)燈點(diǎn)亮?xí)r,串口調(diào)試助手同步顯示被點(diǎn)亮的LED燈號(hào)。
3.3μC/OS-Ⅱ串口通信實(shí)例3.3.1實(shí)例ex3_2
按第3.1節(jié)的方法新建工程ex3_2,保存目錄為D:\ZYUCOSII\ex3_2,工程ex3_2的工作區(qū)如圖3-9所示(這時(shí)的工程ex3_2與工程ex3_1功能完全相同,只是工程名和存儲(chǔ)目錄不同而已)。圖3-9工程ex3_2的最初版本為了清楚地介紹工程ex3_2的創(chuàng)建過(guò)程,下面分步進(jìn)行:
S1.在app.c文件中創(chuàng)建任務(wù)AppTaskStart時(shí),將其優(yōu)先級(jí)指定為5,即OSTaskCreate函數(shù)的最后一個(gè)參數(shù)為5,完整的app.c文件內(nèi)容如下:
1/*FileName:app.c
2**Byzhnyong@21
3**@2009-4-4
4**MainRoutine
5**CopyrightReserved
6*/
7
本書(shū)后面章節(jié)的幾乎所有實(shí)例的主程序文件與上述代碼完全相同,即有意義的代碼只有第8行和第10~15行等7行,程序的功能主要在appfun.c文件中實(shí)現(xiàn)。
S2.在bsp.h文件的末尾,添加一行串口0初始化函數(shù)聲明語(yǔ)句,即
voidmyInitUART0(void);//InitializeUART0
在bsp.h文件中添加對(duì)串口0寄存器地址的宏定義語(yǔ)句,如下:
1//---------------------------------------------------------
2//UART0
3//---------------------------------------------------------上述代碼可以放置在bsp.h的任何位置。
在bsp.c文件的末尾,添加上述函數(shù)myInitUART0的函數(shù)體,即
1//InitializeUART0
2voidmyInitUART0(void)
3{
4//SetGPH3:2asRXD0:TXD0
5GPHCON=0xA0;
6
7//SetUART0Baudrate:4800bps,8-bit,1-bitstop
8UFCON0=0x0;
9UMCON0=0x0;
10ULCON0=0x03;
11UCON0=0x05;
12UBRDIV0=0x270;
13}在bsp.c文件的myInitHookBegin函數(shù)內(nèi)添加一條語(yǔ)句,即“my
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 汕尾職業(yè)技術(shù)學(xué)院《科學(xué)計(jì)算與數(shù)據(jù)可視化》2023-2024學(xué)年第一學(xué)期期末試卷
- 公司租賃員工合同范例
- 2024年珠寶翻新修復(fù)服務(wù)合同3篇
- 租賃合同范例與
- 法律英文合同范例
- 2024至2030年無(wú)熱再生吸附式壓縮空氣干燥機(jī)項(xiàng)目投資價(jià)值分析報(bào)告
- 陜西學(xué)前師范學(xué)院《熱力渦輪機(jī)械原理》2023-2024學(xué)年第一學(xué)期期末試卷
- 私人住宅租房合同范例
- 2024年高效復(fù)式真空濾油機(jī)項(xiàng)目可行性研究報(bào)告
- 增資擴(kuò)股服務(wù)合同范例
- 任職資格體系3-某公司營(yíng)銷(xiāo)銷(xiāo)售族銷(xiāo)售、供應(yīng)、客服和職能任職資格
- 2012電池制造行業(yè)分析報(bào)告
- 2024年軍隊(duì)文職統(tǒng)一考試《專(zhuān)業(yè)科目》管理學(xué)試卷(網(wǎng)友回憶版)
- JT-T-973-2015路用非氯有機(jī)融雪劑
- 物業(yè)工作未來(lái)規(guī)劃與展望
- 新制定《公平競(jìng)爭(zhēng)審查條例》全文
- 人體漫游指南(山東聯(lián)盟)智慧樹(shù)知到期末考試答案章節(jié)答案2024年山東協(xié)和學(xué)院
- 現(xiàn)代生命科學(xué)與人居環(huán)境智慧樹(shù)知到期末考試答案章節(jié)答案2024年同濟(jì)大學(xué)
- 2024年淄博星辰供水有限公司招聘筆試參考題庫(kù)附帶答案詳解
- 2024年浙江紹興市高速公路運(yùn)營(yíng)管理有限公司招聘筆試參考題庫(kù)含答案解析
- 中西經(jīng)典對(duì)話(英語(yǔ))暨南大學(xué)2023年秋期末答案
評(píng)論
0/150
提交評(píng)論