FPGA:uart原理+tx发送模块

news2024/11/24 6:00:12

文章目录

  • 一、串口通信
  • 二、UART通信
  • 三、tx发送模块

一、串口通信

处理器与外部设备通信的两种方式:
串行通信: 指数据的各个位使用多条数据线同时进行传输。
并行通信: 将数据分成一位一位的形式在一条数据线上逐个传输。
在这里插入图片描述

串行通信的通信方式:
同步通信: 带时钟同步信号的数据传输,发送方和接收方在同一时钟控制下,同步传输数据。
异步通信: 不带时钟同步信号的数据传输,发送方和接收方使用各自的时钟控制数据的发送和接收过程。在这里插入图片描述

串行通信的传输方向:
单工: 数据只能沿一个方向进行传输。
半双工: 数据传输可以沿两个方向,但需要分时进行。
全双工: 数据可以同时进行双向传输。
在这里插入图片描述

常见的串行通信接口:
在这里插入图片描述

二、UART通信

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器。 它在发送数据时将并行数据转换为串行的数据来传输,在接收数据时将接收到的串行数据转换成并行数据。UART串口通信需要两根信号线来实现,一根用于发送,另一个用于接收。
在这里插入图片描述

协议层:
数据格式,1帧数据由4部分组成。

  • 起始位(1bit)
  • 数据位(6/7/8bit)
  • 奇偶校验位(1bit)
  • 停止位(1bit/1.5bit/2bit)
    在这里插入图片描述

奇校验:原始码流+校验位 总共有奇数个1
偶校验:原始码流+校验位 总共有偶数个1

传输速率:
串口通信速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bit/s(位/秒),简称bps;常用的波特率有9600,115200等。

物理层:
串口电平标准:

  • TTL电平的串口(3.3V)
  • RS232电平的串口(+5V ~ +12V为低电平,-12V ~ -5V为高电平)

三、tx发送模块

tx发送模块:共四个状态,IDLE状态,START状态,DATA状态,FINISH状态。

/*
 * @Description: tx输出,波特率115200,系统时钟50M,传输1bit所需计数434个周期
 * @Author: Fu Yu
 * @Date: 2023-08-15 11:10:41
 * @LastEditTime: 2023-08-15 14:55:04
 * @LastEditors: Fu Yu
 */

module uart_tx (
    input           wire                clk         ,
    input           wire                rst_n       ,
    input           wire [7:0]          tx_din      ,
    input           wire                tx_din_vld  ,

    output          wire                tx_dout     ,
    output          wire                ready           
);

parameter MAX_BIT = 50_000_000/115200;//1bit计数最大值,434

localparam  IDLE   = 4'b0001,
            START  = 4'b0010,
            DATA   = 4'b0100,
            FINISH = 4'b1000;

reg [3:0]   state_c;//现态
reg [3:0]   state_n;//次态

wire        idle_start  ;// IDLE -> START
wire        start_data  ;// START -> DATA
wire        data_finish ;// DATA -> FINISH
wire        finish_idle ;// FINFISH -> IDLE

reg			[8:0]	cnt_bit	   	;
wire				add_cnt_bit	;
wire				end_cnt_bit	;

reg			[11:0]	cnt_data	   	;
wire				add_cnt_data	;
wire				end_cnt_data	;

reg [7:0]   tx_din_r;
reg         tx_dout_r;

//****************************************************************
//--                状态机
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        state_c <= IDLE;
    end
    else begin
        state_c <= state_n;
    end
end

always @( *) begin
    case (state_c)
        IDLE : begin
            if(idle_start) begin
                state_n = START;
            end
            else begin
                state_n = state_c;
            end
        end

        START : begin
            if(start_data) begin
                state_n = DATA;
            end
            else begin
                state_n = state_c;
            end
        end

        DATA : begin
            if(data_finish) begin
                state_n = FINISH;
            end
            else begin
                state_n = state_c;
            end
        end

        FINISH : begin
            if(finish_idle) begin
                state_n = IDLE;
            end
            else begin
                state_n = state_c;
            end
        end

        default : state_n = IDLE;
            
    endcase
