软定时器实验
一.实验目的
本程序展示了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 为软定时器处理任务的流程图。
评论
查看更多