1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > FPGA之实现UART串行异步通信-一字节数据接收

FPGA之实现UART串行异步通信-一字节数据接收

时间:2021-01-28 05:24:09

相关推荐

FPGA之实现UART串行异步通信-一字节数据接收

文章目录

前言一、UART关键参数二、数据接收子功能介绍1.子功能函数2.仿真测试模块总结

前言

使用FPGA自带USB转串口实现指定波特率的单个数据的发送。

一、UART关键参数

1、波特率:每秒钟可以发送或接收的数据比特的个数,发送和接收的设备需要波特率一致才可,常见的波特率有9600、19200、38400、57600等。

2、一帧数据:包含一位起始位;1或1.5或2位停止位;5到8位数据位;1位或没有奇偶校验位。在RS232标准中,最常用的配置是使用8位数据位、1位停止位、1位起始位、无奇偶校验位进行,共十位数据。

3、UART发送一字节数据时序图:

串口接收和串口发送方式略有不同,工业情况下,常常有强电磁干扰,导致数据会被影响,因此只采样一次就作为该数据的电平状态时不可靠的,为消除干扰,采用多次采样求概率的方式进行状态判定:

对于Bit_x这一位数据,共分成16次采样,在发生变化后和即将发生变化时有可能不稳定,因此忽略掉深色部分,对中间六次采样数据进行概率比较,出现次数多的电平为有效电平。(通常不会出现低电平和高电平均为3个的时候,数据不可靠,不做处理)

二、数据接收子功能介绍

使用两个寄存器消除亚稳态查找表查找bps

记采样计数值最大值为bps_DR。分频计数器:将系统50MHz的时钟进行分频,每记数到一个bps_DR即输出一个bps_clk。波特率时钟:波特率时钟,每进行一次分频,bps_clk置1,时间为一个系统周期(20ns)。波特率时钟计数器:

计数满判定:rx_done

rx_done判定:bps_cnt=16*10=160-1时,rx_done置1

清零判定:起始错误数据接收采样:bps_cnt=0时,寄存器r_data_byte置0

当bps_cnt=6时开始采样,此后每加16即为每位数据起始采样点,采样到的数据进行累加并加上同步后的rs232_rx即s1_rs232_rx。数据状态分析:

采样6次,高电平大于三次即为1,反之为0,大于三的有100、101、110,因此只需最高位为1即为1,引入二重数组:[2:0]r_data_byte[7:0]进行判定,结果存在data_byte中。

1.子功能函数

定义:

module uart_byte_rx(clk,rst_n,baud_set,rs232_rx,data_byte,rx_done);input clk;input rst_n;input [2:0]baud_set;input rs232_rx;output reg[7:0]data_byte;output reg rx_done;reg s0_rs232_rx,s1_rs232_rx;//同步寄存器,消除亚稳态reg tmp0_rs232_rx,tmp1_rs232_rx;//数据寄存器reg [15:0]bps_DR;//分频计数器计数最大值reg [15:0]div_cnt;//分频计数器计数最大值reg uart_state;reg [2:0] r_data_byte[7:0]; reg [2:0] START_BIT,STOP_BIT;reg bps_clk;//波特率时钟reg [7:0]bps_cnt;wire nedege;

消除亚稳态

//同步寄存器,消除亚稳态always @(posedge clk or negedge rst_n)if(!rst_n)begins0_rs232_rx<=1'b0;s1_rs232_rx<=1'b0;endelse begins0_rs232_rx<=rs232_rx;s1_rs232_rx<=s0_rs232_rx;end

数据寄存器

//数据寄存器always @(posedge clk or negedge rst_n)if(!rst_n)begintmp0_rs232_rx<=1'b0;tmp1_rs232_rx<=1'b0;endelse begintmp0_rs232_rx<=s1_rs232_rx;tmp1_rs232_rx<=tmp0_rs232_rx;endassign nedege=!tmp0_rs232_rx & tmp1_rs232_rx;

查找表查找bps

always @(posedge clk or negedge rst_n)if(!rst_n)bps_DR<=16'd324;else begincase(baud_set)0:bps_DR<=16'd324;1:bps_DR<=16'd162;2:bps_DR<=16'd80;3:bps_DR<=16'd53;4:bps_DR<=16'd26;default:bps_DR<=16'd324;endcaseend

分频计数器

always @(posedge clk or negedge rst_n)if(!rst_n)div_cnt<=16'd0;else if(uart_state)beginif(div_cnt==bps_DR)div_cnt<=16'd0;elsediv_cnt<=div_cnt+1'b1;endelsediv_cnt<=16'd0;

波特率时钟

always @(posedge clk or negedge rst_n)if(!rst_n)bps_clk<=1'b0;else if(div_cnt==16'd1)bps_clk<=1'b1;elsebps_clk<=1'b0;

波特率时钟计数器

