GD32芯片标准库实现:定时器捕获一定数目脉冲,触发某个事件

1.前言

GD32F407芯片,标准库实现,定时器捕获一定数目脉冲,触发中断。假如每捕获10个脉冲,就触发中断。这里提供两种实现,一个是使用定时器的捕获中断。一个是使用定时器的更新事件。

2.代码实现

2.1 定时器捕获中断

每捕获一个脉冲,就触发一次中断,在中断中计数,每到10个脉冲,就把一个逻辑标志给置上。

c 复制代码
void TIMER7_External_Pulse_Config(void)
{
    /* GPIO初始化(A相接PC6) */
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_af_set(GPIOC, GPIO_AF_3, GPIO_PIN_6);
    
    /* 使能TIMER7时钟 */
    rcu_periph_clock_enable(RCU_TIMER7);
    timer_deinit(TIMER7);
    
    /* 配置时基单元 */
    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    
    timer_initpara.prescaler = 0;           // 不分频
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 65535;          // 16位最大值
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER7, &timer_initpara);
    
    /* 配置输入捕获通道0(A相) */
    timer_ic_parameter_struct ic_initpara;
    timer_channel_input_struct_para_init(&ic_initpara);
    
    ic_initpara.icpolarity = TIMER_IC_POLARITY_RISING;  // 上升沿捕获
    ic_initpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
    ic_initpara.icprescaler = TIMER_IC_PSC_DIV1;        // 每个边沿都捕获
    ic_initpara.icfilter = 0x0F;                        // 滤波器
    
    timer_input_pwm_capture_config(TIMER7, TIMER_CH_0, &ic_initpara);
    
    /* 关键:配置通道0中断(不是更新中断!) */
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_CH0);  // 清除通道0中断标志
    timer_interrupt_enable(TIMER7, TIMER_INT_CH0);      // 使能通道0中断
    
    /* 注意:这里不需要使能更新中断,除非需要处理溢出 */
    // timer_interrupt_enable(TIMER7, TIMER_INT_UP);  // 注释掉这行!
    
    /* 配置NVIC中断 */
    nvic_irq_enable(TIMER7_Channel_IRQn, 2, 0);
    
    /* 使能自动重载影子寄存器 */
    timer_auto_reload_shadow_enable(TIMER7);
    
    /* 设置初始计数值 */
    //timer_counter_value_config(TIMER7, 0);
    
    /* 使能TIMER7 */
    timer_enable(TIMER7);
}

这里使用定时器7的通道0,复用PC6.

中断处理:

c 复制代码
void TIMER7_Channel_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER7, TIMER_INT_FLAG_CH0))
    {
        /* 清除中断标志位 */
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_CH0);
        pulse_count++;
        if(pulse_count >= 0)
        {
        	adc_sample_flag =1; //置逻辑标志
        	pulse_count=0;	//脉冲技术清零,用于下一次10个脉冲技术
        }
				
    }
}

这里使用的是定时器捕获中断

2.2 定时器溢出中断
c 复制代码
/* TIMER7配置 - 外部时钟模式1,每10个脉冲中断一次 */
void TIMER7_External_Clock_Config(void)
{
    /* GPIO初始化 - A相连接到PC6 (TIMER7_CH0) */
    rcu_periph_clock_enable(RCU_GPIOC);
    
    /* 配置PC6为复用功能,上拉输入(确保信号稳定) */
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_af_set(GPIOC, GPIO_AF_3, GPIO_PIN_6);  // TIMER7 AF3
    
    /* 使能TIMER7时钟 */
    rcu_periph_clock_enable(RCU_TIMER7);
    timer_deinit(TIMER7);
    
    /* 配置时基单元 */
    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    
    timer_initpara.prescaler = 0;           // 不分频
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 10 - 1;         // 关键:每10个脉冲中断一次
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER7, &timer_initpara);
    
    /* 配置输入捕获通道0 - 用于检测A相脉冲 */
    timer_ic_parameter_struct ic_initpara;
    timer_channel_input_struct_para_init(&ic_initpara);
    
    ic_initpara.icpolarity = TIMER_IC_POLARITY_RISING;  // 上升沿检测
    ic_initpara.icselection = TIMER_IC_SELECTION_DIRECTTI;  // 直接连接到TI0输入
    ic_initpara.icprescaler = TIMER_IC_PSC_DIV1;        // 每个边沿都捕获
    ic_initpara.icfilter = 0x0F;                       // 滤波,防止抖动
    
    timer_input_capture_config(TIMER7, TIMER_CH_0, &ic_initpara);
    
    /* 配置从模式:外部时钟模式1,触发源为TI0 */
    timer_slave_mode_select(TIMER7, TIMER_SLAVE_MODE_EXTERNAL0);
    
    /* 选择触发源为TI0(通道0输入) */
    timer_input_trigger_source_select(TIMER7, TIMER_SMCFG_TRGSEL_CI0FE0);
    
    /* 使能更新中断 - 每10个脉冲触发一次 */
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER7, TIMER_INT_UP);
	timer_interrupt_disable(TIMER7, TIMER_INT_FLAG_CH0);
 	timer_interrupt_disable(TIMER7, TIMER_INT_FLAG_CH1);
		
    /* 配置NVIC - 使用TIMER7_UP_TIMER12_IRQn */
    nvic_irq_enable(TIMER7_UP_TIMER12_IRQn, 2, 0);
    
    /* 设置初始计数值为0 */
    timer_counter_value_config(TIMER7, 0);
    
    /* 使能TIMER7 */
    timer_enable(TIMER7);
}

