1、uC/OSII簡介
u C / O S 是一種免費公開源代碼、結構小巧、具有可剝奪實時內核的實時操作系統(tǒng)。
μC/OS-II 的前身是μC/OS,最早出自于1992 年美國嵌入式系統(tǒng)專家Jean J.Labrosse 在《嵌入式系統(tǒng)編程》雜志的5 月和6 月刊上刊登的文章連載,并把μC/OS 的源碼發(fā)布在該雜志的B B S 上。
μC/OS 和μC/OS-II 是專門為計算機的嵌入式應用設計的, 絕大部分代碼是用C語言編寫的。CPU 硬件相關部分是用匯編語言編寫的、總量約200行的匯編語言部分被壓縮到最低限度,為的是便于移植到任何一種其它的CPU 上。用戶只要有標準的ANSI 的C交叉編譯器,有匯編器、連接器等軟件工具,就可以將μC/OS-II嵌人到開發(fā)的產品中。μC/OS-II 具有執(zhí)行效率高、占用空間小、實時性能優(yōu)良和可擴展性強等特點, 最小內核可編譯至 2KB 。μC/OS-II 已經移植到了幾乎所有知名的CPU 上。
嚴格地說uC/OS-II只是一個實時操作系統(tǒng)內核,它僅僅包含了任務調度,任務管理,時間管理,內存管理和任務間的通信和同步等基本功能。沒有提供輸入輸出管理,文件系統(tǒng),網絡等額外的服務。但由于uC/OS-II良好的可擴展性和源碼開放,這些非必須的功能完全可以由用戶自己根據(jù)需要分別實現(xiàn)。
uC/OS-II目標是實現(xiàn)一個基于優(yōu)先級調度的搶占式的實時內核,并在這個內核之上提供最基本的系統(tǒng)服務,如信號量,郵箱,消息隊列,內存管理,中斷管理等。
1.1任務管理
uC/OS-II 中最多可以支持64 個任務,分別對應優(yōu)先級0~63,其中0 為最高優(yōu)先級。63為最低級,系統(tǒng)保留了4個最高優(yōu)先級的任務和4個最低優(yōu)先級的任務,所有用戶可以使用的任務數(shù)有56個。
uC/OS-II提供了任務管理的各種函數(shù)調用,包括創(chuàng)建任務,刪除任務,改變任務的優(yōu)先級,任務掛起和恢復等。
系統(tǒng)初始化時會自動產生兩個任務:一個是空閑任務,它的優(yōu)先級最低,該任務僅給一個整形變量做累加運算;另一個是系統(tǒng)任務,它的優(yōu)先級為次低,該任務負責統(tǒng)計當前cpu的利用率。
1.2 時間管理
uC/OS-II的時間管理是通過定時中斷來實現(xiàn)的,該定時中斷一般為10毫秒或100毫秒發(fā)生一次,時間頻率取決于用戶對硬件系統(tǒng)的定時器編程來實現(xiàn)。中斷發(fā)生的時間間隔是固定不變的,該中斷也成為一個時鐘節(jié)拍。
uC/OS-II要求用戶在定時中斷的服務程序中,調用系統(tǒng)提供的與時鐘節(jié)拍相關的系統(tǒng)函數(shù),例如中斷級的任務切換函數(shù),系統(tǒng)時間函數(shù)。
1.3 內存管理
在ANSI C中是使用malloc和free兩個函數(shù)來動態(tài)分配和釋放內存。但在嵌入式實時系統(tǒng)中,多次這樣的操作會導致內存碎片,且由于內存管理算法的原因,malloc和free的執(zhí)行時間也是不確定。
uC/OS-II中把連續(xù)的大塊內存按分區(qū)管理。每個分區(qū)中包含整數(shù)個大小相同的內存塊,但不同分區(qū)之間的內存快大小可以不同。用戶需要動態(tài)分配內存時,系統(tǒng)選擇一個適當?shù)姆謪^(qū),按塊來分配內存。釋放內存時將該塊放回它以前所屬的分區(qū),這樣能有效解決碎片問題,同時執(zhí)行時間也是固定的。
1.4 任務間通信與同步
對一個多任務的操作系統(tǒng)來說,任務間的通信和同步是必不可少的。uC/OS-II中提供了4中同步對象,分別是信號量,郵箱,消息隊列和事件。所有這些同步對象都有創(chuàng)建,等待,發(fā)送,查詢的接口用于實現(xiàn)進程間的通信和同步。
1.5 任務調度
uC/OS-II 采用的是可剝奪型實時多任務內核??蓜儕Z型的實時內核在任何時候都運行就緒了的最高優(yōu)先級的任務。
uC/os-II的任務調度是完全基于任務優(yōu)先級的搶占式調度,也就是最高優(yōu)先級的任務一旦處于就緒狀態(tài),則立即搶占正在運行的低優(yōu)先級任務的處理器資源。為了簡化系統(tǒng)設計,uC/OS-II規(guī)定所有任務的優(yōu)先級不同,因為任務的優(yōu)先級也同時唯一標志了該任務本身。
uC/OS-II詳細用法可參考相關資料。
2、FPGA下的uC/OS-II
下面就介紹怎樣在以黑金開發(fā)板EP2C208上進行uC/OSII實驗。
第一步:添加一個用于系統(tǒng)時鐘節(jié)拍的定時器timer_ucos,定時時間為100ms(根據(jù)任務定)。
第二步:在Nios下設置相關選項。請看下面操作步驟。
打開Quart II工程,以黑金開發(fā)板EP2C208的工程為例,進入SOPC Builder界面下如圖:
在左側的“System Contents”下單擊Peripherais的左側“
”;在彈出的菜單下單擊Microcotroller Peripherais的左側“
”;如下圖。
找到 “Interval Timer”并雙擊,彈出如下圖并按下圖進行相關設置,單擊完成。
命名為timer_ucos;如下圖。
時鐘節(jié)拍定時器到此已添加完成,單擊Generate按鈕生成SOPC系統(tǒng)。
接下來對Quart II工程進行編譯并把 “.pof”通過AS接口下接到EPCS中。至此Quart II工程工作完畢.。[!--empirenews.page--]
拉下來對Nios工程進行設置。如果沒有關閉SOPC界面,可點擊“System Generation”下的Nios ii IDE按鈕即可進行Nios工程,前提是安裝了Nios ii 軟件。
新建一個Nios II工程,單擊“File”菜單下“New”下的“Nios II C/C++ Application”如下圖。
進入后出現(xiàn)如下圖,并按圖中參數(shù)設置(注ucosII為工程名,ep2c8q為SOPC系統(tǒng),Micro uC/OS-II tutorial為uCOS-II模板)。
單擊Next按鈕后按下圖設置后單擊Finish。
接下來對工程進行基本的設置,右擊uCOSII選擇彈出菜單中的“System Library Properties”出現(xiàn)如下界面并按照如下參數(shù)設置。然后單擊OK。
把ucosii_tutorial.c中文件內容用下面代碼代替。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
[!--empirenews.page--]
/* * ===================================================================================== * * Filename: ds1302.c * * Description: DS1302驅動 * * Version: 1.0.0 * Created: 2010.4.16 * Revision: none * Compiler: Nios II 9.0 IDE * * Author: 馬瑞 (AVIC) * Email: avic633@gmail.com * * ===================================================================================== */ #include <stdio.h> #include <unistd.h> #include <string.h> #include "includes.h" #include "alt_ucosii_simple_error_check.h" #include"ds1302.h" #include "altera_avalon_pio_regs.h" #include "altera_avalon_timer_regs.h" #include "alt_types.h" #include "sys/alt_irq.h" //定義椎棧 #define TASK_STACKSIZE 2048 OS_STK initialize_task_stk[TASK_STACKSIZE]; OS_STK ds1302_task_stk[TASK_STACKSIZE]; [!--empirenews.page--]
OS_STK led_task_stk[TASK_STACKSIZE]; OS_STK seg_task_stk[TASK_STACKSIZE]; //定義優(yōu)先級 #define INITIALIZE_TASK_PRIORITY 6 #define LED_TASK_PRIORITY 10 #define DS1302_TASK_PRIORITY 11 #define SEG_TASK_PRIORITY 12 //格式為: 秒 分 時 日 月 星期 年 unsigned char time[7] = {0x00,0x19,0x14,0x17,0x03,0x17,0x10}; unsigned char ti[][7]={ "一" , "二" , "三" , "四" , "五" , "六" , "日" }; alt_u8 segtab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned char bittab[6]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf}; unsigned char led_buffer[8]={1,2,3,4,5,6,7,8}; static unsigned char cnt=0; void seg_handler( void ); /* * === FUNCTION ====================================================================== * Name: ds1302_task * Description: 任務1 調用ds1302驅動并通過串口顯示數(shù)據(jù) * ===================================================================================== */ void ds1302_task( void * pdata) [!--empirenews.page--]
{ INT8U return_code = OS_NO_ERR; ds1302.set_time(time); printf( "Hello from Nios II!n" ); while (1){ printf( "Hello from Nios II!rn" ); ds1302.get_time(time); printf( "%02d-%02d-%02d %02d:%02d:%02d 星期%srn" , time[6],time[4],time[3],time[2],time[1],time[0],ti[time[5]-1]); OSTimeDlyHMSM(0, 0, 1, 0); } } /* * === FUNCTION ====================================================================== * Name: led_task * Description: 任務2 調用LED驅動并通過串口顯示數(shù)據(jù) * ===================================================================================== */ void led_task( void * pdata) { INT8U return_code = OS_NO_ERR; unsigned int num=0; LED->DATA =0xffffffff; while (1){ [!--empirenews.page--]
printf( "led is running!rn" ); if (num%2==0) LED->DATA =0xffffffff; else LED->DATA =0; num++; OSTimeDlyHMSM(0, 0, 2, 0); } } /* * === FUNCTION ====================================================================== * Name: seg_task * Description: 任務3 調用數(shù)碼管驅動并通過串口顯示數(shù)據(jù) * ===================================================================================== */ void seg_task( void * pdata) { INT8U return_code = OS_NO_ERR; unsigned int numseg=0; while (1){ numseg++; seg_handler(); OSTimeDlyHMSM(0, 0, 0, 300); } } /* * === FUNCTION ====================================================================== [!--empirenews.page--]
* Name: seg_handler * Description: * ===================================================================================== */ void seg_handler( void ) { IOWR_ALTERA_AVALON_PIO_DATA(SEG_SEL_BASE, 0xff); IOWR_ALTERA_AVALON_PIO_DATA(SEG_SEL_BASE, bittab[cnt]); IOWR_ALTERA_AVALON_PIO_DATA(SEG_DAT_BASE, segtab[led_buffer[cnt]]); cnt++; if (cnt==6) cnt=0; } /* * === FUNCTION ====================================================================== * Name: main * Description: * ===================================================================================== */ void initialize_task( void * pdata) { INT8U return_code = OS_NO_ERR; initCreateTasks(); return_code = OSTaskDel(OS_PRIO_SELF); while (1); } /* [!--empirenews.page--]
* === FUNCTION ====================================================================== * Name: main * Description: * ===================================================================================== */ int main ( int argc, char * argv[], char * envp[]) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreateExt(initialize_task, NULL, ( void *)&initialize_task_stk[TASK_STACKSIZE], INITIALIZE_TASK_PRIORITY, INITIALIZE_TASK_PRIORITY, initialize_task_stk, TASK_STACKSIZE, NULL, 0); OSStart(); return 0; } [!--empirenews.page--]
/* * === FUNCTION ====================================================================== * Name: initCreateTasks * Description: * ===================================================================================== */ int initCreateTasks( void ) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreateExt(ds1302_task, NULL, ( void *)&ds1302_task_stk[TASK_STACKSIZE], DS1302_TASK_PRIORITY, DS1302_TASK_PRIORITY, ds1302_task_stk, TASK_STACKSIZE, NULL, 0); return_code = OSTaskCreateExt(led_task, NULL, ( void *)&led_task_stk[TASK_STACKSIZE], [!--empirenews.page--]
LED_TASK_PRIORITY, LED_TASK_PRIORITY, led_task_stk, TASK_STACKSIZE, NULL, 0); return_code = OSTaskCreateExt(seg_task, NULL, ( void *)&seg_task_stk[TASK_STACKSIZE], SEG_TASK_PRIORITY, SEG_TASK_PRIORITY, seg_task_stk, TASK_STACKSIZE, NULL, 0); return 0; } |
編譯Nios II工程,下載到EPCS中,下載的方法前面章節(jié)講過,這里就不再重復了。下面是PC機上串口調試工具上的數(shù)據(jù)。在開發(fā)板上還可以看到四個LED燈在閃爍和數(shù)碼管顯示654321。