2_stm32定时中断点灯

       定时器是个好东西啊~

       之前搞上层应用时,通过定时器可以以某种频率刷新状态,stm32定时器的一种功能就是如此。此外,stm32的定时器还有很多其他功能,如PWM输出等。定时器具体再细分可以分为高级控制定时器、通用定时器、基本定时器等。

1、定时时间的计算

       基本定时器只具备基本的定时功能,也就是在时钟源的驱动下,从0开始累加脉冲计数,直到超过预定值,然后触发中断或者触发DMA请求。基本定时器和通用定时器的时钟源都是TIMxCLK,TIMxCLK在时钟树中的位置如下:

adc586b6e1209c92b500aff90cd7b63a.png

当APB1的预分频系数为1时,则TIMxCLK就是APB1的频率(也等于AHB的频率);而当APB1的预分频系数不为1时,则TIMxCLK就是APB1的频率的2倍。比如在常见的配置中,AHB=168Mhz,而APB1二分频为84Mhz,那么TIMxCLK就为84Mhz*2=168Mhz。

TIMxCLK的脉冲还会再经过一道分频,然后被TIMx_CNT寄存器累加计数。这个分频器叫做PSC预分频器。PSC预分频器可以设置为任意16位值。当TIMx_CNT的值等于TIMx_ARR寄存器中的值时,产生溢出事件,可用于触发中断。    

根据定时器时钟的频率,比如时钟的频率是168MHZ,可以理解为一秒钟STM32会自己数168M次,预分频系数就是将频率分割,比如分频系数是168,则该时钟的频率会变成168MHZ/168=1MHZ,但是在设置的时候要注意,数值应该是168-1。假定分频系数是168-1,那么频率变成1MHZ,也就意味着STM32在一秒钟会数1M次,即1us数一次。

       接下来就是确定预装载值,比如需要定时1ms,由于1ms=1us*1000,那么预装载值就是1000-1;如此类推,在预分频系数确定的情况下,定时的时长就由预装载值确定了。

       定时1秒设置实例:

//168M/16800=10000Hz
TIM_Prescaler         = 16800-1;
//0.0001s*10000 = 1s
TIM_Period            = 10000-1;

2、定时器与中断的配置

//20240801
void TIM3_Conf(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  //168M/16800=10000Hz    
  TIM_TimeBaseStructure.TIM_Prescaler         = 16800-1;
  TIM_TimeBaseStructure.TIM_Period            = 10000-1;
  TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;
  TIM_TimeBaseStructure.TIM_ClockDivision     = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
      
  TIM_ARRPreloadConfig(TIM3,ENABLE);
  TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
  TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
  TIM_Cmd(TIM3,ENABLE);
}       


void NVIC_Conf()
{
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;    
  NVIC_Init(&NVIC_InitStructure);
}


void TIM3_IRQHandler(void)
{
  TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
  GPIO_WriteBit(GPIOC,GPIO_Pin_9,g_led_state);
  g_led_state = !g_led_state;
}

       主函数调用:

GPIO_Conf();
TIM3_Conf();
NVIC_Conf();


while(1)
{             
     Delay(10000);
}

       效果如下:

1eb092b2e8143266f4b0568e5edc7b4f.gif

欢迎关注:

a52d78eb1d53de4748f372b9f9baf9d3.png

https://zhou-yuxin.github.io/articles/2016/STM32%E5%AE%9A%E6%97%B6%E5%99%A8%E7%9A%84%E4%BD%BF%E7%94%A8%EF%BC%88%E5%AE%9A%E6%97%B6%E5%99%A8%E4%B8%AD%E6%96%AD%E3%80%81PWM%E8%BE%93%E5%87%BA%E5%92%8C%E8%B7%B3%E5%8F%98%E6%8D%95%E8%8E%B7%E3%80%81%E4%B8%BB%E4%BB%8E%E6%A8%A1%E5%BC%8F%EF%BC%89/index.html

https://blog.csdn.net/ZIIllIIll/article/details/118117534

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用STM32定时中断来控制点灯。以下是一个简单的示例代码,使用定时器TIM2的中断,每隔一段时间触发一次中断,然后在中断处理函数中切换LED的状态。 首先,初始化LED引脚和定时器: ```c #include "stm32f10x.h" #define LED_PIN GPIO_Pin_13 #define LED_PORT GPIOC void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = LED_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_PORT, &GPIO_InitStructure); } void TIM2_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 中断周期为1ms TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1; // 定时器频率为72MHz/7200=10kHz TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 允许更新中断 TIM_Cmd(TIM2, ENABLE); // 启动定时器 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } ``` 然后,编写定时中断处理函数和点灯函数: ```c void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 切换LED状态 GPIO_WriteBit(LED_PORT, LED_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_PIN))); } } void LED_Toggle(void) { GPIO_WriteBit(LED_PORT, LED_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(LED_PORT, LED_PIN))); } ``` 最后,在主函数中初始化LED和定时器,并启动主循环: ```c int main(void) { LED_Init(); TIM2_Init(); while (1) { // 主循环中可以执行其他任务 } } ``` 这样,每隔1ms,定时中断会触发一次,切换LED的状态,实现点灯效果。你可以根据自己的需求修改定时器的周期和LED的引脚信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值