📄 demo1_opex.c
字号:
///////////////////////////////
// demo1_opex.c
// (C) 2004 Steve Childress stevech@san.rr.com
// See main(), below. It begins here.
#include "OPEX.h"
void OW_test_main(OPEX_TCB *);
void DS1820(OPEX_TCB *);
extern OPEX_TCB *schedQ, *flagwaitQ, *pendingQ;
extern unsigned int _stack_watch; // see Timerv1.c
// for the ATmega32
#define JMPBOOT "jmp 0x3c00" // boot in mega32
/////////////////////////////////////////////////////////////////////////////
void usart_init(void);
void io_init(void);
void timer_init(void);
///////////////////////////////////
char StringBuf1[128]; // global scratch buffer for string work
BYTE reporting; // flag
BYTE mcusr; // MCUSR at startup
//////////////////////////////////////
// LED blinker
void led_toggle(BYTE bitmask)
{
PORTC ^= bitmask; // PORTC has some LEDs
}
//////////////////////////////////////////////////
// the idle task. see OPEX_sched_setIdleFunc(&idle), below
//
void idle(void)
{
static unsigned long idlex;
static BYTE idlemark_sec;
//if (reporting) {
if (idlemark_sec != time.second) {
idlemark_sec = time.second;
OPEX_format_time(StringBuf1, &time);
OPEX_puts(StringBuf1);
sprintf_P(StringBuf1, PSTR(" calls per second to idle() = %lu "), idlex);
OPEX_putline(StringBuf1);
idlex = 0;
}
else {
++idlex; // a long
}
//}
}
/////////////////////////////////////
// debug tool. print report on OPEX_TCB passed
void report(OPEX_TCB *f)
{
if (reporting) {
if (f != NULL) {
OPEX_format_time(StringBuf1, &time); // show current time
OPEX_puts(StringBuf1);
OPEX_sched_showQitem(f, StringBuf1, 0); // show function status
}
}
}
/// SCHEDULED ///////////////////////
// A task to display task queue then quit
void task_showQ(OPEX_TCB *me)
{
int n;
n = (unsigned int)me->pinfo; // parent task can set this flag
OPEX_sched_show_mem(StringBuf1, RAMEND); // memory statistics (RAMEND is in io.h of AVR includes
OPEX_sched_showQ(StringBuf1, (BYTE)n); // do the command
OPEX_sched_quit();
}
// SCHEDULED ///////////////////////////////////////////////
// This task schedules itself to run the next time time changes
// to/from daylight saving.
// If time is changed via host command, this prog is resched to run right now.
void OPEX_sched_showQitem(OPEX_TCB *f, char *p, char showflags);
void DST_monitor(OPEX_TCB *me)
{
int dst;
if (OPEX_daylight_saving_adjust()) // possibly adjust time of day
OPEX_sched_time_changed(); // time did change, tell scheduler
dst = OPEX_is_daylight_saving(); // get current DST status 1 = DST, 0 = Standard
me->state = dst; // just FYI
OPEX_sched_showQitem(me, StringBuf1, 1);
// now determine when to run this again
OPEX_daylight_saving_changes_at(0, &me->when); // get ending DST date for DST this year
// run this only if not now in DST. In DST, the next time to run was set in the code above
if (!dst) { // not in DST now
--me->when.hour; // DST ends at 1AM standard time
if (OPEX_compare_dt(&time, &me->when) >= 0) { // if date/time is >= end of DST
++me->when.year; // so no more DST this year
OPEX_daylight_saving_changes_at(1, &me->when); // get starting date for DST NEXT year
}
else
OPEX_daylight_saving_changes_at(1, &me->when); // get starting date for DST this year
}
OPEX_sched_showQitem(me, StringBuf1, 1);
// The next desired time for this task to run is in the OPEX_TCB (*me)
}
// SCHEDULED ///////////////////////////////////////////////
// spawn a task to do a brief mode display of the scheduler's queues
// thus, task0 will appear in the queue.
// reschedule myself to run again later
void task0(OPEX_TCB *me)
{
OPEX_TCB *f;
report(me);
if ((f = OPEX_sched_new(&task_showQ, NULL)) != NULL) // schedule this to run then quit
f->pinfo = (void *)1; // set flag = brief mode
OPEX_sched_resched(me, 0, 0, 0, 15, 0); // run me again later
}
// SCHEDULED ///////////////////////////////////////////////
void task1(OPEX_TCB *me)
{
led_toggle(1); // toggle LED every second
report(me);
OPEX_sched_now(me); // get current time
me->when.tick = 0; // tick could be non-zero if this ran a little late
OPEX_date_add( &me->when, 0, 0, 0, 1, 0); // run again in one second
}
// SCHEDULED ///////////////////////////////////////////////
void task2(OPEX_TCB *me)
{
led_toggle(2); // toggle LED eacah time run
report(me);
//now(&me->when);
me->when.tick = 0; // not really needed, but shows if tardy
OPEX_date_add(&me->when, 0, 0, 0, rand() % 10, 0); // random seconds mod 10 later
me->when.tick = TicksPerSecond/2; // on the half second
}
// SCHEDULED ///////////////////////////////////////////////
// each time this runs, it creates a new task then quits.
char task3name[10];
BYTE task3num;
void task3(OPEX_TCB *me)
{
OPEX_TCB *f;
char oldname[sizeof(task3name)];
led_toggle(4); // toggle LED eacah time run
//report(me);
//OPEX_sched_showQ(StringBuf1);
memcpy(oldname, me->name, sizeof(oldname)); // get copy of old task name
sprintf_P(task3name, PSTR("TASK3-%d"), (int)(++task3num));
f = OPEX_sched_new(&task3, task3name); // make a new task
f->when.tick = 0; // not really needed, but shows if tardy
// days hrs mins secs ticks
OPEX_sched_resched(f, 0, 0, 0, 5, 0); // change when it will first run
sprintf_P(StringBuf1, PSTR("%s Quitting, %s started"), oldname, f->name);
OPEX_putline(StringBuf1);
OPEX_sched_quit(); // abandon this task
}
struct MYINFO { // used by task3
BYTE status;
DATE_TIME mark;
};
// SCHEDULED ///////////////////////////////////////////////
// first time run, this task adds a user data structure on
// the OPEX_TCB.
// Each time it's run thereafer, it shows the noted time and
// an incrementing state counter
// the user data also carries a counter called "state" which is shown.
void task4(OPEX_TCB *me)
{
struct MYINFO *myinfo; // lotta stack space for this
led_toggle(8); // toggle LED eacah time run
if (me->pinfo == 0) { // check if first time called since instantiated
myinfo = (void *) OPEX_malloc(me, sizeof(struct MYINFO)); // get added user memory space
////myinfo = (void *) malloc(sizeof(struct MYINFO)); // get added user memory space
me->pinfo = myinfo;
myinfo->status = 0; // initialize the state counter of this instance
OPEX_now(&myinfo->mark); // remember when I first ran
////OPEX_sched_malloc(me, 32); // get some RAM, to test OPEX_sched_free, ignore return
}
report(me); // show that I ran
myinfo = me->pinfo;
// print out my name, state counter, and date/time of the "first ran at mark"
sprintf(StringBuf1, "%s status=%d mark: ", me->name, (int)(myinfo->status++));
OPEX_puts(StringBuf1);
OPEX_format_date_time(StringBuf1, &myinfo->mark);
OPEX_putline(StringBuf1);
// reschedule me to run later
OPEX_sched_now(me); // get current time and add some to it
OPEX_date_add( &me->when, 0, 0, 0, 30, TicksPerSecond/2); // again in x seconds and 1/2 sec)
}
// SCHEDULED ///////////////////////////////////////////////
BYTE task5count = 0;
void task5(OPEX_TCB *me)
{
OPEX_TCB *f;
led_toggle(0x10); // toggle LED eacah time run
report(me);
if (task5count == 0) {
while (task5count < 3) {
f = OPEX_sched_new(&task5, "Task5x");
f->pinfo = (void *) (int) task5count;
OPEX_sched_resched(f, 0, 0, 0, 5+task5count, 0); // run n seconds from now
++task5count;
}
}
else {
task5count--;
OPEX_sched_quit();
}
OPEX_sched_resched(me, 0, 0, 0, 30, 0);
}
// SCHEDULED ///////////////////////////////////////////////
// this runs once per clock tick, unless the serial port is blocking
// due to buffer full oun output from other tasks.
// every 2 seconds worth of ticks, it reports. So check time between reports = 2sec
void task6(OPEX_TCB *me)
{
static BYTE task6n;
led_toggle(0x20); // toggle LED eacah time run
OPEX_sched_resched(me, 0, 0, 0, 0, 1);
if (--task6n == 0) {
task6n = TicksPerSecond*2;
report(me);
}
}
// SCHEDULED ///////////////////////////////////////////////
// runs when odd numbered bits in "task7_flags" change;
// the serial port monitor task toggles that flag when digits 0-7 come in from serial port.
BYTE task7_flags;
void task7(OPEX_TCB *me)
{
report(me);
sprintf_P(StringBuf1, PSTR("%s: flags are now 0x%X"), me->name, task7_flags);
OPEX_putline(StringBuf1);
OPEX_sched_on_flag(&task7_flags, 0xAA); // run this code again when certain bits change
}
////// SCHEDULED /////////////
// poll I/O bit for change in state, and debounce it assuming it's a pushbutton switch.
// Assume no interrupt is possible for this I/O, so must use polling.
// This also shows how to avoid additional static variables
// And, this is done as a finite state machine
#define task8bitno 0
void task8(OPEX_TCB *me)
{
BYTE b, n;
b = PINA & (1<<task8bitno); // get I/O bit state
n = TicksPerSecond/8; // default clock ticks to when this run again
switch ((int)me->pinfo) { // finite state machine
case 0:
cbi(DDRA, task8bitno); // make this bit an input
sbi(PORTA, task8bitno); // enable the pull-up resistor
me->pinfo = (void *)1; // am initialized, set finite state machine
break;
case 1:
me->flagmask = b; // note the state of the I/O pin
me->pinfo = (void *)2; // wait for a change of state
break;
case 2:
if (me->flagmask != b) { // has I/O bit changed state?
me->pinfo = (void *)3; // yes, check again soon for continued same bit
n = 1; // faster poll now
}
break;
case 3:
OPEX_puts(me->name); // display taskname
if (me->flagmask != b) { // still in changed state?
sprintf_P(StringBuf1, PSTR(" PORTA bit changed 0x%X"), b);
OPEX_putline(StringBuf1);
me->flagmask = b; // note new state
me->pinfo = (void *)2; // look for another change in bit
}
else {
OPEX_putline(" PORTA glitch ignored");
me->pinfo = (void *)2; // ignore too brief state change
break;
}
}
OPEX_sched_resched(me, 0, 0, 0, 0, n); // run again in x clock ticks
}
////// SCHEDULED /////////////
// poll I/O bit for change in state, and debounce it assuming it's a pushbutton switch.
// This task does the state machine as in Task 8 but by changing function pointers
// instead of the method in task8.
#define task9bitno 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -