使用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

AI 编程新王 Codex 全面上手指南

AI 编程新王 Codex 全面上手指南 一篇文章带你精通 Codex 四大环境 + 免费使用方法 💡 前言:AI 编程的新时代 AI 编程的竞争正进入“第二轮洗牌期”。 过去几个月,Claude Code 一度成为开发者的宠儿,但频繁的限速、封号、降智问题让不少人头疼。 如今,OpenAI 推出的 Codex 迅速崛起,凭借强大的编程能力和超高性价比,成为“AI 编程新王”。 Codex 是什么? 它是基于 GPT-5 模型打造的专用编程环境,支持命令行、VS Code 插件、SDK 集成、云端操作等多种运行模式。 不论你是写脚本、做项目、还是维护仓库,Codex 都能像“AI 结对程序员”一样协助你高效开发。

用 OpenClaw 配置 Codex 5.3:一套“性价比很高”的个人 AI 编程方案

用 OpenClaw 配置 Codex 5.3:一套“性价比很高”的个人 AI 编程方案

这篇是我自己的实战复盘:从 OAuth 报错、模型没切过去,到最终把 OpenClaw 稳定跑在 openai-codex/gpt-5.3-codex 上,并通过飞书远程使用。 先说结论 如果你也在找「便宜 + 强 + 可控」的方案,我现在这套组合非常能打: * OpenClaw 负责 Agent 编排(工具、文件、会话、渠道) * OpenAI Codex 5.3 负责核心编码能力 * Feishu 作为消息入口(随时远程下指令) * 本地 Workspace 放在 G:\claw,项目资产可控 这套的性价比点在于: 1. 不需要重搭一整套复杂平台 2. Codex 5.3 编码质量明显高于普通通用模型

GitHub Awesome Copilot 项目深度解析:社区驱动的 AI 编程助手增强工具库

GitHub Awesome Copilot 项目深度解析:社区驱动的 AI 编程助手增强工具库

概要 GitHub Awesome Copilot 是一个由社区驱动的开源项目,专注于为 GitHub Copilot 提供丰富的自定义增强工具。该项目汇集了全球开发者贡献的指令、提示词、配置和代理,旨在帮助用户最大化利用 GitHub Copilot 的 AI 编程能力。通过提供模块化的自定义组件,该项目将 Copilot 从一个通用的代码生成工具,升级为能够适应特定领域、工作流和最佳实践的智能编程伙伴。随着 AI 编程助手技术的快速发展,此类社区项目在推动工具实用性和普及性方面扮演着关键角色,特别是在个性化、专业化场景的支持上。 整体架构流程 Awesome GitHub Copilot 项目采用模块化、分层式的架构设计,确保各类自定义组件能够独立管理又相互协作。整体架构流程可分为五个核心层次: 1. 资源层(Resource Layer):作为基础层,包含所有原始的自定义组件文件,如提示词文件(.prompt.md)、指令文件(.instructions.md)

2026年3月23日技术资讯洞察:AI Agent失控,Claude Code引领AI编程新趋势

兄弟们早上好!今天是2026年3月23日,我又准时给大家分享今天的技术资讯啦,就是这么准时!话不多说,开始上菜! 1. Meta内部AI Agent失控:首个Sev 1级生产事故敲响安全警钟 来源: InfoQ《Meta 内部 Agent 失控升级:首个 Sev 1 级事故曝光,系统数据裸奔了两小时》 发布时间: 2026年3月20日 事件回顾:权限失控两小时 上周,Meta内部发生了一起典型的"Agent失控"生产事故。一名Meta员工在内部论坛发帖求助技术问题,另一名工程师调用公司内部的AI Agent来分析问题。然而,这个Agent没有跟调用者私聊,而是直接在论坛上公开发布了建议回复。 更糟糕的是,Agent给出的建议是错误的。提问员工按照这个错误信息操作,导致权限配置出错,大量公司内部数据+用户相关数据短暂暴露给一批原本无权限的工程师。整个暴露过程持续近2小时,Meta内部将其定为Sev 1级,即公司安全事件体系中第二高的严重等级。 技术剖析:上下文压缩的安全隐患