赞
踩
自学fpga,练习一年半,终于从一名车间操作工转行到fpga工程师。入职后领导鉴于我的技术水平(毕竟练习时长不到两年半),所以安排了他口中的小任务——电机信号采样并输出电机转速,任务不难,但还是慌了,下面是我的项目历程。
一、任务分析。
电机的驱动脉冲是一对频率相同的周期性方波,这对周期性方波在相位上相差90度,根据A、B的相位情况判断转动方向,项目使用的电机速率是4000个脉冲一转。现在要输出当前电机的转速、方向,只需对A、B信号采样计数即可。
这样一个小项目,本来没啥可说的,只是一点涉及到抖动的过滤,实际上在信号传输中会产生很多噪声,这些都干扰了信号的采集,所以首先得对输入的信号滤波。
二、代码实现
首先对接收到的信号进行滤波,这里设置了一个阈值,即如果方波的带宽少于5us则视为杂波脉冲,就要将此杂波脉冲屏蔽,然后将滤波后的波形描绘出来。描绘出波形后,对此波形进行边沿计数(这里采取对上升沿计数),计数4000次。在开始对所描绘的波形上升沿计数的时候,同时开始对系统时钟的周期计数(系统时钟周期已知,这里按照开发板为20ns)。由获得4000个采样波形周期的总时间,确定电机的转动周期。
具体代码与注释如下:
- `timescale 1ns / 1ps
- //
- // Company:
- // Engineer:
- //
- // Create Date: 2021/07/17 17:11:41
- // Design Name:
- // Module Name: get_signal
- // Project Name:
- // Target Devices:
- // Tool Versions:
- // Description:
- //
- // Dependencies:
- //
- // Revision:
- // Revision 0.01 - File Created
- // Additional Comments:
- //
- //
-
- module get_signal(
- input sys_clock,
- input rst_n,
- input signalA,
- input signalB
- );
-
- //参数定义
- parameter SYSCLK_TIME=20; //系统时钟的周期
- parameter DELAY_TIME=26'd25_000; //上电后延时一段时间
- parameter NUMBER_pluse=4000;
-
- //上电延时
- reg [25:0]cnt_delay=0;//延时计数器,
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- cnt_delay<=0;
- else if (cnt_delay>= DELAY_TIME) //延时时间有待确认,这里设置成0.5ms,仿真时候可以简化
- cnt_delay<=cnt_delay;
- else
- cnt_delay<=cnt_delay+1;
- end
-
- //将两个信号打两拍寄存
- reg r0_signalA;
- reg r1_signalA;
- reg r1_signalB;
- reg r0_signalB;
- always@(posedge sys_clock )
- begin //思考:这时候打拍子,在复位时,寄存器需要清零吗
- r0_signalA<=signalA;
- r1_signalA<=r0_signalA;
- end
- always@(posedge sys_clock )
- begin
- r0_signalB<=signalB;
- r1_signalB<=r0_signalB;
- end
-
- //获得输入信号的上升沿(使用assign还是使用always块?根据testbench可以看出差别来)
- reg raise_A; //A上升沿
- reg raise_B; //B上升沿
- reg fall_A; //A下降沿
- reg fall_B; //B下降沿
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- raise_A<=0;
- else if ({r1_signalA,r0_signalA}== 2'b01)
- raise_A<=1;
- else
- raise_A<=0;
- end
-
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- raise_B<=0;
- else if ({r1_signalB,r0_signalB}== 2'b01)
- raise_B<=1;
- else
- raise_B<=0;
- end
- //获得两输入信号的下降沿
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- fall_A<=0;
- else if ({r1_signalA,r0_signalA}== 2'b10)
- fall_A<=1;
- else
- fall_A<=0;
- end
-
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- fall_B<=0;
- else if ({r1_signalB,r0_signalB}== 2'b10)
- fall_B<=1;
- else
- fall_B<=0;
- end
-
- /***************************** 第一步:先把滤波后的信号描绘出来*****************************/
- //signalA
- reg [15:0]cnt;
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- cnt<=0;
- else if (cnt_delay>= DELAY_TIME) begin
- if (raise_A||fall_A)
- cnt<=0;
- else
- cnt<=cnt+1;
- end
- else
- cnt<=cnt;
- end
-
-
- reg signalA_sample;
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- signalA_sample<=0;
- else if (cnt==250)
- signalA_sample<=signalA;
- else
- signalA_sample<=signalA_sample;
- end
-
- //signalB
- reg [15:0]cntB;
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- cntB<=0;
- else if (cnt_delay>= DELAY_TIME) begin
- if (raise_B||fall_B)
- cntB<=0;
- else
- cntB<=cntB+1;
- end
- else
- cntB<=cntB;
- end
-
- reg signalB_sample;
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)
- signalB_sample<=0;
- else if (cntB== 250)
- signalB_sample<=signalB;
- else
- signalB_sample<=signalB_sample;
- end
-
- /*************************然后对滤波得到的信号脉冲计数,4000次,并得到总的时间**********************/
- //signalA部分脉冲计数器
- reg [15:0]cnt_sample_pulseA=0 ;
- always@(posedge signalA_sample or negedge rst_n) begin
- if (!rst_n)
- cnt_sample_pulseA<=0;
- else if (cnt_sample_pulseA==NUMBER_pluse+1)
- cnt_sample_pulseA<=cnt_sample_pulseA;
- else
- cnt_sample_pulseA<=cnt_sample_pulseA+1;
- end
-
- //signalB部分脉冲计数器
- reg [15:0]cnt_sample_pulseB=0 ;
- always@(posedge signalB_sample or negedge rst_n) begin
- if (!rst_n)
- cnt_sample_pulseB<=0;
- else if (cnt_sample_pulseB==NUMBER_pluse+1)
- cnt_sample_pulseB<=cnt_sample_pulseB;
- else
- cnt_sample_pulseB<=cnt_sample_pulseB+1;
- end
-
- //触发计时计数器开始对系统时钟计时计数,直到出现4000个脉冲后不再计数,保持不变
- reg[39:0]Motor_time; //电机转动一圈的总时间
- reg[39:0]cnt1=0;
- always@(posedge sys_clock or negedge rst_n) begin
- if (!rst_n)begin
- cnt1<=0;
- Motor_time<=0;end
- else if(cnt_sample_pulseA)begin //第一个有效脉冲出现后开始计数
- if (cnt_sample_pulseA == NUMBER_pluse+1)begin //这里是PULSE_CNT 还是PULSE_CNT+1;
- cnt1<=cnt1;
- Motor_time<=(cnt1*SYSCLK_TIME);end //电机转动周期就是Motor_time乘以sys_clock的周期,乘法也可转化成移位(cnt1<<4+cnt1<<2)
- else begin
- cnt1<=cnt1+1;
- Motor_time<=0;end
- end
- else
- cnt1<=cnt1;
- end
- /**********************第三部分:比较两路信号的先后顺序*****************/
- //延时完成后立即计时,分别到A、B上升沿来时停止计时
- reg [20:0] cnt_Araise=0;
- reg [20:0] cnt_Braise=0;
- always@(posedge sys_clock or negedge rst_n)begin
- if (!rst_n)
- cnt_Araise<=0;
- else if (cnt_delay>=DELAY_TIME)begin
- if (cnt_sample_pulseA)
- cnt_Araise<=cnt_Araise;
- else
- cnt_Araise<=cnt_Araise+1;end
- else
- cnt_Araise<=0;
- end
-
- always@(posedge sys_clock or negedge rst_n)begin
- if (!rst_n)
- cnt_Braise<=0;
- else if (cnt_delay>=DELAY_TIME)begin
- if (cnt_sample_pulseB)
- cnt_Braise<=cnt_Braise;
- else
- cnt_Braise<=cnt_Braise+1;end
- else
- cnt_Braise<=0;
- end
- //最后比较信号信号顺序确定电机方向
- wire Motor_direction;
- assign Motor_direction=(cnt_sample_pulseA&cnt_sample_pulseB)?(!(cnt_Braise>cnt_Araise)):0; // 1代表正转,0代表反转
-
-
- //探针
- ila_0 your_instance_name (
- .clk(sys_clock), // input wire clk
- .probe0(signalA), // input wire [0:0] probe0
- .probe1(signalB), // input wire [0:0] probe1
- .probe2(Motor_direction), // input wire [0:0] probe2
- .probe3(Motor_time) // input wire [39:0] probe3
- );
- endmodule
三、仿真
(1)这里给出功能仿真所用到的testbench如下。
这里主要产生了系统时钟,以及两路有90度相位差的带有毛刺的方波信号。
- `timescale 1ns / 1ps
-
-
- module test_bench( );
- reg sys_clock;
- reg rst_n;
- reg signalA;
- reg signalB;
-
- get_signal get_signal(
- .sys_clock(sys_clock),
- .rst_n(rst_n),
- .signalA(signalA),
- .signalB(signalB)
-
- );
-
-
- initial sys_clock=0;
- always #10 sys_clock=~sys_clock; //产生50M的系统时钟信号
-
-
- initial signalA=0; //生成带毛刺噪声的10KHz信号
- always
- begin
- #20000 signalA =~signalA;
- #2000 signalA =~signalA;
- #20000 signalA =~signalA;
- #4000 signalA =~signalA;
- #4000 signalA =~signalA;
- #20000 signalA =~signalA;
- #2000 signalA =~signalA;
- #20000 signalA =~signalA;
- #4000 signalA =~signalA;
- #4000 signalA =~signalA;
- end
-
-
- initial begin
- signalB=0;
- # 25000
- repeat(10000)
- begin
- #20000 signalB =~signalB;
- #2000 signalB =~signalB;
- #20000 signalB =~signalB;
- #4000 signalB =~signalB;
- #4000 signalB =~signalB;
- #20000 signalB =~signalB;
- #2000 signalB =~signalB;
- #20000 signalB =~signalB;
- #4000 signalB =~signalB;
- #4000 signalB =~signalB;
- end
- end
-
-
- initial begin
- rst_n=1;
- # 5000
- rst_n=1;
- # 10000000
- $stop;
- end
- endmodule
(2)下面是仿真的结果,可以看出滤波效果达到预期,输出的电机转动周期也与预期相同。
今天的分享就这样,欢迎一起讨论进步哦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。