STM32F407VET6底层驱动之定时器寄存器封装
因为在项⽬中引⼊了操作系统,所以使⽤定时器的地⽅不多,因此这⾥只⽤了三个定时器,每个定时器可以注册⼗个任务。
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)
programme 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; // 定时任务计数器
jav008 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位响应优先级
critical是什么意思
抢占优先级和响应优先级的数值越⼩,优先级越⾼,处理器优
先⽐较抢占优先级然后再看响应优先级。
* 形参:prio:抢占优先级(分组4的响应优先级固定为0)
channel:中断通道
* 返回值:⽆
********************************************************/
static void tim_nvic_t(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; // 设置分组
// 设置NVIC
unsigned int temp;
unsigned char sub_prio = 0; // 分组4的响应优先级固定为0
// 注:优先级的设置必须要⼤于configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
// 否则不能在中断服务函数中调⽤FreeRTOS相关的API函数
if(prio <= 5)
{
prio = 6;
}
el 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 = fal;
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)
{
ca eTIM2: TIMx = TIM2; IRQn = TIM2_IRQn; bit = 0; break;
ca eTIM3: TIMx = TIM3; IRQn = TIM3_IRQn; bit = 1; break;
ca eTIM4: TIMx = TIM4; IRQn = TIM4_IRQn; bit = 2; break;
default: return 1;
}
jnu // ⾼级定时器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_t(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)
{
ca eTIM2: TIMx = TIM2; break;
ca eTIM3: TIMx = TIM3; break;
ca 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)
{
come back if(tim >= eTIM_COUNT)
{
return 1;
}
TIM_TypeDef *TIMx = NULL;
switch(tim)
{
ca eTIM2: TIMx = TIM2; break;伤感英文歌
ca eTIM3: TIMx = TIM3; break;
ca 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 == fal)
{
sTimTaskList[tim][i].task_count = 0;
sTimTaskList[tim][i].task_interval = interval; // 单位:微秒
hermes怎么读 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)
{
no problem sTimTaskList[tim][i].enable = fal;
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 = fal;
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; // 任务启动成功
}
}