定时器模块结构(Air105定时器)运行模式

Air105有1个Timer单元,包括8个独立的定时器:Timer0到Time7,8个定时器中断源独立,每个定时器占用一个独立的中断源,使用PCLK时钟频率作为定时器时钟源,定时器采用递减计数方法。每个Timer单元定时器都支持PWM模式,PWM模式最高频率为PCLK/2,PWM单发(单发)功能,使用定时器控制板载LED闪烁,呼吸灯效果示例代码。

目录 Air105 的计时器

定时器的两种工作模式

PWM定时器相关代码

以下代码基于air105_project的库函数

定时器模块结构

在Air105中,全局只有一个定时器模块,TIMM0

typedef struct
{
    TIM_TypeDef TIM[TIM_NUM];
    __I  uint32_t TIM_IntStatus;
    __I  uint32_t TIM_EOI;
    __I  uint32_t TIM_RawIntStatus;
    __I  uint32_t TIM_Comp;
    __IO uint32_t TIM_ReloadCount[TIM_NUM];
} TIM_Module_TypeDef;

这个TIMM0的地址定义在air105.h

#define TIMM0                                   ((TIM_Module_TypeDef *)TIMM0_BASE)
#define AIR105_PERIPH_BASE                      (0x40000000UL)   /*!< (Peripheral) Base Address */
#define AIR105_APB0_BASE                        (AIR105_PERIPH_BASE + 0x10000)
#define TIMM0_BASE                              (AIR105_APB0_BASE + 0x3000)

定时器初始化

定时器的初始化只需要两个参数:TIMx,周期(时钟数),为了配合定时器,还需要定义一个中断

void Timer_Init(void)
{
    TIM_InitTypeDef TIM_InitStruct;
    NVIC_InitTypeDef NVIC_InitStructure;

图片[1]-定时器模块结构(Air105定时器)运行模式-唐朝资源网

// 开启定时器的外设时钟 SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_TIMM0, ENABLE); SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_TIMM0, ENABLE); // 定时器的时钟是 PCLK, 计数间隔为 1ms 对应的时钟数 TIM_InitStruct.TIM_Period = SYSCTRL->PCLK_1MS_VAL; // 使用 定时器0 TIM_InitStruct.TIMx = TIM_0; // 初始化 TIM_Init(TIMM0, &TIM_InitStruct); // 开启定时器0的中断 TIM_ITConfig(TIMM0, TIM_InitStruct.TIMx, ENABLE); //NVIC NVIC_SetPriorityGrouping(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannel = TIM0_0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); // 启动定时器0 TIM_Cmd(TIMM0, (TIM_NumTypeDef)TIM_0, ENABLE); }

在库函数中,模式将设置为用户自定义,即自动循环,重复加载循环并产生中断。

图片[2]-定时器模块结构(Air105定时器)运行模式-唐朝资源网

/**
  * @brief  Initializes the TIMx Unit peripheral according to the specified parameters.
  * @param  TIMMx: x can be 0 to select the TIM peripheral
  * @param  TIM_InitStruct: pointer to a TIM_InitTypeDef structor that contains the configuration information
  * @retval None
  */
void TIM_Init(TIM_Module_TypeDef *TIMMx, TIM_InitTypeDef *TIM_InitStruct)
{
    TIM_Cmd(TIMMx, TIM_InitStruct->TIMx, DISABLE);
    
    TIMMx->TIM[TIM_InitStruct->TIMx].ControlReg = 0;
    TIMMx->TIM[TIM_InitStruct->TIMx].ControlReg |= TIMER_CONTROL_REG_TIMER_MODE;
    TIMMx->TIM[TIM_InitStruct->TIMx].ControlReg &= ~TIMER_CONTROL_REG_TIMER_PWM;
    TIMMx->TIM[TIM_InitStruct->TIMx].LoadCount = TIM_InitStruct->TIM_Period;
}

定时器中断处理

Air105对应每个定时器,每个都有一个中断处理函数,可以在startup.air10中查看中断向量定义5.s

TIM0_0_IRQHandler
TIM0_1_IRQHandler
TIM0_2_IRQHandler
TIM0_3_IRQHandler
TIM0_4_IRQHandler
TIM0_5_IRQHandler
TIM0_6_IRQHandler
TIM0_7_IRQHandler

对应Timer0的中断处理,写在air105_it.c中。必须调用 TIM_ClearITPendingBit 和 NVIC_ClearPendingIRQ 来清除中断

图片[3]-定时器模块结构(Air105定时器)运行模式-唐朝资源网

void TIM0_0_IRQHandler(void)
{
    TIM_ClearITPendingBit(TIMM0, TIM_0);
    NVIC_ClearPendingIRQ(TIM0_0_IRQn);
}

下面添加处理逻辑的例子,每秒调用timer_handler(),注意不要在中断处理中使用耗时的工作

extern uint32_t timer_count;
extern void timer_handler(void);
void TIM0_0_IRQHandler(void)
{
    timer_count++;
    if (timer_count >= 1000)
    {
        timer_count = 0;
        timer_handler();
    }
    TIM_ClearITPendingBit(TIMM0, TIM_0);
    NVIC_ClearPendingIRQ(TIM0_0_IRQn);
}

定时器示例代码

使用 Timer0 控制板载 LED 每秒闪烁一次

Air105 的 PWM

Air105 的 8 个独立定时器可通过编程产生 PWM 信号。当用户将 TimerNControlReg 中的 PWM 位设置为 1 时,定时器进入 PWM 工作模式。此时,PWM 由 TimerNLoadCount2 和 TimerNLoadCount 寄存器分别控制为高电平。和低级循环反转输出。

频率和占空比设置PWM相关代码

PWM初始化也只需要三个参数TIMx和两个高低电平周期,加起来就是一个PWM周期

typedef struct 
{
	TIM_NumTypeDef TIMx;
	uint32_t TIM_LowLevelPeriod;
	uint32_t TIM_HighLevelPeriod;
}TIM_PWMInitTypeDef;

用 Timer5 初始化

void TimerPWM_Init(void)
{
    TIM_PWMInitTypeDef TIM_PWMInitStruct;
    SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_TIMM0, ENABLE);
    SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_TIMM0, ENABLE);
    //Timer5 -> PWM5
    TIM_PWMInitStruct.TIM_HighLevelPeriod = SYSCTRL->PCLK_1MS_VAL;
    TIM_PWMInitStruct.TIM_HighLevelPeriod = 0;
    TIM_PWMInitStruct.TIMx = TIM_5;
    TIM_PWMInit(TIMM0, &TIM_PWMInitStruct);
    TIM_Cmd(TIMM0, TIM_5, ENABLE);
}

