GD32F450ZIT6脉冲捕获会丢失脉冲的问题

news/2024/11/17 12:57:13/

目录

问题描述: 

(1)捕获timer初始化

(2)捕获中断处理函数

(3)速度计算公式

原因查找:

(1)库函数的原因

(2)timer_channel_capture_value_register()位置的原因


问题描述: 

四个脉冲捕获通道均给1000Hz 的脉冲,运行一段时间后,四个通道捕获的脉冲数差距
较大,增加相邻脉冲差值计算代码后,发现同一通道的采集的两个脉冲之间的时钟计数差值
可能是正常情况下的2 倍/3 倍/4 倍/5 倍/6 倍。 

 排查了一两个月,怀疑单板,怀疑芯片,怀疑测试台,怀疑软件,怀疑人生....

我原来的程序是下面这样的:

(1)捕获timer初始化

void initialize_CAP_IN_timer(void)
{uint32_t timer = TIMER1;uint32_t timer_clk = RCU_TIMER1;timer_parameter_struct timer_initpara;timer_ic_parameter_struct timer_icinitpara;rcu_periph_clock_enable(timer_clk);rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);timer_deinit(timer);timer_initpara.prescaler = 199u;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = 0xFFFFFFFFu;timer_initpara.clockdivision = TIMER_CKDIV_DIV1;	timer_initpara.repetitioncounter = 0u;timer_init(timer, &timer_initpara);timer_auto_reload_shadow_enable(timer);timer_channel_input_struct_para_init(&timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_0, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_1, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_2, &timer_icinitpara);timer_input_capture_config(timer, TIMER_CH_3, &timer_icinitpara);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH0);timer_interrupt_enable(timer, TIMER_INT_CH0);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH1);timer_interrupt_enable(timer, TIMER_INT_CH1);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH2);timer_interrupt_enable(timer, TIMER_INT_CH2);timer_interrupt_flag_clear(TIMER1,TIMER_INT_CH3);timer_interrupt_enable(timer, TIMER_INT_CH3);timer_enable(timer);timer_interrupt_flag_clear(timer, TIMER_INT_FLAG_UP);return;
}

(2)捕获中断处理函数

void TIMER1_IRQHandler(void)
{if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)){gw_CAP_NUM_INT[0]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH1)){gw_CAP_NUM_INT[1]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH1);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH2)){gw_CAP_NUM_INT[2]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH2);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH3)){gw_CAP_NUM_INT[3]++;timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH3);}
}

(3)速度计算公式

简单来说,就是看20ms内发生了多少个脉冲。

static void CALC_velocity_and_FRQ(void)
{UINT_8  i, j;UINT_32 sum[4] = {0, 0, 0, 0};UINT_32 every_pulse_tick_avg[4];.../* 获得速度脉冲计数和时钟脉冲计数 */for (i=0; i<=3; i++){gw_CAP_NUM_last[i] = gw_CAP_NUM[i];gl_CAP_TCNT_last[i] = gl_CAP_TCNT[i];/* 读取速度捕获脉冲中断计数值 */gw_CAP_NUM[i] = gw_CAP_NUM_INT[i];gl_CAP_TCNT[i] = timer_channel_capture_value_register_read(TIMER1, i); }/* for (i=0; i<=3; i++) *//* 计算速度脉冲计数和时钟脉冲计数的差值,并计算各轴速度 */for (i=0; i<=3; i++){/* 备份上个周期计算的差值 */gw_CAP_NUM_delta_backup[i]  = gw_CAP_NUM_delta[i];gl_CAP_TCNT_delta_backup[i] = gl_CAP_TCNT_delta[i];/* 计算本周期的差值 */gw_CAP_NUM_delta[i]  = gw_CAP_NUM[i] - gw_CAP_NUM_last[i];gl_CAP_TCNT_delta[i] = gl_CAP_TCNT[i] - gl_CAP_TCNT_last[i];if (gl_CAP_TCNT_delta[i] > 0)       /* 除数为0处理 */{gw_velocity_value[i] = (gl_wheel_with_COEF[i] * gw_CAP_NUM_delta[i])/ gl_CAP_TCNT_delta[i];}...}   /* for (i=0; i<=3; i++) */return;
}   /* CALC_velocity_and_FRQ() */

原因查找:

经过代码排查,最后发现是下面两个原因导致的,芯片售后没有给出具体解释,我也搞不懂。

(1)库函数的原因

这版有问题的程序用的是V2.0.0

/*!\file    gd32f4xx_timer.c\brief   TIMER driver\version 2016-08-15, V1.0.0, firmware for GD32F4xx\version 2018-12-12, V2.0.0, firmware for GD32F4xx
*/...void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt)
{TIMER_INTF(timer_periph) &= (~(uint32_t)interrupt);
}...

需要用新版的库,V2.1.0以后好像都把上面那个“&”给去掉了,中断标志是硬件置位的,软件写0清标志,写1没有影响。按理来讲两种写法没有区别,但是不知道官方为什么会修正这个函数,可能有硬件设计方面的原因?

