STM32G431RBTx嵌入式开发教程:定时器中断流水灯实现

嵌入式开发–STM32G431RBTx-定时器中断流水灯

定时器工作原理

image-20240306221155182

如图有反映stm32g431的定时器资源。

共10个定时器

定时器 定时器类型 个数
TIM6,7 基本定时器 2
TIM2,3,4 全功能通用定时器 3
TIM15,16,17 通用定时器(只有1或2个通道) 3
TIM1,8 高级控制定时器 2


image-20240320163019569

  • 当APB1/2分频系数为1时,给定时器的时钟为X1
  • 当APB1/2分频系数不为1时,给定时器时钟需X2
  • 基本定时功能,当累加的时钟脉冲数超过预定值时,能触发中断或者触发DMA请求。

    是专门用于驱动数模转换器(DAC)

    基本定时器TIM6/7内部结构图

    image-20240320162924796

  • 核心功能是控制CK_INT时钟是否可以正常传输到PSC预分频器内
  • 当更新事件发生的时候,重装载寄存器的数值才传递到影子寄存器里。影子寄存器是真正起作用的寄存器。当使用定时器过程中,如果不修改这个寄存器,就不涉及这个问题。
  • 【寄存器组成】

    计数器寄存器(TIMx_CNT)

    预分频寄存器(TIMx_PSC)

    自动重装载寄存器(TIMx_ARR)

    这三个寄存器都是16位有效数字,可设置的值为0~65535。

    【预分频器】
    CK_CNT=CK_PSC/(PSC[15:0]+1)
    【计数过程】

    每来一个CK_CNT脉冲,TIMx_CNT值就加1,当TIMx_CNT值与TIMx_ARR的设定值相等时就自动生成更新事件(也可以产生DMA请求、产生中断信号或者触发DAC同步电路),并且TIMx_CNT自动清零,然后重新开始计数,不断重复上述过程。因此我们只要设定TIMx_PSC和TIMx_ARR这两个寄存器的值就可以控制事件生成时间。对应的就是程序中定时器预分频设置(斜率)和定时器周期。

    基本定时器TIM6/7时钟和基本信号

    image-20240320173541116

    配置定时器

    设定TIM6定时器

    image-20240320174021480

    设定系数

    image-20240320174808589

    第一个是分频系数(Prescaler)

    第二个是周期计数值,按照分频后的时间进行计数(Counter Period)

    80M的晶振除以8000,得到的工作频率为80 000 000/8 000=10 000

    计算到ARR,如果是1s,就让ARR设置为10 000-1

    如此频率乘周期即为时间,即为一次中断触发的时间为1s

    使用中断

    image-20240320174839457

    关于按键中断的实现

    	struct keys key[4]={0,0,0};	
    
    		if(htim->Instance==TIM3)
    	{
    		key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
    		key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
    		key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
    		key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
        }
    

    这段代码是一个中断回调函数,用于处理定时器 TIM3 的中断事件。代码中包含一个名为 key 的结构体数组,用于记录按键的状态。

    在函数体中,首先通过读取 GPIO 引脚的状态,将按键的状态存储到 key 数组中的相应位置。其中,key[i].key_sta 表示第 i 个按键的状态。

    接下来,使用一个循环遍历 key 数组的每个元素,对每个按键的状态进行判断和处理。

    	for(int i=0;i<4;i++)
    	{
    		switch (key[i].judge_sta)
    		{
    			case 0:  //
    			{
    				if(key[i].key_sta==0) key[i].judge_sta=1;
    			}
    			break;
    			case 1:
    			{
    				if(key[i].key_sta==0)
    				{
    					key[i].judge_sta=2;
    					key[i].single_flag=1;
    				}
    				else key[i].judge_sta=0;
    			}
    			break;
    			case 2:
    			{
    				if(key[i].key_sta==1)
    				{
    					key[i].judge_sta=0;						
    				}
    			}
    			break;	
    		}		
    	}
    

    switch 语句中,根据 key[i].judge_sta 的值来确定需要执行的操作。key[i].judge_sta 表示按键的判断状态。

    key[i].judge_sta的值为 0 时,表示按键处于初始状态。

  • 如果按键的状态为按下(key[i].key_sta 等于 0),则将 key[i].judge_sta 的值设为 1,表示按键已按下。
  • key[i].judge_sta的值为 1 时,表示按键已按下。

  • 如果按键的状态仍然为按下,维持 key[i].judge_sta 的值为 1。
  • 如果按键的状态变为松开(key[i].key_sta 等于 1),则将 key[i].judge_sta 的值设为 2,表示按键已松开,并将 key[i].single_flag 的值设为 1,表示按键被单击。
  • key[i].judge_sta的值为 2 时,表示按键已松开。

  • 如果按键的状态变为按下,将 key[i].judge_sta 的值设为 0,表示按键已按下。
  • 功能实现

    stm32g4xx_it.c文件中TIM6_DAC_IRQHandler函数下添加如下内容。

    void TIM6_DAC_IRQHandler(void)
    {
    
      HAL_TIM_IRQHandler(&htim6);
    	
    	LED_Disp(ledFlag);
    	ledFlag = !ledFlag;
    	
    
    }
    

    即可实现LED在一秒钟亮灭交替效果

    作者:江江江江江江江江江

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32G431RBTx嵌入式开发教程:定时器中断流水灯实现

    发表评论