FPGA处理编码信号进行毛刺滤波
一、前言
在利用处理编码信号时,一般在较为理想的环境下可以很方便进行计算,判断等。但是由于有时候受到电磁干扰等环境因素,会导致编码信号产生毛刺等,这时候如果不对编码信号进行预处理而是直接进行边缘判断等操作则极容易导致错误,所以需要提前对编码信号进行滤波。
二、滤波算法
这里使用的是一篇专利里的滤波方法:
其算法思想也容易理解:如果有电平跳变,则立即进行计数,如果计数值超过设定阈值,则电平跳转有效,否则依然保持原电平不变。另外如果在计数时又发生电平跳转,则重新进行计数。滤波算法跳转图如下:
三、代码设计
首先我们需要确定编码信号的毛刺信号大概时间宽度为多少,这样我们才能设置阈值进行滤波。以Altera芯片设计为例,可以利用SigalTapII嵌入式逻辑观测毛刺的时间宽度。
这样设计代码如下即可实现滤波效果:
module encoder_filter ( input clk, input A, //原始编码信号A output reg A_f, //滤波后的编码信号A_f output led, //观测程序是否烧录成功 output samp_clk_20us //SigalTapII中采样时钟 ); pll_ip pll_ip_inst ( //调用PLL_IP .inclk0 ( clk ), .c0 ( samp_clk_20us ) ); parameter [11:0] Cnt_20us=12'd1000; //20us/20ns=1000; //毛刺的脉宽不会大于20us parameter [1:0] S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11; reg [1:0] state; //当前状态 reg [2:0] A_delay; //延迟打拍 reg [11:0] count; //电平跳转计数 reg last_level; //A的上一个电平状态 reg A_sig_pos; reg A_sig_neg; reg [7:0] reset_counter=8'd0; always@(posedge clk) //软件不发复位信号,FPGA自己产生,逻辑加载起来后马上自己复位一次。 begin if (reset_counter != 8'h59 ) reset_counter <= reset_counter + 8'h1; end reg n_rst; always@(posedge clk) //软件不发复位信号,FPGA自己产生,逻辑加载起来后马上自己复位一次。 begin if((reset_counter > 8'd1)&&(reset_counter < 8'd6)) n_rst <= 1'b0; else n_rst <= 1'b1; end assign led=1'b0; always @(posedge clk or negedge n_rst ) //将外部a信号进行时钟同步 begin if(n_rst==1'b0) A_delay <=2'b00; else A_delay <={A_delay[1:0],A}; end wire A_risingedge=(A_delay[2:1]==2'b01); wire A_fallingedge=(A_delay[2:1]==2'b10); always @(posedge clk or negedge n_rst ) begin if(n_rst==1'b0) begin state<= S0; count<=12'b0; last_level<=1'b0; A_sig_neg<=1'b0; A_sig_pos<=1'b0; end else case(state) S0://空闲状态,判断电平是否变化 begin if(A_risingedge||A_fallingedge) begin state<= S1; count<=12'b0; last_level<=A_delay[2]; end end S1://计数状态 begin if(A_delay[2]==A_delay[1]) if(count==Cnt_20us)//判断计数是否达到20us begin count<=12'b0; state<= S2; end else count<=count+1'b1; else count<=12'b0; end S2://判决状态 begin state<= S3; if(!last_level&&A_delay[1])//确定是由低电平---->高电平 begin A_sig_pos<=1'b1; A_sig_neg<=1'b0; end else if(last_level&&!A_delay[1])//确定是由高电平---->低电平 begin A_sig_neg<=1'b1; A_sig_pos<=1'b0; end else begin A_sig_neg<=1'b0; A_sig_pos<=1'b0; end end S3: begin state<= S0; count<=12'b0; end default: begin state<= S0; count<=12'b0; end endcase end always @(posedge clk or negedge n_rst ) begin if(n_rst==1'b0) A_f<=1'b0; else if(A_sig_pos==1'b1) A_f<=1'b1; else if(A_sig_neg==1'b1) A_f<=1'b0; else A_f<=A_f; end endmodule
值得注意的是:
1、需要根据实际毛刺Cnt_20us的时间宽度改变阈值
2、在程序使用了软复位,由于未设置按键这种异步复位,就实际程序随板子上电后在主时钟下进行软件同步复位
本文作者:一枚来自光电的硅农
本文链接:https://www.cnblogs.com/lgziyan/p/17933486.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步