按键消抖
消抖时间一般为10ms,我使用的板子是ACX720,晶振为50MHZ,20ns为一周期。
状态机
模块设计
设计文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/11 12:18:36
// Design Name:
// Module Name: key_filter
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module key_filter(Clk,Rst_n,Key_in,Key_flag, //按键按下标志位Key_State //高电平,按键按下
);input Clk;input Rst_n;input Key_in;output reg Key_flag;output reg Key_State;parameter Filter_Time=500_000; //10mslocalparam S1=4'b0001,//按键松开S2=4'b0010,//消抖计数S3=4'b0100,//按键松开S4=4'b1000;//消抖计数//捕捉按键上升沿和下降沿reg [2:0] Pos_Neg_r;wire pos_edge;wire neg_edge;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Pos_Neg_r<=0;else beginPos_Neg_r={Pos_Neg_r[1:0],Key_in};endendassign pos_edge=Pos_Neg_r[2:1]==2'b01;//上升沿 //按键松开assign neg_edge=Pos_Neg_r[2:1]==2'b10;//下降沿 //按键按下//消抖延迟计数器reg [18:0] counter_cnt;reg En_counter_cnt;//按键消抖计数的条件wire end_counter_cnt;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)counter_cnt<=19'd0;else if(En_counter_cnt)beginif(end_counter_cnt)counter_cnt<=19'd0;elsecounter_cnt<=counter_cnt+1'd1;endelsecounter_cnt<=19'd0;endassign end_counter_cnt=counter_cnt>=(Filter_Time-1);reg [3:0] cur_state; //定义现态寄存器reg [3:0] next_state; //定义次态寄存器/*-----------------------------------------------------------------------状态机第一段:同步时序描述状态转移-----------------------------------------------------------------------*/always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)cur_state <= S1; //复位初始状态elsecur_state <= next_state; //次态转移到现态end/*-----------------------------------------------------------------------状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出-----------------------------------------------------------------------*/always@(*)begincase(cur_state)S1:begin //按键松开状态if(neg_edge) //按键按下--检测到下降沿next_state=S2;elsenext_state=cur_state;endS2:beginif(pos_edge)next_state=S1;else if(end_counter_cnt)next_state=S3;elsenext_state=cur_state;endS3:begin //按键按下状态if(pos_edge) //按键松开--检测到上升沿next_state=S4;elsenext_state=cur_state;endS4:begin if(neg_edge)next_state=S3;else if(end_counter_cnt)next_state=S1;elsenext_state=cur_state;enddefault:next_state=cur_state;endcaseend/*-----------------------------------------------------------------------状态机第三段:时序逻辑描述输出-----------------------------------------------------------------------*///消抖计数使能always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)En_counter_cnt <= 1'b0; //复位、初始状态 elsecase(cur_state) //根据当前状态进行输出S1: En_counter_cnt <= 1'b0; //不计数 S2: En_counter_cnt <= 1'b1; //计数S3: En_counter_cnt <= 1'b0; //不计数S4: En_counter_cnt <= 1'b1; //计数default:En_counter_cnt <= 1'b0; //默认不计数endcaseend//按键按下标志位always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Key_flag <= 1'b0; //复位、初始状态 //Key_State存在一拍else if(cur_state==S2 && end_counter_cnt) Key_flag<=1'd1;else Key_flag<=1'd0;end//输出按键状态always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Key_State <= 1'b0; //复位、初始状态 else if(cur_state==S3) Key_State<=1'd1;else if(cur_state==S4 && end_counter_cnt)Key_State<=1'd0;elseKey_State<=Key_State;endendmodule
仿真验证
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/06 16:24:27
// Design Name:
// Module Name: key_filter_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module key_filter_tb();reg Clk;reg Rst_n;reg Key_in;wire Key_flag;wire Key_State;key_filter#(.Filter_Time(5000)//100us)key_filter(Clk,Rst_n,Key_in,Key_flag, //按键按下标志位Key_State //高电平,按键按下);initial Clk=1;always #10 Clk=~Clk;initial beginRst_n=0;Key_in=1;#201;Rst_n=1;Key_in=1;#20000;Key_in=0;#20000;Key_in=1;#10000;Key_in=0;#20000;Key_in=1;#20000;Key_in=0;#600000;Key_in=1;#20000;Key_in=0;#20000;Key_in=1;#10000;Key_in=0;#20000;Key_in=1;#20000;Key_in=0;#20000;Key_in=1;#10000;Key_in=0;#20000;Key_in=1;#20000;Key_in=0;#20000;Key_in=1;#10000;Key_in=1;#600000;$stop;endendmodule
串口发送
**注意:**电平信号的传输线中有一个参考电平线(一般是GND),然后信号线上的信号值是由信号线电平和参考电平线的电压差决定。所以我们一定要养成模块之间共地的好习惯。
串口帧
模块设计
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/06 11:30:58
// Design Name:
// Module Name: UART_Byte_Tx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module UART_Byte_Tx#(parameter BaudRate = 115200,//波特率parameter ClockRate = 50_000_000//系统时钟)
(Clk,Rst_n,Send_En,data_byte,Tx_Data,Tx_Done,uart_state
);input Clk;input Rst_n;input Send_En;input [7:0] data_byte;output reg Tx_Data;output reg Tx_Done;output reg uart_state;//设置使能reg tx_en;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)tx_en<=0;else if(Send_En)tx_en<=1'd1;else if(Tx_Done)tx_en<=1'd0;elsetx_en<=tx_en;end//设置波特率localparam Buad_Num = ClockRate/BaudRate;//设置计数器reg [12:0] buad_cnt;wire add_buad_cnt;wire end_buad_cnt;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)buad_cnt<=0;else if(add_buad_cnt)beginif(end_buad_cnt)buad_cnt<=0;else buad_cnt<=buad_cnt+1'b1;endelsebuad_cnt<=0;endassign add_buad_cnt=tx_en;assign end_buad_cnt=buad_cnt>=(Buad_Num-1'd1);//设置发送bit计数reg [3:0] bit_cnt;wire add_bit_cnt;wire end_bit_cnt;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)bit_cnt<=0;else if(add_bit_cnt)bit_cnt<=bit_cnt+1'd1;else if(end_bit_cnt)bit_cnt<=0;elsebit_cnt<=bit_cnt;endassign add_bit_cnt=buad_cnt==1;assign end_bit_cnt=(bit_cnt==4'd10 && add_bit_cnt) || !tx_en;//发送数据always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Tx_Data<=1;else begincase(bit_cnt)4'd1:Tx_Data<=0;4'd2:Tx_Data<=data_byte[0];4'd3:Tx_Data<=data_byte[1];4'd4:Tx_Data<=data_byte[2];4'd5:Tx_Data<=data_byte[3];4'd6:Tx_Data<=data_byte[4];4'd7:Tx_Data<=data_byte[5];4'd8:Tx_Data<=data_byte[6];4'd9:Tx_Data<=data_byte[7];4'd10:Tx_Data<=1;default:Tx_Data<=1;endcaseendend//发送结束always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)Tx_Done<=0;else if(bit_cnt==4'd10 && add_bit_cnt)Tx_Done<=1;elseTx_Done<=0;end//发送状态(有效数据)wire En_uart_state;wire Nen_uart_state;always@(posedge Clk or negedge Rst_n)beginif(!Rst_n)uart_state<=0;else if(En_uart_state)uart_state<=1;else if(Nen_uart_state)uart_state<=0;endassign En_uart_state=bit_cnt==4'd1 && add_bit_cnt;assign Nen_uart_state=bit_cnt==4'd9 && add_bit_cnt;endmodule
仿真验证
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/06 11:31:09
// Design Name:
// Module Name: UART_Byte_Tx_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module UART_Byte_Tx_tb();reg Clk;reg Rst_n;reg Send_En;reg [7:0]data_byte;wire Tx_Data;wire Tx_Done;wire uart_state;initial Clk=1;always #10 Clk=~Clk;initial beginRst_n=0;Send_En=0;data_byte=0;#201;Rst_n=1;data_byte=8'b1001_0110;Send_En=1;#20;Send_En=0;#100000;data_byte=8'b0111_0110;Send_En=1;#20;Send_En=0;#100000;$stop;endUART_Byte_Tx UART_Byte_Tx(.Clk(Clk),.Rst_n(Rst_n),.Send_En(Send_En),.data_byte(data_byte),.Tx_Data(Tx_Data),.Tx_Done(Tx_Done),.uart_state(uart_state));endmodule
按键控制串口发送
RTL视图
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/01/07 13:43:42
// Design Name:
// Module Name: Uart_Key_Send_cmd
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module Uart_Key_Send_cmd(Clk,Rst_n,Key_in,uart_tx
);input Clk;input Rst_n;input Key_in;output uart_tx;//按键模块wire Key_flag;wire Key_State;key_filter key_filter(Clk,Rst_n,Key_in,Key_flag, //按键按下标志位Key_State //高电平,按键按下);//串口发送reg [7:0] data_byte;wire Tx_Done;wire uart_state;//assign data_byte=8'b0100_0001; //发送Aalways@(posedge Clk or negedge Rst_n)beginif(!Rst_n) data_byte<=8'b0100_0001; //发送Aelse if(Tx_Done)data_byte<=data_byte+1'b1;//数据加一endUART_Byte_Tx UART_Byte_Tx(.Clk(Clk),.Rst_n(Rst_n),.Send_En(Key_flag),.data_byte(data_byte),.Tx_Data(uart_tx),.Tx_Done(Tx_Done),.uart_state(uart_state));endmodule