【verilog】 AB相旋转编码器驱动(fpga,正交编码器,霍尔编码器驱动)

I 编码器时序

在这里插入图片描述
A的上升沿时候如果B为低电平,则旋转编码器向右转。
A的下降沿B为高电平,则一次右转结束。
A上升沿时候如果B为高电平,则旋转编码器向左转
A的下降沿B为低电平,则一次左转结束。

II 电路设计

在这里插入图片描述

III 程序设计

module abcode(
                clk, 
                rst_n,
                A, //A相
                B, //B相
                testcnt
);

input   clk,rst_n;
input   A,B;
output  reg [3:0] testcnt;

//10ms计数器,用于消抖。
reg ok_10ms;
reg [31:0]cnt0;
always@(posedge clk,negedge rst_n)
begin
    if(!rst_n)begin
        cnt0 <= 0;
        ok_10ms <= 1'b0;
    end
    else begin
        if(cnt0 < 32'd49_9999)begin//10ms消抖 //我的编码器 此值设置为4999可用!!!!!!!!!!!!!
            cnt0 <= cnt0 + 1'b1;
            ok_10ms <= 1'b0;
        end
        else begin
            cnt0 <= 0;
            ok_10ms <= 1'b1;
        end
    end
end


//同步/消抖 A、B
reg A_reg,A_reg0;
reg B_reg,B_reg0;
wire A_Debounce;
wire B_Debounce;
always@(posedge clk,negedge rst_n)begin
    if(!rst_n)begin
        A_reg <= 1'b1;
        A_reg0 <= 1'b1;
        B_reg <= 1'b1;
        B_reg0 <= 1'b1;
    end
    else begin
        if(ok_10ms)begin
            A_reg <= A;
            A_reg0 <= A_reg;
            B_reg <= B;
            B_reg0 <= B_reg;
        end
    end
end

assign A_Debounce = A_reg0 && A_reg && A;
assign B_Debounce = B_reg0 && B_reg && B;


//对消抖后的A进行上升沿,下降沿检测。
reg A_Debounce_reg;
wire A_posedge,A_negedge;
always@(posedge clk,negedge rst_n)begin
    if(!rst_n)begin
        A_Debounce_reg <= 1'b1;
    end
    else begin
        A_Debounce_reg <= A_Debounce;
    end
end
assign A_posedge = !A_Debounce_reg && A_Debounce;
assign A_negedge = A_Debounce_reg && !A_Debounce;


//对AB相编码器的行为进行描述
reg rotary_right;
reg rotary_left;
always@(posedge clk,negedge rst_n)begin
    if(!rst_n)begin
        rotary_right <= 1'b1;
        rotary_left <= 1'b1;
    end
    else begin
        //A的上升沿时候如果B为低电平,则旋转编码器向右转
        if(A_posedge && !B_Debounce)begin
            rotary_right <= 1'b1;
        end
        //A上升沿时候如果B为高电平,则旋转编码器向左转
        else if(A_posedge && B_Debounce)begin
            rotary_left <= 1'b1;
        end
        //A的下降沿B为高电平,则一次右转结束
        else if(A_negedge && B_Debounce)begin
            rotary_right <= 1'b0;
        end
        //A的下降沿B为低电平,则一次左转结束
        else if(A_negedge && !B_Debounce)begin
            rotary_left <= 1'b0;
        end
    end
end


//通过上面的描述,可以发现,
//“rotary_right”为上升沿的时候标志着一次右转
//“rotary_left” 为上升沿的时候标志着一次左转
//以下代码是对其进行上升沿检测
reg rotary_right_reg,rotary_left_reg;
wire rotary_right_pos,rotary_left_pos;
always@(posedge clk,negedge rst_n)begin
    if(!rst_n)begin
        rotary_right_reg <= 1'b1;
        rotary_left_reg <= 1'b1;
    end
    else begin
        rotary_right_reg <= rotary_right;
        rotary_left_reg <= rotary_left;
    end
end

assign rotary_right_pos = !rotary_right_reg && rotary_right;
assign rotary_left_pos = !rotary_left_reg && rotary_left;

//用于测试的计数器 右转+1 左转-1
always@(posedge clk,negedge rst_n)begin
    if(!rst_n)
         testcnt <= 4'd0;
    else if(rotary_right_pos)
         testcnt <= testcnt + 4'd1;
    else if(rotary_left_pos)
         testcnt <= testcnt - 4'd1;
end


endmodule

IV 仿真

1testbench

`timescale 1ns/1ns
`define clk_period 20

module tb;

                reg clk; 
                reg rst_n;
                reg A; //A相
                reg B; //B相
                wire[3:0] testcnt;
	
    abcode f1(
                .clk(clk), 
                .rst_n(rst_n),
                .A(A), //A相
                .B(B), //B相
                .testcnt(testcnt)
);
					
	initial clk = 1'd0;
	always #(`clk_period/2) clk = ~ clk;
	
	initial begin
		rst_n = 1'b0;
        A = 1;
        B = 1;
		#(`clk_period*20)
		rst_n = 1'b1;
		#(`clk_period)

//模拟右转
            A = 1;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 0 ;
            #250_000_00;
            A = 1;
            B = 0 ;
            #250_000_00;
            A = 1;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 0 ;
            #250_000_00;
            A = 1;
            B = 0 ;
            #250_000_00;
            A = 1;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 1 ;
            #250_000_00;
            A = 0;
            B = 0 ;
            #250_000_00;
            A = 1;
            B = 0 ;
            #250_000_00;
//------------------------------------------            
            A = 1'bz;
            B = 1'bz;
            #50_000_00;

            
//模拟左转         
            B = 1;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 0 ;
            #250_000_00;
            B = 1;
            A = 0 ;
            #250_000_00;
            B = 1;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 0 ;
            #250_000_00;
            B = 1;
            A = 0 ;
            #250_000_00;
            B = 1;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 1 ;
            #250_000_00;
            B = 0;
            A = 0 ;
            #250_000_00;
            B = 1;
            A = 0 ;
            #250_000_00;
//------------------------------------------ 
        #2000;
		$stop;
	end 
	
	endmodule 

2波形

在这里插入图片描述

  • 20
    点赞
  • 111
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搞IC的那些年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值