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

📄 timer.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
字号:
//++
//timer.c - basic timer and time keeping functions
//
// Copyright (C) 2005 by Spare Time Gizmos.  All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA  02111-1307  USA.
//
//DESCRIPTION:
//   This routine uses the 8051's timer 2 to generate a periodic 20ms (that's
// 50Hz!) interrupt, and from that it derives several basic time keeping and
// delay functions.  Not all that exciting, really...
//
//   One thing which you might not expect, however, is that the timer interrupt
// also drives the user interface.  All push buttons and switches are polled by
// the timer interrupt code - this gives us a convenient way to debounce mech-
// anical switches (the 20ms timer tick interval automatically imposes a debounce
// interval), and it also makes it easy to differentiate short presses ("clicks")
// from a button that's held down for a while.
//
//REVISION HISTORY:
// dd-mmm-yy    who     description
// 30-May-05	RLA	New file.
// 12-Oct-05	RLA	Change TimerInterrupt() to PUBLIC for SDCC.
//--

// Include files...
#include <stdio.h>		// needed so DBGOUT(()) can find printf!
#include "standard.h"		// standard types - BYTE, WORD, BOOL, etc
#include "reg66x.h"		// declarations for Philips 89C66x processors
#include "player.h"		// project wide (hardware configuration) declarations
#include "timer.h"		// declarations for this module

// Local variables for this module...
PRIVATE volatile BYTE m_bOnceASecond;
PRIVATE volatile BYTE m_bDelayCounter;

//   This module implements a very simple clock in the form of a word that's
// incremented once a second.  It can count up to a maximum of 65536 seconds,
// or a little over 1000 minutes and is used to display the running time of
// the current MP3 file.  The g_fTimerRunning can be used to pause the timer
// - when g_fTimerRunning is FALSE the clock holds its current value.
//
//   Interacting with this clock/timer is so simple that there are no sub-
// routines for manipulating it; instead there are several macros in timer.h
// that look like subroutine calls.
PUBLIC volatile WORD g_wSecondsTimer;
PUBLIC bit g_fTimerRunning, g_fTimerChanged;


PUBLIC void TimerInterrupt (void) interrupt TIMER2_VECTOR
{
  //   The m_nDelayCounter is used by the WaitMS() routine to implement a
  // timed delay.  Anytime it is non-zero, we count it down...
  if (m_bDelayCounter != 0) --m_bDelayCounter;
  //   We decrement the once-a-second counter on every interrupt, and when
  // it reaches zero we can perform (what else?) the once a second code...
  if (--m_bOnceASecond == 0) {
    //   If the seconds clock/timer is running then increment it now.  Notice
    // that we're careful never to let this timer overflow and wrap around -
    // when it reaches the maximum count it simply stops there.
    if (g_fTimerRunning)
      if (g_wSecondsTimer != 0xFFFF) ++g_wSecondsTimer, g_fTimerChanged=TRUE;
    m_bOnceASecond = HERTZ;
  }
  //   The hardware doesn't clear the timer flag automatically, even in auto
  // reload mode, so if we don't do it we'll never come here again!
  TF2 = 0;
}


//++
//   This routine implements a programmable delay which is independent of the
// CPU speed (at least it will be if we've programmed the timer correctly!).
// The argument specifies the delay in milliseconds, however the resolution
// of the delay is the same as our timebase - HERTZ.  Thus a request for a
// 1 millisecond delay will actually wait for 20ms, assuming HERTZ == 50.
// A request for 105ms would wait for 120, and so on.  Note that the actual
// delay count we use is a BYTE value, so the maximum possible delay is
// 255*(1/HERTZ) or about 5.1 seconds at 50 HERTZ. 
//--
PUBLIC void DelayMS (WORD wDelay)
{
  ASSERT( (wDelay <= (255*(1000/HERTZ))), ("DelayMS: argument too large %u\n", wDelay) );
  //   Since m_bDelayCounter is a single byte value, there's really no need
  // to turn off interrupts here.  No matter how many instructions it may
  // take to evaluate this expression, the final step of assigning a value
  // to m_bDelayCounter is always atomic.
  m_bDelayCounter = (BYTE) ((wDelay+HERTZ-1)/HERTZ);
  //   Now just wait, with interrupts on, until the timer ISR counts m_bDelayCounter
  // down to zero...
  while (m_bDelayCounter != 0) ;
}


//++
//   This routine will configure timer 2 for periodic 20ms interrupts.  Timer
// two is especially convenient for this usage because it has a 16 bit auto-
// reload capability - such a long interval is beyond the range of timer 0 or 1
// with an automatic hardware reload.  You can reload timer 0 or 1 with software
// in the ISR, of course, but this is susceptible to timing deviations caused
// by interrupt latency.  Since timer 2 is reloaded automatically by hardware, 
// the interrupt can be delayed by an aribtrary time (so long as it occurs before
// the next tick!) without affecting the accuracy.
//
//   This routine enables timer 2 interrupts, but it does NOT set the global
// interrupt enable.  The clock will start running as soon as EA is set.
//--
PUBLIC void InitializeTimer (void)
{
  // Initialize module variables first...
  m_bOnceASecond = HERTZ;  m_bDelayCounter = 0;
  g_wSecondsTimer = 0;  g_fTimerRunning = FALSE;  g_fTimerChanged = FALSE;
  //   Initialize RCAP2 with the timer reload value (this is calculated from the
  // CPU oscillator frequency and the constant HERTZ) and the timer control reg-
  // isters.  Note that the "classic" 8051 timer counts once for every machine
  // cycle, which is 1/12 the CPU clock frequency.  The Philips high speed parts
  // are the similar, however in this case a machine cycle is 1/6th the clock.
  RCAP2H = HIBYTE(-(CPU_CLOCK/CPU_CLOCKS_PER_CYCLE/HERTZ));
  RCAP2L = LOBYTE(-(CPU_CLOCK/CPU_CLOCKS_PER_CYCLE/HERTZ));
  //  Every standard 8051 puts the interrupt enable bit for timer 2 in IE.5,
  // however for some reason Philips decided to use this bit for ES1 (second
  // serial port interrupt enable).  Philips parts have a second interrupt
  // enable register, IE1, which holds the timer 2 enable in IE1.0.  Fortunately
  // we don't have to worry about this since the REG66x.H header takes care of
  // defining ET2 correctly, but it's something to keep in mind if you port this
  // module to another processor.
  T2CON = 0;  T2MOD = 0;  TR2 = 1; ET2 = 1;
  DBGOUT(("Timer initialized at %buHz ...\n", (BYTE) HERTZ));
}

⌨️ 快捷键说明

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