軟定時器實驗
一.實驗目的
本程序展示了Small RTOS51 中使用一個任務實現多個軟定時器管理,軟定時器的精度
達到1 個系統節拍。
二.設備及器件
IBM PC 機 一臺
DP-51PROC 單片機綜合仿真實驗儀 一臺
三.實驗步驟
1. 將A2 區的A0~A2 分別連接到B3 區的A0~A2。
2. 將A2 區的P10 連接到B3 區的RST。
3. 將A3 區的Y0 連接到B3 區的/CS。
4. 將A2 區的A15~A10 分別連接到A3 區的相關控制引腳,如下:
A15 --- /G2B
A14 --- /G2A
A13 --- G1
A12 --- C
A11 --- B
A10 --- A
5. 在B3 區的J92 插入圖形液晶模塊(單色,128×64 點)。
6. 將B3 區的J85 短接,A3 區的JP4 短接。
四.實驗參考程序主要部分
/**********************************************************
** Small RTOS(51)
** The Real-Time Kernel(For Keil c51)
** (c) Copyright 2002-2002, chenmingji
** All Rights Reserved
** V1.20
**************************************************************/
#include "config.h"
uint8 TimeAdd[4]; //時間計數,用于紀錄從復位以來的時間
void TimeSum(void);
/**********************************************************
** 函數名稱: main
** 功能描述: 主函數,用戶程序從這里執行
**********************************************************/
void main(void)
{
OSInit();
TMOD = (TMOD & 0XF0) | 0X01;
TH0 = (65536 - (11059200 / 12) / 100) / 256;
TL0 = (65536 - (11059200 / 12) / 100) % 256;
TR0 = 1;
ET0 = 1;
TF0 = 0;
OSSemCreate(ZL12864_SEM, 1);
LCM_DispIni();
OSDispClr();
OSTaskCreate(TimeSum, NULL, 0);
OSTaskCreate(SoftTimer, NULL, 1);
while(1)
{
PCON = PCON | 0x01; /* CPU 進入休眠狀態 */
}
}
/**********************計時*************************/
void SoftTimerFunction2(void);
/*******************************************************
** 函數名稱: SoftTimerFunction1
** 功能描述: 軟定時器0 運行的任務,與軟定時器1 配合使LCD 顯示的“:”閃爍
********************************************************/
void SoftTimerFunction1(void)
{
OSDispChar(3, 7, ':');
SoftTimerRun(1,(OS_TICKS_PER_SEC + 1) / 2,SoftTimerFunction2);
}
/*********************************************************
** 函數名稱: SoftTimerFunction2
** 功能描述: 軟定時器1 運行的任務,與軟定時器0 配合使LCD 顯示的“:”閃爍
***********************************************************/
void SoftTimerFunction2(void)
{
OSDispChar(3, 7, ' ');
SoftTimerRun(0,OS_TICKS_PER_SEC / 2,SoftTimerFunction1);
}
/************************************************************
** 函數名稱: SoftTimerFunction3
** 功能描述: 軟定時器2 運行的任務,與任務TimeSum 配合使LCD 顯示閃爍
*************************************************************/
void SoftTimerFunction3(void)
{
OSDispChar(3, 5, ' ');
OSDispChar(3, 6, ' ');
OSDispChar(3, 8, ' ');
OSDispChar(3, 9, ' ');
SoftTimerRun(2,OS_TICKS_PER_SEC * 4,SoftTimerFunction3);
}
/**************************************************************
** 函數名稱: TimeSum
** 功能描述: 記錄復位以來的時間的任務
***********************************************************/
void TimeSum(void)
{
/* 初始化軟定時器模塊 */
InitSoftTimer();
/* 運行兩個軟定時器 */
SoftTimerRun(1,OS_TICKS_PER_SEC / 2,SoftTimerFunction2);
SoftTimerRun(2,OS_TICKS_PER_SEC * 4
+ OS_TICKS_PER_SEC / 2,SoftTimerFunction3);
OSDispChar(3, 7, ':');
while (1)
{
OSDispChar(3, 5, TimeAdd[0] + '0');
OSDispChar(3, 6, TimeAdd[1] + '0');
OSDispChar(3, 8, TimeAdd[2] + '0');
OSDispChar(3, 9, TimeAdd[3] + '0');
OSWait(K_TMO,OS_TICKS_PER_SEC);
/* 計時并顯示 */
TimeAdd[3]++;
if (TimeAdd[3] >= 10)
{
TimeAdd[3] = 0;
TimeAdd[2]++;
if (TimeAdd[2] >= 6)
{
TimeAdd[2] = 0;
TimeAdd[1]++;
if (TimeAdd[1] >= 10)
{
TimeAdd[1] = 0;
TimeAdd[0]++;
if(TimeAdd[0] >= 10)
{
TimeAdd[0] = 0;
}
}
}
}
}
}
SoftTimer. c 文件源代碼
#define IN_SOFT_TIMER
#include "config.h"
/* 軟定時器的數據結構 */
typedef SOFT_TIMER_MEM_SEL struct _TySoftTimerData
{
uint8 Falg; /* 軟定時器狀態 */
uint16 DelayTime; /* 軟定時器運行時間 */
void (const * Fuction)(void); /* 軟定時器溢出調用的函數 */
};
#if MAX_SOFT_TIMER > 0
uint16 SoftTimerCnt; /* 輔助定時器 */
uint16 SoftTimerThisDelay; /* 輔助定時器初始值 */
struct _TySoftTimerData SOFT_TIMER_MEM_SEL SoftTimerData[MAX_SOFT_TIMER];
/**********************************************************
** 函數名稱: SoftTimerSum
** 功能描述: 每次系統節拍處理時調用的函數,一個輔助定時器
******************************************************************/
void SoftTimerSum(void)
{
if( --SoftTimerCnt == 0)
{
OSIntSendSignal(SOFT_TIMER_TASK_ID);
}
}
/**************************************************************
** 函數名稱: InitSoftTimer
** 功能描述: 初始化軟定時器模塊
************************************************************/
void InitSoftTimer(void)
{
uint8 i;
OS_ENTER_CRITICAL();
for (i = 0; i < MAX_SOFT_TIMER; i++)
{
SoftTimerData[i].Falg = 0;
SoftTimerData[i].DelayTime = 0;
SoftTimerData[i].Fuction = NULL;
}
OS_EXIT_CRITICAL();
}
/*****************************************************************
** 函數名稱: SoftTimerRun
** 功能描述: 運行一個軟定時器
** 輸 入: Index:軟定時器的索引
** Delay:延時時間
** Fuction:定時器溢出執行的函數
** 輸 出: NOT_OK:參數錯誤
** SOFT_TIMER_OK:操作正確
*********************************************************/
uint8 SoftTimerRun(uint8 Index, uint16 Delay, void (const * Fuction)(void))
{
#if EN_SOFT_TIMER_CHK > 0
if (Index >= MAX_SOFT_TIMER)
{
return NOT_OK;
}
#endif
if (Delay != 0 && Fuction != NULL)
{
OS_ENTER_CRITICAL();
SoftTimerData[Index].Fuction = Fuction;
SoftTimerThisDelay -= SoftTimerCnt;
SoftTimerCnt = 0;
SoftTimerData[Index].DelayTime = Delay + SoftTimerThisDelay;
SoftTimerData[Index].Falg &= ~SOFT_TIMER_TIMER_OUT;
SoftTimerData[Index].Falg |= SOFT_TIMER_TIMER_RUN;
OS_EXIT_CRITICAL();
OSSendSignal(SOFT_TIMER_TASK_ID);
return SOFT_TIMER_OK;
}
else
{
return NOT_OK;
}
}
/*********************************************************
** 函數名稱: SoftTimerStop
** 功能描述: 停止一個正在運行的軟定時器
** 輸 入: Index:軟定時器的索引
** 輸 出: NOT_OK:軟定時器不存在
** SOFT_TIMER_OK:操作成功
** 全局變量: SoftTimerData
** 調用模塊: OS_ENTER_CRITICAL(),OS_EXIT_CRITICAL()
************************************************************/
uint8 SoftTimerStop(uint8 Index)
{
#if EN_SOFT_TIMER_CHK > 0
if (Index >= MAX_SOFT_TIMER)
{
return NOT_OK;
}
#endif
OS_ENTER_CRITICAL();
SoftTimerData[Index].DelayTime = 0;
SoftTimerData[Index].Fuction = NULL;
SoftTimerData[Index].Falg &=
~(SOFT_TIMER_TIMER_OUT | SOFT_TIMER_TIMER_RUN);
OS_EXIT_CRITICAL();
return SOFT_TIMER_OK;
}
/***************軟定時器任務***************************************/
/****************************************************************
** 函數名稱: SoftTimer
** 功能描述: 軟定時器管理任務
***************************************************************/
void SoftTimer(void)
{
uint16 ThisDelay;
uint8 i;
SoftTimerCnt = 0;
while (1)
{
OS_ENTER_CRITICAL();
// 找到定時最短的定時器
ThisDelay = -1;
for (i = 0; i< MAX_SOFT_TIMER; i++)
{
if (SoftTimerData[i].DelayTime != 0 &&
SoftTimerData[i].DelayTime < ThisDelay)
{
ThisDelay = SoftTimerData[i].DelayTime;
}
}
// 計算等待時間
if (ThisDelay > -SoftTimerCnt)
{
SoftTimerCnt += ThisDelay;
}
else
{
SoftTimerCnt = 1;
}
SoftTimerThisDelay = ThisDelay;
OSWait(K_SIG,0);
ThisDelay = SoftTimerThisDelay;
// 查詢定時到的軟定時器
for (i = 0; i < MAX_SOFT_TIMER; i++)
{
SoftTimerData[i].Falg &= ~SOFT_TIMER_TIMER_OUT;
if (SoftTimerData[i].DelayTime != 0)
{
if (SoftTimerData[i].DelayTime <= ThisDelay)
{
SoftTimerData[i].DelayTime = 0;
if (SoftTimerData[i].Fuction != NULL)
{
SoftTimerData[i].Falg |= SOFT_TIMER_TIMER_OUT;
}
}
else
{
SoftTimerData[i].DelayTime -= ThisDelay;
}
}
}
SoftTimerThisDelay = 0;
OS_EXIT_CRITICAL();
// 執行軟定時器指定的任務
for (i = 0; i < MAX_SOFT_TIMER; i++)
{
if (((SoftTimerData[i].Falg & SOFT_TIMER_TIMER_OUT) != 0) &&
(SoftTimerData[i].Fuction != NULL))
{
SoftTimerData[i].Falg &= ~SOFT_TIMER_TIMER_OUT;
SoftTimerData[i].Fuction();
}
}
}
}
#endif
五.實驗例程簡析
本軟件定時器所使用的存儲空間由程序自己分配,并通過一個唯一的索引(即序號)
來表示每一個軟定時器。由于軟定時器執行的任務時間等因素不確定,所以一般把這個任務
優先級定得比較低(表示任務的優先權越高)。
要使用軟定時器模塊,首先需要初始化軟定時器模塊。這是由調用函數InitSoftTimer( )
實現的。初始化后,就可以調用函數SoftTimerRun( )來運行一個軟定時器,或是調用函數
SoftTimerStop( )來停止一個定時器。
在模塊初始化之后,任務就可以調用函數SoftTimerRun( )運行一個軟定時器。
SoftTimerRun9( )有三個參數。第一個參數Index 用來指示使用的軟定時器;第二個參數Delay
用來設置定時器運行的時間,以系統時鐘節拍為單位,范圍大約是0~65000;第三個參數
Function 是一個函數指針,指向一個無參數、無返回值的函數,當軟定時器溢出時會調用這
個函數。圖5.1 為SoftTimerRun( )函數的偽流程圖。
為了提高程序的執行效率,程序沒有使用讓每一個時鐘節拍將每一個軟定時器的計數
值都減1 的方法。這種方法雖然簡單易懂,但會大量消耗CPU 時間。而且,由于軟定時器
引入了不確定的函數,為了避免這些不確定的函數對系統造成大的影響,軟定時器管理任務
的優先級比較低。這樣,當每個系統節拍都需要處理每一個軟件定時器時,如果高優先級的
任務運行時間超過一個時鐘節拍,則軟定時器就會出現誤差,且誤差會積累。本程序使用一
個輔助減計數器來減少這些負面影響。軟定時器管理任務首先要查找這些軟定時器中等待時
間最短的,然后將它的等待值賦予輔助減計數器。輔助減計數器每個系統節拍都減一,且與
系統時鐘節拍處理函數一起執行。當輔助減計數器溢出時通知軟定時器管理任務,軟定時器
管理任務再進行其他處理。輔助減計數器的代碼見函數SoftTimerSum ( )。
圖5.2 為軟定時器處理任務的流程圖。
評論
查看更多