📄 timerb.c
字号:
/*** BeginHeader */
#ifndef _TIMERB_FUNC_
#define _TIMERB_FUNC_
/*** EndHeader */
/* START LIBRARY DESCRIPTION *********************************************
timerb.lib
Generic TIMERB.
Support the following:
1. periodic call to user routine every timer int
2. supports times from about 15us to 1500 seconds with 11.0592mHz xtal (22.1 clock)
3. Note serial port baud rates <2700 effect timer, set up serial ports first
Interrupts faster than 20,000/sec start to become too much overhead for use
TimerBinit() must be called to initialize the ISR
assumes 11.0592mHz x2 crystal (CPU is 22.1mhz)
unless XTAL_FREQ is set to freq in hz
Calls user-supplied function root nodebug void TimerBRoutine()
if FAST_TIMERB is defined, only, hl,de,ix,a,f are saved in ISR and TimerBRoutine
must be asm code that saves any regs it uses
END DESCRIPTION **********************************************************/
/* START FUNCTION DESCRIPTION ********************************************
TimerBInit <TIMERB.LIB>
SYNTAX: int TimerBInit(int usec)
DESCRIPTION:
Cause a user function TimerBRoutine() to be called every usec microseconds
Notes:
1. periodic call to user routine every timer int
2. supports times from about 20us to 1500 seconds with 11.0592mHz xtal (22.1 clock)
3. Interrupts faster than 20,000/sec start to become too much overhead for use
4. TimerBinit() must be called to initialize the ISR
5. Uses bios freq_divider for calcs
6. If <100us, best to modify library asm isr. (inlince code, no call to ext)
7. Note serial port baud rates <2700 effect timer, set up serial ports first
Calls user-supplied function root nodebug void TimerBRoutine()
if FAST_TIMERB is defined, only regs: hl,de,ix,a,f are saved in ISR and
TimerBRoutine MUST be asm code that saves any regs it uses
RETURN VALUE: non-0 if out of range
END DESCRIPTION **********************************************************/
/*** Beginheader */
#ifndef XTAL_FREQ
// bios has 19200*16 divisor calculated
#define XTAL_FREQ ((long)freq_divider * 307200L)
#endif
//extern unsigned int task_ms_no,task_20ms_no,task_100ms_no,task_1s_no;
//extern unsigned char task_inv_no;
//extern unsigned char task_20ms_en ;
unsigned int _timerb_scale;
unsigned long _timerb_divisor;
int _timerb_inc;
unsigned int _timerb_ctr;
// used by isr
int _timerb_match;
/*** EndHeader */
/*** BeginHeader TimerBInit */
int TimerBInit( unsigned long usec, char intlevel );
/*** EndHeader */
nodebug int TimerBInit( unsigned long usec, char intlevel )
{
auto unsigned long divisor;
auto long timeradiv, intscale;
#GLOBAL_INIT
{
// init timer a for 1/256 divide. Serial ports set to <2700 baud will
// change this (BTW, bug in serial lib will screw up if more than
// one port is set to two different rates below 2600.)
WrPortI( TAT1R, &TAT1RShadow, 0xFF ); // the bios does not init this
}
WrPortI( TBCSR, &TBCSRShadow, 0x00 ); // disable timer B and its interrupts
_timerb_scale = 0; // no scale be default
// if serial ports are using timer A1 we cant modify it.
timeradiv = TAT1RShadow + 1L;
if( timeradiv < 8 )
timeradiv = 8; // if <8 then we must use only t2
divisor = (long)(((float)usec * (float)XTAL_FREQ) / 1.0e6 + 0.5);
// use intlevel to calc TBCR value
if( divisor < 165 ) // not enough instructions for accurate time between ints
return 1;
if( divisor > (1024L*timeradiv*65535L) ) // max for using both timer a and b
return 1;
if( divisor > (1024L*timeradiv) ) // max for using both timer a and b
{
// try to calc best value
intscale = divisor/(1024L*timeradiv) - 1;
if( intscale < 2L )
intscale = 2L; // sanity chck
while( (divisor/(long)intscale) > (1024L*timeradiv) )
++intscale;
if( intscale > 65535L )
return 1;
divisor = divisor / intscale; // nearest
_timerb_scale = _timerb_ctr = (unsigned int) intscale; // init first
}
if( divisor <= 1024L ) // timer b with pclk/2 direct
{
intlevel &= 3; // mask valid
_timerb_divisor = divisor;
}
else if( divisor <= 8192L ) // timer b with pclk/16
{
intlevel = 0x8 | (intlevel & 3); // mask valid set pclk/2
divisor = (divisor + 4L) / 8L; // round to nearest
_timerb_divisor = divisor * 8L;
}
else
{
// we need timerA! // timera --> timerb
intlevel = 0x4 | (intlevel & 3); // mask valid set timera
divisor = (divisor + (timeradiv >> 1)) / timeradiv;
_timerb_divisor = divisor * timeradiv;
}
_timerb_inc = (int)((divisor & 0xff) | ((divisor << 6) & 0xc000)); // val for isr
if( _timerb_scale )
_timerb_divisor *= _timerb_scale; // we use scale in isr
SetVectIntern( 0x0B, _TimerBISR ); // set up ISR
WrPortI( TBCR, &TBCRShadow, intlevel ); // clock timer B with Ai out and
WrPortI( TBL1R, NULL, 0x00 ); // set initial match, isr calcs acutal
WrPortI( TBM1R, NULL, 0x00 );
WrPortI( TBCSR, &TBCSRShadow, 0x03 ); // enable timer B and B1 match interrupts
return 0; // :-)
}
/*** Beginheader _TimerBISR */
interrupt _TimerBISR(void);
/*** Endheader */
#ifdef FAST_TIMERB
#asm root nodebug fast
_TimerBISR::
push hl
push ix
push de
push af
#else
nodebug interrupt _TimerBISR(void)
{
#asm nodebug fast
#endif
ld hl,(_timerb_match)
ld de,(_timerb_inc)
add hl,de
ld a,h
bit 0,a ; carry?
jr z,no_inc
add a,03fh ; if carry, inc upper two bits
// and 0xc0 ; need this so lower does not carry into calced upper
ld h,a
no_inc:
ld (_timerb_match),hl
; high is aready in a
ioi ld (TBM1R), a ; NOTE: you _need_ to reload the match
ld a, l ; next low in a
ioi ld (TBL1R), a ; set up next B1 match (at timer = 0000h)
; register after every interrupt!
ioi ld a, (TBCSR) ; load B1, B2 interrupt flags (clears flag)
; are we scaling int calls to user routine?
ld hl, (_timerb_scale)
ld ix,hl ; 'cache' value for later (faster than ld hl,(..))
bool hl
jr z,no_scale
; ok so we need to count down
ld hl,(_timerb_ctr)
dec hl
ld (_timerb_ctr),hl
bool hl
jr nz,skip_user
ld (_timerb_ctr),ix
no_scale:
call TimerBRoutine ; do user func
skip_user:
#ifdef FAST_TIMERB
pop af
pop de
pop ix
pop hl
ipres
ret
#endasm
#else
#endasm
}
#endif
/*** BeginHeader TimerBRoutine */
void TimerBRoutine(void);
/*** EndHeader */
void TimerBRoutine(void)
{
unsigned char i;
for(i=0;i<MAX_CHANNEL;++i)
{
Calcval(i);
}
}
/*** BeginHeader */
#endif
/*** EndHeader */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -