⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 demo1_opex.c

📁 学完单片机就要使用实时系统在单片机上运行
💻 C
📖 第 1 页 / 共 2 页
字号:

void task9A(OPEX_TCB *);	// forward reference declarations
void task9B(OPEX_TCB *);
// state: initialize 
void task9(OPEX_TCB *me)
{
	// initialize port
	cbi(DDRA,  task9bitno); 	// make this bit an input
	sbi(PORTA, task9bitno); 	// enable the pull-up resistor
	me->state = (PINA & (1<<task9bitno)); 	// retain I/O bit state
	me->funcp = &task9A;		// change state
	OPEX_sched_resched(me, 0, 0, 0, 0, 1); // run next state on next tick
}
///////////////////////
// state: periodic poll and look for change on I/O bit
void task9A(OPEX_TCB *me)
{
	BYTE b;	
	
	b = (PINA & (1<<task9bitno)); 	// get I/O bit state
	if (b != me->state) {  		// has bit changed yet?
		me->funcp = &task9B;  	// yes, change state
		OPEX_sched_resched(me, 0, 0, 0, 0, 1); // run next state on next tick
	}
	else // bit is unchanged
		OPEX_sched_resched(me, 0, 0, 0, 0, TicksPerSecond/8); // run task9A again leisurely rate
}
///////////////////////
// state: if bit is same as prior to delay from state 9A, it's changed.
//        if bit is different than prior to delay, it was a debounce glitch
void task9B(OPEX_TCB *me)
{
	BYTE b;
	
	b = (PINA & (1<<task9bitno));	// get the I/O
	OPEX_puts(me->name); // display taskname
	if (b != me->state)  { // is bit still changed?
		me->state = b; 	// retain I/O bit state
		sprintf_P(StringBuf1, PSTR(" PORTA bit changed 0x%X"), b);
		OPEX_putline(StringBuf1);
	}
	else  {
		OPEX_putline(" PORTA glitch ignored");
		OPEX_sched_resched(me, 0, 0, 0, 0, 8); // run task9A again more leisurely rate
	}
	me->funcp = &task9A;  // next state is
	OPEX_sched_resched(me, 0, 0, 0, 0, TicksPerSecond/8); // run task9A again more leisurely rate
}

//////////////////////////////////////////////////
//////////////////////////////////////////////////
//// Scheduled /////
void show_named_task(OPEX_TCB *me)
{
	char taskname[32];
		
	if (me->pinfo == NULL)  { // NULL if this was just launched
		me->pinfo = (void *)1;
		OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) );  // run this func again when another nl comes in
	}
	else  {
		OPEX_puts_P(PSTR("find named task: "));
		OPEX_putline(taskname);
		if (OPEX_gets(taskname, sizeof(taskname), 0) > 1)	// if not an empty line
			report(OPEX_sched_get_named(taskname));
		OPEX_sched_quit();
	}
}