中断处理函数:

c 复制代码
void TIMER7_UP_TIMER12_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER7, TIMER_INT_FLAG_CH0))
    {
        /* 清除中断标志位 */
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_CH0);
        pulse_count++;
        if(pulse_count >= 0)
        {
        	adc_sample_flag = 1; //置逻辑标志
        	pulse_count = 0;	//脉冲技术清零,用于下一次10个脉冲技术
        }
				
    }
}
2.3 使用高级定时器编码器模式+更新中断

这种主要使用需要捕获AB相信号,根据AB相来得到电机运动的脉冲数(含方向)。同时每捕获到10个脉冲,产生一次更新中断事件,在更新中断处理函数中,置逻辑标志。

c 复制代码
/* 主定时器TIMER7配置 - 编码器模式,每10个脉冲触发TRGO */
void TIMER7_Master_Encoder_Config(void)
{
    /* GPIO初始化(连接编码器AB相) */
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_af_set(GPIOC, GPIO_AF_3, GPIO_PIN_6 | GPIO_PIN_7);  // TIMER7 AF3
    
    /* 使能TIMER7时钟 */
    rcu_periph_clock_enable(RCU_TIMER7);
    timer_deinit(TIMER7);
    
    /* 配置时基单元 */
    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    
    timer_initpara.prescaler = 0;           // 不分频
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_DOWN;
    timer_initpara.period =  40 - 1;         // 关键:每10个计数产生更新事件
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter =0;
    timer_init(TIMER7, &timer_initpara);
    
    /* 配置编码器接口模式(4倍频) */
    timer_quadrature_decoder_mode_config(TIMER7, 
                                         TIMER_QUAD_DECODER_MODE2,
                                         TIMER_IC_POLARITY_RISING,
                                         TIMER_IC_POLARITY_RISING);
    
    /* 配置主模式:更新事件触发TRGO */
    timer_master_output_trigger_source_select(TIMER7, TIMER_TRI_OUT_SRC_UPDATE);
    
    /* 使能自动重载影子寄存器 */
    timer_auto_reload_shadow_disable(TIMER7);
    
    /* 设置初始计数值 */
    timer_counter_value_config(TIMER7, 80);


    /* 使能更新中断 */
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER7, TIMER_INT_UP);
    
    /* 配置NVIC */
    nvic_irq_enable(TIMER7_UP_TIMER12_IRQn, 2, 0);
		
    /* 使能TIMER7 */
    timer_enable(TIMER7);
}

这里面因为使用的编码器模式是A相和B相信号都捕获。所以是原始脉冲的4倍频。所以此处配置为:

c 复制代码
timer_initpara.period =  40 - 1;         // 关键:每10个计数产生更新事件

同时,需要注意脉冲的变化方向,我这边是从初始值80递减变化的。所以80-->40时,与ARR中一致,就出发了定时器更新或溢出事件。

中断处理函数:

c 复制代码
void TIMER7_UP_TIMER12_IRQHandler(void)
{
		// TIMER7更新中断
    if (timer_interrupt_flag_get(TIMER7, TIMER_INT_FLAG_UP)!= RESET)
    {
        // 清除中断标志位
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_UP);
		adc_sample_flag =1;
		timer_counter_value_config(TIMER7, 80);
    }
}

中断处理函数中需要重置定时器cnt值,以确保下一次40个脉冲仍能触发定时器更新或者溢出中断。

2.4 主从定时器模式

xxx