end


assign idle_start  = state_c == IDLE && tx_din_vld ;
assign start_data  = state_c == START &&  end_cnt_bit;
assign data_finish = state_c == DATA &&  end_cnt_data;
assign finish_idle = state_c == FINISH && end_cnt_bit;

//****************************************************************
//--                    计数器
//****************************************************************
//1bit计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_bit <= 'd0;
    end 
    else if(add_cnt_bit)begin 
        if(end_cnt_bit)begin 
            cnt_bit <= 'd0;
        end
        else begin 
            cnt_bit <= cnt_bit + 1'b1;
        end 
    end
end 

assign add_cnt_bit = state_c == START || state_c == FINISH || state_c == DATA;
assign end_cnt_bit = add_cnt_bit && cnt_bit == MAX_BIT - 1;

//8bit计数器
always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_data <= 'd0;
    end 
    else if(add_cnt_data)begin 
        if(end_cnt_data)begin 
            cnt_data <= 'd0;
        end
        else begin 
            cnt_data <= cnt_data + 1'b1;
        end 
    end
end 

assign add_cnt_data = state_c == DATA && end_cnt_bit;
assign end_cnt_data = add_cnt_data && cnt_data == 8 - 1 ;


//****************************************************************
//--                输入数据寄存
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        tx_din_r <= 0;
    end
    else begin
        tx_din_r <= tx_din;
    end
end


//****************************************************************
//--            实现串口时序
//****************************************************************
always @( *) begin
    case (state_c)
        IDLE : begin
            tx_dout_r = 1;
        end

        START : begin
            tx_dout_r = 0;
        end

        DATA : begin
            if(tx_din_r[cnt_data]) begin
                tx_dout_r = 1;
            end
            else begin
                tx_dout_r = 0;
            end
        end

        FINISH : begin
            tx_dout_r = 1;
        end

        default : tx_dout_r = 1;
    endcase
end

assign tx_dout = tx_dout_r;

assign ready = state_c == IDLE;


endmodule //uart_tx

测试文件:

/*
 * @Description: uart_tx仿真模块
 * @Author: Fu Yu
 * @Date: 2023-08-15 14:58:32
 * @LastEditTime: 2023-08-15 15:06:49
 * @LastEditors: Fu Yu
 */


