769 lines
27 KiB
C
769 lines
27 KiB
C
/*
|
||
*********************************************************************************************************
|
||
*
|
||
* 模块名称 : 定时器模块
|
||
* 文件名称 : bsp_timer.c
|
||
* 版 本 : V1.2
|
||
* 说 明 : 配置systick定时器作为系统滴答定时器。缺省定时周期为1ms。
|
||
*
|
||
* 实现了多个软件定时器供主程序使用(精度1ms), 可以通过修改 TMR_COUNT 增减定时器个数
|
||
* 实现了ms级别延迟函数(精度1ms) 和us级延迟函数
|
||
* 实现了系统运行时间函数(1ms单位)
|
||
*
|
||
* 修改记录 :
|
||
* 版本号 日期 作者 说明
|
||
* V1.0 2013-02-01 armfly 正式发布
|
||
* V1.1 2013-06-21 armfly 增加us级延迟函数 bsp_DelayUS
|
||
* V1.2 2014-09-07 armfly 增加TIM4 硬件定时中断,实现us级别定时.20us - 16秒
|
||
*
|
||
* Copyright (C), 2014-2015, 安富莱电子 www.armfly.com
|
||
*
|
||
*********************************************************************************************************
|
||
*/
|
||
|
||
//#include "bsp.h"
|
||
#include "bsp_timer.h"
|
||
#include "stm32f10x_tim.h"
|
||
#include "public_diy.h"
|
||
#include "bsp_core.h"
|
||
// /* 外部时钟源定时器 */
|
||
// #define TIM_EXTERN_INPUT TIM2
|
||
// #define TIM_EXTERN_INPUT_IRQn TIM2_IRQn
|
||
// #define TIM_EXTERN_INPUT_RCC RCC_APB1Periph_TIM2
|
||
|
||
|
||
/* 硬件定时器 */
|
||
#define TIM_HARD TIM3
|
||
#define TIM_HARD_IRQn TIM3_IRQn
|
||
#define TIM_HARD_RCC RCC_APB1Periph_TIM3
|
||
/* PWM输出比较 定时器 */
|
||
#define TIM_PWM TIM4
|
||
#define TIM_PWM_IRQn TIM4_IRQn
|
||
#define TIM_PWM_RCC RCC_APB1Periph_TIM4
|
||
#define TIM_PWM_CH1_PORT GPIOB
|
||
#define TIM_PWM_CH1_PIN GPIO_Pin_6
|
||
|
||
|
||
// /* 测试 TIM2_ETR 是否使用重映射功能 */
|
||
// #define USE_REMAP_PA15_ENABLE
|
||
|
||
/* 这2个全局变量转用于 bsp_DelayMS() 函数 */
|
||
static volatile uint32_t s_uiDelayCount = 0;
|
||
static volatile uint8_t s_ucTimeOutFlag = 0;
|
||
|
||
/* 定于软件定时器结构体变量 */
|
||
static SOFT_TMR s_tTmr[TMR_COUNT];
|
||
|
||
/*
|
||
全局运行时间,单位1ms
|
||
最长可以表示 24.85天,如果你的产品连续运行时间超过这个数,则必须考虑溢出问题
|
||
*/
|
||
__IO int32_t g_iRunTime = 0;
|
||
|
||
static void bsp_SoftTimerDec(SOFT_TMR *_tmr);
|
||
|
||
/* 保存 TIM定时中断到后执行的回调函数指针 */
|
||
static void (*s_TIM_CallBack1)(void);
|
||
static void (*s_TIM_CallBack2)(void);
|
||
static void (*s_TIM_CallBack3)(void);
|
||
static void (*s_TIM_CallBack4)(void);
|
||
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: SysTick_ISR
|
||
* 功能说明: SysTick中断服务程序,每隔1ms进入1次
|
||
* 形 参: 无
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
extern void bsp_RunPer1ms(void);
|
||
extern void bsp_RunPer10ms(void);
|
||
|
||
void SysTick_ISR(void)
|
||
{
|
||
// static uint8_t s_count = 0;
|
||
uint8_t i;
|
||
|
||
/* 每隔1ms进来1次 (仅用于 bsp_DelayMS) */
|
||
if (s_uiDelayCount > 0)
|
||
{
|
||
if (--s_uiDelayCount == 0)
|
||
{
|
||
s_ucTimeOutFlag = 1;
|
||
}
|
||
}
|
||
|
||
/* 每隔1ms,对软件定时器的计数器进行减一操作 */
|
||
for (i = 0; i < TMR_COUNT; i++)
|
||
{
|
||
bsp_SoftTimerDec(&s_tTmr[i]);
|
||
}
|
||
|
||
/* 全局运行时间每1ms增1 */
|
||
// g_iRunTime++;
|
||
// if (g_iRunTime == 0x7FFFFFFF) /* 这个变量是 int32_t 类型,最大数为 0x7FFFFFFF */
|
||
// {
|
||
// g_iRunTime = 0;
|
||
// }
|
||
|
||
// bsp_RunPer1ms(); /* 每隔1ms调用一次此函数,此函数在 bsp.c */
|
||
|
||
// if (++s_count >= 10)
|
||
// {
|
||
// s_count = 0;
|
||
|
||
// bsp_RunPer10ms(); /* 每隔10ms调用一次此函数,此函数在 bsp.c */
|
||
// }
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_SoftTimerDec
|
||
* 功能说明: 每隔1ms对所有定时器变量减1。必须被SysTick_ISR周期性调用。
|
||
* 形 参: _tmr : 定时器变量指针
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
static void bsp_SoftTimerDec(SOFT_TMR *_tmr)
|
||
{
|
||
if (_tmr->Count > 0)
|
||
{
|
||
/* 如果定时器变量减到1则设置定时器到达标志 */
|
||
if (--_tmr->Count == 0)
|
||
{
|
||
_tmr->Flag = 1;
|
||
|
||
/* 如果是自动模式,则自动重装计数器 */
|
||
if(_tmr->Mode == TMR_AUTO_MODE)
|
||
{
|
||
_tmr->Count = _tmr->PreLoad;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_DelayMS
|
||
* 功能说明: ms级延迟,延迟精度为正负1ms
|
||
* 形 参: n : 延迟长度,单位1 ms。 n 应大于2
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_DelayMS(uint32_t n)
|
||
{
|
||
if (n == 0)
|
||
{
|
||
return;
|
||
}
|
||
else if (n == 1)
|
||
{
|
||
n = 2;
|
||
}
|
||
|
||
DISABLE_INT(); /* 关中断 */
|
||
|
||
s_uiDelayCount = n;
|
||
s_ucTimeOutFlag = 0;
|
||
|
||
ENABLE_INT(); /* 开中断 */
|
||
|
||
while (1)
|
||
{
|
||
// bsp_Idle(); /* CPU空闲执行的操作, 见 bsp.c 和 bsp.h 文件 */
|
||
|
||
/*
|
||
等待延迟时间到
|
||
注意:编译器认为 s_ucTimeOutFlag = 0,所以可能优化错误,因此 s_ucTimeOutFlag 变量必须申明为 volatile
|
||
*/
|
||
if (s_ucTimeOutFlag == 1)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_DelayUS
|
||
* 功能说明: us级延迟。 必须在systick定时器启动后才能调用此函数。
|
||
* 形 参: n : 延迟长度,单位1 us
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_DelayUS(uint32_t n)
|
||
{
|
||
uint32_t ticks;
|
||
uint32_t told;
|
||
uint32_t tnow;
|
||
uint32_t tcnt = 0;
|
||
uint32_t reload;
|
||
|
||
reload = SysTick->LOAD;
|
||
ticks = n * (SystemCoreClock / 1000000); /* 需要的节拍数 */
|
||
|
||
tcnt = 0;
|
||
told = SysTick->VAL; /* 刚进入时的计数器值 */
|
||
|
||
while (1)
|
||
{
|
||
tnow = SysTick->VAL;
|
||
if (tnow != told)
|
||
{
|
||
/* SYSTICK是一个递减的计数器 */
|
||
if (tnow < told)
|
||
{
|
||
tcnt += told - tnow;
|
||
}
|
||
/* 重新装载递减 */
|
||
else
|
||
{
|
||
tcnt += reload - tnow + told;
|
||
}
|
||
told = tnow;
|
||
|
||
/* 时间超过/等于要延迟的时间,则退出 */
|
||
if (tcnt >= ticks)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_StartTimer
|
||
* 功能说明: 启动一个定时器,并设置定时周期。
|
||
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
|
||
* _period : 定时周期,单位1ms
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_StartTimer(uint8_t _id, uint32_t _period)
|
||
{
|
||
if (_id >= TMR_COUNT)
|
||
{
|
||
/* 打印出错的源代码文件名、函数名称 */
|
||
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
|
||
while(1); /* 参数异常,死机等待看门狗复位 */
|
||
}
|
||
|
||
DISABLE_INT(); /* 关中断 */
|
||
|
||
s_tTmr[_id].Count = _period; /* 实时计数器初值 */
|
||
s_tTmr[_id].PreLoad = _period; /* 计数器自动重装值,仅自动模式起作用 */
|
||
s_tTmr[_id].Flag = 0; /* 定时时间到标志 */
|
||
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 1次性工作模式 */
|
||
|
||
ENABLE_INT(); /* 开中断 */
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_StartAutoTimer
|
||
* 功能说明: 启动一个自动定时器,并设置定时周期。
|
||
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
|
||
* _period : 定时周期,单位10ms
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_StartAutoTimer(uint8_t _id, uint32_t _period)
|
||
{
|
||
if (_id >= TMR_COUNT)
|
||
{
|
||
/* 打印出错的源代码文件名、函数名称 */
|
||
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
|
||
while(1); /* 参数异常,死机等待看门狗复位 */
|
||
}
|
||
|
||
DISABLE_INT(); /* 关中断 */
|
||
|
||
s_tTmr[_id].Count = _period; /* 实时计数器初值 */
|
||
s_tTmr[_id].PreLoad = _period; /* 计数器自动重装值,仅自动模式起作用 */
|
||
s_tTmr[_id].Flag = 0; /* 定时时间到标志 */
|
||
s_tTmr[_id].Mode = TMR_AUTO_MODE; /* 自动工作模式 */
|
||
|
||
ENABLE_INT(); /* 开中断 */
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_StopTimer
|
||
* 功能说明: 停止一个定时器
|
||
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_StopTimer(uint8_t _id)
|
||
{
|
||
if (_id >= TMR_COUNT)
|
||
{
|
||
/* 打印出错的源代码文件名、函数名称 */
|
||
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
|
||
while(1); /* 参数异常,死机等待看门狗复位 */
|
||
}
|
||
|
||
DISABLE_INT(); /* 关中断 */
|
||
|
||
s_tTmr[_id].Count = 0; /* 实时计数器初值 */
|
||
s_tTmr[_id].Flag = 0; /* 定时时间到标志 */
|
||
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 自动工作模式 */
|
||
|
||
ENABLE_INT(); /* 开中断 */
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_CheckTimer
|
||
* 功能说明: 检测定时器是否超时
|
||
* 形 参: _id : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
|
||
* _period : 定时周期,单位1ms
|
||
* 返 回 值: 返回 0 表示定时未到, 1表示定时到
|
||
*********************************************************************************************************
|
||
*/
|
||
uint8_t bsp_CheckTimer(uint8_t _id)
|
||
{
|
||
if (_id >= TMR_COUNT)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
if (s_tTmr[_id].Flag == 1)
|
||
{
|
||
s_tTmr[_id].Flag = 0;
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_GetRunTime
|
||
* 功能说明: 获取CPU运行时间,单位1ms。最长可以表示 24.85天,如果你的产品连续运行时间超过这个数,则必须考虑溢出问题
|
||
* 形 参: 无
|
||
* 返 回 值: CPU运行时间,单位1ms
|
||
*********************************************************************************************************
|
||
*/
|
||
int32_t bsp_GetRunTime(void)
|
||
{
|
||
int32_t runtime;
|
||
|
||
DISABLE_INT(); /* 关中断 */
|
||
|
||
runtime = g_iRunTime; /* 这个变量在Systick中断中被改写,因此需要关中断进行保护 */
|
||
|
||
ENABLE_INT(); /* 开中断 */
|
||
|
||
return runtime;
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************************************
|
||
* @brief 配置 TIM2,用于us级别硬件定时。自由运行,永不停止.
|
||
*
|
||
* @warning
|
||
* @note
|
||
*************************************************************************************/
|
||
void bsp_InitHardTimer(void)
|
||
{
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||
NVIC_InitTypeDef NVIC_InitStructure; /* 中断结构体在 misc.h 中定义 */
|
||
/* 1. 使能TIM时钟 */
|
||
RCC_APB1PeriphClockCmd(TIM_HARD_RCC, ENABLE);
|
||
/* 2. 使用内部时钟 */
|
||
TIM_InternalClockConfig(TIM_HARD);
|
||
/* 3. 配置时基单元 */
|
||
/*-----------------------------------------------------------------------
|
||
system_stm32f10x.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
|
||
|
||
HCLK = SYSCLK / 1 (AHBPeriph)
|
||
PCLK2 = HCLK / 1 (APB2Periph)
|
||
PCLK1 = HCLK / 2 (APB1Periph)
|
||
|
||
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock;
|
||
因为APB2 prescaler = 1, 所以 APB2上的TIMxCLK = PCLK2 = SystemCoreClock;
|
||
|
||
注意TIM_Prescaler 和 TIM_Period 不要溢出(0-65535)
|
||
|
||
----------------------------------------------------------------------- */
|
||
// 时基单元定义 此处定义1ms的
|
||
TIM_TimeBaseStructure.TIM_Period = (10 - 1); // 周期 ARR自动重装器的值
|
||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 10000) - 1 ; // PSC预分频器的值
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数器模式
|
||
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器的值,高级定时器才有
|
||
TIM_TimeBaseInit(TIM_HARD, &TIM_TimeBaseStructure);
|
||
/* 4. 开启更新中断到NVIC的通路 */
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_Update);
|
||
// 在开启更新中断之前,先把这个更新中断清掉,防止一开始就触发了更新中断
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_Update, ENABLE);
|
||
// 启用影子寄存器
|
||
TIM_ARRPreloadConfig(TIM_HARD, ENABLE);
|
||
/* 5. 配置TIM定时中断 (Update) */
|
||
NVIC_InitStructure.NVIC_IRQChannel = TIM_HARD_IRQn;
|
||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; /* 比串口优先级低 */
|
||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||
NVIC_Init(&NVIC_InitStructure);
|
||
/* 6. TIMx enable counter */
|
||
TIM_Cmd(TIM_HARD, ENABLE);
|
||
}
|
||
|
||
void bsp_pwm_init(void)
|
||
{
|
||
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||
GPIO_InitTypeDef GPIO_InitStructure;
|
||
// NVIC_InitTypeDef NVIC_InitStructure; /* 中断结构体在 misc.h 中定义 */
|
||
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||
/* 1. 使能TIM时钟 */
|
||
RCC_APB1PeriphClockCmd(TIM_PWM_RCC, ENABLE);
|
||
/* 2. 使用内部时钟 */
|
||
TIM_InternalClockConfig(TIM_PWM);
|
||
/* 3. 初始化GPIO */
|
||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||
GPIO_StructInit(&GPIO_InitStructure);
|
||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||
GPIO_InitStructure.GPIO_Pin = TIM_PWM_CH1_PIN;
|
||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||
GPIO_Init(TIM_PWM_CH1_PORT, &GPIO_InitStructure);
|
||
/* 3. 配置时基单元 */
|
||
/*-----------------------------------------------------------------------
|
||
system_stm32f10x.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:
|
||
|
||
HCLK = SYSCLK / 1 (AHBPeriph)
|
||
PCLK2 = HCLK / 1 (APB2Periph)
|
||
PCLK1 = HCLK / 2 (APB1Periph)
|
||
|
||
因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock;
|
||
因为APB2 prescaler = 1, 所以 APB2上的TIMxCLK = PCLK2 = SystemCoreClock;
|
||
|
||
注意TIM_Prescaler 和 TIM_Period 不要溢出(0-65535)
|
||
|
||
----------------------------------------------------------------------- */
|
||
// 时基单元定义 此处定义1ms的
|
||
TIM_TimeBaseStructure.TIM_Period = (10 - 1); // 周期 ARR自动重装器的值
|
||
TIM_TimeBaseStructure.TIM_Prescaler = (36 - 1); // PSC预分频器的值
|
||
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数器模式
|
||
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器的值,高级定时器才有
|
||
TIM_TimeBaseInit(TIM_PWM, &TIM_TimeBaseStructure);
|
||
|
||
TIM_OCStructInit(&TIM_OCInitStructure);
|
||
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||
TIM_OCInitStructure.TIM_Pulse = 0;
|
||
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
|
||
TIM_OC1Init(TIM_PWM, &TIM_OCInitStructure);
|
||
// /* 4. 开启更新中断到NVIC的通路 */
|
||
// TIM_ClearITPendingBit(TIM_PWM, TIM_IT_Update);
|
||
// // 在开启更新中断之前,先把这个更新中断清掉,防止一开始就触发了更新中断
|
||
// TIM_ITConfig(TIM_PWM, TIM_IT_Update, ENABLE);
|
||
// 启用影子寄存器
|
||
TIM_ARRPreloadConfig(TIM_PWM, ENABLE);
|
||
// /* 5. 配置TIM定时中断 (Update) */
|
||
// NVIC_InitStructure.NVIC_IRQChannel = TIM_HARD_IRQn;
|
||
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; /* 比串口优先级低 */
|
||
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||
// NVIC_Init(&NVIC_InitStructure);
|
||
/* 6. TIMx enable counter */
|
||
TIM_Cmd(TIM_PWM, ENABLE);
|
||
}
|
||
|
||
void bsp_change_pwm(uint8_t ucData)
|
||
{
|
||
TIM_SetCompare1(TIM_PWM, ucData);
|
||
}
|
||
|
||
/*************************************************************************************
|
||
* @brief 呼吸灯测试例程
|
||
*
|
||
* @warning
|
||
* @note
|
||
*************************************************************************************/
|
||
void bsp_pwm_test_loop(void)
|
||
{
|
||
int8_t tmp_i = 0;
|
||
for(tmp_i = 0; tmp_i <= 10; ++tmp_i)
|
||
{
|
||
bsp_change_pwm(tmp_i);
|
||
bsp_DelayMS(50);
|
||
}
|
||
for(tmp_i = 10; tmp_i >= 0; tmp_i--)
|
||
{
|
||
bsp_change_pwm(tmp_i);
|
||
bsp_DelayMS(50);
|
||
}
|
||
}
|
||
|
||
|
||
/*************************************************************************************
|
||
* @brief 初始化外部时钟
|
||
* 此处使用TIM2_ETR 外部时钟模式2, 假设外部时钟频率为 100kHz
|
||
* TIM2_ETR 使用 PA0引脚
|
||
*
|
||
* @warning
|
||
* @note
|
||
*************************************************************************************/
|
||
//void bsp_InitExternInputTimer(void)
|
||
//{
|
||
// /* 采用PA0 作为外部ETR时钟信号 */
|
||
// GPIO_InitTypeDef GPIO_InitStructure;
|
||
// TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||
// NVIC_InitTypeDef NVIC_InitStructure;
|
||
// /* 1. 使能TIM时钟 */
|
||
// RCC_APB1PeriphClockCmd(TIM_EXTERN_INPUT_RCC, ENABLE);
|
||
// /* 2. 使用外部时钟 ETR */
|
||
// TIM_ETRClockMode2Config(TIM_EXTERN_INPUT, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0x00);
|
||
// /* 3. 初始化GPIO */
|
||
//#ifdef USE_REMAP_PA15_ENABLE
|
||
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 PA 端口时钟
|
||
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能 PA 端口时钟
|
||
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
|
||
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE);
|
||
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // ETR-->PA.0 端口配置
|
||
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // ? 上拉输入
|
||
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度为 50MHz
|
||
//#else
|
||
// GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0
|
||
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 PA 端口时钟
|
||
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // ETR-->PA.0 端口配置
|
||
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // ? 上拉输入
|
||
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度为 50MHz
|
||
// GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0
|
||
|
||
//#endif
|
||
// /* 4. 定义时基单元 */
|
||
// // 此处以外部时钟为100KHz为例
|
||
// TIM_TimeBaseStructure.TIM_Period = (100u - 1); // 周期 ARR自动重装器的值
|
||
// TIM_TimeBaseStructure.TIM_Prescaler = (1000u - 1) ; // PSC预分频器的值
|
||
// TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||
// TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数器模式
|
||
// TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 重复计数器的值,高级定时器才有
|
||
// TIM_TimeBaseInit(TIM_EXTERN_INPUT, &TIM_TimeBaseStructure);
|
||
// /* 5. 开启更新中断到NVIC的通路 */
|
||
// TIM_ITConfig(TIM_EXTERN_INPUT, TIM_IT_Update, ENABLE);
|
||
// // 在开启更新中断之前,先把这个更新中断清掉,防止一开始就触发了更新中断
|
||
// TIM_ITConfig(TIM_EXTERN_INPUT, TIM_IT_Update, ENABLE);
|
||
// // 启用影子寄存器
|
||
// TIM_ARRPreloadConfig(TIM_EXTERN_INPUT, ENABLE);
|
||
// /* 6. 配置TIM定时中断 (Update) */
|
||
// NVIC_InitStructure.NVIC_IRQChannel = TIM_EXTERN_INPUT_IRQn;
|
||
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; /* 比串口优先级低 */
|
||
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||
// NVIC_Init(&NVIC_InitStructure);
|
||
// /* 7. TIMx enable counter */
|
||
// TIM_Cmd(TIM_EXTERN_INPUT, ENABLE);
|
||
//}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_StartHardTimer
|
||
* 功能说明: 使用TIM2-5做单次定时器使用, 定时时间到后执行回调函数。可以同时启动4个定时器,互不干扰。
|
||
* 定时精度正负10us (主要耗费在调用本函数的执行时间,函数内部进行了补偿减小误差)
|
||
* TIM2和TIM5 是32位定时器。定时范围很大
|
||
* TIM3和TIM4 是16位定时器。
|
||
* 形 参: _CC : 捕获通道几,1,2,3, 4
|
||
* _uiTimeOut : 超时时间, 单位 1us. 对于16位定时器,最大 65.5ms; 对于32位定时器,最大 4294秒
|
||
* _pCallBack : 定时时间到后,被执行的函数
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_StartHardTimer(uint8_t _CC, uint32_t _uiTimeOut, void * _pCallBack)
|
||
{
|
||
uint32_t cnt_now;
|
||
uint32_t cnt_tar;
|
||
|
||
/*
|
||
执行下面这个语句,时长 = 18us (通过逻辑分析仪测量IO翻转)
|
||
bsp_StartTimer2(3, 500, (void *)test1);
|
||
*/
|
||
if (_uiTimeOut < 5)
|
||
{
|
||
;
|
||
}
|
||
else
|
||
{
|
||
_uiTimeOut -= 5;
|
||
}
|
||
|
||
cnt_now = TIM_GetCounter(TIM_HARD); /* 读取当前的计数器值 */
|
||
cnt_tar = cnt_now + _uiTimeOut; /* 计算捕获的计数器值 */
|
||
if (_CC == 1)
|
||
{
|
||
s_TIM_CallBack1 = (void (*)(void))_pCallBack;
|
||
|
||
TIM_SetCompare1(TIM_HARD, cnt_tar); /* 设置捕获比较计数器CC1 */
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC1);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC1, ENABLE); /* 使能CC1中断 */
|
||
|
||
}
|
||
else if (_CC == 2)
|
||
{
|
||
s_TIM_CallBack2 = (void (*)(void))_pCallBack;
|
||
|
||
TIM_SetCompare2(TIM_HARD, cnt_tar); /* 设置捕获比较计数器CC2 */
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC2);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC2, ENABLE); /* 使能CC2中断 */
|
||
}
|
||
else if (_CC == 3)
|
||
{
|
||
s_TIM_CallBack3 = (void (*)(void))_pCallBack;
|
||
|
||
TIM_SetCompare3(TIM_HARD, cnt_tar); /* 设置捕获比较计数器CC3 */
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC3);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC3, ENABLE); /* 使能CC3中断 */
|
||
}
|
||
else if (_CC == 4)
|
||
{
|
||
s_TIM_CallBack4 = (void (*)(void))_pCallBack;
|
||
|
||
TIM_SetCompare4(TIM_HARD, cnt_tar); /* 设置捕获比较计数器CC4 */
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC4);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC4, ENABLE); /* 使能CC4中断 */
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: bsp_InitTimer
|
||
* 功能说明: 配置systick中断,并初始化软件定时器变量
|
||
* 形 参: 无
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void bsp_timer_init(void)
|
||
{
|
||
uint8_t i;
|
||
|
||
/* 清零所有的软件定时器 */
|
||
for (i = 0; i < TMR_COUNT; i++)
|
||
{
|
||
s_tTmr[i].Count = 0;
|
||
s_tTmr[i].PreLoad = 0;
|
||
s_tTmr[i].Flag = 0;
|
||
s_tTmr[i].Mode = TMR_ONCE_MODE; /* 缺省是1次性工作模式 */
|
||
}
|
||
|
||
/*
|
||
配置systic中断周期为1ms,并启动systick中断。
|
||
|
||
SystemCoreClock 是固件中定义的系统内核时钟,对于STM32F4XX,一般为 168MHz
|
||
|
||
SysTick_Config() 函数的形参表示内核时钟多少个周期后触发一次Systick定时中断.
|
||
-- SystemCoreClock / 1000 表示定时频率为 1000Hz, 也就是定时周期为 1ms
|
||
-- SystemCoreClock / 500 表示定时频率为 500Hz, 也就是定时周期为 2ms
|
||
-- SystemCoreClock / 2000 表示定时频率为 2000Hz, 也就是定时周期为 500us
|
||
|
||
对于常规的应用,我们一般取定时周期1ms。对于低速CPU或者低功耗应用,可以设置定时周期为 10ms
|
||
*/
|
||
SysTick_Config(SystemCoreClock / 1000);
|
||
/* 开启硬件定时中断 */
|
||
// bsp_InitHardTimer();
|
||
// /* 初始化外部输入定时器 */
|
||
// bsp_InitExternInputTimer();
|
||
// /* 初始化 pwm 输出比较 */
|
||
// bsp_pwm_init();
|
||
}
|
||
|
||
/*************************************************************************************
|
||
* @brief TIM2 中断服务程序
|
||
*
|
||
* @warning
|
||
* @note
|
||
*************************************************************************************/
|
||
void TIM2_IRQHandler(void)
|
||
{
|
||
|
||
// if(RESET != TIM_GetITStatus(TIM_EXTERN_INPUT, TIM_IT_Update))
|
||
// {
|
||
// TIM_ClearITPendingBit(TIM_EXTERN_INPUT, TIM_IT_Update);
|
||
// /* add your code here. */
|
||
// // bsp_LedToggle(LED1);
|
||
// }
|
||
}
|
||
|
||
/*************************************************************************************
|
||
* @brief TIM3 中断服务程序
|
||
*
|
||
* @warning
|
||
* @note
|
||
*************************************************************************************/
|
||
void TIM3_IRQHandler(void)
|
||
{
|
||
|
||
if(RESET != TIM_GetITStatus(TIM_HARD, TIM_IT_Update))
|
||
{
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_Update);
|
||
/* add your code here. */
|
||
// bsp_LedToggle(LED2);
|
||
}
|
||
|
||
|
||
if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC1))
|
||
{
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC1);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC1, DISABLE); /* 禁能CC1中断 */
|
||
|
||
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
|
||
s_TIM_CallBack1();
|
||
}
|
||
|
||
if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC2))
|
||
{
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC2);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC2, DISABLE); /* 禁能CC2中断 */
|
||
|
||
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
|
||
s_TIM_CallBack2();
|
||
}
|
||
|
||
if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC3))
|
||
{
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC3);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC3, DISABLE); /* 禁能CC3中断 */
|
||
|
||
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
|
||
s_TIM_CallBack3();
|
||
}
|
||
|
||
if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC4))
|
||
{
|
||
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC4);
|
||
TIM_ITConfig(TIM_HARD, TIM_IT_CC4, DISABLE); /* 禁能CC4中断 */
|
||
|
||
/* 先关闭中断,再执行回调函数。因为回调函数可能需要重启定时器 */
|
||
s_TIM_CallBack4();
|
||
}
|
||
}
|
||
|
||
/*
|
||
*********************************************************************************************************
|
||
* 函 数 名: SysTick_Handler
|
||
* 功能说明: 系统嘀嗒定时器中断服务程序。启动文件中引用了该函数。
|
||
* 形 参: 无
|
||
* 返 回 值: 无
|
||
*********************************************************************************************************
|
||
*/
|
||
void SysTick_Handler(void)
|
||
{
|
||
SysTick_ISR();
|
||
}
|
||
|
||
/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
|