// SCHEDULED ///////////////////////////////////////////////
// monitor the serial port incoming for a 1 char cmd
// this one looks ever second or so for a certain char
//
// This task runs each time a single character arrives on the serial port.
// when a particular character arrives, via the switch statement below,
// various actions are taken.
// when a 'd' is received, the task for the function host_cmd2() is launched, then this task quits.
// The host_cmd2() task sleeps until a carriage return comes in, signifying the end of the d command's 
// data has arrived. Then the d command (set date/time) is processed. Then this command, host_cmd1() is
// relaunched by host_cmd2();
// This technique yields non-blocking I/O and assures fast executing, without polling.
//
void host_cmd1(OPEX_TCB *me)
{
	void host_cmd2(OPEX_TCB *);  // declare  reference to this function
	void echotest(OPEX_TCB *);  // ditto
		
	OPEX_TCB *f, *f1;
	char c[1];
	BYTE b;	
	
	
	//report(me);
	
	while(OPEX_peek(c, 0) != 0)   {  // inspect all newly arrived chars
		// input the char and take action
		OPEX_getc(c);	// get from FIFO (peekc above said there's >=1 chars waiting)
		switch (c[0])  {
			case '$':  		// jump to bootstrap code 
					//save_date();
					OPEX_putline_P(PSTR(JMPBOOT));
					while (serial_get_txIE());	// let serial output finish
						;
					cli();
					asm(JMPBOOT);
					break;
			case 'd':  // host set date command. Give the serial port to the command processor
						// this will read the rest of the command line, up to a CR
					OPEX_sched_new(&host_cmd2, "host_cmd2"); // do the command
					OPEX_sched_quit();  // stop checking chars, host_cmd2 will restart me
					break;  // never gets here
			case 'e': // echo serial test
					OPEX_sched_new(&echotest, "echotest2"); // do the command
					OPEX_sched_quit();  // stop checking chars, host_cmd2 will restart me
					break;  // never gets here				
			case 'K':	// kill all tasks
					while (flagwaitQ != NULL) //kill those in this queue
						OPEX_sched_kill(flagwaitQ);
					f = schedQ;		// kill all but me in the sched time sorted queue
					f = f->next; // skip this task (me)
					while (f)  {
						f1 = f->next;  
						OPEX_sched_kill(f);
						f = f1;
					}
					OPEX_sched_quit();  // now I quit
					break;					
			case 'k':  // kill all tasks except this one
					while (flagwaitQ != NULL) 
						OPEX_sched_kill(flagwaitQ);
					f = schedQ;  // kill all but me in the sched time sorted queue
					f = f->next; // // skip this task (me)
					while (f)  {
						f1 = f->next;  
						OPEX_sched_kill(f);
						f = f1;
					}
					break;  // leave me running
			case 'm':
					sprintf_P(StringBuf1, PSTR("Startup MCUSR=0x%X"), mcusr);
					OPEX_putline(StringBuf1);
					OPEX_sched_show_mem(StringBuf1, RAMEND); // do the command
					break;	
			case 'n':
					OPEX_sched_new(&show_named_task, NULL);
					break;
			case 'q':  // brief  display
					f = OPEX_sched_new(&task_showQ, NULL); // do the command as a separate task, NULL name
					f->pinfo = (void *)1; // set brief mode flag
					break;
			case 'Q':  // verbose display
					f = OPEX_sched_new(&task_showQ, NULL); // do the command as a separate task, NULL name
					f->pinfo = NULL; // set brief mode flag
					//OPEX_sched_showQ(StringBuf1, 0);  // do the command
					break;
			case 'r':  // toggle reporting of task executions on/off
					reporting ^= 1;
					break;
			case 't': // test daylight savings (US times, change if EU)
					if (OPEX_is_daylight_saving())  {
						cli();
						OPEX_daylight_saving_changes_at(0, &time); // get ending DST date for DST this year
						--time.hour; time.minute = 59; time.second = 30;  // just before that time
						sei();
					}
					else {
						cli();
						OPEX_daylight_saving_changes_at(1, &time); // get starting DST date for DST this year
						--time.hour; time.minute = 59; time.second = 30;  // just before that time
						sei();
					}
					OPEX_daylight_saving_adjust();
					OPEX_sched_time_changed();  // inform all tasks of change - also gets dst monitor task 
					break;
			case 'x':
					OPEX_sched_new(&OW_test_main, "OW_Test");
					break;
			case 'y':
					OPEX_sched_new(&DS1820, "DS1820");
					break;		
			case '0':  // these toggle flag bits for test7
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
					b = (BYTE) (c[0] & 7);  // key typed is the binary bit #
					// for digit b (0 to 7) received, toggle flag bit b
					// task 7 runs when any odd bit # changes (task 7's mask is 0xAA)
					//				  flag pointer, bit number,  new value
					OPEX_sched_change_flag( &task7_flags, b, ( (task7_flags & (1 << b)) ) ? 0 : 1 );
					break;			
			default:
					break;					
		}  // switch
	}  // while
	// run this func again later when a character arrives on serial port
	OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_ANY) );
}





// SCHEDULED ///////////////////////////////////////////////
//    Parse the received string and set the date/time or just print same. Then quit.
//
void host_cmd2(OPEX_TCB *me)			
{
	int mo, d, y, h, m, s, gmt_offset;

	if ( (OPEX_sched_flags & (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR)) == 0)
		// wait for CR received flag to come on, or it may already be on
		OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) ); 
	 	// the above OPEX call does not return, it reschedules this function upon receipt of CR
	 	
	// ??? this has a possible race condition with the ISR
	OPEX_sched_flags &= ~(1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR); 
		
	// read in a line of text which has arrived with a CR
	d = OPEX_gets(StringBuf1, 63, 0);	// get line of text from serial port, no wait, clears the flag bit
 	// process the received line of text
	if (strlen(StringBuf1) >1)  { 
		if (sscanf_P(StringBuf1, PSTR("%d %3s %d/%d/%d %d:%d:%d"), // valid format?
						&gmt_offset, &StringBuf1, &d, &mo, &y, &h, &m, &s) == 8) 
			{ 
			y %= 100; // oh well, assume century 20xx
			GMT_offset_standard = (int8_t)gmt_offset; // <<< offset for STANDARD time, no matter DST
			OPEX_date_stuff(&time, (BYTE)y, (BYTE)d, (BYTE)mo, (BYTE)h, (BYTE)m, (BYTE)s , 0);
			save_date();	// save to EEPROM
			OPEX_daylight_saving_adjust();
			OPEX_sched_time_changed();  // inform all tasks of change - also gets dst monitor task
			}
		else  { // invalid format
			sprintf_P(StringBuf1, PSTR("Err, e.g.:-8 Sun mm/dd/yy hh:mm:ss"));
			OPEX_putline(StringBuf1);
		}  
	}
	OPEX_sched_new(&host_cmd1, "host_cmd1");  // restart single char cmd processor
	OPEX_sched_quit();
} 


// Echo line of test to serial port - test/demo
// see 'e' command in host_cmd1
void echotest(OPEX_TCB *me)
{
	switch (me->state)  {
		case 0:
			OPEX_putline_P(PSTR("Enter text and CR - not echoed"));	
			me->state = 1;	
			OPEX_sched_on_flag(&OPEX_sched_flags, (1<<OPEX_sched_FLAGBIT_SERIAL_RECEIVED_CR) );			
			// the above line of code causes this func to run again when CR is received
			break; // never gets here
		case 1:
			OPEX_gets(StringBuf1, 63, 0); // get string, no wait
			OPEX_putline(StringBuf1);
			OPEX_sched_new(&host_cmd1, "host_cmd1");  // restart single char cmd processor
			OPEX_sched_quit();
	}
}


//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// MAIN ///
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////


int main(void)
{
	char *p;

	
	mcusr = MCUSR;  // retain cause of reset
	MCUSR = 0;		// reset causes
	
	io_init();		// see AVR_dependent for these...
	timer_init();
	serial_init();
	
	OPEX_com_init();		// init OPEX serial I/O
	
	//Global interrupt enable
	sei();
	OPEX_putline_P(PSTR("\r\nRESET"));
	
	OPEX_init_dateTime();	// set OPEX date and time defaults

	reporting = 1;

	// top level 
	for ( ;; )  {
		_stack_watch = 0xffff;
		// initialization - 
		while (OPEX_getc(StringBuf1) != 0)  // purge left over serial data if any
			;
		OPEX_putline_P(PSTR("\r\n\nLaunching"));

		OPEX_sched_setIdleFunc(&idle);		// establish an idle user task
		
		// launch recurring tasks (the if expressions are in case one fails to launch due to malloc()
		// non of these execute until all are launched	
		if ( 
					(OPEX_sched_new(&DST_monitor, (p = "DST")) == NULL)
				||	(OPEX_sched_new(&host_cmd1, (p = "Host_Cmd1")) == NULL)
				||	(OPEX_sched_new(&task0, (p = "TASK0")) == NULL)
				||	(OPEX_sched_new(&task1, (p = "TASK1")) == NULL)   
				||	(OPEX_sched_new(&task2, (p = "TASK2")) == NULL)  
				||	(OPEX_sched_new(&task3, (p = "TASK3")) == NULL)   
				||	(OPEX_sched_new(&task4, (p = "TASK4")) == NULL) 	
				||	(OPEX_sched_new(&task5, (p = "TASK5")) == NULL) 	
				||	(OPEX_sched_new(&task6, (p = "TASK6")) == NULL) 
				||	(OPEX_sched_new(&task7, (p = "TASK7")) == NULL)
				||	(OPEX_sched_new(&task8, (p = "TASK8")) == NULL)
				||	(OPEX_sched_new(&task9, (p = "TASK9")) == NULL)
				//||	(OPEX_sched_new(&DS1820, (p = "DS1820")) == NULL)
			)
		  	{
				sprintf_P(StringBuf1, PSTR("OPEX_sched_new err on %s"), p);
				OPEX_putline(StringBuf1);
			}
		else  { // all launched successfully, so start scheduler
			OPEX_putline_P(PSTR("Starting Scheduler") );
			OPEX_sched_start();	// returns when all tasks quit, just start up again	
			OPEX_putline_P(PSTR("Scheduler returned!") );
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -