12 ABC串口接收原理与思路

1. 串口接收原理

基本原理:通过数据起始位判断要是否要开始接收的数据,通过采样的方式确定每一位数据是0还是1。

如何判断数据起始位到来:通过边沿检测电路检测起始信号的下降沿

如何采样:一位数据采多次,统计得到高电平出现的次数,次数多的就是该位的电平值

2. 自己写的代码(不完善)

设计代码

module uart_byte_rx(
    clk,
    rstn,
    uart_byte_rx,
    blaud_set,
    data,
    rx_done
);

    input clk;
    input rstn;
    input uart_byte_rx;
    input blaud_set;
    output reg [7:0] data;
    output reg rx_done;
    
    //Blaud_set = 0时,波特率 = 9600;
    //Blaud_set = 1时,波特率 = 19200;
    //Blaud_set = 2时,波特率 = 38400;
    //Blaud_set = 3时,波特率 = 57600;
    //Blaud_set = 4时,波特率 = 115200;
    
    reg[17:0] bps_dr;
    always@(*)
        case(blaud_set)
            0: bps_dr = 1000000000/9600/20;
            1: bps_dr = 1000000000/19200/20;
            2: bps_dr = 1000000000/38400/20;
            3: bps_dr = 1000000000/57600/20;
            4: bps_dr = 1000000000/115200/20;
        endcase

    reg [1:0] test;
    reg get_en;
    always@(posedge clk or negedge rstn) //边沿检测,使能后续的采样
    if(!rstn) begin
        data <= 0;
        test <= 0;
        get_en <= 0;
        rx_done <= 0;
    end
    else begin
        test[0] <= uart_byte_rx;
        test[1] <= test[0];
        if((test[0] ==0 )&&(test[1] == 1))
            get_en <= 1;
            rx_done <= 0;
    end

    reg [17:0] div_cnt;
    reg [3:0] counter;
    reg [3:0] tx_counter;
    always@(posedge clk or negedge rstn) //计数时钟,一个计数周期代表一位数据
    if(!rstn) 
        div_cnt <= 0;
    else if(get_en)begin
        if(div_cnt == 434 - 1)
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'd1;
    end        
    
    wire bps_clk;
    assign bps_clk = (div_cnt == 1);
    always@(posedge clk or negedge rstn) //数据段,包含起始位和终止位,共十段
    if(!rstn) 
        tx_counter <= 0;
    else if(get_en)begin
         if(tx_counter == 11)
             tx_counter <= 0;
         else if(div_cnt == 1)
             tx_counter <= tx_counter + 1'd1;
     end       
            
     always@(posedge clk or negedge rstn) //数据采样,每段数据采样8次。
     if(!rstn)
        counter <= 0;
     else if(div_cnt == 3)
        counter <= 0;
     else if((div_cnt == 1*433/8 - 10)||
     (div_cnt == 2*433/8 - 10)||
     (div_cnt == 3*433/8 - 10)||
     (div_cnt == 4*433/8 - 10)||
     (div_cnt == 5*433/8 - 10)||
     (div_cnt == 6*433/8 - 10)||
     (div_cnt == 7*433/8 - 10)||
     (div_cnt == 8*433/8 - 10))
        counter <= counter + uart_byte_rx;
               
     always@(posedge clk or negedge rstn) //
     if(!rstn) 
        counter <= 0;
     else if(div_cnt == 2)
     case(tx_counter)
        2:if(counter > 4 )data[0] <= 1; else if(counter <4) data[0] <= 0;
        3:if(counter > 4 )data[1] <= 1; else if(counter <4) data[1] <= 0; 
        4:if(counter > 4 )data[2] <= 1; else if(counter <4) data[2] <= 0; 
        5:if(counter > 4 )data[3] <= 1; else if(counter <4) data[3] <= 0; 
        6:if(counter > 4 )data[4] <= 1; else if(counter <4) data[4] <= 0; 
        7:if(counter > 4 )data[5] <= 1; else if(counter <4) data[5] <= 0; 
        8:if(counter > 4 )data[6] <= 1; else if(counter <4) data[6] <= 0; 
        9:if(counter > 4 )data[7] <= 1; else if(counter <4) data[7] <= 0;
        11:begin rx_done <= 1; get_en <= 0; div_cnt <= 0; end
        default: begin rx_done <= 0; data <= data; end
     endcase        
endmodule

仿真波形

3. 看完视频后写的代码(完善)

设计代码

3.1 需学习的点:

1.将div_cnt划分为最小时间段

2.某些判断信号直接用assign利用,而不需要利用寄存器

3.仿真代码中task的使用

module uart_byte_rx1(
    clk,
    rstn,
    blaud_set,
    uart_rx,
    data,
    rx_done
);

    input clk;
    input rstn;
    input [2:0]blaud_set;
    input uart_rx;
    output reg [7:0] data;
    output rx_done;

    reg [8:0] bps_dr;
    always@(*)
        case(blaud_set)
            0:bps_dr = 1000000000/9600/16/20;
            1:bps_dr = 1000000000/19200/16/20;
            2:bps_dr = 1000000000/38400/16/20;
            3:bps_dr = 1000000000/57600/16/20;
            4:bps_dr = 1000000000/115200/16/20;
            default : bps_dr = 1000000000/9600/16/20;
        endcase
        
    //边沿信号检测
    reg [1:0] uart_rx_r; //用两位寄存器分别存储两个时间沿的uart_rx信号
    always@(posedge clk) begin
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0];
    end
    
    //将两位寄存器的值直接通过导线输出进行判断(不需要再使用寄存器)
    wire nedge_uart_rx;  //掌握一下这个方法,之前一直使用的是寄存器
    //法一:
    //assign nedge_uart_rx = ((uart_rx_r[0] == 0)&&(uart_rx_r == 1));
    //法二:
    assign nedge_uart_rx = (uart_rx_r == 2'b10);
    
    reg rx_en;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        rx_en <= 0;
    else if(nedge_uart_rx)
        rx_en <= 1;
    else if(rx_done)
        rx_en <= 0;
    
    
    //周期计数器
    reg [8:0] div_cnt;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        div_cnt <= 0;
    else if(rx_en) begin
        if(div_cnt == bps_dr - 1)
            div_cnt <= 0;
        else
            div_cnt <= div_cnt + 1'd1;
    end
    else
        div_cnt <= 0;
    
    
    wire [3:0]bps_clk_16x; //(一定要记得加位宽)采样信号,这种写法很灵活
    assign bps_clk_16x = bps_dr/2; //采样每一段的中点值,同时也可以用它来计数。
    
    //发送一字节的数据有需要十个数据位,每位数据有16个小段供采样,共160
    reg [7:0]bps_cnt;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        bps_cnt <= 0;
    else if(rx_en) begin
        if(bps_cnt == 159)
            bps_cnt <= 0;
        else if(div_cnt ==bps_clk_16x)
            bps_cnt <= bps_cnt + 1'd1; 
    end
    else  
        bps_cnt <= 0;
    
    reg[2:0] r_data[7:0];//二维数据,代表八个r_data,每个r_data有3位寄存器存储数值。
    reg[2:0] sta_data;
    reg[2:0] sto_data;
    always@(posedge clk or negedge rstn)
    if(!rstn)begin
        sta_data <= 0;
        sto_data <= 0;
        r_data[0] <= 0; //语法规定,二维数组赋值要分开赋值
        r_data[1] <= 0;    
        r_data[2] <= 0;
        r_data[3] <= 0;    
        r_data[4] <= 0;  
        r_data[5] <= 0;    
        r_data[6] <= 0; 
        r_data[7] <= 0;        
    end
    else if(div_cnt == bps_clk_16x - 1)
    case(bps_cnt) //下面合在一起的写法是允许的
        0:begin
        r_data[0] <= 0; 
        r_data[1] <= 0;    
        r_data[2] <= 0;
        r_data[3] <= 0;    
        r_data[4] <= 0;  
        r_data[5] <= 0;    
        r_data[6] <= 0; 
        r_data[7] <= 0;
        end   
        5,6,7,8,9,10,11: sta_data <= sta_data + uart_rx;
        21,22,23,24,25,26,27: r_data[0] <= r_data[0] + uart_rx;
        37,38,39,40,41,42,43: r_data[1] <= r_data[1] + uart_rx;
        53,54,55,56,57,58,59: r_data[2] <= r_data[2] + uart_rx;
        69,70,71,72,73,74,75: r_data[3] <= r_data[3] + uart_rx;
        85,86,87,88,89,90,91: r_data[4] <= r_data[4] + uart_rx;
        101,102,103,104,105,106,107: r_data[5] <= r_data[5] + uart_rx;
        117,118,119,120,121,122,123: r_data[6] <= r_data[6] + uart_rx;
        133,134,135,136,137,138,139: r_data[7] <= r_data[7] + uart_rx;
        149,150,151,152,153,154,155: sto_data <= sto_data + uart_rx;
        default:;
    endcase        
    
    reg rx_done;
    always@(posedge clk or negedge rstn)
    if(!rstn)
        rx_done <= 0;
    else if(bps_cnt == 159) begin
        rx_done <= 1;
    end
    else
        rx_done <= 0;
    
    //数据接收完成后赋值给data输出
    always@(posedge clk or negedge rstn)
    if(!rstn)
        data <= 0;
    else if(rx_done)begin
        data[0] <= (r_data[0] >= 4 ) ? 1 : 0; //可换种写法,写法如下
        data[1] <= (r_data[1] >= 4 ) ? 1 : 0;
        data[2] <= (r_data[2] >= 4 ) ? 1 : 0;
        data[3] <= (r_data[3] >= 4 ) ? 1 : 0;
        data[4] <= (r_data[4] >= 4 ) ? 1 : 0;
        data[5] <= (r_data[5] >= 4 ) ? 1 : 0;
        data[6] <= (r_data[6] >= 4 ) ? 1 : 0;
        data[7] <= (r_data[7] >= 4 ) ? 1 : 0;
    end

    // data[1] <= r_data[1][2]
    
    // 0:3'd000
    // 1:3'd001
    // 2:3'd010
    
    // 4:3'd100
    // 5:3'd101
    // 6:3'd110
    // 7:3'd111 利用第3位的区别给data赋值

endmodule

仿真代码

`timescale 1ns/1ns

module uart_byte_rx1_tb();
    
    reg clk;
    reg rstn;
    reg uart_rx;
    wire [2:0]blaud_set;
    wire [7:0]data;
    wire rx_done;
    
    uart_byte_rx1 uart_byte_rx_inst1(
        .clk(clk),
        .rstn(rstn),
        .blaud_set(blaud_set),
        .uart_rx(uart_rx),
        .data(data),
        .rx_done(rx_done)
    );
    
    assign blaud_set = 3'd4;
    
    initial clk = 1;
    always #10 clk = ~clk;
    
    initial begin
        rstn = 0;
        uart_rx = 1;
        #201;
        rstn = 1;
        #200;
        uart_tx_byte(8'h5a);
        @(posedge rx_done)
        #5000;
        uart_tx_byte(8'ha5);
        @(posedge rx_done)
        #5000;
        uart_tx_byte(8'h86);
        @(posedge rx_done)
        #5000;
        $stop;

    end
    
    
    task uart_tx_byte;
        input [7:0] tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
        end
    endtask

endmodule

仿真波形

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

压敏电阻简介

压敏电阻 原理 压敏电阻器是一种具有瞬态电压抑制功能的元件&#xff0c;可以用来代替瞬态抑制二极管、齐纳二极管和电容器的组合。压敏电阻器可以对IC及其它设备的电路进行保护&#xff0c;防止因静电放电、浪涌及其它瞬态电流&#xff08;如雷击等&#xff09;而造成对它们…

书生·浦语大模型第三课作业

基础作业&#xff1a; 复现课程知识库助手搭建过程 (截图) 进阶作业&#xff1a; 选择一个垂直领域&#xff0c;收集该领域的专业资料构建专业知识库&#xff0c;并搭建专业问答助手&#xff0c;并在 OpenXLab 上成功部署&#xff08;截图&#xff0c;并提供应用地址&#x…

VUE学习——事件处理

事件分为内联事件和方法事件。 我们可以使用【v-on】&#xff08;简写&#xff1a;&#xff09;来处理。 内联 <button v-on:click"count">按钮</button><button click"count">按钮</button><p>{{ count }}</p>方法

【闲谈】初识深度学习

在过去的十年中&#xff0c;深度学习彻底改变了我们处理数据和解决复杂问题的方式。从图像识别到自然语言处理&#xff0c;再到游戏玩法&#xff0c;深度学习的应用广泛且深入。本文将探讨深度学习的基础知识、关键技术以及最新的研究进展&#xff0c;为读者提供一个全面的视角…

谈谈安全对抗的本质

前言 红队和蓝队的兄弟们都辛苦了&#xff0c;趁夜深人静的时候写了一点东西&#xff0c;算是一点心得与体会&#xff0c;谈谈安全对抗的本质&#xff0c;仅供大家参考。 今年的活动&#xff0c;笔者和去年一样&#xff0c;镇守公司&#xff0c;运筹帷幄之中&#xff0c;决胜千…

问题:老年人心理健康维护与促进的原则为________、________、发展原则。 #媒体#知识分享

问题&#xff1a;老年人心理健康维护与促进的原则为________、________、发展原则。 参考答案如图所示

Spring IoC容器详解

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 基本概念 Spring IoC容器是Spring框架的核心组件&#xff0c;它实现了控制反转&#xff08;Inversion of Control&#xff0c;IoC&#xff09;的设计原则。IoC是一种编程思…

【RabbitMQ(一)】:基本介绍 | 配置安装与快速入门

应该是新年前最后一篇博客了&#xff0c;明天浅浅休息一下&#xff0c;提前祝大家新年快乐捏&#xff01;&#x1f60a;&#x1f60a;&#x1f60a; 01. 基础理解 1.1 同步调用和异步调用 &#x1f449; 同步调用 的时候调用者会 阻塞 等待被调用函数或方法执行完成&#xff…

【MySQL】MySQL表的增删改查(基础)

MySQL表的增删改查&#xff08;基础&#xff09; 1. CRUD2. 新增&#xff08;Create&#xff09;2.1 单行数据全列插入2.2 多行数据 指定列插入 3. 查询&#xff08;Retrieve&#xff09;3.1 全列查询3.2 指定列查询3.3 查询字段为表达式3.4 别名3.5 去重&#xff1a;DISTINCT…

K8S系列文章之 [使用 Alpine 搭建 k3s]

官方文档&#xff1a;K3s - 轻量级 Kubernetes | K3s 官方描述&#xff0c;可运行在 systemd 或者 openrc 环境上&#xff0c;那就往精简方向走&#xff0c;使用 alpine 做系统。与 RHEL、Debian 的区别&#xff0c;主要在防火墙侧&#xff1b;其他基础配置需求类似&#xff0…

每日五道java面试题之java基础篇(一)

第一题 什么是java? PS&#xff1a;碎怂 Java&#xff0c;有啥好介绍的。哦&#xff0c;⾯试啊。 Java 是⼀⻔⾯向对象的编程语⾔&#xff0c;不仅吸收了 C语⾔的各种优点&#xff0c;还摒弃了 C⾥难以理解的多继承、指针等概念&#xff0c;因此 Java 语⾔具有功能强⼤和简单易…

Python爬虫实战:抓取猫眼电影排行榜top100#4

爬虫专栏系列&#xff1a;http://t.csdnimg.cn/Oiun0 抓取猫眼电影排行 本节中&#xff0c;我们利用 requests 库和正则表达式来抓取猫眼电影 TOP100 的相关内容。requests 比 urllib 使用更加方便&#xff0c;而且目前我们还没有系统学习 HTML 解析库&#xff0c;所以这里就…

Linux开发:PAM1 介绍

PAM(Pluggable Authentication Modules )是Linux提供的一种通用的认证方式,他可以根据需要动态的加载认证模块,从而减少认证开发的工作量以及提供认证的灵活度。 1.PAM的框架 PAM的框架由一下几个部分构成 1)应用程序,即需要使用认证服务的程序,这些应用程序是使用抽象…

剑指offer——二维数组中的查找(杨氏矩阵)

目录 1. 题目描述2. 常见错误思路3. 分析3.1 特例分析3.2 规律总结 4. 完整代码 1. 题目描述 在一个二维数组中&#xff0c;每一行都按照从左到右递增的顺序排序&#xff0c;每一列都按照从上到下递增的顺序排序。请完成一个函数&#xff0c;输入这样的一个二维数组和一个整数&…

[SAP] ABAP代码程序美化器大小写格式化设置

按照ABAP开发的规范&#xff0c;ABAP源代码里推荐将所有的关键字大写&#xff0c;其余ABAP变量小写 我们可以手动修改上述代码大小写规范的问题&#xff0c;但如果代码量很多的情况下&#xff0c;手动确保这个规范(所有的关键字大写&#xff0c;其余ABAP变量小写)有点费事&…

机器学习系列——(二十)密度聚类

引言 在机器学习的无监督学习领域&#xff0c;聚类算法是一种关键的技术&#xff0c;用于发现数据集中的内在结构和模式。与传统的基于距离的聚类方法&#xff08;如K-Means&#xff09;不同&#xff0c;密度聚类关注于数据分布的密度&#xff0c;旨在识别被低密度区域分隔的高…

谷歌 DeepMind 联合斯坦福推出了主从式遥操作双臂机器人系统增强版ALOHA 2

谷歌 DeepMind 联合斯坦福推出了 ALOHA 的增强版本 ——ALOHA 2。与一代相比&#xff0c;ALOHA 2 具有更强的性能、人体工程学设计和稳健性&#xff0c;且成本还不到 20 万元人民币。并且&#xff0c;为了加速大规模双手操作的研究&#xff0c;ALOHA 2 相关的所有硬件设计全部开…

VDB-具有动态拓扑的高分辨率稀疏体积表示方法

论文地址&#xff1a;Museth_TOG13.pdf 概述 论文提出了一个称为VDB的新颖数据结构和算法&#xff0c;它可以高效地表示三维网格上的稀疏、随时间变化的数据。 VDB的数据结构基于B树&#xff0c;包含一个动态的根节点&#xff0c;以及多个内部节点和叶节点层次&#xff0c;这…

Guava RateLimiter单机实战指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Guava RateLimiter单机实战指南 前言maven坐标引入业务实现重要参数和方法关于warmupPeriod实战 前言 想象一下你是一位大厨&#xff0c;正在烹饪美味佳肴。突然之间&#xff0c;前来就餐的人潮如潮水…

查看系统进程信息的Tasklist命令

Tasklist命令是一个用来显示运行在本地计算机上所有进程的命令行工具&#xff0c;带有多个执行参数。另外&#xff0c;Tasklist可以代替Tlist工具。通过任务管理器&#xff0c;可以查看到本机完整的进程列表&#xff0c;而且可以通过手工定制进程列表方式获得更多进程信息&…