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 {
// 反向转动
}
*/
}
}
############################################################################################################
交流使人进步,碰撞产生火花! 欢迎 大家留言评论! ############################################################################################################