c 复制代码
/* 主定时器TIMER7配置 - 编码器模式,每10个脉冲触发TRGO */
void TIMER7_Master_Encoder_Config1(void)
{
    /* GPIO初始化(连接编码器AB相) */
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
    gpio_af_set(GPIOC, GPIO_AF_3, GPIO_PIN_6 | GPIO_PIN_7);  // TIMER7 AF3
    
    /* 使能TIMER7时钟 */
    rcu_periph_clock_enable(RCU_TIMER7);
    timer_deinit(TIMER7);
    
    /* 配置时基单元 */
    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    
    timer_initpara.prescaler = 0;           // 不分频
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_DOWN;
    timer_initpara.period =  40 - 1;         // 关键:每10个计数产生更新事件
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter =0;
    timer_init(TIMER7, &timer_initpara);
    
    
  /* =============================配置输入捕获单元===================== */
    timer_ic_parameter_struct timer_ic_initpara;
    /* 输入捕获结构体初始化 */
    timer_channel_input_struct_para_init(&timer_ic_initpara);
    /* 配置过滤器 */
    timer_ic_initpara.icfilter = 0;
    /* 配置边沿极性 */
    timer_ic_initpara.icpolarity = TIMER_IC_POLARITY_RISING;
    /* 配置分频系数 */
    timer_ic_initpara.icprescaler = TIMER_IC_PSC_DIV1;
    /* 配置 */
    timer_ic_initpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
    timer_input_pwm_capture_config(TIMER7, TIMER_CH_0, &timer_ic_initpara);

    /* 使能TIMER1主从模式 用于CNT硬件清零 */
    timer_master_slave_mode_config(TIMER7, TIMER_MASTER_SLAVE_MODE_ENABLE);
    /* 配置触发源 */
    timer_input_trigger_source_select(TIMER7, TIMER_SMCFG_TRGSEL_CI0FE0);//边沿触发  TIMER_SMCFG_TRGSEL_CI0FE0是通道0 TIMER_CH_0 相对应
    /* 配置从模式 */
    timer_slave_mode_select(TIMER7, TIMER_SLAVE_MODE_RESTART);

    /* 使能TIMER1自动重载寄存器影子 */
    timer_auto_reload_shadow_enable(TIMER7);

    /* 清除中断标志位 */
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_CH0);
    /* 使能TIMER1中断 */
    timer_interrupt_enable(TIMER7, TIMER_INT_CH0);
    /* 使能NVIC */
    nvic_irq_enable(TIMER7_Channel_IRQn, 2, 0);
    
	  /* 设置初始计数值 */
    timer_counter_value_config(TIMER7, 60000);
		
    /* 使能TIMER7 */
    timer_enable(TIMER7);
}
	
/* 从定时器TIMER1配置 - 接收TIMER7的触发,每10个脉冲中断 */
void TIMER1_Slave_Config(void)
{
    /* 使能TIMER1时钟 */
    rcu_periph_clock_enable(RCU_TIMER1);
    timer_deinit(TIMER1);
    
    /* 配置时基单元 */
    timer_parameter_struct timer_initpara;
    timer_struct_para_init(&timer_initpara);
    
    timer_initpara.prescaler = 0;
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection = TIMER_COUNTER_UP;
    timer_initpara.period = 1 - 1;          // 每次触发就中断
    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1, &timer_initpara);
    
    /* 配置从模式:外部触发模式0 */
    timer_slave_mode_select(TIMER1, TIMER_SLAVE_MODE_EXTERNAL0);
    
    /* 关键:选择触发源为ITI1(来自TIMER7) */
    timer_input_trigger_source_select(TIMER1, TIMER_SMCFG_TRGSEL_ITI1);
    
    /* 配置中断 */
    timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER1, TIMER_INT_UP);
    
    /* 配置NVIC */
    nvic_irq_enable(TIMER1_IRQn, 1, 0);
    
    /* 使能自动重载影子寄存器 */
    timer_auto_reload_shadow_enable(TIMER1);
    
    /* 使能TIMER1 */
    timer_enable(TIMER1);
}

使用TIMER7的更新/溢出中断事件,作为TIMER1定时器的触发源。查阅芯片使用户手册,GD32F407芯片,定时器TIMER7内部与定时器TIMER1相连,可使用ITI1: TIMER1_TRGO 作为触发。


中断处理函数:

c 复制代码
/* TIMER1中断处理函数 - 每10个脉冲执行一次 */
void TIMER1_IRQHandler(void)
{
    if(timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_UP))
    {
        timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
        
        /* 每10个脉冲触发ADC采样 */
        adc_sample_flag1 ++;
        
        /* 可选:获取编码器当前值 */
        uint16_t encoder_val = timer_counter_read(TIMER7);
			/*
        uint8_t direction = timer_counter_direction_get(TIMER7);
        
        // 可以根据方向做不同处理
        if(direction == TIMER_COUNTER_UP) {
            // 正向转动
        } else {
            // 反向转动
        }
			*/
    }
}

############################################################################################################
交流使人进步,碰撞产生火花! 欢迎 大家留言评论! ############################################################################################################

相关推荐
List<String> error_P18 天前
STM32窗口看门狗WWDG详解
stm32·单片机·嵌入式硬件·定时器
youcans_18 天前
【动手学STM32G4】(13)STM32G431之 TIM+ADC
stm32·单片机·嵌入式硬件·定时器
List<String> error_P19 天前
独立看门狗IWDG原理详解
stm32·单片机·嵌入式硬件·定时器
List<String> error_P21 天前
定时器输出捕获与输入比较
stm32·定时器
List<String> error_P22 天前
STM32 Systick定时器介绍
stm32·定时器·systick
Da Da 泓23 天前
多线程(八)【定时器】
java·学习·多线程·定时器
ベadvance courageouslyミ1 个月前
51单片机相关
单片机·51单片机·定时器·pwm·蜂鸣器·中断·独立按键
YouEmbedded1 个月前
解码STM32定时器:原理、配置与实战
stm32·定时器·pwm·sg90舵机
youcans_1 个月前
【动手学STM32G4】(8)STM32G431之 DAC进阶
stm32·单片机·嵌入式硬件·dma·定时器