📄 main.c
字号:
/************************************************************
Copyright (C) 1995-2002 Pumpkin, Inc. and its
Licensor(s). Freely distributable.
$Source: C:\\RCS\\d\\salvo\\demo\\d1\\main.c,v $
$Author: aek $
$Revision: 3.16 $
$Date: 2003-07-17 23:47:22-07 $
Demo program runs 8 tasks simultaneously and uses the
PICDEM-2's LED array to display useful information.
Compiled with HI_TECH PIC C
Works with Microchip PIC16C64/65/67/77 & PIC18C452
Runs on Microchip PICDEM-2 demo board at 4MHz for 9600 bps.
************************************************************/
#include "main.h"
#include <salvo.h>
#if defined(SYSE)
/* MPLAB-C18 requires that we explicitly place */
/* const objects in ROM. Must come after header */
/* files ... */
#define const rom const
#endif
/************************************************************
**** ****
** **
Local #defines and function prototypes.
** **
**** ****
************************************************************/
/* task and event handles */
#define TASK_STATS_P OSTCBP(7)
#define TASK_DUMMY_P OSTCBP(8)
#define SEM1_P OSECBP(1)
#define SEM2_P OSECBP(2)
#define SEM3_P OSECBP(3)
#define SEM4_P OSECBP(4)
#define SEM5_P OSECBP(5)
/* bitfields for flag */
#define FLAG_MODE 0x01 /* delays (mode 1) or */
/* events (mode 2) */
#define FLAG_CALL_OSRPT 0x02 /* call OSRpt() */
#define FLAG_SHOW_CTXSWS 0x04 /* control '.'s */
#define FLAG_MODE_CHANGED 0x08 /* pass up to main */
/* function prototypes */
void ShowMode(void);
void TaskBlinkLED(void);
void TaskDummy(void);
void TaskRandom(void);
void TaskStats(void);
void TaskWaitAWhile(void);
/* external function prototypes */
extern void putch(char c);
extern void putstr(const char *c);
/* extern void putASCIIHex(char c); */
extern void InitTx(void);
extern void SndTxChar(void);
extern unsigned char RtnRoomInTxBuff(void);
/* bargraph LED patterns */
const char LEDs[9] = { 0x00,
0x80, 0xC0, 0xE0, 0xF0,
0xF8, 0xFC, 0xFE, 0xFF };
/* semaphores associated with tasks 1-5. Entries 0-4 are */
/* used by tasks 1-4 to wait on sems 1-4. Entries 0-5 are */
/* used to randomly signal sems 1-5. */
OStypeEcbP const semP[8] = { SEM1_P,
SEM2_P,
SEM3_P,
SEM4_P,
SEM4_P,
SEM5_P,
0,
0 };
/* priorities of tasks 0-5 */
const OStypePrio prio[6] = { 2, 3, 4, 5, 5, 1 };
/* splash screen */
const char strSplash[] =
NEWLINE
"Salvo(TM) Demo #1: (C)Copyright 1995-2002 Pumpkin, Inc. All Rights Reserved." NEWLINE NEWLINE
"Task | Mode 1 | Mode 2 Sem PORT/LED" NEWLINE
" 1 | Run for a random -+ | Wait on specified 1 0" NEWLINE
" 2 | number of ticks, | number | semaphore with a 2 1" NEWLINE
" 3 | then delay for a | of | timeout of random 3 2" NEWLINE
" 4 | random number of | eligible | ticks, then flash 4 3" NEWLINE
" 5 | ticks | tasks | LED for 20ms 4 4" NEWLINE
" 6 | \"\" | shown on | Signal random sem, 1-5 5" NEWLINE
" | | LED | flash LED for 20ms" NEWLINE
" 7 | Read S2 & S3 | bargraph | Read S2 & S3, toggle LED 6" NEWLINE
" 8 | Dummy task -+ | Toggle LED when idling 7\n" NEWLINE
"S1/'1': reset, S2/'2': display kernel status (toggle), S3/'3': change modes." NEWLINE
"Each \'*\' represents 125 context switches, each \'.\' represents 125 idling" NEWLINE
" function calls, each 80-char line 10,000. RS-232 @ 9600,N,8,1." NEWLINE NEWLINE;
const char strMode1[] = " mode 1 (delays) ";
const char strMode2[] = " mode 2 (events) ";
const char strEnv1[] = "\n\rTarget, Compiler, Ticks: ";
const char strEnv2[] = STR_PROC_TYPE;
/* context-switching labels */
_OSLabel(TaskBlinkLED1)
_OSLabel(TaskDummy1)
_OSLabel(TaskRandom1)
_OSLabel(TaskRandom2)
_OSLabel(TaskRandom3)
_OSLabel(TaskRandom4)
_OSLabel(TaskRandom5)
_OSLabel(TaskStats1)
_OSLabel(TaskStats2)
_OSLabel(TaskStats3)
_OSLabel(TaskStats4)
_OSLabel(TaskStats5)
_OSLabel(TaskWaitAWhile1)
_OSLabel(TaskWaitAWhile2)
/************************************************************
**** ****
** **
main()
This program illustrates a typical main() structure
for a Salvo application: initialize Salvo, install the
system timer, create and start tasks, and then begin
multitasking.
A bunch of extra stuff is added in for display / diagnostic
purposes. Of special note is the calculation of time (in
cycles) between successive context switches.
** **
**** ****
************************************************************/
int main( void )
{
InitTestHw();
/* set PORT for output and turn off all */
/* PORT LEDs. */
InitPORT();
/* initialize Salvo. */
OSInit();
/* initialize RS-232 transmitter software. */
InitTx();
/* initialize timers and peripherals. */
Init();
/* enable interrupts (UART is interrupt- */
/* driven. */
OSEi();
/* show splash screen */
putstr(strSplash);
/* setup the tasks with pseudo-random */
/* behavior and the key-reading and -acting*/
/* task ... */
for ( i = 1 ; i <= SIGNALING_TASKID ; i++ )
OSCreateTask(TaskRandom, OSTCBP(i), prio[i-1]);
OSCreateTask(TaskStats, TASK_STATS_P, 0);
OSCreateTask(TaskDummy, TASK_DUMMY_P, OSLOWEST_PRIO);
/* initialize all the semaphores to 0. */
for ( i = 1 ; i <= OSEVENTS ; i++ )
OSCreateSem(OSECBP(i), 0);
/* initialize placeholders. */
minCtxSw = 10000;
maxCtxSw = 0;
/* initialize vars used to keep track of */
/* context switches, etc. */
j = DOTS_PER_CTXSW;
k = DOTS_PER_CTXSW;
flag = FLAG_SHOW_CTXSWS;
/* enable TMR2 so that OSTimer() is called. */
/* didn't want to do this earlier because */
/* OSSched() wasn't being called and */
/* putstr() takes > 100 system ticks to */
/* display splash screen. */
EnableTMR2();
/* satisfy PICC & PICC-18 callgraphs */
#if defined(SYSA) || defined(SYSF)
if (0)
;
#endif
/* start multitasking. */
for (;;)
{
/* dispatch the current most-eligible */
/* task. */
#if !OSUSE_INLINE_OSSCHED
OSSched();
#else
#include "sched.c"
#endif
/* complete the context-switching calc */
/* that was started in OSSchedHook(). */
DisableTMR1();
currTMR1 = TMR1;
EnableTMR1();
ctxSw = currTMR1 - prevTMR1;
if ( ctxSw < 0 )
ctxSw = -ctxSw;
/* update min- and max- placeholders. */
if ( maxCtxSw < ctxSw )
maxCtxSw = ctxSw;
if ( minCtxSw > ctxSw )
minCtxSw = ctxSw;
/* OSRpt() call depth is too deep to */
/* call from a task in a PIC ... also, */
/* disable calls to OSTimer() while */
/* we're doing the dump. */
if ( flag & FLAG_CALL_OSRPT ) {
DisableTMR2();
putstr(strEnv1);
putstr(strEnv2);
ShowMode();
#if USE_PRINTF
printf(".\n\rContext-switching times: "
"from %d to %d cycles",
minCtxSw-TWEAK_CYCLE_COUNT,
maxCtxSw-TWEAK_CYCLE_COUNT);
OSRpt();
#endif
EnableTMR2();
flag &= ~FLAG_CALL_OSRPT;
}
if ( flag & FLAG_MODE_CHANGED ) {
flag &= ~FLAG_MODE_CHANGED;
ShowMode();
}
}
}
/************************************************************
**** ****
** **
OSIdlingHook()
Displays idle fn activity to the screen when required.
Also toggles LED, but only in mode 2.
** **
**** ****
************************************************************/
void OSIdlingHook( void )
{
if ( !--k && (flag & FLAG_SHOW_CTXSWS) ) {
k = DOTS_PER_CTXSW;
putch('.');
}
if ( flag & FLAG_MODE )
PORT ^= 0x80;
}
/************************************************************
**** ****
** **
OSSchedDispatchHook()
In order to count the number of eligible tasks, we have
to do it inside the scheduler.
** **
**** ****
************************************************************/
void OSSchedDispatchHook ( void )
{
OStypeTcbP tcbP;
char i;
/* count the current number of eligible */
/* tasks and display it via an LED */
/* bargraph. */
/* show them now, instead of after when */
/* when OSSched() runs, because odds */
/* of catching the eligible queue full */
/* are much better now than after the */
/* current task runs. */
if ( !(flag & FLAG_MODE) ) {
i = 0;
#if OSUSE_ARRAYS
u.prioA = OSeligQP;
if ( OSeligQP & 0x01 ) i++;
if ( OSeligQP & 0x02 ) i++;
if ( OSeligQP & 0x04 ) i++;
if ( OSeligQP & 0x08 ) i++;
if ( OSeligQP & 0x10 ) i++;
if ( OSeligQP & 0x20 ) i++;
if ( OSeligQP & 0x40 ) i++;
if ( OSeligQP & 0x80 ) i++;
#else
tcbP = OSeligQP;
for (;;)
if ( tcbP != 0 ) {
i++;
tcbP = tcbP->nextTcbP;
}
else
break;
#endif
PORT = LEDs[i];
}
/* while we're at it, figure out how */
/* long the trip through the scheduler */
/* takes -- this is indicative of the */
/* time between context switches in */
/* this particular application. */
/* Note that this measurement disregards*/
/* the signaled event and delay queues. */
DisableTMR1();
prevTMR1 = TMR1;
EnableTMR1();
}
/************************************************************
**** ****
** **
OSSchedRtnHook()
For every 125 context switches, output a '.'. Note that we
do not count idle fn calls here -- just task context
switches.
** **
**** ****
************************************************************/
void OSSchedReturnHook( void )
{
if ( !--j && (flag & FLAG_SHOW_CTXSWS) ) {
j = DOTS_PER_CTXSW;
putch('*');
}
}
/************************************************************
**** ****
** **
TaskDummy()
Doesn't do anything. Is used in mode 1 only so that up to
8 events can be eligible at one time, and can therefore
light up 8 LEDs on the bargraph. I.e. in mode 1 there is
always 1 eligible task, and often more than 1, up to 8.
In mode 2 this task is stopped.
** **
**** ****
************************************************************/
void TaskDummy( void )
{
for (;;)
OS_Yield(TaskDummy1);
}
/************************************************************
**** ****
** **
TaskRandom()
In mode 1, the task(s) context-switches a semi-random number
of times, based on the upper bits of Timer 1. Then it delays
itself for a random time based on Timer 0.
In mode 2, tasks 1-5 wait on a particular semaphore. Once
the semaphore has been signalled, the LED corresponding to
the task is flashed for 20ms. Task 6 signals a random
semaphore based on Timer1, and then also flashes its LED.
The tasks wait with a pseudo-random timeout.
This is pretty funky. Six different tasks use this task
structure -- taskIDs 1-5 are tasks that wait for a particular
semaphore, and taskID 6 signals (semi-randomly) a semaphore.
Task 1 waits for semaphore 1
Task 2 waits for semaphore 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -