当前位置:   article > 正文

【TIM】定时器外部时钟_tim_tixexternalclockconfig

tim_tixexternalclockconfig
用到的TIM配置函数
  • TIM_TimeBaseInit();时基单元初始化
  • TIM_TimeBaseStructInit();给结构体变量赋一个默认值
  • TIM_Cmd();使能计数器
  • TIM_ITConfig();使能中断输出控制
///时钟源选择用这里的六个参数
  • TIM_InternalClockConfig();选择内部时钟
  • TIM_ITRxExternalClockConfig();选择ITRx其他定时器的时钟
  • TIM_TIxExternalClockConfig();选择TIx捕获通道的时钟
  • TIM_ETRClockMode1Config();选择ETR通过外部时钟模式1输入的时钟
  • TIM_ETRClockMode2Config(); 选择ETR通过外部时钟模式2输入的时钟
  • TIM_ETRConfig();配置ETR引脚的预分频器、极性、滤波器等参数
  • TIM_PrescalerConfig();用来单独写预分频值
  • TIM_CounterModeConfig();用来改变计数器的计数模式
  • TIM_ARRPreloadConfig();自动重装器预装功能配置
  • TIM_SetCounter();手动写一个计数值
  • TIM_SetAutoreload(); 手动写一个自动重装值
  • TIM_GetCounter();获取当前计数器的值
  • TIM_GetPrescaler();获取当前预分频器的值

编写TIM定时器外部时钟代码(基本任务仍然是定时中断,时钟由内部时钟改为使用外部时钟)
初始化定时器时从左至右参考该图流程
1、完成驱动文件导入操作和编写驱动程序基本代码(参考之前文章)
//TIM定时器不涉及外部硬件,因此将配置文件放在【System】文件夹里
2、在Timer.c中初始化函数 Timer _Init
void Timer_Init(void)
{
//第一步:开启外部时钟和外设时钟(注意使用APB1的开启时钟函数,因为TIM2是APB1总线的外设
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    
//需要额外配置GPIO来驱动对射式红外传感器
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
//第二步:选择时基单元的时钟(在stm32f10x_tim.h文件中查找函数)
    TIM_ETRClockMode2Config(TIM2,TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted,0x04);
//通过ETR引脚的外部时钟模式2配置
//时基单元就由外部时钟ETR(查表可知引脚PA0)驱动了
    
//第三步:配置时基单元(在stm32f10x_tim.h文件中查找函数)
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//指定时钟分频
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//指定计数器模式(此处选择向上计数)
    TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//指定要在下一次更新事件时加载到ARR自动重新加载寄存器中的周期值  ARR取值[0,65535]
    TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;//指定用于划分TIM时钟的预分频器值    PSC取值[0,65535]
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//指定重复计数器的值(高级定时器才用得上,本项目给0)
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);//初始化时基单元
    
    TIM_ClearFlag(TIM2,TIM_FLAG_Update);
    
//第四步:使能更新中断(在stm32f10x_tim.h文件中查找函数)
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//开启了更新中断到NVIC的通路
//第五步:配置NVIC
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC优先级分组
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;//指定中断通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//指定IRQ通道的抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//指定IRQ通道的响应优先级
    NVIC_Init(&NVIC_InitStructure);
//第六步:启动定时器(在stm32f10x_tim.h文件中查找函数)
    TIM_Cmd(TIM2,ENABLE);
    
//至此定时器就可以开始工作了,当产生更新时,就会触发中断
}
3、在Timer.c中编写中断服务程序函数 TIM2_IRQHandler
在STM32中,中断函数的名字都是固定的,每个中断通道都对应一个中断函数(名字参考启动文件startup_stm32f10x_md.s)
文件中以 IRQHandler结尾的字符串就是中断函数的名字
中断函数都是无参无返回值的
void TIM2_IRQHandler(void)//当定时器产生更新中断时,这个函数就会被自动执行
{
    if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位
    {
    Num ++;
    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
    }
}
在Timer.c中编写获取CNT计数器值的函数 Timer_GetCounter
uint16_t Timer_GetCounter(void)
{
    return TIM_GetCounter(TIM2);
}
4、实现 定时器每秒自动加Num功能
//在maic.c文件中定义一个全局变量uint16_t Num
//中断函数是在Timer模块里,如果在中断函数里写Num++,那么Num就是跨越不同.c文件的变量了
-----------------解决方法一
如果想跨文件使用变量,可以在使用变量的那个文件顶部用【extern】声明要用的变量
extern uint16_t Num;
extern声明变量就是告诉编译器我现在有Num这个变量,请求编译器帮忙在全文件中查找
-----------------解决方法二
直接将Timer.c文件中的中断服务程序函数TIM2_IRQHandler放在main.c的主函数外定义使用,注释掉原来Timer.c的中断函数
//对于定时器而言,这个中断函数就是为别的文件服务的,所以中断函数可以放在使用它的地方
5、在Timer.h中声明初始化函数 Timer _In it和CNT计数器值的函数 Timer_GetCounter
void Timer_Init(void);
uint16_t Timer_GetCounter(void);
//中断函数不用声明,因为中断函数不需要调用,会自动执行
6、在主程序main.c中 #includ " Timer .h "
#include "Timer.h"
7、在主循环之前先初始化外部中断
8、在主循环中编写程序主体
int main(void)
{
    OLED_Init();
    Timer_Init();
    
    OLED_ShowString(1,1,"Num:");
    OLED_ShowString(2,1,"CNT:");
    while(1)
    {
        OLED_ShowNum(1,5,Num,5);
        OLED_ShowNum(2,5,Timer_GetCounter(),5);//观察CNT计数器的变化情况
    }
}
void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)//检查中断标志位
    {
        Num ++;
        TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除中断标志位
    }
}
实现功能:上电后OLED显示Num:00000,对射式红外传感器每触发一次中断,CNT++,CNT到9后清零,Num++

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/285279?site
推荐阅读
相关标签
  

闽ICP备14008679号