因为在项目中引入了操作系统,所以使用定时器的地方不多,因此这里只用了三个定时器,每个定时器可以注册十个任务。
1、定时器封装接口如下:
a、定时器初始化:unsigned int tim_init(eTimType_t tim, unsigned short interval, unsigned char prio)
b、定时器禁能:unsigned int tim_stop(eTimType_t tim)
c、定时器重新开始计时:unsigned int tim_restart(eTimType_t tim)
d、定时器任务注册:unsigned int tim_task_append(void (*pfunc)(void *), const void *parg, unsigned int interval, eTimType_t tim)
e、定时器任务删除:unsigned int tim_task_delete(void (*pfunc)(void *), eTimType_t tim)
f、定时器任务禁能:unsigned int tim_task_stop(void (*pfunc)(void *), eTimType_t tim)
g、定时器任务使能:unsigned int tim_task_start(void (*pfunc)(void *), eTimType_t tim)
2、定时器模块对外开放的枚举类型如下:
// 定时器类型
typedef enum _eTimType
{
eTIM2,
eTIM3,
eTIM4,
eTIM_COUNT, // 注:这不是定时器类型,不可删除,仅用做数量统计
}eTimType_t;
#define TIM_TASK_COUNT ((unsigned char)10) // 每个定时器支持的任务个数
3、定时器模块代码实现如下:
#pragma pack(push, 1)
typedef struct _sTimTaskList
{
bool enable; // 任务使能标志位
unsigned int task_count; // 定时任务计数器
unsigned int tim_interval; // 定时中断时间间隔,单位:微秒
unsigned int task_interval; // 定时任务执行时间间隔,单位:毫秒
void (*pCallBack)(void *); // 定时器回调函数指针
void *parg; // 定时器回调函数形参
}sTimTaskList_t;
#pragma pack(pop)
// 定时器任务链表(STM32F407最多支持8个定时器)
static sTimTaskList_t sTimTaskList[eTIM_COUNT][TIM_TASK_COUNT] = {0};
* 函数功能:定时器中断优先级设置(组4),注意优先级不能超过设
定的组的范围否则会有意想不到的错误。组划分如下:
组0:0位抢占优先级,4位响应优先级
组1:1位抢占优先级,3位响应优先级
组2:2位抢占优先级,2位响应优先级
组3:3位抢占优先级,1位响应优先级
组4:4位抢占优先级,0位响应优先级
抢占优先级和响应优先级的数值越小,优先级越高,处理器优
先比较抢占优先级然后再看响应优先级。
* 形 参:prio:抢占优先级(分组4的响应优先级固定为0)
channel:中断通道
* 返 回 值:无
********************************************************/
static void tim_nvic_set(unsigned char prio, unsigned char channel)
{
// unsigned int temp, temp1;
// 设置分组
unsigned char nvic_group = 4; // 0 - 4
// temp1 = (~nvic_group) & 0x07; // 取后三位
// temp1 = temp1 << 8;
// temp = SCB->AIRCR; // 读取先前的设置
// temp &= 0x0000F8FF; // 清空先前分组
// temp |= 0x05FA0000; // 写入钥匙
// temp |= temp1;
// SCB->AIRCR = temp; // 设置分组
unsigned int temp;
unsigned char sub_prio = 0; // 分组4的响应优先级固定为0
// 注:优先级的设置必须要大于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
// 否则不能在中断服务函数中调用FreeRTOS相关的API函数
if(prio <= 5)
{
prio = 6;
}
else if(prio > 15)
{
prio = 15;
}
temp = prio << (4 - nvic_group);
temp |= sub_prio & (0x0F >> nvic_group);
temp = temp & 0xF; // 取低四位
NVIC->ISER[channel >> 5] |= 1 << (channel % 32); // 使能中断位(要清除的话,设置ICER对应位为1即可)
NVIC->IP[channel] |= temp << 4; // 设置响应优先级和抢断优先级
}
/********************************************************
* 函数功能:定时器初始化(初始化完成后定时器自动启动,重复初始化会将该定时器下的所有任务清空)
* 形 参:tim:指定定时器(定时器时钟频率1MHz,递增计数模式)
interval:定时器中断时间间隔,单位:微秒
prio:中断优先级(范围:6 - 15,数值越小优先级越高)
* 返 回 值:0=成功
1=定时器类型错误
2=定时周期错误
********************************************************/
unsigned int tim_init(eTimType_t tim, unsigned short interval, unsigned char prio)
{
if(tim >= eTIM_COUNT)
{
return 1;
}
if(interval == 0)
{
return 2;
}
// 清空该定时器下的所有任务
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
sTimTaskList[tim][i].parg = NULL;
sTimTaskList[tim][i].enable = false;
sTimTaskList[tim][i].task_count = 0;
sTimTaskList[tim][i].pCallBack = NULL;
sTimTaskList[tim][i].task_interval = 0;
sTimTaskList[tim][i].tim_interval = interval;
}
unsigned char bit = 0;
unsigned char IRQn = 0;
TIM_TypeDef *TIMx = NULL;
switch(tim)
{
case eTIM2: TIMx = TIM2; IRQn = TIM2_IRQn; bit = 0; break;
case eTIM3: TIMx = TIM3; IRQn = TIM3_IRQn; bit = 1; break;
case eTIM4: TIMx = TIM4; IRQn = TIM4_IRQn; bit = 2; break;
default: return 1;
}
// 高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11的时钟来源是APB2总线
// 通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7的时钟来源是APB1总线
RCC->APB1ENR |= 0x1 << bit; // 定时器时钟使能
TIMx->CNT = 0; // 计数器清零
TIMx->ARR = interval; // 设定计数器自动重装值
TIMx->PSC = 84 - 1; // 预分频器(时钟频率1MHz)
TIMx->DIER |= 0x01; // 使能更新中断(计数器更新)
TIMx->CR1 |= 0x01; // 使能计数器(递增模式)
tim_nvic_set(prio, IRQn); // 抢占优先级10,响应优先级0,优先级分组4
return 0;
}
/********************************************************
* 函数功能:定时器停止计数
* 形 参:tim:指定定时器
* 返 回 值:0=成功
1=定时器类型错误
********************************************************/
unsigned int tim_stop(eTimType_t tim)
{
if(tim >= eTIM_COUNT)
{
return 1;
}
TIM_TypeDef *TIMx = NULL;
switch(tim)
{
case eTIM2: TIMx = TIM2; break;
case eTIM3: TIMx = TIM3; break;
case eTIM4: TIMx = TIM4; break;
default: return 1;
}
TIMx->CNT = 0; // 计数器清零
TIMx->DIER &= ~0x01; // 禁能更新中断(计数器更新)
TIMx->CR1 &= ~0x01; // 禁能计数器(递增模式)
return 0;
}
/********************************************************
* 函数功能:定时器重新开始计数
* 形 参:tim:指定定时器
* 返 回 值:0=成功
1=定时器类型错误
********************************************************/
unsigned int tim_restart(eTimType_t tim)
{
if(tim >= eTIM_COUNT)
{
return 1;
}
TIM_TypeDef *TIMx = NULL;
switch(tim)
{
case eTIM2: TIMx = TIM2; break;
case eTIM3: TIMx = TIM3; break;
case eTIM4: TIMx = TIM4; break;
default: return 1;
}
TIMx->CNT = 0; // 计数器清零
TIMx->DIER |= 0x01; // 使能更新中断(计数器更新)
TIMx->CR1 |= 0x01; // 使能计数器(递增模式)
return 0;
}
/********************************************************
* 函数功能:定时器任务追加(任务立即进入运行状态)
* 形 参:pfunc:任务函数指针
parg:任务函数形参
interval:任务执行时间间隔,单位:微秒
tim:指定定时器
* 返 回 值:0=成功
1=任务链表满了,无法再追加任务
2=任务函数指针为NULL
3=定时器类型错误
4=任务执行时间间隔错误
* 开 发 者:王志超
* 维护日期:2020年5月5日
* 修订日志:开发
********************************************************/
unsigned int tim_task_append(void (*pfunc)(void *), const void *parg, unsigned int interval, eTimType_t tim)
{
if(pfunc == NULL)
{
return 2;
}
if(tim >= eTIM_COUNT)
{
return 3;
}
if(interval == 0)
{
return 4;
}
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
if(sTimTaskList[tim][i].enable == false)
{
sTimTaskList[tim][i].task_count = 0;
sTimTaskList[tim][i].task_interval = interval; // 单位:微秒
sTimTaskList[tim][i].parg = (void *)parg;
sTimTaskList[tim][i].pCallBack = pfunc;
sTimTaskList[tim][i].enable = true;
return 0; // 任务添加成功
}
}
return 1; // 任务链表满了,无法再追加任务
}
/********************************************************
* 函数功能:定时器任务删除
* 形 参:pfunc:任务函数指针
tim:指定定时器
* 返 回 值:0=成功
1=未找到与之匹配的任务
2=任务函数指针为NULL
3=定时器类型错误
********************************************************/
unsigned int tim_task_delete(void (*pfunc)(void *), eTimType_t tim)
{
if(pfunc == NULL)
{
return 2;
}
if(tim >= eTIM_COUNT)
{
return 3;
}
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
if(sTimTaskList[tim][i].pCallBack == pfunc)
{
sTimTaskList[tim][i].enable = false;
sTimTaskList[tim][i].parg = NULL;
sTimTaskList[tim][i].task_count = 0;
sTimTaskList[tim][i].tim_interval = 0;
sTimTaskList[tim][i].task_interval = 0;
sTimTaskList[tim][i].pCallBack = NULL;
return 0;
}
}
return 1; // 未找到与之匹配的任务
}
/********************************************************
* 函数功能:定时器任务停止运行
* 形 参:pfunc:任务函数指针
tim:指定定时器
* 返 回 值:0=成功
1=未找到与之匹配的任务
2=任务函数指针为NULL
3=定时器类型错误
********************************************************/
unsigned int tim_task_stop(void (*pfunc)(void *), eTimType_t tim)
{
if(pfunc == NULL)
{
return 2;
}
if(tim >= eTIM_COUNT)
{
return 3;
}
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
if(sTimTaskList[tim][i].pCallBack == pfunc)
{
sTimTaskList[tim][i].enable = false;
return 0; // 任务停止成功
}
}
return 1; // 未找到与之匹配的任务
}
/********************************************************
* 函数功能:定时器任务启动运行(从上次的停止时的状态继续运行)
* 形 参:pfunc:任务函数指针
tim:指定定时器
* 返 回 值:0=成功
1=未找到与之匹配的任务
2=任务函数指针为NULL
3=定时器类型错误
********************************************************/
unsigned int tim_task_start(void (*pfunc)(void *), eTimType_t tim)
{
if(pfunc == NULL)
{
return 2;
}
if(tim >= eTIM_COUNT)
{
return 3;
}
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
if(sTimTaskList[tim][i].pCallBack == pfunc)
{
sTimTaskList[tim][i].enable = true;
return 0; // 任务启动成功
}
}
return 1; // 未找到与之匹配的任务
}
/********************************************************
* 函数功能:定时器中断任务处理函数(中断专用)
* 形 参:无
* 返 回 值:无
********************************************************/
static void tim_isr_callback(TIM_TypeDef *TIMx, eTimType_t tim)
{
if((TIMx->SR & 0x0001) == 0x0001) // 溢出中断
{
TIMx->SR &= ~(0x0001);//清除中断标志位
// 执行定时器任务
for(unsigned char i = 0; i < TIM_TASK_COUNT; i++)
{
if(sTimTaskList[tim][i].enable == true)
{
sTimTaskList[tim][i].task_count += sTimTaskList[tim][i].tim_interval; // 单位:微秒
if(sTimTaskList[tim][i].task_count >= sTimTaskList[tim][i].task_interval)
{
sTimTaskList[tim][i].task_count = 0;
if(sTimTaskList[tim][i].pCallBack != NULL)
{
sTimTaskList[tim][i].pCallBack(sTimTaskList[tim][i].parg); // 执行任务
}
else
{
// 任务函数为NULL,无需做任何操作
}
}
else
{
// 任务执行时间未到达,无需做任何操作
}
}
else
{
// 任务处于暂停或停止状态,无需做任何操作
}
}
}
}
/********************************************************
* 函数功能:定时器2中断服务函数(中断时间间隔请查看初始化时的设置)
* 形 参:无
* 返 回 值:无
********************************************************/
void TIM2_IRQHandler(void)
{
tim_isr_callback(TIM2, eTIM2);
}
/********************************************************
* 函数功能:定时器3中断服务函数(中断时间间隔请查看初始化时的设置)
* 形 参:无
* 返 回 值:无
********************************************************/
void TIM3_IRQHandler(void)
{
tim_isr_callback(TIM3, eTIM3);
}
/********************************************************
* 函数功能:定时器4中断服务函数(中断时间间隔请查看初始化时的设置)
* 形 参:无
* 返 回 值:无
********************************************************/
void TIM4_IRQHandler(void)
{
tim_isr_callback(TIM4, eTIM4);
}