`timescale 1ns/1ns
    
module tb_uart_tx();

//激励信号定义 
    reg				tb_clk  	;
    reg				tb_rst_n	;
    reg		[7:0]   tb_tx_din	;
    reg             tb_tx_din_vld;

//输出信号定义	 
    wire			tx_dout	;
    wire			ready    ;

//时钟周期参数定义	
    parameter		CLOCK_CYCLE = 20;   
    defparam  u_uart_tx.MAX_BIT = 10;
//模块例化
uart_tx u_uart_tx(
   /*input           wire       */  .       clk       (tb_clk)  ,
   /*input           wire       */  .       rst_n     (tb_rst_n)  ,
   /*input           wire [7:0] */  .       tx_din    (tb_tx_din) ,
   /*input           wire       */  .       tx_din_vld(tb_tx_din_vld) ,
   /*output          wire       */  .       tx_dout   (tx_dout)  ,
   /*output          wire       */  .       ready     (ready)      
);

//产生时钟
    initial 		tb_clk = 1'b0;
    always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;

//产生激励
    initial  begin 
        tb_rst_n = 1'b1;
        tb_tx_din = 0;
        tb_tx_din_vld = 0;
        #(CLOCK_CYCLE*2);
        tb_rst_n = 1'b0;
        #(CLOCK_CYCLE*20);
        tb_rst_n = 1'b1;

        
        repeat(10) begin
            tb_tx_din_vld = 1;
            tb_tx_din = {$random};
            #20;
            tb_tx_din_vld = 0;
            wait(ready == 1);
            #20;
        end

        #1000;
        $stop;
    end

endmodule 

仿真波形图:
在这里插入图片描述
上板验证:
加入按键控制模块,每一次按下,输出8’hAB

按键消抖模块:

/*
 * @Description: 按键消抖,使用延迟方法,消抖后输出高电平信号
 * @Author: Fu Yu
 * @Date: 2023-08-07 14:22:56
 * @LastEditTime: 2023-08-07 14:48:48
 * @LastEditors: Fu Yu
 */


module key_filter #(
    parameter WITDH = 3//WITDH表示位宽
)(
    input       wire                clk         ,
    input       wire                rst_n       ,

    input       wire [WITDH-1:0]    key_in      ,

    output      wire [WITDH-1:0]    key_down
);

parameter MAX_20MA = 20'd999_999;//20ms

reg [WITDH - 1:0]   key_r0;//同步信号
reg [WITDH - 1:0]   key_r1;//打拍
reg [WITDH - 1:0]   key_r2;
reg [WITDH - 1:0]   key_down_r;
reg [19:0]          cnt_20ms;
reg                 flag;//开始计数信号

wire [WITDH - 1:0]  nedge;//下降沿
wire add_cnt_20ms;
wire end_cnt_20ms;


//****************************************************************
//--同步,打拍
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        key_r0 <= {WITDH{1'b1}};
        key_r1 <= {WITDH{1'b1}};
        key_r2 <= {WITDH{1'b1}};
    end
    else begin
        key_r0 <= key_in;
        key_r1 <= key_r0;
        key_r2 <= key_r1;
    end
end

//下降沿检测
assign nedge = ~key_r1 & key_r2;


//****************************************************************
//--flag
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        flag <= 1'b0;
    end
    else if(nedge) begin//检测到下降沿开始计数
        flag <= 1'b1;
    end
    else if(end_cnt_20ms) begin//20ms后停止计数
        flag <= 1'b0;
    end
    else begin
        flag <= flag;
    end
end


//****************************************************************
//--20ms计数器
//****************************************************************


always @(posedge clk or negedge rst_n)begin 
   if(!rst_n)begin
        cnt_20ms <= 20'd0;
    end 
    else if(add_cnt_20ms)begin 
        if(end_cnt_20ms)begin 
            cnt_20ms <= 20'd0;
        end
        else begin 
            cnt_20ms <= cnt_20ms + 1'b1;
        end 
    end
end 

assign add_cnt_20ms = flag;
assign end_cnt_20ms = add_cnt_20ms && cnt_20ms == MAX_20MA;

//****************************************************************
//--key_down
//****************************************************************
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        key_down_r <= {WITDH{1'b0}};
    end
    else if(end_cnt_20ms) begin
        key_down_r <= ~key_r2;
    end
    else begin
        key_down_r <= {WITDH{1'b0}};
    end
end

assign key_down = key_down_r;

endmodule //key_filter

顶层模块:

module top (
    input           wire            clk         ,
    input           wire            rst_n       ,
    input           wire            key_in      ,

    output          wire            tx
);


wire        key_wire;
wire        ready;


key_filter #(.WITDH(1)) u_key_filter(
   /* input       wire            */.   clk     (clk)    ,
   /* input       wire            */.   rst_n   (rst_n)    ,
   /* input       wire [WITDH-1:0]*/.   key_in  (key_in)    ,
   /* output      wire [WITDH-1:0]*/.   key_down(key_wire)
);

uart_tx u_uart_tx(
   /*input           wire       */  .       clk       (clk)  ,
   /*input           wire       */  .       rst_n     (rst_n)  ,
   /*input           wire [7:0] */  .       tx_din    (8'hab)  ,
   /*input           wire       */  .       tx_din_vld(key_wire && ready)  ,
   /*output          wire       */  .       tx_dout   (tx)  ,
   /*output          wire       */  .       ready     (ready)      
);


endmodule //top

效果展示:
在这里插入图片描述

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

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

相关文章

SpringBoot中properties、yml、yaml的优先级

原理 配置优先级低的会先加载然后会被配置优先级高的覆盖 验证 创建SpringBoot项目&#xff08;网址&#xff09; 在resource目录下创建application.properties、application.yml、application.yaml文件 运行 结论 优先级顺序&#xff1a; properties>yml>yaml

ARM处理器

1、RISC处理器&#xff1a; RISC (Reduced Instruction Set Computer) 微处理器是一种计算机微处理器架构&#xff0c;其设计原则是通过简化指令集来提高执行速度。 (1)、RISC处理器的设计理念&#xff1a; 简化指令集&#xff1a;RISC 微处理器的指令集非常精简&#xff0c…

匠心工艺-易天注胶设备新升级

随着科技的不断发展&#xff0c;注胶设备也在不断地升级换代。近期&#xff0c;易天光通信自主研发的注胶新设备投入DAC产线使用&#xff0c;新升级的注胶设备在原有的基础上&#xff0c;投入了更加先进的工艺技术&#xff0c;大幅度提升生产工作效率。 一、注胶设备的功能与性…

【UE】Web Browser内嵌网页在场景中的褪色问题

使用WebBrowser放置在场景中时&#xff0c;网页颜色会出现异常的褪色。 这是因为 Web 浏览器插件以 sRGB 格式输出其颜色数据&#xff0c;而 Widget/3D Widget 需要线性 RGB 格式的数据。 可以通过创建在 3D Widget 中使用的新材质&#xff08;而不是默认的 Widget3DPassthr…

Rust语法:所有权引用生命周期

文章目录 所有权垃圾回收管理内存手动管理内存Rust的所有权所有权转移函数所有权传递 引用与借用可变与不可变引用 生命周期悬垂引用函数生命周期声明结构体的生命周期声明Rust生命周期的自行推断生命周期约束静态生命周期 所有权 垃圾回收管理内存 Python&#xff0c;Java这…

远程仓库上创建一个新的分支 `b` 并将远程分支 `a` 的内容克隆到 `b` 分支上

一、需求&#xff1a; 要在远程仓库上创建一个新的分支 b 并将远程分支 a 的内容克隆到 b 分支上&#xff0c;你可以按照以下步骤进行操作&#xff1a; 二、解决方案&#xff1a; 1. 首先&#xff0c;使用 git clone 命令克隆远程仓库到本地。例如&#xff0c;要克隆一个名为…

Python数据分析实战-dataframe 某一列数据每个元素做处理并新增一列(附源码和实现效果)

实现功能 dataframe 某一列数据每个元素做处理并新增一列 实现代码 import pandas as pd# 创建示例数据 df pd.DataFrame({A: [1, 2, 3], B: [foo, bar, baz]}) # 对列 B 中的每个元素加上 processed_ 前缀&#xff0c;并将结果添加为新列 C df[C] df[B].apply(lambda x: p…

台湾shopee:虾皮电商平台选品方法与市场机遇

台湾Shopee虾皮电商平台为台湾本土卖家和消费者提供了一个线上交易平台。对于想要在台湾市场做虾皮电商的卖家来说&#xff0c;选择合适的产品是非常重要的。本文介绍一些做虾皮电商的选品方法和策略。 首先&#xff0c;了解市场需求是选品的基础。在进入台湾Shopee市场之前&a…

Linux6.39 Kubernetes Pod控制器

文章目录 计算机系统5G云计算第三章 LINUX Kubernetes Pod控制器一、Pod控制器及其功用二.pod控制器有多种类型1.ReplicaSet2.Deployment3.DaemonSet4.StatefulSet5.Cronjob 三、Pod与控制器之间的关系1.Deployment2.SatefulSet1&#xff09;为什么要有headless2&#xff09;为…

注解@Value获取配置文件内容 (demo)

1. 自定义配置文件内容 (application.yml) 2. 使用 Value("${xxx}") 注入属性 import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;Compone…

【声波】声波在硼酸、硫酸镁 (MgSO4) 和纯水中的吸收研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

棒球发展史·棒球1号位

棒球发展史 1. 棒球的起源 棒球的起源地棒球的起源地。棒球&#xff0c;也被称为垒球或棒球运动&#xff0c;起源于19世纪晚期的美国。当时在美国&#xff0c;体育运动已经有了较为完备的体制&#xff0c;也形成了多种不同的运动形式。然而&#xff0c;最受欢迎的体育运动主要…

主存储器结构

计算机存储器又称内存&#xff0c;是一种利用半导体技术做成的电子设备&#xff0c;用来存储数据。电子电路的数据是以二进制的方式存储&#xff0c;存储器的每一个存储单元称做记忆元。 存储器以二进制计算容量&#xff0c;基本单位是Byte&#xff1a; 1KiB1,024B 1MiB1,0…

反序列化与序列化过程分析

前言 在学习反序列化的漏洞时,大致都是了解了一些知识,比如序列化就是写入对象,反序列化就是读取文件恢复对象,在这个过程中会自动调用一些方法,readObject,writeObject,静态代码块等,但是从来没有了解过这个过程是怎么样的,一直很模糊,所以在这篇文章里面会记录整个学习过程,…

⛳ Docker - Centos 安装配置

目录 ⛳ Docker - Centos 安装配置&#x1f3ed; Docker 安装&#xff1a;&#x1f4e2; 一、安装依赖包&#x1f4ac; 二、添加 Docker 下载源地址&#x1f43e; 三、更新yum缓存&#x1f463; 四、安装Docker&#x1f4bb; 五、启动Docker&#x1f381; 六、查看Docker状态和…

网络编程(8.15)io模型,IO多路复用(select,poll)

1.使用select函数实现IO多路复用 使用select函数实现IO多路复用的服务器&#xff1a; #include<stdio.h> #include<head.h> #include<netinet/in.h> #include<sys/select.h> #include<arpa/inet.h> #define PROT 1112 #define IP "192.16…

缓存淘汰算法(LFU LRU FIFO)及进程的状态和转换

目录 一、缓存淘汰算法 1.LFU&#xff08;Least Frequently Used&#xff09;最近最不常用算法 2.LRU&#xff08;Least Recently User&#xff09;最近最少使用算法 3.FIFO&#xff08;First in first out&#xff09;先进先出算法 二、进程的状态和转换 1.最基本的三种状…

解决Mac系统android monitor启动时卡住,显示白屏的问题

一.启动环境 清安装1.8版本的jdk&#xff0c;java1.8版本以上不支持android monitor&#xff1b;如果你电脑上安装有java 11等高级别的版本&#xff0c;请自行搜索&#xff0c;如果在mac上安装多jdk&#xff0c;以及如何切换到1.8版本上 二.解决方案 请更新SWT插件&#xff…

x86架构芯片启动过程分析

1、上电启动顺序 上电自检 读取ROM里的bios程序 bios程序会进行硬件检测&#xff0c;比如&#xff1a;内存、硬盘、显卡等 bios完成自检后&#xff0c;需要选择引导设备。比如设备上有U盘、SSD、eMMC、机械硬盘&#xff0c;bios需要知道从哪个启动介质去启动计算机 bios操作界面…

资料分析(四)—— 倍数、比重、平均数

倍数 现期倍数 &#xff08;A是B的几倍&#xff09;&#xff1a; 多几倍 1 增长率 1 增长倍数&#xff08;A比B多几倍&#xff09;&#xff1a; - 1 是几倍 - 1 增长率&#xff08;增长几倍&#xff09; 超过倍数&#xff08;A超过B的 n 倍&#xff09;&#xff1a;A …