//波特率时钟计数器always @(posedge clk or negedge rst_n)if(!rst_n)bps_cnt<=8'b0;else if(rx_done | (bps_cnt==8'd12 && (START_BIT>2)))bps_cnt<=8'b0;else if(bps_clk)bps_cnt<=bps_cnt+1'b1;else bps_cnt<=bps_cnt;

接收完毕信号

always @(posedge clk or negedge rst_n)if(!rst_n)rx_done<=1'b0;else if(bps_cnt==8'd159)rx_done<=1'b1;elserx_done<=1'b0;

数据接收采样

always @(posedge clk or negedge rst_n)if(!rst_n)beginSTART_BIT=3'd0;r_data_byte[0]<=3'd0;r_data_byte[1]<=3'd0;r_data_byte[2]<=3'd0;r_data_byte[3]<=3'd0;r_data_byte[4]<=3'd0;r_data_byte[5]<=3'd0;r_data_byte[6]<=3'd0;r_data_byte[7]<=3'd0;STOP_BIT=3'd0;endelse begincase(bps_cnt)0:beginSTART_BIT=3'd0;r_data_byte[0]<=3'd0;r_data_byte[1]<=3'd0;r_data_byte[2]<=3'd0;r_data_byte[3]<=3'd0;r_data_byte[4]<=3'd0;r_data_byte[5]<=3'd0;r_data_byte[6]<=3'd0;r_data_byte[7]<=3'd0;STOP_BIT=3'd0;end6,7,8,9,10,11:START_BIT<=START_BIT+s1_rs232_rx;22,23,24,25,26,27:r_data_byte[0]<=r_data_byte[0]+s1_rs232_rx;38,39,40,41,42,43:r_data_byte[1]<=r_data_byte[1]+s1_rs232_rx;54,55,56,57,58,59:r_data_byte[2]<=r_data_byte[2]+s1_rs232_rx;70,71,72,73,74,75:r_data_byte[3]<=r_data_byte[3]+s1_rs232_rx;86,87,88,89,90,91:r_data_byte[4]<=r_data_byte[4]+s1_rs232_rx;102,103,104,105,106,107:r_data_byte[5]<=r_data_byte[5]+s1_rs232_rx;118,119,120,121,122,123:r_data_byte[6]<=r_data_byte[6]+s1_rs232_rx;134,135,136,137,138,139:r_data_byte[7]<=r_data_byte[7]+s1_rs232_rx;150,151,152,153,154,155:STOP_BIT<=STOP_BIT+s1_rs232_rx;default;endcaseend

数据状态分析

always @(posedge clk or negedge rst_n)if(!rst_n)data_byte<=8'd0;else if(bps_cnt==8'd159) begindata_byte[0]=r_data_byte[0][2];data_byte[1]=r_data_byte[1][2];data_byte[2]=r_data_byte[2][2];data_byte[3]=r_data_byte[3][2];data_byte[4]=r_data_byte[4][2];data_byte[5]=r_data_byte[5][2];data_byte[6]=r_data_byte[6][2];data_byte[7]=r_data_byte[7][2];end

uart_state状态

always @(posedge clk or negedge rst_n)if(!rst_n)uart_state<=1'b0;else if(nedege)uart_state<=1'b1;else if(rx_done || (bps_cnt==8'd12 && (START_BIT>2)))uart_state<=1'b0;elseuart_state<=uart_state;

2.仿真测试模块

`timescale 1ns/1ns`define clk_period 20module uart_byte_rx_tb;reg clk;reg rst_n;reg [2:0]baud_set;reg rs232_rx;wire [7:0]data_byte_r;wire rx_done;reg send_en;reg [7:0]data_byte_t;wire rs232_tx;wire tx_done;wire uart_state;uart_byte_rx uart_byte_rx(.clk(clk),.rst_n(rst_n),.baud_set(baud_set),.rs232_rx(rs232_rx),.data_byte(data_byte_r),.rx_done(rx_done));uart_byte_tx uart_byte_tx1(.clk(clk),.rst_n(rst_n),.send_en(send_en),.data_byte(data_byte_t),.baud_set(baud_set),.rs232_tx(rs232_tx),.tx_done(tx_done),.uart_state(uart_state));initial clk=1;always #(`clk_period/2) clk=~clk;initial beginrst_n=1'b0;send_en=1'b0;data_byte_t=8'd0;baud_set=3;#(`clk_period*20+1)rst_n=1'b1;send_en=1'b1;data_byte_t=8'haa;#`clk_period;send_en=1'b0;@(posedge tx_done)#(`clk_period*5000);data_byte_t=8'h55;send_en=1'b1;#`clk_period;send_en=1'b0;@(posedge tx_done)#(`clk_period*5000);$stop;endendmodule

总结

以上便是UART串行异步通信实现单个数据的接收原理及代码。板级验证时使用FPGA自带的USB转串口实现数据接收。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。