相信用过芯塘NUC1xx系列单片机的朋友们对NUC1xx 固件库函数一定不陌生.
本人用的固件库版本是V1.05.001,在用定时器的库函数的时候发现了一个问题:
本人用定时器监控一个信号,这个信号平时是高电平,当它变为低电平的时候,启动定时器,开始计时,假设计时时间为120S,
如果这个信号保持低电平120S,则会触发中断函数,从而使这个信号不再起作用,
如果在这120S内,这个信号恢复高电平,则重置计数器,在下次这个信号变为低电平的时候,从新计数。
以下是本人设置的函数:
/**************************************************
*函数名: initialize_timer *
*功能: 初始化timer必须调用的函数 *
*出口参数:无 *
*入口参数:无 *
*************************************************/
void initialize_timer (void)
{
DrvTIMER_Init (); //初始化timer必须调用的函数
}
/**************************************************
*函数名: initialize_timer0 *
*功能: 初始化timer0 *
*出口参数:无 *
*入口参数:无 *
*************************************************/
void initialize_timer0 (void)
{
DrvSYS_UnlockProtectedReg (); //解锁受保护的系统寄存器
DrvSYS_SelectIPClockSource (E_SYS_TMR0_CLKSRC, 0x00); //设置定时器0的时钟源为外部12M晶振
DrvSYS_LockProtectedReg (); //对系统寄存器上锁
delay (50); //延迟使时钟稳定
DrvTIMER_Open (E_TMR0, //使能定时器0
1, //每秒计数1次
E_PERIODIC_MODE); //单周期模式
}
/**************************************************
*函数名: setup_ptt_limit_time *
*功能: 调整发定时时间 *
*出口参数:无 *
*入口参数:无 *
*************************************************/
void setup_ptt_limit_time (int32_t PTT_limit_time_) //参数最后加"_"是为了区别全局变量
{
DrvTIMER_SetTimerEvent (E_TMR0, //定时器0
PTT_limit_time_, //发定时时间,单位为秒
PTT_callback, //发定时回调函数,回调函数类型必须为typedef void (*TIMER_CALLBACK)(uint32_t data); /* function pointer */,否则应像例子那样用强制转换类型符
0); //传给回调函数的参数,暂无用
}
/**************************************************
*函数名: PTT_callback *
*功能: PTT定时回调函数,用于停发 *
*出口参数:无 *
*入口参数:有,暂时无用 *
*************************************************/
void PTT_callback (uint32_t callback_data)
{
DrvTIMER_DisableInt(E_TMR0); //关定时器0中断,发定时一直起作用的时候无需多次进入该中断中
DrvTIMER_ClearIntFlag(E_TMR0); //清空定时器0中断标志位
PTT_time_off = 1; //发定时到
}
简单的讲:就是先设定1秒中断几次,假如说想要200ms的中断,就设置1秒计数5次,计数1次就进入中断,
如果想要的是400ms,就设置1秒计数5次,计数两次进入中断
本人发现用定时器的one-shot模式,根本进不到中断函数中,只好用单周期模式,不知何解。
严归正传以上的函数是用以初始化定时器,并设置用户的中断服务函数,其实我们之后可以看到
用户设置的中断函数,并不是真的中断部分函数,而是在厂家的固件库函数里,通过函数指针来调用用户的中断函数。
笔者用以上的几个函数来初始化定时器中断
之后是笔者用来启动定时器和清除定时计数次数的函数
if ((enable_PTT_limit == 1) && (active_PTT_limit == 0)) //如果使能发定时并且没有使能定时器0中断
{
DrvTIMER_EnableInt (E_TMR0); //使能定时器0中断
DrvTIMER_Start (E_TMR0); //定时器0开始计时
active_PTT_limit = 1; //发定时已激活
}
else if ((PTT_mic == 0) && (PTT_remote == 0))
{
DrvTIMER_Stop(E_TMR0); //暂停定时0并清空当前计时
PTT_time_off = 0; //清除发定时到时标志
PTT_start = 0; //PTT未发起
active_PTT_limit = 0; //清除发定时已使能标志,使得定时器可以在PTT_on中再次被激活
}
其中DrvTIMER_Stop(E_TMR0); 这个函数是笔者自己写的
这样就能完成笔者所要的目的了,其中使能中断和定时器开始计数,只不过是对TCSR这个寄存器的几个控制位进行操作,在此就不贴出了
之后我们来看固件库函数,笔者一共用到的固件库函数如下:大家只用注意看有中文注释的部分即可
另外大家要对TIMER的寄存器有所了解 具体可参看NUC130-140数据手册
还有注意看红体字的部分那是很重要的
由于笔者只用定时器0,而且其他定时器的函数都是重复的,建议大家只看定时器0即可
/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvTIMER_Open */
/* */
/* Parameters: */
/* ch - [in] */
/* E_TIMER_CHANNEL, it could be E_TMR0/E_TMR1/E_TMR2/E_TMR3 */
/* uTicksPerSecond - [in] */
/* This value means how many timer interrupt ticks in one second */
/* op_mode - [in] */
/* E_TIMER_OPMODE, E_ONESHOT_MODE/E_PERIODIC_MODE/E_TOGGLE_MODE/E_CONTINUOUS_MODE */
/* Returns: */
/* E_SUCCESS Operation successful */
/* E_DRVTIMER_CHANNEL Invalid Timer channel */
/* E_DRVTIMER_CLOCK_RATE Calculate initial value fail */
/* Description: */
/* Open the specified timer channel with specified operation mode. */
/*---------------------------------------------------------------------------------------------------------*/
int32_t DrvTIMER_Open(E_TIMER_CHANNEL ch, uint32_t uTicksPerSecond, E_TIMER_OPMODE op_mode)
{
uint32_t i;
uint32_t uRegTcmpr, uRegTcr = 0x0;
switch (ch)
{
case E_TMR0:
{
if ((bIsTimer0Initial != TRUE) || (bIsTimer0Used != FALSE))
return E_DRVTIMER_EIO;
bIsTimer0Used = TRUE; //定时器0正在使用标志
SYSCLK->APBCLK.TMR0_EN = 1; //打开定时器0的APB时钟
outpw((uint32_t)&TIMER0->TCSR, 0); /* disable timer,这个很巧妙,是将TCSR整个32位全部赋0,注意看强制转换uint32_t并且按位与 */
TIMER0->TISR.TIF = 1; /* write 1 to clear for safty ,清定时器0中断标志位*/
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
tTime0Event[i].active = FALSE; //设置定时器0事件未激活,给下一个事件设置函数做准备
}
uTimer0Tick = 0; //定时器0 Tick设置为0
_sys_uTimer0TickPerSecond = uTicksPerSecond; //将用户设置的1秒内Tick数传递给_sys_uTimer0TickPerSecond
uRegTcmpr = CalTimerInitValue(GetTimerClock(E_TMR0), uTicksPerSecond); //进行计算
if (uRegTcmpr == (uint32_t)-1)
{
return E_DRVTIMER_CLOCK_RATE;
}
TIMER0->TCMPR = (uRegTcmpr << 8) >> 8; //对24位定时器比较寄存器赋值,注意移位运算
outpw((uint32_t)&TIMER0->TCSR, (uRegTcr|(uRegTcmpr>>24))|(op_mode<<27)); //初始化TCSR
break;
}
case E_TMR1:
{
if ((bIsTimer1Initial != TRUE) || (bIsTimer1Used != FALSE))
return E_DRVTIMER_EIO;
bIsTimer1Used = TRUE;
SYSCLK->APBCLK.TMR1_EN = 1;
outpw((uint32_t)&TIMER1->TCSR, 0); /* disable timer */
TIMER1->TISR.TIF = 1; /* write 1 to clear for safty */
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
tTime1Event[i].active = FALSE;
}
uTimer1Tick = 0;
_sys_uTimer1TickPerSecond = uTicksPerSecond;
uRegTcmpr = CalTimerInitValue(GetTimerClock(E_TMR1), uTicksPerSecond);
if(uRegTcmpr == (uint32_t)-1)
{
return E_DRVTIMER_CLOCK_RATE;
}
TIMER1->TCMPR = (uRegTcmpr << 8) >> 8;
outpw((uint32_t)&TIMER1->TCSR, (uRegTcr|(uRegTcmpr>>24))|(op_mode<<27));
break;
}
case E_TMR2:
{
if ((bIsTimer2Initial != TRUE) || (bIsTimer2Used != FALSE))
return E_DRVTIMER_EIO;
bIsTimer2Used = TRUE;
SYSCLK->APBCLK.TMR2_EN =1;
outpw((uint32_t)&TIMER2->TCSR, 0); /* disable timer */
TIMER2->TISR.TIF = 1; /* write 1 to clear for safty */
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
tTime2Event[i].active = FALSE;
}
uTimer2Tick = 0;
_sys_uTimer2TickPerSecond = uTicksPerSecond;
uRegTcmpr = CalTimerInitValue(GetTimerClock(E_TMR2), uTicksPerSecond);
if(uRegTcmpr == (uint32_t)-1)
{
return E_DRVTIMER_CLOCK_RATE;
}
TIMER2->TCMPR = (uRegTcmpr << 8) >> 8;
outpw((uint32_t)&TIMER2->TCSR, (uRegTcr|(uRegTcmpr>>24))|(op_mode<<27));
break;
}
case E_TMR3:
{
if ((bIsTimer3Initial != TRUE) || (bIsTimer3Used != FALSE))
return E_DRVTIMER_EIO;
bIsTimer3Used = TRUE;
SYSCLK->APBCLK.TMR3_EN = 1;
outpw((uint32_t)&TIMER3->TCSR, 0); /* disable timer */
TIMER3->TISR.TIF = 1; /* write 1 to clear for safty */
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
tTime3Event[i].active = FALSE;
}
uTimer3Tick = 0;
_sys_uTimer3TickPerSecond = uTicksPerSecond;
uRegTcmpr = CalTimerInitValue(GetTimerClock(E_TMR3), uTicksPerSecond);
if(uRegTcmpr == (uint32_t)-1)
{
return E_DRVTIMER_CLOCK_RATE;
}
TIMER3->TCMPR = (uRegTcmpr << 8) >> 8;
outpw((uint32_t)&TIMER3->TCSR, (uRegTcr|(uRegTcmpr>>24))|(op_mode<<27));
break;
}
default:
{
return E_DRVTIMER_CHANNEL ;
}
}
if (op_mode == E_TOGGLE_MODE)
{
switch (ch)
{
case E_TMR0:
case E_TMR1:
case E_TMR2:
case E_TMR3:
{
DrvGPIO_InitFunction((E_DRVGPIO_FUNC)((uint32_t)E_FUNC_TMR0 + (uint32_t)ch));
}
default:
{
return E_DRVTIMER_CHANNEL ;
}
}
}
return E_SUCCESS;
}
/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvTIMER_SetTimerEvent */
/* */
/* Parameters: */
/* ch - [in] */
/* E_TIMER_CHANNEL, it could be E_TMR0/E_TMR1/E_TMR2/E_TMR3 */
/* uInterruptTicks - [in] */
/* Number of timer interrupt occurred */
/* pTimerCallback - [in] */
/* The function pointer of the interrupt callback function */
/* parameter - [in] */
/* A parameter of the callback function */
/* */
/* Returns: */
/* uTimerEventNo The timer event number */
/* E_DRVTIMER_EVENT_FULL The timer event is full */
/* Description: */
/* Install the interrupt callback function of the specified timer channel. */
/* And trigger timer callback functuion when interrupt occur specified times. */
/*---------------------------------------------------------------------------------------------------------*/
int32_t DrvTIMER_SetTimerEvent(E_TIMER_CHANNEL ch, uint32_t uInterruptTicks, TIMER_CALLBACK pTimerCallback, uint32_t parameter)
{
volatile int32_t i;
int32_t uTimerEventNo = 0;
switch (ch)
{
case E_TMR0:
{
if (uTime0EventCount >= TIMER_EVENT_COUNT) //如果已经设置事件了
return E_DRVTIMER_EVENT_FULL; //返回事件已满
bIsSetTime0Event = TRUE; //有事件
uTime0EventCount++; //设置事件计数器加1
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime0Event[i].active == FALSE) //如果定时器0事件激活状态为0
{
tTime0Event[i].active = TRUE; //设置激活状态为1
tTime0Event[i].initTick = uInterruptTicks; //将传入的多少次Tick进入用户中断赋值给初始化Tick及当前Tick两个变量
tTime0Event[i].curTick = uInterruptTicks; //当前Tick数
tTime0Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback; //用户自定义的回调函数
tTime0Event[i].transParam = parameter; //用户自定义的回调函数的参数
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR1:
{
if (uTime1EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime1Event = TRUE;
uTime1EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime1Event[i].active == FALSE)
{
tTime1Event[i].active = TRUE;
tTime1Event[i].initTick = uInterruptTicks;
tTime1Event[i].curTick = uInterruptTicks;
tTime1Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime1Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR2:
{
if (uTime2EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime2Event = TRUE;
uTime2EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime2Event[i].active == FALSE)
{
tTime2Event[i].active = TRUE;
tTime2Event[i].initTick = uInterruptTicks;
tTime2Event[i].curTick = uInterruptTicks;
tTime2Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime2Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR3:
{
if (uTime3EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime3Event = TRUE;
uTime3EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime3Event[i].active == FALSE)
{
tTime3Event[i].active = TRUE;
tTime3Event[i].initTick = uInterruptTicks;
tTime3Event[i].curTick = uInterruptTicks;
tTime3Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime3Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
default:
{
break;
}
}
return uTimerEventNo;
}
固件库里给了两个函数,看名字貌似是获得当前计数次数和清除当前计数次数我们来看函数:
/
|