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

📄 eval_rtos.c

📁 C89c51 usb驱动程序,实现了usb转串口的功能,提供了一个虚拟的串口
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 **********************************************************************************
 *
 *  Project Name:  AT89C5131 MCU and Hi-Tech 8051 compiler evaluation
 *
 *  File Name:  eval_rtos.c
 *
 *  Copyright 2004++ by Michael J Bauer  [www.hotkey.net.au/~mjbauer/free_ip.htm]
 *
 *  Date Created: 2004.08.26
 *
 *  This source module contains a low-end embedded real-time kernel and I/O device
 *  drivers comprising a simple RTOS known as "ALERT".
 *
 *  So far as possible, hardware platform dependencies should be confined to this
 *  module and dedicated device driver modules (e.g. Atmel's USB library files).
 *
 **********************************************************************************
 */

#include "a89c5131.h"        /* MCU-specific definitions */
#include "intrpt.h"          /* Compiler-specific interrupt support defs (Hi-Tech C 8051) */
#include "eval_defs.h"       /* Eval common definitions (incl. RTOS defs) */
#include "usb_vuart_lib.h"   /* Atmel USB library defs */
#include "usb_drv.h"
#include "usb_cdc_enum.h"

const  char    kacCopyright[] = "ALERT RTOS copyright 2004++ M.J.Bauer ";

/***  globals  ***/

idata  uint8   gubTaskFlags;          /* Background task control/status flags */
idata  uint8   gubMiscFlags;          /* Misc. system control & status flags */
idata  uint16  gwSystemError;         /* System Error/Warning flags (16b)  */
idata  uint8   gbHCI_Stream;		  /* Determines HCI I/O data stream - USB or UART */

idata  struct  tDateTime  gsRTCbuf;          /* global RTC buffer for use by application */


/***  static variables private to this module ***/

static const uint8 kaubDaysinMonth[] =
		{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

static  idata  uint8   ubRxCount;           /* number of chars in host RX buffer */
static  idata  char  * pcRxTail;      	    /* RX ram buffer pointers */
static  idata  char  * pcRxHead;
static  idata  char    acRxFIFObuf[RXBUFSIZE];    /* UART receive buffer in low RAM */

static  idata  uint16  uwTickTimer;         /* General-purpose ticks timer (unit = 5mS) */
static  idata  struct  tDateTime  sRTC;     /* "live" RTC date-time registers */


/***
*   EEPROM page addresses -- see also  _defs.h
*/
far  uint8  habEEPROM_page0[128]  @ 0x0000;
far  uint8  habEEPROM_page1[128]  @ 0x0080;
far  uint8  habEEPROM_page2[128]  @ 0x0100;
far  uint8  habEEPROM_page3[128]  @ 0x0180;
far  uint8  habEEPROM_page4[128]  @ 0x0200;
far  uint8  habEEPROM_page5[128]  @ 0x0280;
far  uint8  habEEPROM_page6[128]  @ 0x0300;
far  uint8  habEEPROM_page7[128]  @ 0x0380;



/*************************  RTOS Initialisation routine  *********************************
*
*  Hardware devices and program variables not initialised by the asm startup module
*  are initialised here. The application environment and CLI are initialised elsewhere.
*
*/
void
initialise_rtos( void )
{
	CKCON0 |= BIT0;				/* Set MCU clock 'X2' mode */
	IPL0 = 0x12;                /* Set IRQ priorities (host UART = highest) */
	IPH0 = 0x11;

	Set_Bit( LEDCON, BIT3 );	/* Configure P3.3 as LED driver (green?) */
	Set_Bit( LEDCON, BIT5 );	/* Configure P3.5 as LED driver (red?)   */

#if DEBUG
	SetLEDoutput( LED_1, ON );    /*** Switch RED LED ON ***/
	for ( uwTickTimer = 0; uwTickTimer < 10000; uwTickTimer++ )
	{
		;	                      /* Delay to let user see red LED */
	}
	SetLEDoutput( LED_1, OFF );   /*** Switch RED LED OFF ***/
#endif

#if WATCHDOG_ENABLED
	WDTPRG = 2;                 /* Set WDT prescaler */
	service_watchdog();			/* Activate the 8051 on-chip watchdog timer */
#endif

	initialise_RTI_timer();
	initialise_uart();

	gsRTCbuf.year = 0;          /* Set RTC to "relative time" until set correctly */
	gsRTCbuf.month = 1;
	gsRTCbuf.day = 1;
	gsRTCbuf.dow = 6;
	gsRTCbuf.hour = 0;
	gsRTCbuf.min = 0;
	gsRTCbuf.sec = 0;

	set_RTC_date_time();		/* Default to Saturday 01/01/2000 00:00:00 */
	Set_Bit( gwSystemError, RTC_INVALID );

	ei();		/* Launch foreground -- Enable global interrupts */
}


/*****
*  	Watchdog service routine.  Enables and resets the watchdog timer.
*  	Called frequently from periodic background task, at intervals not exceeding 10 mSec.
*  	If the background process hangs somewhere, or if the RTI tick interrupt fails,
*	the watchdog will cause an MCU reset.
*/
void
service_watchdog( void )
{
	WDTRST = 0x1E;				/* Reset the watchdog timer */
	WDTRST = 0xE1;
}


/*****
*	RTI timer (8051 Timer T0) initialisation.
*  	Timer T0 is setup to generate a periodic interrupt. Tick interval = 5 mSec.
*
*	Timer clock freq (X1 mode), Fclk = Fosc/12 = 16/12 MHz = 1.333MHz.
*	Timer clock period (X1 mode), Tclk = 12/16 uS = 0.75uS.
*	Req'd RTI tick interval = 5mS = 5000uS/0.75 clocks = 6666 clocks => CLOCKS_PER_TICK.
*	(This number may need tweaking to compensate for Timer ISR processing overheads.)
*
*  	Called by:  initialise_rtos()
*  	Entry args: --
*  	Returns:    --
*  	Affects:    --
*
*/
void
initialise_RTI_timer( void )
{
	/* Install vector for Timer 0 interrupt service */
	ROM_VECTOR( 0x0B, Timer0_service );

	TCON = 0x00;								/* Stop the timer */
	TMOD = 0x01;								/* Set T0 to mode 1:  16-bit timer  */
	TH0 = HI_BYTE( 65535 - CLOCKS_PER_TICK );	/* Load timer registers */
	TL0 = LO_BYTE( 65535 - CLOCKS_PER_TICK );
	Set_Bit( IEN0, BIT1 );						/* Enable Timer 0 interrupt */
	Set_Bit( TCON, BIT4 );						/* Start the timer */
}


/*
*   8051 timer T0 service function -- calls the RTI "tick" handler.
*   Timer T0 is configured to interrupt every 5 milli-seconds;
*	(see "initialise_RTI_timer()")
*   Timer T0 overflow/INT flag (TCON<TF0>) is cleared automatically on vectoring to this ISR.
*/
interrupt
Timer0_service( void )
{
	Clear_Bit( TCON, BIT4 );					/* Stop the timer */
	TH0 = HI_BYTE( 65535 - CLOCKS_PER_TICK );	/* Reload timer registers */
	TL0 = LO_BYTE( 65535 - CLOCKS_PER_TICK );
	Set_Bit( TCON, BIT4 );						/* Restart the timer */
	RTI_Tick_Handler();
}


/*****
*	RTI_Tick_Handler
*
*	Function is called every 5 milliSec (=tick) from the Timer 0 interrupt service routine.
*	The real-time clock/calendar is maintained here.
*	Periodic background tasks are scheduled here.
*	Any other *brief* time-critical foreground tasks may be called from this function.
*/
void
RTI_Tick_Handler( void )
{
	static  idata  uint8  ubTicks;
	uint8   ubDaysintheMonth;
	bool    yLeapYear;
	bool    yRollSec = FALSE;
	bool    yRollDay = FALSE;

	uwTickTimer++ ;

	if ( ++ubTicks >= 200 )     /* This happens every second */
	{
		ubTicks = 0;
		yRollSec = TRUE;

		if ( ++sRTC.sec >= 60 )
		{
			sRTC.sec = 0;
			if ( ++sRTC.min >= 60 )
			{
				sRTC.min = 0;
				if ( ++sRTC.hour >= 24 )
				{
					sRTC.hour = 0;
					yRollDay = TRUE;
				}
			}
		}
	}
	if ( yRollDay )    /* This happens every day at midnight */
	{
		sRTC.dow++ ;
		if ( sRTC.dow >= 7 )  sRTC.dow = 0;		/* it must be Sunday */

		yLeapYear = ( sRTC.year % 4 == 0 && sRTC.year != 0 );
		if ( yLeapYear && sRTC.month == 2 )
			ubDaysintheMonth = 29;
		else
			ubDaysintheMonth = kaubDaysinMonth[sRTC.month];

		if ( ++sRTC.day > ubDaysintheMonth )
		{
			sRTC.day = 1;
			if ( ++sRTC.month > 12 )
			{
				sRTC.month = 1;
				if ( ++sRTC.year > 99 )     /* year is 2099 ! */
					sRTC.year = 0;
			}
		}
	}

	if ( Test_Bit( gubTaskFlags, TICKS_TASK ) )
		Set_Bit( gwSystemError, TICK_TASK_OVRUN );
	Set_Bit( gubTaskFlags, TICKS_TASK );     			  /* Invoke this background task every tick */
	
	if ( (ubTicks % 10) == 0 )   
	{
		if ( Test_Bit( gubTaskFlags, FIFTY_MSEC_TASK ) )
			Set_Bit( gwSystemError, FIFTYMS_TASK_OVRUN );
		Set_Bit( gubTaskFlags, FIFTY_MSEC_TASK );         /* Invoke this task every 50mSec (10 ticks) */
	}
	if ( yRollSec )
	{
		if ( Test_Bit( gubTaskFlags, SECONDS_TASK ) )
			Set_Bit( gwSystemError, SEC_TASK_OVRUN );
		Set_Bit( gubTaskFlags, SECONDS_TASK );			  /* Invoke this B/G task every second */
	}
	if ( yRollDay )
	{
		if ( Test_Bit( gubTaskFlags, NEWDAY_TASK ) )
			Set_Bit( gwSystemError, NEWDAY_TASK_OVRUN );
		Set_Bit( gubTaskFlags, NEWDAY_TASK );			  /* Invoke this B/G task every day at 00:00 */
	}

	LED_Refresh();
}


/*
*   get_ticks() is a general-purpose timing function.
*   It returns the value of a continuous free-running 16-bit timer "register", uwTickTimer,
*   which is incremented every tick (5mS) by the RTI timer service routine.
*   Because uwTickTimer is a 2-byte variable, RTI timer interrupts must be disabled while
*   the variable is being read.
*/
uint16
get_ticks( void )
{
	uint16  uwTicksNow;
	uint8   bIntStatus = IEN0;       // Save INT status register
	
	Clear_Bit( IEN0, BIT7 );         // Disable global INT
	uwTicksNow = uwTickTimer;        // Capture uwTickTimer
	IEN0 = bIntStatus;               // Restore INT status register
	return  uwTicksNow;
}


/*
*  Waits for a specified number of timer ticks (=arg1).
*  Background tasks will be executed as usual while waiting.
*  This function cannot be called from within the background process.
*  
*  Called by:  Command functions
*  Entry args: (uint16) uwDuration = time delay (ticks = mS x 5)
*  Returns:    void
*  Affects:    uwTickTimer (decremented by timer "tick" service routine)
*/
void
wait_ticks( uint16 uwDuration )
{
	uint16  wStartTime = get_ticks();
	
	while ( get_ticks() - wStartTime < uwDuration )
	{
		background_process();
	}
}



/*************************  REAL-TIME CLOCK FUNCTIONS  ******************************
*
*  Set the real-time clock registers from date/time values stored in the global
*  RTC buffer: gsRTCbuf, which must be setup before the call.
*  The process is repeated if the "live" RTC 'seconds' register rolls over
*  during the process, to ensure that the live data are not currupted by a timer
*  tick interrupt. One re-try should suffice, but the function will loop until
*  doomsday (i.e. until watchdog reset occurs) if necessary.
*
*  The day-of-the-week value is computed from the set date and time, based on 01/01/2000
*  being a Saturday (dow = 6) and the number of days passed since that day.
*/
void
set_RTC_date_time( void )
{
	uint8    bYear;
	uint16   wDaysPassed = 0;			/* Days passed since Saturday 01/01/2000 */

	do
	{
		sRTC.sec   = gsRTCbuf.sec;
		sRTC.min   = gsRTCbuf.min;
		sRTC.hour  = gsRTCbuf.hour;
		sRTC.day   = gsRTCbuf.day;
		sRTC.month = gsRTCbuf.month;
		sRTC.year  = gsRTCbuf.year;
	}
	while ( sRTC.sec != gsRTCbuf.sec );

	for ( bYear=0;  bYear < gsRTCbuf.year;  bYear++ )
	{
		wDaysPassed += days_in_whole_year( bYear );
	}
	wDaysPassed += day_of_this_year() - 1;
	sRTC.dow = (wDaysPassed + 6) % 7 ;        /***  DOW: 0==SUN, 1==MON, ... 6==SAT  ***/
}


/*
*  Read the "live" real-time clock registers into the global RTC buffer: gsRTCbuf.
*  The process is repeated if the "live" RTC seconds register rolls over
*  during the process, to ensure that the buffer's data are not currupted
*  by a timer tick interrupt.  One re-try should suffice.
*  The buffered RTC date/time is checked for validity;  if invalid,
*  the function returns FALSE, otherwise TRUE.
*/
bool
read_RTC_date_time( void )
{
	do
	{
		gsRTCbuf.sec   = sRTC.sec;
		gsRTCbuf.min   = sRTC.min;
	  	gsRTCbuf.hour  = sRTC.hour;
	  	gsRTCbuf.dow   = sRTC.dow;
	  	gsRTCbuf.day   = sRTC.day;
		gsRTCbuf.month = sRTC.month;
		gsRTCbuf.year  = sRTC.year;
	}
	while ( sRTC.sec != gsRTCbuf.sec );

	if ( ( gsRTCbuf.month > 12 )
	||   ( gsRTCbuf.month == 0 )
	||   ( gsRTCbuf.day   > 31 )
	||   ( gsRTCbuf.day   == 0 )
	||   ( gsRTCbuf.hour  > 23 )
	||   ( gsRTCbuf.min   > 59 )
	||   ( gsRTCbuf.sec   > 59 ) )
	{
		Set_Bit( gwSystemError, RTC_INVALID );
		return FALSE;
	}
	else  return TRUE;
}


/*****
*	Compute number of days in whole of year specified.
*
*	Arg(s):   (uint8) bYear = year in the range 0..99 (0 => 2000)
*	Returns:  366 if bYear is a leap year, else 365.
*/
uint16
days_in_whole_year( uint8 bYear )
{
	if ( bYear % 4 == 0 )  return 366;    /* It's a leap year */
	else  return 365;
}


/*****
*	Compute the 'day-of-year" number (1..366) for the date stored in the global date.time
*	structure, gsRTCbuf.
*
*	Returns:  Day-of-year, in the range 1..365, (1..366 if it's a leap year).
*/
uint16
day_of_this_year( void )
{
	uint8   bMonth;
	uint16  wResult = gsRTCbuf.day;
	bool    yLeapYear = ( gsRTCbuf.year % 4 == 0 );

	for ( bMonth = 1;  bMonth < gsRTCbuf.month;  bMonth++ )
	{
		if ( yLeapYear && bMonth == 2 )  wResult += 29;
		else  wResult += kaubDaysinMonth[bMonth];
	}
	return  wResult;
}



/****************************  UART I/O FUNCTIONS  **********************************
*
*   Async serial comms interface support routines (to suit AT89C5131 on-chip UART).
*   This firmware uses interrupt mode for received data only.
*   The UART provides a command/response comms link to the Host PC (or user terminal).
*
*	The internal Baud-rate register value (BRL) is selected by the formula:
*		BRL = 256 - BDCLKDIV,  where BDCLKDIV is the Baudrate clock divisor value...
*		BDCLKDIV = (Fosc / 2) / (16 * BAUD),  where BAUD is the required Baud rate,

⌨️ 快捷键说明

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