申明:本文内容大多是网上资料的总结,作者有亲自试过的思路:输入捕获法、FPGA+STM32(F103ZET6)。文章只是总结一下思路。附STM32输入捕获法的代码。
1、STM32测频率方案:
思路1:使用外部时钟计数器
这种方法推荐。思路是配置两个定时器,定时器a设置为外部时钟计数器模式,定时器b设置为定时器(比如50ms溢出一次,也可以用软件定时器),然后定时器b中断函数中统计定时器a在这段时间内的增量,简单计算即可。
缺点:
1. 无法测量占空比,高频的占空比测量方法见下文。
2. 在频率较低的情况下,测量精度不如思路 3 (因为测量周期为 100ms ,此时如果脉冲周期是 200ms ……)。
3. 输入幅值必须超过 3V 。如果不够或者超出,需要加入前置放大器。
总结:这种方法精度很高。(作者没试过)
思路2:输入捕获
一般来说,对STM32有一定了解的坛友们在测量频率的问题上往往都会想到利用输入捕获。首先设定为上升沿触发,当进入中断之后(rising)记录与上次中断(rising_last)之间的间隔(周期,其倒数就是频率)。再设定为下降沿,进入中断之后与上升沿时刻之差即为高电平时间(falling-rising_last),高电平时间除周期即为占空比。
优点:该方法尤其是在中低频( <100kHz)之下精度不错。
缺点:稍有经验的朋友们应该都能看出来,该方法仍然会带来极高的中断频率。在高频之下,首先是 CPU时间被完全占用,此外,更重要的是,中断程序时间过长往往导致会错过一次或多次中断信号,表现就是测量值在实际值、实际值× 2、实际值× 3等之间跳动。实测中,最高频率可以测到约 400kHz。
总结:该方法在低频率( <100kHz)下有着很好的精度,在考虑到其它程序的情况下,建议在 10kHz之下使用该方法。同时,可以参考以下的改进程序减少 CPU负载。
改进:
前述问题,限制频率提高的主要因素是过长的中断时间(一般应用情景之下,还有其它程序部分的限制)。所以进行以下改进:
1. 使用 2个通道,一个只测量上升沿,另一个只测量下降沿。这样可以减少切换触发边沿的延迟,缺点是多用了一个 IO口。
2. 使用寄存器,简化程序
提出了几个改进意见,列出如下:
1. 可以设定仅有通道 2 进行下降沿捕获并触发中断,而通道 1 捕获上升沿不触发中断。在中断函数当中,一次读取 CCR1 和 CCR2 。这样可以节省大量时间。
2. 可以先进行一次测量,根据测量值改变预分频值 PSC ,从而提高精度
3. 间隔采样。例如每 100ms 采样 10ms.
这样的改进应当能够将最高采样频率增加到 2M.
总体方案:
首先 ADC 测量幅值并据此改变前置放大器放大倍数,调整幅值为 3.3V ,同时测量得到参考占空比。而后使用外部时钟计数器测量得到频率,如果较高( >10000 )则确认为频率数据,同时 ADC 测量占空比确认为占空比数据。否则再使用输入捕获方法测量得到频率、占空比数据。
对于各个方法存在的线性误差,使用了线性补偿来提高精度。一般情况下,使用存储在 ROM 中的数据作为参数,当需要校正时,采用如下校正思路:
波形发生器生成一些预设参数波形(例如 10Hz , 10% ; 100K , 50% ; 2M , 90% ……),在不同区间内多次测量得到数据,随后以原始数据为 x ,真实数据为 y ,去除异常数据之后,做 y=f(x) 的线性回归,并取相关系数最高的作为新的参数,同时存储在 ROM 当中。
下面特别讲作者亲自试过的STM32输入捕获程序思路(没做数据的补偿,实时串口输出,绝对误差在10^-1级别),直接看我代码就行。
TIM配置注意点:
1、在TI1输入的上升沿时捕获计数器的值到TIMx_CCR1寄存器(CCR1[15:0]:捕获/比较通道1的值 (Capture/Compare 1 value))中
2、TIMx_CCR1必须连接到TI1输入
3、当发生一个输入捕获时:
● 产生有效的电平转换时,计数器的值被传送到TIMx_CCR1寄存器。
● CC1IF标志被设置(中断标志)。当发生至少2个连续的捕获时,而CC1IF未曾被清除,CC1OF也被置’1’。
● 如设置了CC1IE位,则会产生一个中断。
● 如设置了CC1DE位,则还会产生一个DMA请求
TIM_IT_CC1
TIM 捕获/比较 1 中断源
TIM_IT_CC2
TIM 捕获/比较 2 中断源
3、TIMx通道对应的IO口配置问题
I/O口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz),这个速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在I/O口 的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。
输入模式可以不用配置速度,直接配成先拉输入。
数据分析:
计数n=T/Ttimer=1/f测*Ttimer
测量信号与单片机应该共地,否则测试不准
思路三:FPGA+MCU方法通信,(FPGA负责检测频率、相位)作者亲测很准,但是别人的代码就不分享了。
频率检测:由STM32的GPIO产生高低电平,FPGA检测下降沿,打开闸门开关T1S_gate(状态为1有效,计数1s后关闭)-->被测信号上升沿-->打开测率开关(Freq_real_gate),同时计数被测信号和基准时钟信号(由Freq_real_gate控制),直到1s后闸门关闭-->闸门关闭,检测Freq_real_gate下降沿-->输出检测完成信号(Done_sig,高电平有效)
相位检测:同时检测两个信号上升沿-->信号1上升沿来时,信号1开始位(r_start1)有效(1)-->若开始位有效和计数输出为零-->测试位有效r_detect_avail(‘1’)-->允许基准时钟计数
信号2上升沿来时,信号2开始位(r_start2)有效(1)(计数数据输出)--->同时测试位失效r_detect_avail(‘0’)-->下一个基准时钟上升沿来时,计数数据清零
数据传输:
9600波特率,1/9600s传输一位0或1。若时钟为25Mhz,需计数到25*10^6/9600=2604次传输1bit
计数模块:根据基准时钟(25Mhz),计数/传输数据信号有效(‘1’)-->计数到1302产生传输一位数据的信号(BPS_CLK,计数到1302为高电平),计数到2046,重新计数。
控制发送模块:计数/传输数据信号有效(‘1’)-->若BPS_CLK有效(‘1’)--i=0时,无效数据‘0’发送。i=1~8时,发送输入的数据。i=9~12,连续发送3个‘1’
顶层调用多数据发送模块:频率检测完成信号有效Done_sig-->将输入端口的数据转移到存储器模块,reg根据输入数据的大小而定。-->若传输数据转移完成 j=1且允许传输寄存器失效ren=0-->根据 j的值,赋值对应转移数据寄存器区域数据给控制发送模块输入端口,传输数据使能有效ren=1.
STM32输入捕获:https://download.csdn.net/download/m0_47789085/20298584