使用FPGA实现频率检测(频率鉴别)

使用FPGA实现频率检测(频率鉴别)

        使用FPGA实现频率检测通常由两种方式,周期测量法和频率测量法。周期测量法是测量信号一个周期内基准时钟的个数,频率测量法是测量固定时间内有多少个信号周期。

        虽然频率测量法测量高频信号时精度更高,但其需要一个闸门时间,响应速度不够快,另外我想是实现的是可以区分1khz、10khz、高电平和低电平的功能,可以说是一个鉴频器,而不是一个频率计,所以根据我的需求说说我的思路和实现方式。

        我的基本思路是利用采样时钟对输入信号的周期和一个周期内的高电平进行计数,将测量值和不同频率的阈值范围进行比较,从而鉴别该输入信号的频率。这个过程不得不涉及到两个问题,一是信号频率识别范围,一是信号占空比的范围。信号传输过程中尤其是远距离传输必然会发生一些失真,所以需要对频率和占空比设计一个合理值,防止误识别。根据需求,我将频率识别范围设置为±10%,占空比设置为±5%,因为我设计的是频率区分,所以范围设计的稍宽,好处就是对不同的环境、温度漂移等容忍性更高。

        在实际使用代码时,遇到一些问题,比如当信号出现高频干扰,代码有时会将1khz误识别为10khz,又进行了一些优化,现记录一下目前的逻辑处理流程。

1、信号预处理。

        我使用了20mhz的外部晶振,系统时钟也选用了该时钟频率。一般情况下高频干扰是ns级别,几ns到几百ns,我将干扰持续时间设置为2us,足够消除高频干扰。具体做法是在每个时钟上升沿,将当前的输入电平与内部已锁存的信号进行比对。如果输入电平发生变化,启动滤波计数器。如果输入电平在 40个时钟周期(2µs) 内发生抖动,计数器清零,变化被忽略。代码如下:

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            glitch_filter_cnt <= 0;
            signal_filtered   <= 1'b0;
            signal_in_d1      <= 1'b0;
        end else begin
            signal_in_d1 <= signal_in; // 同步打拍
            if (signal_in_d1 == signal_filtered) begin
                // 输入与当前输出一致,复位计数器
                glitch_filter_cnt <= 0;
            end else begin
                // 输入电平发生变化,开始计时
                if (glitch_filter_cnt < GLITCH_FILTER_CYCLES) begin
                    glitch_filter_cnt <= glitch_filter_cnt + 1;
                end else begin
                    // 当电平连续稳定维持超过2µs,允许翻转
                    signal_filtered   <= signal_in_d1; 
                    glitch_filter_cnt <= 0;
                end
            end
        end
    end

2、测量计数。

        对经过滤波的信号进行处理,实时检测信号的上升沿和下降沿,通过两个相邻上升沿完成周期测量,通过上升沿和紧邻的下降沿完成脉宽测量,如果输入信号一直没变化,则设置超时时间,让计数器一直累加,达到超时时间后判断是高电平还是低电平。

