/*
*********************************************************************************************************
*
*	模块名称 : 定时器模块
*	文件名称 : 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

/* 电机驱动PWM定时器 */
#define TIM_MOTOR                       TIM4
#define TIM_MOTOR_IRQn	                TIM4_IRQn
#define	TIM_MOTOR_PERIPH_RCC	        RCC_APB1Periph_TIM4

// /* 测试 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[soft_timer_num];

/*
	全局运行时间，单位1ms
	最长可以表示 24.85天，如果你的产品连续运行时间超过这个数，则必须考虑溢出问题
*/
__IO int32_t g_iRunTime = 0;


// 用户使用的systick时间
volatile static uint32_t systick_ms = 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);

uint32_t bsp_get_systick_ms(void)
{
    return systick_ms;
}

/*
*********************************************************************************************************
*	函 数 名: 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]);
	}

    systick_ms++;
	/* 全局运行时间每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 >= soft_timer_num)
	{
		/* 打印出错的源代码文件名、函数名称 */
		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);
}

/*************************************************************************************
 * @brief    tb6612 定时器初始化
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
void bsp_timer_tb6612_init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;	
    /* 1. 使能TIM时钟 */
    RCC_APB1PeriphClockCmd(TIM_MOTOR_PERIPH_RCC, ENABLE);

    /* 3. Configures the TIMx internal Clock */
    TIM_InternalClockConfig(TIM_MOTOR);
    /* 4. 定义时基单元 */
    TIM_TimeBaseStructure.TIM_Period = (100u - 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_MOTOR, &TIM_TimeBaseStructure);
    /* 5. 输出比较 */
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;	// PWM模式1（CNT<CCR时高电平）
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;	// 高电平有效
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	// 使能输出
    TIM_OCInitStructure.TIM_Pulse = 0;		//CCR	占空比
    // 应用至TIM2_CHx[1,7](@ref)
    /* PWMA */
    TIM_OC3Init(TIM_MOTOR, &TIM_OCInitStructure);
    /* PWMB */
    TIM_OC4Init(TIM_MOTOR, &TIM_OCInitStructure);

    TIM_ARRPreloadConfig(TIM_MOTOR, ENABLE);
    /* 6. TIMx enable counter */
    TIM_Cmd(TIM_MOTOR, ENABLE);
}
/*************************************************************************************
 * @brief    通过修改pwm，来修改左轮电机的速度
 * @param[in/out] Compare【参数注释】
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
void bsp_timer_tb6612_pwmA_change(uint16_t Compare)
{
	TIM_SetCompare3(TIM_MOTOR, Compare);
}
/*************************************************************************************
 * @brief    通过修改pwm，来修改右轮电机的速度
 * @param[in/out] Compare【参数注释】
 * 
 * @warning  【不可重入,阻塞等警告】
 * @note     【重大修改】
  *************************************************************************************/
void bsp_timer_tb6612_pwmB_change(uint16_t Compare)
{
	TIM_SetCompare4(TIM_MOTOR, Compare);
}

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);
}

/*************************************************************************************
 * @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) *********************************/
