Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2012 / uCOS / uCOSII_ebook.pdf
Скачиваний:
84
Добавлен:
10.02.2015
Размер:
1.08 Mб
Скачать

void Task (void *data)

{

UBYTE x; UBYTE y; UBYTE err;

for (;;) {

 

OSSemPend(RandomSem, 0, &err);

(1)

x = random(80);

(2)

y = random(16);

 

OSSemPost(RandomSem);

(3)

PC_DispChar(x, y + 5, *(char *)data, DISP_FGND_LIGHT_GRAY); (4)

OSTimeDly(1);

(5)

}

 

}

Listing 1.10,

Task that displays a number at random locations on the screen.

1.08 Example #2

Example #2 makes use of the extended task create function and µC/OS-II’s stack checking feature. Stack checking is useful when you don’t actually know ahead of time how much stack space you need to allocate for each task. In this case, you allocate much more stack space than you think you need and you let µC/OS-II tell you exactly how much stack space is actually used up. You obviously need to run the application long enough and under your worst case conditions to get proper numbers. Your final stack size should accommodate for system expansion so make sure you allocate between 10 and 25% more. In safety critical applications, however, you may even want to consider 100% more. What you should get from stack checking is a ‘ballpark’figure; you are not looking for an exact stack usage.

µC/OS-II’s stack checking function assumes that the stack is initially filled with zeros when the task is created. You accomplish this by telling OSTaskCreateExt() to clear the stack upon task creation

(i.e. you OR both OS_TASK_OPT_STK_CHK and OS_TASK_OPT_STK_CLR for the opt

argument). If you intend to create and delete tasks, you should set these options so that a new stack is cleared every time the task is created. You should note that having OSTaskCreateExt() clear the stack

increases execution overhead which obviously depends on the stack size. µC/OS -II scans the stack starting at the bottom until it finds a non-zero entry (see figure 1-1). As the stack is scanned, µC/OS-II increments a counter that indicates how many entries are free (Stack Free).

Bottom-Of-Stack

/OS-II 'Scans' stack

Stack Growth

Top-Of-Stack

0x0000

0x0000

0x0000

0x0000

 

Stack Free

0x0000

Stack Size

0x0000

0x0000

Stack Used

Figure 1-1 µC/OS-II Stack checking

The second example is found in \SOFTWARE\uCOS-II\EX2_x86L and consists of a total of 9

tasks. Again, µC/OS-II creates two ‘internal’tasks: the idle task and the task that determines CPU usage. EX2L.C creates the other 7 tasks. As with example #1, TaskStart() is created by main() and

its function is to create the other tasks and display the following statistics on the screen:

1)the number of task switches in one second,

2)the CPU usage in %,

3)the number of context switches,

4)the current date and time, and

5)µC/OS-II’s version.

OSTaskStkChk().

1.08.01 Example #2, main()

main() looks just like the code for example #1 (see listing 1.11) except for two small differences. First, main() calls PC_ElapsedInit() L1.11(1) to in itialize the elapsed time measurement function which will be used to measure the execution time of Second, all tasks are created using the extended task create function instead of OSTaskCreate() L1.11(2). This allows us, among

other things, to perform stack checking on each task. In addition to the same four arguments needed by OSTaskCreate(), OSTaskCreateExt() requires five additional arguments: a task ID, a

pointer to the bottom of the stack, the stack size (in number of elements), a p ointer to a user supplied Task Control Block (TCB) extension, and a variable used to specify options to the task. One of the options is used to tell µC/OS-II that stack checking is allowed on the created task. Example #2 doesn’t make use of the TCB (Task Control Block) extension pointer.

void main (void)

 

{

 

PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);

 

OSInit();

 

PC_DOSSaveReturn();

 

PC_VectSet(uCOS, OSCtxSw);

 

PC_ElapsedInit();

(1)

OSTaskCreateExt(TaskStart,

(2)

(void *)0, &TaskStartStk[TASK_STK_SIZE-1], TASK_START_PRIO, TASK_START_ID, &TaskStartStk[0], TASK_STK_SIZE,

(void *)0,

OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);

OSStart();

}

Listing 1.11, main() for example #2.

1.08.02 Example #2, TaskStart()

Listing 1.12 shows the pseudo code for TaskStart(). The first five operations are similar to those found in example #1. TaskStart() creates two mailboxes that will be used by Task #4 and Task #5 L1.12(1). A task that will display the current date and time is created as well as five application tasks L1.12(20).

void TaskStart (void *data)

{

Prevent compiler warning by assigning ‘data’ to itself; Display a banner and non-changing text;

Install uC/OS-II’s tick handler; Change the tick rate to 200 Hz; Initialize the statistics task;

Create 2 mailboxes which are used by Task #4 and #5; (1) Create a task that will display the date and time on the screen; (2) Create 5 application tasks;

for (;;) {

Display #tasks running; Display CPU usage in %;

Display #context switches per seconds; Clear the context switch counter; Display uC/OS-II’s version;

if (Key was pressed) {

if (Key pressed was the ESCAPE key) { Return to DOS;

}

}

Delay for 1 second;

}

}