边沿检测代码:

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) 
            edge_detect_reg <= 2'b00;
        else 
            edge_detect_reg <= {edge_detect_reg[0], signal_filtered};
    end

    // 01 -> 上升沿, 10 -> 下降沿
    assign is_rising_edge  = (edge_detect_reg == 2'b01);
    assign is_falling_edge = (edge_detect_reg == 2'b10);

计数器逻辑:

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            period_cnt     <= 0;
            high_width_cnt <= 0;
            watchdog_cnt   <= 0;
            dc_level_cnt   <= 0;
        end else begin
            // 看门狗计数器
            // 只要有边沿会清零看门狗,否则一直累加直到超时时间
            if (is_rising_edge || is_falling_edge || is_watchdog_timeout) begin
                watchdog_cnt <= 0;
            end else begin
                watchdog_cnt <= watchdog_cnt + 1;
            end

            // 周期计数器
            // 上升沿清零,重新开始测量
            if (is_rising_edge) begin
                period_cnt <= 0;
            end else if (period_cnt < COUNTER_MAX) begin
                period_cnt <= period_cnt + 1;
            end

            // 高电平脉宽计数器
            // 上升沿清零,仅在高电平期间累加
            if (is_rising_edge) begin
                high_width_cnt <= 0;
            end else if (signal_filtered) begin
                if (high_width_cnt < COUNTER_MAX) begin
                    high_width_cnt <= high_width_cnt + 1;
                end
            end

            // 直流电平统计 (DC Level Statistic)
            // 用于超时后判断高电平还是低电平
            if (is_watchdog_timeout || is_rising_edge || is_falling_edge) begin
                dc_level_cnt <= 0;
            end else if (signal_filtered) begin
                dc_level_cnt <= dc_level_cnt + 1;
            end
        end
    end

    assign is_watchdog_timeout = (watchdog_cnt == WATCHDOG_LIMIT_CYCLES);

3、状态输出。

        最终的状态我定义了4种状态,分别用00表示低电平,11表示高电平,01表示10khz,10表示1khz,高低电平属于故障状态,应具有较高优先级,也就是上文提到的看门狗超时时间,我定义的是1.5ms,也就是比1khz的周期再多半个。然后在再次检测到上升沿时判断频率信号的情况,如果周期在0.9ms~1.1ms 之间,且脉宽在0.45ms~0.55ms之间就输出10,如果周期在 90µs~110µs 之间,且脉宽在45µs~55µs之间就输出01,否则输出11,如果既没有发生超时,也不是上升沿时刻,那么输出信号保持上一状态不变。

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            freq_status_out <= STATUS_DC_LOW;
        end else begin
            if (is_watchdog_timeout) begin
                // 高优先级
                if (dc_level_cnt < DC_DETECT_THRESHOLD)
                    freq_status_out <= STATUS_DC_LOW;  // 低电平
                else
                    freq_status_out <= STATUS_UNKNOWN; // 高电平
            end 
            else if (is_rising_edge) begin
                // 低优先级,检测1khz
                if ((period_cnt > PERIOD_MIN_1K) && (period_cnt < PERIOD_MAX_1K) && 
                    (high_width_cnt > WIDTH_MIN_1K) && (high_width_cnt < WIDTH_MAX_1K)) begin
                    freq_status_out <= STATUS_1K;
                end 
                // 检测10khz
                else if ((period_cnt > PERIOD_MIN_10K) && (period_cnt < PERIOD_MAX_10K) && 
                         (high_width_cnt > WIDTH_MIN_10K) && (high_width_cnt < WIDTH_MAX_10K)) begin
                    freq_status_out <= STATUS_10K;
                end 
                // 其他情况输出11
                else begin
                    freq_status_out <= STATUS_UNKNOWN; 
                end
            end
            // 如果没有超时,也没有检测到上升沿,锁存
        end
    end

        上面是我优化后的代码的核心内容,但这份代码还存在一些问题,就是仅仅测量一次就输出结果,没有经过滤波处理,后续应该加上几级滤波处理再输出更好一些。另外,目前的代码只能检测两种频率信号,后续可以增加多频检测功能,比如1kHz,2kHz,5kHz,10kHz,修改相对来说简单,因为逻辑和基本框架已经搭建好了,但如果检测更高频率的信号,比如1mhz,需要注意高频干扰的2us不合适,会把1mhz信号当作干扰滤掉,需要更小滤波深度,比如200ns。

附上一张流程图:

链接:我的代码文件https://download.ZEEKLOG.net/download/xinzhong123456/92555674

Read more

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码_ide_葡萄城技术团队-葡萄城开发者空间 TRAE与Figma MCP:iOS原生应用UI自动生成的艺术-易源AI资讯 | 万维易源 Login | Figma 基于提供的Figma设计文件和网页链接,开发一个完整的前端网站项目。具体要求如下: 1. 页面展示要求: * 采用平铺式布局展示所有页面 * 严格遵循Figma设计稿中的视觉规范 * 实现IOS风格的高保真原型效果 * 确保所有交互元素与设计稿一致 2. 技术实现要求: * 使用现代前端框架(如React/Vue) * 实现响应式布局,适配不同设备 * 添加平滑的页面过渡动画 * 确保所有UI组件的高还原度 3. 交付物要求: * 完整的可运行前端代码 * 详细的部署文档 * 跨浏览器兼容性测试报告 * 性能优化方案 4. 质量标准: * 像素级还原设计稿 * 所有交互功能完整可用 * 代码符合最佳实践

By Ne0inhk

别装了!你写的JS代码全在“裸奔”,99%前端都在背锅!

今天,我想直接撕开一个血淋淋的真相。 在这个行业里,我审查过无数的JavaScript应用程序,甚至包括那些大厂出品的标杆项目。然而,它们几乎无一例外地都藏着致命的安全漏洞。 这不是因为前端开发者们在摸鱼,也并非因为团队对最佳实践视而不见。 真正的原因在于,现代JavaScript这头巨兽实在太复杂、进化太快了,而且它从头到脚都布满了让人防不胜防的暗坑。 无论是在初创公司的草台班子、企业级的豪华看板,还是那些每天处理着真金白银和海量真实用户的核心生产系统里,我一遍又一遍地看着同样的悲剧反复上演。 JS的安全漏洞,最喜欢玩“死一般寂静” 报错导致APP崩溃?那反而是你修了八辈子福得来的福报! 通常来说,当你把代码搞砸了,你立马就能收到反馈。 比如一个直接报错的API请求,一个四分五裂的页面布局,或者测试控制台里那片刺眼的爆红。 但是,安全漏洞根本不跟你玩这套,它们就像隐形杀手一样,蛰伏在死一般的寂静中。 你的UI看起来美轮美奂。你的API跑得顺风顺水。你的自动化测试全绿通过。 可就在同时,在那些你看不见的阴暗角落里,黑客可能正在疯狂窃取你用户的会话令牌(Session

By Ne0inhk
【AI×实时Linux:极速实战宝典】视觉SLAM - 在实时Linux上优化ORB-SLAM3,解决前端特征提取的丢帧问题

【AI×实时Linux:极速实战宝典】视觉SLAM - 在实时Linux上优化ORB-SLAM3,解决前端特征提取的丢帧问题

1. 简介:为什么要在实时 Linux 上跑 SLAM? 视觉 SLAM(vSLAM)是移动机器人、AR/VR、自动驾驶的“视觉小脑”。ORB-SLAM3 作为目前最完整的开源方案,支持单目、双目、IMU,但在 ARM 嵌入式板(如 Jetson Nano、树莓派 5、RK3588)上跑 640×480@30 fps 时,前端特征提取经常“卡帧”——一帧图像超过 33 ms 才能处理完,导致: * 地图漂移,定位精度下降 * 后端优化线程饥饿,直接丢帧 * 用户空间非实时线程被 Linux CFS 调度器“抢跑”

By Ne0inhk
前端拖拽排序实现详解:从原理到实践 - 附完整代码

前端拖拽排序实现详解:从原理到实践 - 附完整代码

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战 🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解 🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用 🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例 ✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧 💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程 🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整 👍《Spring Security》专栏中我们将逐步深入Spring Security的各个

By Ne0inhk