我是靠谱客的博主 发嗲红牛,最近开发中收集的这篇文章主要介绍FPGA之实现UART串行异步通信-一字节数据接收前言一、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)begin
s0_rs232_rx<=1'b0;
s1_rs232_rx<=1'b0;
end
else begin
s0_rs232_rx<=rs232_rx;
s1_rs232_rx<=s0_rs232_rx;
end
- 数据寄存器
//数据寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
tmp0_rs232_rx<=1'b0;
tmp1_rs232_rx<=1'b0;
end
else begin
tmp0_rs232_rx<=s1_rs232_rx;
tmp1_rs232_rx<=tmp0_rs232_rx;
end
assign nedege=!tmp0_rs232_rx & tmp1_rs232_rx;
- 查找表查找bps
always @(posedge clk or negedge rst_n)
if(!rst_n)
bps_DR<=16'd324;
else begin
case(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;
endcase
end
- 分频计数器
always @(posedge clk or negedge rst_n)
if(!rst_n)
div_cnt<=16'd0;
else if(uart_state)begin
if(div_cnt==bps_DR)
div_cnt<=16'd0;
else
div_cnt<=div_cnt+1'b1;
end
else
div_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;
else
bps_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;
else
rx_done<=1'b0;
- 数据接收采样
always @(posedge clk or negedge rst_n)
if(!rst_n)begin
START_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;
end
else begin
case(bps_cnt)
0:begin
START_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;
end
6,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;
endcase
end
- 数据状态分析
always @(posedge clk or negedge rst_n)
if(!rst_n)
data_byte<=8'd0;
else if(bps_cnt==8'd159) begin
data_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;
else
uart_state<=uart_state;
2.仿真测试模块
`timescale 1ns/1ns
`define clk_period 20
module 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 begin
rst_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;
end
endmodule
总结
以上便是UART串行异步通信实现单个数据的接收原理及代码。板级验证时使用FPGA自带的USB转串口实现数据接收。
最后
以上就是发嗲红牛为你收集整理的FPGA之实现UART串行异步通信-一字节数据接收前言一、UART关键参数二、数据接收子功能介绍总结的全部内容,希望文章能够帮你解决FPGA之实现UART串行异步通信-一字节数据接收前言一、UART关键参数二、数据接收子功能介绍总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复