Listing 1.12, Pseudo-code for TaskStart().

1.08.03 Example #2, TaskN()

The code for Task1() checks the size of the stack for each of the seven application tasks. The execution time of OSTaskStkChk() is measured L1.13(1)-(2) and displayed along with the stack size information. Note that all stack size data are displayed in number of bytes. This task executes 10 times per second L1.13(3).

void Task1 (void *pdata)

 

 

 

{

 

 

 

 

INT8U

err;

 

 

 

OS_STK_DATA data;

 

 

 

INT16U

time;

 

 

 

INT8U

i;

 

 

 

char

s[80];

 

 

 

pdata = pdata;

 

 

 

for (;;) {

 

 

 

 

for (i = 0; i < 7; i++) {

 

 

 

PC_ElapsedStart();

 

 

(1)

err

= OSTaskStkChk(TASK_START_PRIO+i, &data);

time = PC_ElapsedStop();

 

 

(2)

if (err == OS_NO_ERR) {

 

 

 

 

sprintf(s, "%3ld

%3ld

%3ld

%5d",

 

data.OSFree + data.OSUsed,

 

 

data.OSFree,

 

 

 

 

data.OSUsed,

 

 

 

 

time);

 

 

 

}

PC_DispStr(19, 12+i, s, DISP_FGND_YELLOW);

 

 

 

 

}

 

 

 

 

OSTimeDlyHMSM(0, 0, 0, 100);

 

 

(3)

}

 

 

 

 

}

 

 

 

 

Listing 1.13, Example #2, Task #1.

Task2() displays a clockwise rotating wheel on the screen. Each rotation completes in 200 mS (i.e. 4 x 10 ticks x 5 mS/tick).

void Task2 (void *data)

{

data = data; for (;;) {

PC_DispChar(70, 15, '|', DISP_FGND_WHITE + DISP_BGND_RED); OSTimeDly(10);

PC_DispChar(70, 15, '/', DISP_FGND_WHITE + DISP_BGND_RED); OSTimeDly(10);

PC_DispChar(70, 15, '-', DISP_FGND_WHITE + DISP_BGND_RED); OSTimeDly(10);

PC_DispChar(70, 15, '\\', DISP_FGND_WHITE + DISP_BGND_RED); OSTimeDly(10);

}

}

Listing 1.14, Rotating wheel task.

Task3() also displays a rotating wheel but, the rotation is in the opposite direction. Also, Task3() allocates storage on the stack. I decided to fill the dummy array to show that OSTaskStkChk() takes less time to determine stack usage when the stack is close to being fully used up L1.15(1).

void Task3 (void *data)

{

char dummy[500]; INT16U i;

data = data;

for (i = 0; i < 499; i++) { (1) dummy[i] = '?';

}

for (;;) {

PC_DispChar(70, 16, '|', DISP_FGND_WHITE + DISP_BGND_BLUE); OSTimeDly(20);

PC_DispChar(70, 16, '\\', DISP_FGND_WHITE + DISP_BGND_BLUE); OSTimeDly(20);

PC_DispChar(70, 16, '-', DISP_FGND_WHITE + DISP_BGND_BLUE); OSTimeDly(20);

PC_DispChar(70, 16, '/', DISP_FGND_WHITE + DISP_BGND_BLUE); OSTimeDly(20);

}

}

Listing 1.15, Rotating wheel task.

Task4() sends a message to Task5() and waits for an acknowledgement from Task5() L1.16(1). The message sent is simply a pointer to a character. Every time Task4() receives an acknowledgement from Task5() L1.16(2), Task4() increments the ASCII character value before sending the next message L1.16(3). When Task5() receives the message L1.17(1) (i.e. the character) it displays the character on the screen L1.17(2) and then waits one second L1.17(3) before acknowledging it to task #4 L1.17(4).

void Task4 (void *data)

{

char txmsg; INT8U err;

data =

data;

 

txmsg = 'A';

 

for (;;) {

 

while (txmsg <= 'Z') {

 

 

OSMboxPost(TxMbox, (void *)&txmsg);

(1)

 

OSMboxPend(AckMbox, 0, &err);

(2)

}

txmsg++;

(3)

 

 

txmsg = 'A';

}

}

Listing 1.16, Task #4 communicates with task #5.

void Task5 (void *data)

 

{

 

 

char

*rxmsg;

 

INT8U

err;

 

data = data;

 

for (;;) {

 

rxmsg = (char *)OSMboxPend(TxMbox, 0, &err);

(1)

PC_DispChar(70, 18, *rxmsg, DISP_FGND_YELLOW+DISP_BGND_RED); (2)

OSTimeDlyHMSM(0, 0, 1, 0);

(3)

OSMboxPost(AckMbox, (void *)1);

(4)

}

 

 

}

 

 

Listing 1.17, Task #5 receives and displays a message.

TaskClk() (listing 1.18) is a task that displays the current date and time every second.

Соседние файлы в папке uCOS