FPGA 按键控制串口发送

news2024/12/22 18:27:11

按键消抖

消抖时间一般为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

仿真验证

`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

在这里插入图片描述

串口发送

**注意:**电平信号的传输线中有一个参考电平线(一般是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

仿真验证

`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

在这里插入图片描述

按键控制串口发送

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

板级验证

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaEE进阶(14)Linux基本使用和程序部署(博客系统部署)

接上次博客&#xff1a;JavaEE进阶&#xff08;13&#xff09;案例综合练习——博客系统-CSDN博客 目录 程序配置文件修改和打包 构建项目并打包 分平台配置 数据准备 上传jar包到云服务器并运行 开放端口号 验证程序 如何查看日志得到报错信息 常见问题 关于Linux基…

【自然语言处理】NLP入门(五):1、正则表达式与Python中的实现(5):字符串常用方法:对齐方式、大小写转换详解

文章目录 一、前言二、正则表达式与Python中的实现1.字符串构造2. 字符串截取3. 字符串格式化输出4.字符转义符5. 字符串常用函数函数与方法之比较 6. 字符串常用方法1. 对齐方式center()ljust()rjust() 2. 大小写转换lower()upper()capitalize()title()swapcase() 一、前言 本…

maven项目结构管理统一项目配置操作

一、maven分模块开发 Maven 分模块开发 1.先创建父工程&#xff0c;pom.xml文件中&#xff0c;打包方式为pom 2.然后里面有许多子工程 3.我要对父工程的maven对所有子工程进行操作 二、解读maven的结构 1.模块1 <groupId>org.TS</groupId><artifactId>TruthS…

Java基于微信小程序的医院挂号系统(V2.0),附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal

ThreadLocal, InheritableThreadLocal和TransmittableThreadLocal ThreadLocal(TL) 后续部分地方会使用ThraedLocal简称为TL 什么是TL? ThreadLocal是Java中的一个类, 也称为线程本地变量, 它提供了线程局部变量的功能。每个ThreadLocal对象都可以存储一个线程本地的变量副…

【数据结构】二、线性表:4.循环链表的定义及其基本操作(循环单链表,循环双链表的初始化、判空、判断头结点、尾结点、插入、删除)

文章目录 4.循环链表4.1循环单链表4.1.1初始化4.1.2判断单链表是否为空4.1.3判断p结点是否为循环单链表的表尾结点 4.2循环双链表4.2.1初始化4.2.2判断循环链表是否为空4.2.3判断结点p是否为循环双链表的表尾结点4.2.4双链表的插入4.2.5双链表的删除 4.循环链表 4.1循环单链表…

R语言:多值提取到点

ArcGIS中有相关工具实现多值提取到点的功能&#xff0c;在这里&#xff0c;我将使用R语言进行操作&#xff1a; library(dplyr) library(readxl) library(sf) library(raster)setwd("D:/Datasets") Bio <- stack(paste0("D:/Datasets/Data/worldclim2_1km/…

关于并发编程和并行

目录 前言: 并发编程: 1.并发编程的定义: 2. 并发编程的目的 2.1提高性能&#xff1a; 2.2增强响应性&#xff1a; 2.3资源利用&#xff1a; 3. 并发编程的实现方式 3.1多线程&#xff1a; 3.2多进程&#xff1a; 3.3异步编程&#xff1a; 3.4协程&#xff1a; 4. …

16、电源管理入门之驱动Runtime PM管理

目录 1. 框架介绍 1.1 为什么需要Runtime PM Framework? 1.2 系统框架图 2. Drivers 3. Runtime PM core 4. power domain framework 5. runtime pm的sysfs 6参考: Runtime PM管理也就是设备驱动里面的电源管理,即设备驱动结构体里面的struct dev_pm_ops,只控制设…

简明固体物理--晶体的形成与晶体结构的描述

简明固体物理-国防科技大学 chapter 1 Formation of Crystal Contents and roadmapQuantum Mechanics and atomic structureElectronsOld quantum theoryMethod of Quantum MechanicsDistributing functions of micro-particles BindingCrystal structure and typical crystal…

【打工日常】使用docker部署IT运维管理平台CAT

​一、CAT介绍 CAT是一个专为 IT 运维从业者打造的一站式解决方案平台&#xff0c;包含资产管理、工单、工作流、仓储等功能模块。 本项目是celaraze/chemex重构版&#xff0c;原项目chemex名称弃用&#xff1b;CAT采用全新架构设计&#xff0c;大量提升使用体验的细节&#xf…

Tensorflow实现手写数字识别

模型架构 具有10个神经元&#xff0c;对应10个类别&#xff08;0-9的数字&#xff09;。使用softmax激活函数&#xff0c;对多分类问题进行概率归一化。输出层 (Dense):具有64个神经元。激活函数为ReLU。全连接层 (Dense):将二维数据展平成一维&#xff0c;为全连接层做准备。展…

Solidworks界面左边FeatureManager/设计树/模型树/树区域/零件树/零件栏不见了

Solidworks界面左边FeatureManager/设计树/模型树/树区域/零件树/零件栏不见了&#xff0c;按F9还原/隐藏&#xff0c;有的笔记本按FnF9

Koa: 打造高效、灵活的Node.js后端 (介绍与环境部署)

在上一篇文章中&#xff0c;我们了解了Node.js的基础知识&#xff0c;今天我们将进一步学习Node.js 较新的一个轻量级Web框架Koa&#xff0c;一起创建NodeJS后端服务器吧&#xff01; 一、介绍 Koa是一个新生代Node.js Web框架&#xff0c;由Express原团队成员开发&#xff0c…

大模型笔记:最少到最多提示过程 (Least to Most prompting, LtM)

LEAST-TO-MOST PROMPTING ENABLES COMPLEX REASONING IN LARGE LANGUAGE MODELS 2023 ICLR 1 概述 进一步发展维链提示过程 (CoT prompting) 分为两个阶段&#xff1a; 第一阶段&#xff1a;向语言模型提出查询&#xff0c;将问题分解成子问题。第二阶段&#xff1a;再次向语…

【数据结构】二、线性表:2.单链表的插入、删除、查找

文章目录 2.3插入2.3.1按位序插入2.3.2指定结点后插入2.3.3指定结点前插入 2.4删除2.4.1按位序删除2.4.2指定结点删除 2.5查找2.5.1按位查找2.5.2按值查找 2.3插入 2.3.1按位序插入 ListInsert(&L,i,e)&#xff1a;插入操作。在表L中的第i个位置上插入指定元素e。 带头结…

【MATLAB第98期】基于MATLAB的MonteCarlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】

【MATLAB第98期】基于MATLAB的Monte Carlo蒙特卡罗结合kriging克里金代理模型的全局敏感性分析模型【更新中】 PS:因内容涉及较多&#xff0c;所以一时半会更新不完 后期会将相关原理&#xff0c;以及多种功能详细介绍。 麻烦点赞收藏&#xff0c;及时获取更新消息。 引言 在…

从《繁花》看图数据库的关联力!

2024年开年&#xff0c;最热的电视剧非《繁花》莫属。 这部现象级剧集不仅在全国掀起了一股怀旧潮&#xff0c;还引发了对故事情节和人物关系的深入探讨。 随着《繁花》的热播&#xff0c;不少观众为了更好地理解复杂的故事情节&#xff0c;开始自制人物关系图。 这些关系图以…

【Spring Boot 3】获取已注入的Bean

【Spring Boot 3】获取已注入的Bean 背景介绍开发环境开发步骤及源码工程目录结构总结 背景 软件开发是一门实践性科学&#xff0c;对大多数人来说&#xff0c;学习一种新技术不是一开始就去深究其原理&#xff0c;而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历…

java SSM科研管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM科研管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S…