在初始化PWM的库函数中,默认模式设置为用户自定义,自动加载周期,屏蔽中断

/**
  * @brief  Initializes the TIMx PWM Unit peripheral according to the specified parameters.
  * @param  TIMMx: x can be 0 to select the TIM peripheral
  * @param  TIM_PWMInitStruct: pointer to a TIM_PWMInitTypeDef structor that contains the configuration information
  * @retval None

  */
void TIM_PWMInit(TIM_Module_TypeDef *TIMMx, TIM_PWMInitTypeDef *TIM_PWMInitStruct)
{
    TIM_Cmd(TIMMx, TIM_PWMInitStruct->TIMx, DISABLE);
    TIMMx->TIM[TIM_PWMInitStruct->TIMx].ControlReg = 0;
    TIMMx->TIM[TIM_PWMInitStruct->TIMx].ControlReg |= TIMER_CONTROL_REG_TIMER_MODE;
    TIMMx->TIM[TIM_PWMInitStruct->TIMx].ControlReg |= TIMER_CONTROL_REG_TIMER_PWM;
    TIMMx->TIM[TIM_PWMInitStruct->TIMx].ControlReg |= TIMER_CONTROL_REG_TIMER_INTERRUPT;
    TIMMx->TIM[TIM_PWMInitStruct->TIMx].LoadCount = TIM_PWMInitStruct->TIM_LowLevelPeriod;
    TIMMx->TIM_ReloadCount[TIM_PWMInitStruct->TIMx] = TIM_PWMInitStruct->TIM_HighLevelPeriod;
}

将PB5功能复用到PWM5

GPIO_InitTypeDef gpio;
gpio.GPIO_Pin = GPIO_Pin_5;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
gpio.GPIO_Remap = GPIO_Remap_2;
GPIO_Init(GPIOB, &gpio);
printf("GPIO Initrn");

实时调整占空比,最后两个参数代表PCLK时钟周期数

TIM_SetPWMPeriod(TIMM0, TIM_5, period - high_period, high_period);

PWM 示例代码

使用PWM5(Timer5)控制LED产生呼吸灯效果

接线示例:

根据开发板的BOM PCB查看

示例中使用Timer4,Timer5对应的PWM4和PWM5输出分别为PB4和PB5,分别对应开发板的SP2_MO和SP2_MI,开发板上的PWM5对应PC7。注意不要接错。

运行示例,将两个LED串联一个1-5K的电阻,接GND再接SP2_MO和SP2_MI,就可以看到呼吸灯的效果了

© 版权声明
THE END
喜欢就支持一下吧
点赞211 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片