国外镜像 ASP.NET recursion collections drupal redis常用语句 gdb grunt Seajs ionic framework Avalon NEJ vue学习 vue样式 vue学习教程 bootstrap后台管理 直销系统源码 jquery的each循环 python程序界面 idea整理代码 时间戳java maya曲线建模 cad正在执行命令 kubernetes架构 react python3入门 python中str函数 python返回值 java编译 java连接mysql数据库 java中string的方法 java中scanner用法 linux密码 adobe清理工具 相机权限 华为一键root工具 linux多线程编程 混沌世界隐藏英雄密码 ps3d字体 cad自动保存位置
当前位置: 首页 > 学习教程  > 编程语言

uart串口发送模块功能实现及仿真

2020/11/24 10:44:23 文章标签: 测试文章如有侵权请发送至邮箱809451989@qq.com投诉后文章立即删除

前言 博客上面,人人都说uart简单,刚上手时,笔者也是一脸懵逼。只能假装uart协议确实简单,只不过。。。。(手动笑脸) 00.串口发送原理图 01.串口发送模块uart_byte_tx.v module uart_byte_tx(Clk ,//5…

前言

博客上面,人人都说uart简单,刚上手时,笔者也是一脸懵逼。只能假装uart协议确实简单,只不过。。。。(手动笑脸)

00.串口发送原理图

在这里插入图片描述

01.串口发送模块uart_byte_tx.v

module uart_byte_tx(
	Clk				,//50M时钟
	Rst_n				,//复位信号
	send_en			,//发送使能信号
	baud_set			,//波特率选项
	data_byte		,//要发送的单字节数据
	
	rs232_tx			,//要发送出去的单比特数据
	rx_done			,//发送接收标志
	rx_state			 //发送的状态

);

	input 			Clk			;
   input 			Rst_n			;
   input 			send_en		;
   input 	[2:0]	baud_set		;
   input 	[7:0]	data_byte	;

	output 	reg		rs232_tx		;
	output 	reg		rx_done	;
	output 	reg 		rx_state	;
	
	//两级寄存器消除亚稳态
	reg [7:0] r_data_byte;
	
	//根据波特率选择查找表,选择分频计数时的最大值
	reg [15:0] baud_dr;
	
	//根据上面分频计数时的最大值,生成波特率时钟	
	reg 			bps_clk;
	reg [15:0] 	div_cnt;
	
	//这是根据波特时钟产生的计数器,方便后面进一步控制数据串并转换
	reg [3:0] bps_cnt;
	
	
	
	
//两级寄存器消除亚稳态
	//reg [7:0] r1_data_byte,r2_data_byte;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)begin
		r_data_byte <= 'd0;
	end
	else if(send_en) begin
		r_data_byte <= data_byte;
	end
	
//根据波特率选择查找表,选择分频计数时的最大值
	//reg [15:0] baud_dr;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		baud_dr <= 15'd5207;
	else begin 
		case(baud_set)
			0:baud_dr <= 16'd5207;
			1:baud_dr <= 16'd2603;
			2:baud_dr <= 16'd1301;
			3:baud_dr <= 16'd867;
			4:baud_dr <= 16'd433;
			default:baud_dr <= 16'd5207;
		endcase
	end
	
		
//根据上面分频计数时的最大值,生成波特率时钟	
	//reg 			bps_clk;
	//reg [15:0] 	div_cnt;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		div_cnt <= 'd0;
	else if(rx_state)
		if(div_cnt == baud_dr)//这里之前赋值为baud_set了,波形不对
			div_cnt <= 'd0;
		else 
			div_cnt <= div_cnt + 1'b1;
	else div_cnt <= 'd0;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_clk <= 1'b0;
	//else if(div_cnt == baud_dr)//这是每次计数完的时候产生的波特率时钟,如果在计数结束时生成时钟就统一往后延迟了下,可以选择在div_cnt=1时生成
	else if(div_cnt == 1'b1)
		bps_clk <= 1'b1;
	else 
		bps_clk <= 1'b0;
	
//这是根据波特时钟产生的计数器,方便后面进一步控制数据串并转换
	//reg [3:0] bps_cnt;
	
	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		bps_cnt <= 'd0;
	else if(bps_cnt == 'd11)
		bps_cnt <= 'd0;
	else if(bps_clk)
		bps_cnt <= bps_cnt + 1'b1;
	else 
		bps_cnt <= bps_cnt;
		
//根据波特率时钟产生的计数器,选择数据的传输
	localparam START_BIT = 1'b0;
	localparam STOP_BIT = 1'b1;


	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		rs232_tx <= 1'b1;
	else 
		case(bps_cnt)
			'd0:rs232_tx <= 1'b1;
			'd1:rs232_tx <= START_BIT;
			'd2:rs232_tx <= r_data_byte[0];
			'd3:rs232_tx <= r_data_byte[1];
			'd4:rs232_tx <= r_data_byte[2];
			'd5:rs232_tx <= r_data_byte[3];
			'd6:rs232_tx <= r_data_byte[4];
			'd7:rs232_tx <= r_data_byte[5];
			'd8:rs232_tx <= r_data_byte[6];
			'd9:rs232_tx <= r_data_byte[7];
			'd10:rs232_tx <= STOP_BIT;
			default:rs232_tx <= 1'b1;
		endcase
		
//rx_done:当波特率时钟计数器计数到11时,计数就清零,方便进行下一轮的计数

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		rx_done <= 1'b0;
	else if(bps_cnt == 'd11)
		rx_done <= 1'b1;
	else 
		rx_done <= 1'b0;
	
	
//rx_state:通过send_en和波特率计数(bps_cnt == 11)描述出发送的状态

	always@(posedge Clk or negedge Rst_n)
	if(!Rst_n)
		rx_state <= 1'b0;
	else if(send_en)
		rx_state <= 1'b1;
	else if(bps_cnt == 'd11)
		rx_state <= 1'b0;
	else 
		rx_state <= rx_state;
	
endmodule

02.串口发送仿真uart_byte_tx_tb.v

`timescale 1ns/1ns
`define clock_period 20

module uart_byte_tx_tb;

	reg 			Clk			;
   reg 			Rst_n			;
   reg 			send_en		;
   reg 	[2:0]	baud_set		;
   reg 	[7:0]	data_byte	;

	wire			rs232_tx		;
	wire			rx_done	;
	wire 			rx_state	;
	

	uart_byte_tx  uart_byte_tx_inst(
		.Clk			(Clk			),
		.Rst_n		(Rst_n		),
		.send_en		(send_en		),
		.baud_set	(baud_set	),
		.data_byte	(data_byte	),
	                
		.rs232_tx	(rs232_tx	),
		.rx_done	(rx_done	),
		.rx_state	(rx_state	)

	);

	//产生时钟
	initial  Clk = 1'b1;
	always #(`clock_period/2) Clk = ~Clk;

	//产生激励信号
	initial begin
		Rst_n = 1'b0;
		data_byte = 8'b0;
		send_en = 1'b0;
		baud_set = 3'd4;
		#(`clock_period*20 + 1);
		Rst_n = 1'b1;
		
		
		#(`clock_period*50);
		data_byte = 8'haa;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge rx_done);
		
		
		#(`clock_period*5000);
		data_byte = 8'h55;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge rx_done);
		
		
		#(`clock_period*5000);
		data_byte = 8'hdc;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge rx_done);
		
		#(`clock_period*5000);
		data_byte = 8'hcd;
		send_en = 1'd1;
		#`clock_period;
		send_en = 1'd0;
		@(posedge rx_done);
		
		#(`clock_period*5000);
		$stop;	
	end


endmodule

功能仿真如下:

在这里插入图片描述

后记

下面就开始,串口接收模块。


本文链接: http://www.dtmao.cc/news_show_400327.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?