基于NIOS II的uC/OS系統(tǒng)的開發(fā)
1、uC/OSII簡介
u C / O S 是一種免費(fèi)公開源代碼、結(jié)構(gòu)小巧、具有可剝奪實(shí)時(shí)內(nèi)核的實(shí)時(shí)操作系統(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 是專門為計(jì)算機(jī)的嵌入式應(yīng)用設(shè)計(jì)的, 絕大部分代碼是用C語言編寫的。CPU 硬件相關(guān)部分是用匯編語言編寫的、總量約200行的匯編語言部分被壓縮到最低限度,為的是便于移植到任何一種其它的CPU 上。用戶只要有標(biāo)準(zhǔn)的ANSI 的C交叉編譯器,有匯編器、連接器等軟件工具,就可以將μC/OS-II嵌人到開發(fā)的產(chǎn)品中。μC/OS-II 具有執(zhí)行效率高、占用空間小、實(shí)時(shí)性能優(yōu)良和可擴(kuò)展性強(qiáng)等特點(diǎn), 最小內(nèi)核可編譯至 2KB 。μC/OS-II 已經(jīng)移植到了幾乎所有知名的CPU 上。
嚴(yán)格地說uC/OS-II只是一個(gè)實(shí)時(shí)操作系統(tǒng)內(nèi)核,它僅僅包含了任務(wù)調(diào)度,任務(wù)管理,時(shí)間管理,內(nèi)存管理和任務(wù)間的通信和同步等基本功能。沒有提供輸入輸出管理,文件系統(tǒng),網(wǎng)絡(luò)等額外的服務(wù)。但由于uC/OS-II良好的可擴(kuò)展性和源碼開放,這些非必須的功能完全可以由用戶自己根據(jù)需要分別實(shí)現(xiàn)。
uC/OS-II目標(biāo)是實(shí)現(xiàn)一個(gè)基于優(yōu)先級(jí)調(diào)度的搶占式的實(shí)時(shí)內(nèi)核,并在這個(gè)內(nèi)核之上提供最基本的系統(tǒng)服務(wù),如信號(hào)量,郵箱,消息隊(duì)列,內(nèi)存管理,中斷管理等。
1.1任務(wù)管理
uC/OS-II 中最多可以支持64 個(gè)任務(wù),分別對(duì)應(yīng)優(yōu)先級(jí)0~63,其中0 為最高優(yōu)先級(jí)。63為最低級(jí),系統(tǒng)保留了4個(gè)最高優(yōu)先級(jí)的任務(wù)和4個(gè)最低優(yōu)先級(jí)的任務(wù),所有用戶可以使用的任務(wù)數(shù)有56個(gè)。
uC/OS-II提供了任務(wù)管理的各種函數(shù)調(diào)用,包括創(chuàng)建任務(wù),刪除任務(wù),改變?nèi)蝿?wù)的優(yōu)先級(jí),任務(wù)掛起和恢復(fù)等。
系統(tǒng)初始化時(shí)會(huì)自動(dòng)產(chǎn)生兩個(gè)任務(wù):一個(gè)是空閑任務(wù),它的優(yōu)先級(jí)最低,該任務(wù)僅給一個(gè)整形變量做累加運(yùn)算;另一個(gè)是系統(tǒng)任務(wù),它的優(yōu)先級(jí)為次低,該任務(wù)負(fù)責(zé)統(tǒng)計(jì)當(dāng)前cpu的利用率。
1.2 時(shí)間管理
uC/OS-II的時(shí)間管理是通過定時(shí)中斷來實(shí)現(xiàn)的,該定時(shí)中斷一般為10毫秒或100毫秒發(fā)生一次,時(shí)間頻率取決于用戶對(duì)硬件系統(tǒng)的定時(shí)器編程來實(shí)現(xiàn)。中斷發(fā)生的時(shí)間間隔是固定不變的,該中斷也成為一個(gè)時(shí)鐘節(jié)拍。
uC/OS-II要求用戶在定時(shí)中斷的服務(wù)程序中,調(diào)用系統(tǒng)提供的與時(shí)鐘節(jié)拍相關(guān)的系統(tǒng)函數(shù),例如中斷級(jí)的任務(wù)切換函數(shù),系統(tǒng)時(shí)間函數(shù)。
1.3 內(nèi)存管理
在ANSI C中是使用malloc和free兩個(gè)函數(shù)來動(dòng)態(tài)分配和釋放內(nèi)存。但在嵌入式實(shí)時(shí)系統(tǒng)中,多次這樣的操作會(huì)導(dǎo)致內(nèi)存碎片,且由于內(nèi)存管理算法的原因,malloc和free的執(zhí)行時(shí)間也是不確定。
uC/OS-II中把連續(xù)的大塊內(nèi)存按分區(qū)管理。每個(gè)分區(qū)中包含整數(shù)個(gè)大小相同的內(nèi)存塊,但不同分區(qū)之間的內(nèi)存快大小可以不同。用戶需要?jiǎng)討B(tài)分配內(nèi)存時(shí),系統(tǒng)選擇一個(gè)適當(dāng)?shù)姆謪^(qū),按塊來分配內(nèi)存。釋放內(nèi)存時(shí)將該塊放回它以前所屬的分區(qū),這樣能有效解決碎片問題,同時(shí)執(zhí)行時(shí)間也是固定的。
1.4 任務(wù)間通信與同步
對(duì)一個(gè)多任務(wù)的操作系統(tǒng)來說,任務(wù)間的通信和同步是必不可少的。uC/OS-II中提供了4中同步對(duì)象,分別是信號(hào)量,郵箱,消息隊(duì)列和事件。所有這些同步對(duì)象都有創(chuàng)建,等待,發(fā)送,查詢的接口用于實(shí)現(xiàn)進(jìn)程間的通信和同步。
1.5 任務(wù)調(diào)度
uC/OS-II 采用的是可剝奪型實(shí)時(shí)多任務(wù)內(nèi)核。可剝奪型的實(shí)時(shí)內(nèi)核在任何時(shí)候都運(yùn)行就緒了的最高優(yōu)先級(jí)的任務(wù)。
uC/os-II的任務(wù)調(diào)度是完全基于任務(wù)優(yōu)先級(jí)的搶占式調(diào)度,也就是最高優(yōu)先級(jí)的任務(wù)一旦處于就緒狀態(tài),則立即搶占正在運(yùn)行的低優(yōu)先級(jí)任務(wù)的處理器資源。為了簡化系統(tǒng)設(shè)計(jì),uC/OS-II規(guī)定所有任務(wù)的優(yōu)先級(jí)不同,因?yàn)槿蝿?wù)的優(yōu)先級(jí)也同時(shí)唯一標(biāo)志了該任務(wù)本身。
uC/OS-II詳細(xì)用法可參考相關(guān)資料。
2、FPGA下的uC/OS-II
下面就介紹怎樣在以黑金開發(fā)板EP2C208上進(jìn)行uC/OSII實(shí)驗(yàn)。
第一步:添加一個(gè)用于系統(tǒng)時(shí)鐘節(jié)拍的定時(shí)器timer_ucos,定時(shí)時(shí)間為100ms(根據(jù)任務(wù)定)。
第二步:在Nios下設(shè)置相關(guān)選項(xiàng)。請(qǐng)看下面操作步驟。
打開Quart II工程,以黑金開發(fā)板EP2C208的工程為例,進(jìn)入SOPC Builder界面下如圖:
在左側(cè)的“System Contents”下單擊Peripherais的左側(cè)“
”;在彈出的菜單下單擊Microcotroller Peripherais的左側(cè)“
”;如下圖。
找到 “Interval Timer”并雙擊,彈出如下圖并按下圖進(jìn)行相關(guān)設(shè)置,單擊完成。
命名為timer_ucos;如下圖。
時(shí)鐘節(jié)拍定時(shí)器到此已添加完成,單擊Generate按鈕生成SOPC系統(tǒng)。
接下來對(duì)Quart II工程進(jìn)行編譯并把 “.pof”通過AS接口下接到EPCS中。至此Quart II工程工作完畢.。[!--empirenews.page--]
拉下來對(duì)Nios工程進(jìn)行設(shè)置。如果沒有關(guān)閉SOPC界面,可點(diǎn)擊“System Generation”下的Nios ii IDE按鈕即可進(jìn)行Nios工程,前提是安裝了Nios ii 軟件。
新建一個(gè)Nios II工程,單擊“File”菜單下“New”下的“Nios II C/C++ Application”如下圖。
進(jìn)入后出現(xiàn)如下圖,并按圖中參數(shù)設(shè)置(注ucosII為工程名,ep2c8q為SOPC系統(tǒng),Micro uC/OS-II tutorial為uCOS-II模板)。
單擊Next按鈕后按下圖設(shè)置后單擊Finish。
接下來對(duì)工程進(jìn)行基本的設(shè)置,右擊uCOSII選擇彈出菜單中的“System Library Properties”出現(xiàn)如下界面并按照如下參數(shù)設(shè)置。然后單擊OK。
把ucosii_tutorial.c中文件內(nèi)容用下面代碼代替。
?
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驅(qū)動(dòng) * * 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)先級(jí) #define INITIALIZE_TASK_PRIORITY 6 #define LED_TASK_PRIORITY 10 #define DS1302_TASK_PRIORITY 11 #define SEG_TASK_PRIORITY 12 //格式為: 秒 分 時(shí) 日 月 星期 年 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: 任務(wù)1 調(diào)用ds1302驅(qū)動(dòng)并通過串口顯示數(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: 任務(wù)2 調(diào)用LED驅(qū)動(dòng)并通過串口顯示數(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: 任務(wù)3 調(diào)用數(shù)碼管驅(qū)動(dòng)并通過串口顯示數(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é)講過,這里就不再重復(fù)了。下面是PC機(jī)上串口調(diào)試工具上的數(shù)據(jù)。在開發(fā)板上還可以看到四個(gè)LED燈在閃爍和數(shù)碼管顯示654321。