/*!\file    gd32f4xx_timer.c\brief   TIMER driver\version 2016-08-15, V1.0.0, firmware for GD32F4xx\version 2018-12-12, V2.0.0, firmware for GD32F4xx\version 2020-09-30, V2.1.0, firmware for GD32F4xx\version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/void timer_interrupt_flag_clear(uint32_t timer_periph, uint32_t interrupt)
{TIMER_INTF(timer_periph) = (~(uint32_t)interrupt);
}

(2)timer_channel_capture_value_register()位置的原因

读取脉冲发生时刻timer_count寄存器值的函数timer_channel_capture_value_register()放在中断里,而不能放在20ms中断里。也是搞不懂。。。

uint32_t gl_timer_channel_capture_value[i]; /*用来存放触发时刻timer寄存器的值*/void TIMER1_IRQHandler(void)
{if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)){gw_CAP_NUM_INT[0]++;gl_timer_channel_capture_value[0] = timer_channel_capture_value_register_read(TIMER1, 0);   timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH1)){gw_CAP_NUM_INT[1]++;gl_timer_channel_capture_value[1] = timer_channel_capture_value_register_read(TIMER1, 1);   timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH1);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH2)){gw_CAP_NUM_INT[2]++;gl_timer_channel_capture_value[2] = timer_channel_capture_value_register_read(TIMER1, 2);   timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH2);}if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH3)){gw_CAP_NUM_INT[3]++;gl_timer_channel_capture_value[3] = timer_channel_capture_value_register_read(TIMER1, 3);   timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH3);}
}
static void CALC_velocity_and_FRQ(void)
{UINT_8  i, j;UINT_32 sum[4] = {0, 0, 0, 0};UINT_32 every_pulse_tick_avg[4];.../* 获得速度脉冲计数和时钟脉冲计数 */for (i=0; i<=3; i++){gw_CAP_NUM_last[i] = gw_CAP_NUM[i];gl_CAP_TCNT_last[i] = gl_CAP_TCNT[i];/* 读取速度捕获脉冲中断计数值 */gw_CAP_NUM[i] = gw_CAP_NUM_INT[i];gl_CAP_TCNT[i] = gl_timer_channel_capture_value[i]; /*这里改用全局变量读取*/}/* for (i=0; i<=3; i++) *//* 计算速度脉冲计数和时钟脉冲计数的差值,并计算各轴速度 */for (i=0; i<=3; i++){/* 备份上个周期计算的差值 */gw_CAP_NUM_delta_backup[i]  = gw_CAP_NUM_delta[i];gl_CAP_TCNT_delta_backup[i] = gl_CAP_TCNT_delta[i];/* 计算本周期的差值 */gw_CAP_NUM_delta[i]  = gw_CAP_NUM[i] - gw_CAP_NUM_last[i];gl_CAP_TCNT_delta[i] = gl_CAP_TCNT[i] - gl_CAP_TCNT_last[i];if (gl_CAP_TCNT_delta[i] > 0)       /* 除数为0处理 */{gw_velocity_value[i] = (gl_wheel_with_COEF[i] * gw_CAP_NUM_delta[i])/ gl_CAP_TCNT_delta[i];}...}   /* for (i=0; i<=3; i++) */return;
}   /* CALC_velocity_and_FRQ() */

 有人遇到同样的问题吗?


http://www.ppmy.cn/news/797713.html

相关文章

计算机控制点火系统如何控制点火提前角,电子点火系统如何控制点火提前角?...

点火提前角正常值范围为6到12。点火提前角&#xff1a;从点火时刻起到活塞到达压缩上止点&#xff0c;这段时间内曲轴转过的角度&#xff0c;能使发动机获得最佳动力性、经济性和最佳排放时的点火提前角称为最佳点火提前角。最小的点火提前角为0度&#xff0c;但是为了防止汽车…

STM32单脉冲模式

STM32的定时器可以设置成单脉冲模式&#xff08;OPM&#xff09;。所谓的单脉冲就是通过程序在一定可控延时后&#xff0c;产生一个脉宽可控的脉冲。这里的延时时间与脉冲宽度都可以设置&#xff0c;主要通过比较&#xff1a;定时器的计数值TIM_CNT、定时器的比较值TIM_CCRx与定…

STM32脉冲计数

STM32脉冲计数&#xff08;ETR&#xff09; 本次我们使用STM32F103RCT6&#xff08;mini&#xff09;最小系统板和STM32cubeMX来教学 首先&#xff1a;基本的配置&#xff1a;时钟、下载配置、串口&#xff08;用于显示&#xff0c;记得重写fputc函数&#xff09; 然后随便…

脉冲按钮

下载VS2008 source and demo project - 34.4 KB介绍 本文演示了如何使用。net 2.0和GDI创建带有动态元素(pulse)的按钮。该控件利用了。net框架的Button类。 按钮状态 这里是不同的按钮状态: 鼠标移过的地方显示为白色(透明)边框&#xff0c;焦点显示为纯橙色。按下状态与默…

【LeetCode】HOT 100(22)

题单介绍&#xff1a; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数据结构的新手和想要在短时间内高效提升的人&#xff0c;熟练掌握这 100 道题&#xff0c;你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

计算机控制点火系统没有分电器对不对,点火系

C. 电阻型火花塞可以抑制点火系统对无线电的干扰 D. 多级型火花塞有多个中央电极 11. 火花塞型号为F5RTC&#xff0c;下列对它的描述正确的是()。 K电阻 C . 多极型 D.锥座 A . 热值为10 B. 装有5~10 12. 下列()不是磁感应信号发生器的组成部分 A. 永久磁铁 B. 信号转子 C. 电容…

4223. 点火游戏

给定一个 N行 M 列的方格矩阵。 其中一部分方格是草地&#xff0c;其余部分是空地。 草地能够被燃烧&#xff0c;空地不会。 当某个草地在 t 时刻被点燃时&#xff0c;其上下左右四个方向的相邻方格中的草地方格也会在 t1 时刻被点燃。 注意&#xff0c;空地方格无论如何都不可…

altronic点火模块维修点火盒维修791010-6

altronic点火模块维修点火盒维修791010-6 ALTRONIC点火线盒维修点火系统模块控制器维修北京 altronic发电机组点火模块维修CD1 点火盒维修胜动700机791010-6 Altronic发电机8缸机点火系统电路板维修 根据故障报警和工作表现初步判断故障的类型和哪些硬件出了问题&#xff0…