• FPGA 按键控制串口发送


    按键消抖

    消抖时间一般为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; //10ms
        localparam 
        		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)begin
            if(!Rst_n)
                Pos_Neg_r<=0;
            else begin
                Pos_Neg_r={Pos_Neg_r[1:0],Key_in};
            end
        end
        assign 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)begin
            if(!Rst_n)
                counter_cnt<=19'd0;
            else if(En_counter_cnt)begin
                if(end_counter_cnt)
                    counter_cnt<=19'd0;
                else
                    counter_cnt<=counter_cnt+1'd1;
            end
            else
                counter_cnt<=19'd0;
        end
        assign 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)begin
            if(!Rst_n)
                cur_state <= S1;				//复位初始状态
            else
                cur_state <= next_state;		//次态转移到现态
        end
         
        /*
        -----------------------------------------------------------------------
        状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
        -----------------------------------------------------------------------
        */
        always@(*)begin
                case(cur_state)
                    S1:begin                    //按键松开状态
                        if(neg_edge)            //按键按下--检测到下降沿
                            next_state=S2;
                        else
                            next_state=cur_state;
                    end
                    S2:begin
                        if(pos_edge)
                            next_state=S1;
                        else if(end_counter_cnt)
                            next_state=S3;
                        else
                            next_state=cur_state;
                    end
                    S3:begin                    //按键按下状态
                        if(pos_edge)            //按键松开--检测到上升沿
                            next_state=S4;
                        else
                            next_state=cur_state;
                    end
                    S4:begin    
                        if(neg_edge)
                            next_state=S3;
                        else if(end_counter_cnt)
                            next_state=S1;
                        else
                            next_state=cur_state;
                    end
                    default:next_state=cur_state;
                endcase
        end
        
        /*
        -----------------------------------------------------------------------
        状态机第三段:时序逻辑描述输出
        -----------------------------------------------------------------------
        */
        //消抖计数使能
        always@(posedge Clk or negedge Rst_n)begin
            if(!Rst_n)
                En_counter_cnt <= 1'b0;			      //复位、初始状态 
            else
                case(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;   //默认不计数
                endcase
        end
        //按键按下标志位
        always@(posedge Clk or negedge Rst_n)begin
            if(!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)begin
            if(!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;
            else
                Key_State<=Key_State;
        end
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169

    仿真验证

    `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 begin
            Rst_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;
            
        end
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    在这里插入图片描述

    串口发送

    **注意:**电平信号的传输线中有一个参考电平线(一般是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)begin
            if(!Rst_n)
                tx_en<=0;
            else if(Send_En)
                tx_en<=1'd1;
            else if(Tx_Done)
                tx_en<=1'd0;
            else
                tx_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)begin
            if(!Rst_n)
                buad_cnt<=0;
            else if(add_buad_cnt)begin
                if(end_buad_cnt)
                    buad_cnt<=0;
                else 
                    buad_cnt<=buad_cnt+1'b1;
            end
            else
                buad_cnt<=0;
        end
        assign 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)begin
            if(!Rst_n)
                bit_cnt<=0;
            else if(add_bit_cnt)
                bit_cnt<=bit_cnt+1'd1;
            else if(end_bit_cnt)
                bit_cnt<=0;
            else
                bit_cnt<=bit_cnt;
        end
        assign 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)begin
            if(!Rst_n)
                Tx_Data<=1;
            else begin
                case(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;
                endcase
            end
        end
        
        //发送结束
        always@(posedge Clk or negedge Rst_n)begin
            if(!Rst_n)
                Tx_Done<=0;
            else if(bit_cnt==4'd10 && add_bit_cnt)
                Tx_Done<=1;
            else
                Tx_Done<=0;
        end
        
        //发送状态(有效数据)
        wire En_uart_state;
        wire Nen_uart_state;
        always@(posedge Clk or negedge Rst_n)begin
            if(!Rst_n)
                uart_state<=0;
            else if(En_uart_state)
                uart_state<=1;
            else if(Nen_uart_state)
                uart_state<=0;
        end
        assign En_uart_state=bit_cnt==4'd1 && add_bit_cnt;
        assign Nen_uart_state=bit_cnt==4'd9 && add_bit_cnt;
        
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

    仿真验证

    `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 begin
            Rst_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;
        end
        
        
        UART_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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    在这里插入图片描述

    按键控制串口发送

    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; //发送A
        always@(posedge Clk or negedge Rst_n)begin
            if(!Rst_n)  
                data_byte<=8'b0100_0001; //发送A
            else if(Tx_Done)
                data_byte<=data_byte+1'b1;//数据加一
        end
        
        UART_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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    板级验证

    在这里插入图片描述

  • 相关阅读:
    重载PreTranslateMessage响应CTreeCtrl控件的回车键后运行程序出现中断ASSERT(::IsWindow(m_hWnd));
    21天打卡进阶Python基础操作
    【信息化】软考高项(信息系统项目管理师)论文自我总结精华和模板
    【文末附gpt升级方案】数据虚拟化技术:起源、发展及市场趋势
    2023MathorCup(妈妈杯) 数学建模挑战赛 解题思路
    ubuntu 20.04 A10配置deepstream6.1.1环境(dGPU)
    2.MySQL ---- 修改数据库的字符集(日常小技巧)
    outsystems合集系列(四)
    Java 是值传递还是?
    将MindSpore运行结果输出到log文件
  • 原文地址:https://blog.csdn.net/m0_55849362/article/details/136549403