我是靠谱客的博主 发嗲红牛,最近开发中收集的这篇文章主要介绍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个的时候,数据不可靠,不做处理)

二、数据接收子功能介绍

在这里插入图片描述

  1. 使用两个寄存器消除亚稳态
  2. 查找表查找bps
    在这里插入图片描述
    记采样计数值最大值为bps_DR。
  3. 分频计数器:将系统50MHz的时钟进行分频,每记数到一个bps_DR即输出一个bps_clk。
  4. 波特率时钟:波特率时钟,每进行一次分频,bps_clk置1,时间为一个系统周期(20ns)。
  5. 波特率时钟计数器:
    计数满判定:rx_done
    rx_done判定:bps_cnt=16*10=160-1时,rx_done置1
    清零判定:起始错误
  6. 数据接收采样:bps_cnt=0时,寄存器r_data_byte置0
    当bps_cnt=6时开始采样,此后每加16即为每位数据起始采样点,采样到的数据进行累加并加上同步后的rs232_rx即s1_rs232_rx。
  7. 数据状态分析:
    采样6次,高电平大于三次即为1,反之为0,大于三的有100、101、110,因此只需最高位为1即为1,引入二重数组:[2:0]r_data_byte[7:0]进行判定,结果存在data_byte中。

1.子功能函数

  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;
  1. 消除亚稳态
//同步寄存器,消除亚稳态
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
  1. 数据寄存器
//数据寄存器
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;
  1. 查找表查找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
  1. 分频计数器
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;
  1. 波特率时钟
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;
  1. 波特率时钟计数器
//波特率时钟计数器	
	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;
  1. 接收完毕信号
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;
  1. 数据接收采样
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
  1. 数据状态分析
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
  1. 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关键参数二、数据接收子功能介绍总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部