【SugerTangYL】UART串口通信 Verilog

目录

前言

 一、UART相关

二、本次设计

 (一)顶层模块

(二)发送模块UART_Tx

 (三)奇校验码产生模块

 (四)接收模块UART_Rx

 (五)单周期脉冲产生模块

 (六)分频器

(七)测试平台


前言

        我好久之前就想做写通信协议接口的,之前写了RISC-V的处理器内核,想试试看SOC怎么搭,所以学习了下UART接口。


 一、UART相关

        UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。因此包含一个发送器和一个接收器。

        工作原理是将传输数据的每个字符以串行方式一位接一位的传输,通信双方需要事先约定传输速率(波特率)。其具体工作时序图如下:

二、本次设计

        本次设计思路为先分别设计收发模块,然后再在顶层组合。发送模块采取状态机写法,一帧数据包含起始位、8位数据位、奇校验位(忘了是奇校验还是偶校验)、结束位。接收模块采用16倍采样接收,从而保证采样准确性。为了能够在FPGA上测试,增加了单周期脉冲模块,用以将按键脉冲变成一个单时钟周期的脉冲信号。

 (一)顶层模块

module top(
	input  wire 		clk,
	input  wire 		key,
	input  wire 		key2,
	input  wire 	[7:0] 	data,
	output wire 		uart_txd,
	output wire	[7:0]	o_data,
	output wire		over_flag
	);

wire clk_divider1;
wire clk_divider2;
wire o_done;
wire signal_send_request;




divider #(7) divider_init1 (clk_divider2,key2,clk_divider1);
divider #(13) divider_init2 (clk,key2,clk_divider2);

UART_Tx UART_Tx_init(.data(data),.clk(clk_divider1),.signal_send_request(signal_send_request),.rst_n(key2),.uart_txd(uart_txd),.o_done(o_done));

Monopulse_clock Monopulse_clock_init(
	.clk(clk_divider1),
	.signal(key),
	.rst_n(key2),
	.o_monopulse(signal_send_request)
);


UART_Rx UART_Rx_init(
	.uart_txd(uart_txd),
	.clk(clk_divider2),
	.rst_n(key2),
	.data(o_data),
	.over_flag(over_flag)
	);
endmodule

(二)发送模块UART_Tx

module UART_Tx(
	input  wire [7:0]	data,
	input  wire			clk,
	input  wire			signal_send_request,
	input  wire 		rst_n,
	output reg 			uart_txd,
	output reg			o_done
);


parameter S_IDLE	= 4'b0000;
parameter S_START = 4'b0001;
parameter S_DATA0	= 4'b0011;
parameter S_DATA1 = 4'b0010;
parameter S_DATA2 = 4'b0110;
parameter S_DATA3 = 4'b0111;
parameter S_DATA4 = 4'b0101;
parameter S_DATA5 = 4'b0100;
parameter S_DATA6 = 4'b1100;
parameter S_DATA7 = 4'b1101;
parameter S_CHECK = 4'b1111;
parameter S_STOP	= 4'b1110;

wire bit_check;//奇校验码
reg [7:0] data_in;//数据缓存单元

/**********数据缓存***********/
always@(posedge signal_send_request or negedge rst_n) begin
	if(!rst_n) begin
		data_in <= 8'b0;
	end
	else data_in <= data;
end

/********状态机********/
reg [3:0] state_current;
reg [3:0] state_next;

/************FSM-1*************/
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		state_current <= S_IDLE;
	end
	else begin
		state_current <= state_next;
	end
end

/************FSM-2*************/
always@(state_current or signal_send_request) begin
	state_next <= S_IDLE;
	case (state_current)
		S_IDLE :if(signal_send_request) begin
					state_next <= S_START;
				  end
				  else state_next <= S_IDLE;
		S_START:state_next <= S_DATA0;
		S_DATA0:state_next <= S_DATA1;
		S_DATA1:state_next <= S_DATA2;
		S_DATA2:state_next <= S_DATA3;
		S_DATA3:state_next <= S_DATA4;
		S_DATA4:state_next <= S_DATA5;
		S_DATA5:state_next <= S_DATA6;
		S_DATA6:state_next <= S_DATA7;
		S_DATA7:state_next <= S_CHECK;
		S_CHECK:state_next <= S_STOP;
		S_STOP :state_next <= S_IDLE;
		default:state_next <= S_IDLE;
	endcase
end

/************FSM-3*************/
always@(*) begin
	if(!rst_n) begin
		uart_txd <= 1'b1;
		o_done	<= 1'b0;
	end
	else begin
		case (state_current)
			S_IDLE	:begin uart_txd <= 1'b1;o_done <= 1'b0;end
			S_START	:	uart_txd <= 1'b0;
			S_DATA0	:	uart_txd <= data_in[0];
			S_DATA1	:	uart_txd <= data_in[1];
			S_DATA2	:	uart_txd <= data_in[2];
			S_DATA3	:	uart_txd <= data_in[3];
			S_DATA4	:	uart_txd <= data_in[4];
			S_DATA5	:	uart_txd <= data_in[5];
			S_DATA6	:	uart_txd <= data_in[6];
			S_DATA7	:	uart_txd <= data_in[7];
			S_CHECK	:	uart_txd <= bit_check;
			S_STOP	:begin uart_txd <= 1'b1;o_done <= 1'b1;end
			default	:	uart_txd <= 1'b1;
		endcase
	end
end


Parity_Checker parity_checker_init(data_in,bit_check);//奇校验码产生

endmodule

 (三)奇校验码产生模块

module Parity_Checker(
	input	 wire [7:0] data,
	output wire		   bit_check
  );

assign bit_check = (data[7]^data[6])^(data[5]^data[4])^(data[3]^data[2])^(data[1]^data[0]);
endmodule

 (四)接收模块UART_Rx

module UART_Rx(
	input 	wire				uart_txd,
	input	wire 				clk,
	input 	wire				rst_n,
	output	reg	    [7:0]		data,
	output  reg 				over_flag
	);

parameter S_IDLE = 1'b0;
parameter S_EXE  = 1'b1;
	

reg [3:0] cmt; 
reg [3:0] c_cmt;
reg current_state;
reg next_state;
reg [10:0] temp;
reg [3:0] buffer;


always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		cmt <= 4'b0;
		c_cmt <= 4'b0;
		buffer <= 4'b0;
		temp <= 11'b0;
	end
	else begin
		if(current_state == S_EXE) begin
			if(cmt == 4'b1111) begin
				cmt <= 4'b0;
				c_cmt <= c_cmt + 4'b0001;
				temp[c_cmt] <= (buffer >4'd8);
				buffer <= 4'b0;
			end
			else begin
				cmt <= cmt + 4'b0001;
				buffer <= buffer + {3'b000,uart_txd};
			end
		end
		else begin
			cmt <= 4'b0;
			c_cmt <= 4'b0;
			buffer <= 4'b0;
		end
	end
end

always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		current_state <= S_IDLE;
	end
	else begin
		current_state <= next_state;
	end
end


always@(uart_txd,current_state,over_flag) begin
	case (current_state) 
		S_IDLE:begin
					if(!uart_txd) begin
						next_state <= S_EXE;
					end
					else next_state <= S_IDLE;
				 end
		S_EXE :begin
					if(over_flag) begin
						next_state <= S_IDLE;
					end
					else next_state <= S_EXE;
				 end
		default:next_state <= S_IDLE;
	endcase
end

always@(current_state,c_cmt) begin
	case (current_state)
		S_IDLE:begin
					over_flag <= 1'b0;
				 end
		S_EXE :begin
					if(c_cmt >= 4'd11) begin
						over_flag <= 1'b1;
					end
					else begin
						over_flag <= 1'b0;
					end
				 end
		default:over_flag <= 1'b0;
	endcase
end

always@(posedge over_flag or negedge rst_n) begin
	if(!rst_n) begin
		data <= 8'b0;
	end
	else begin
		data <= temp[8:1];
	end
end
endmodule

 (五)单周期脉冲产生模块

module Monopulse_clock(
	input  wire 		clk,
	input  wire 		signal,
	input  wire			rst_n,
	output wire 		o_monopulse
	);

reg signal_rst_pre;                
reg signal_rst;                    
 

always @(posedge clk or negedge rst_n) begin
	if (!rst_n) begin
		signal_rst <= 1'b1;                
		signal_rst_pre <= 1'b1;
	end
	else begin
		signal_rst <= signal;                     
		signal_rst_pre <= signal_rst;             
	end    
end
 
assign  o_monopulse = signal_rst_pre & (~signal_rst);

endmodule

 (六)分频器

module divider(
	input  wire 	  clk,
	input  wire 	  rst_n,
	output reg 	  clk_divider
	);
parameter TIMESCALE = 216;

reg [15:0] cmt;

always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		cmt<= 16'b0;
		clk_divider <= 1'b0;
	end
	else begin
		if(cmt >= TIMESCALE) begin
			cmt <= 16'b0;
			clk_divider <= ~clk_divider;
		end
		else begin
			cmt <= cmt + 16'b1;
		end
	end
end
endmodule

(七)测试平台

`timescale 1ns/1ns

module top_tp();
reg	clk;
reg	key;
reg	key2;
reg 	[7:0] 	data;
wire	uart_txd;
wire	[7:0]	o_data;
wire	over_flag;

top top_init(
	.clk(clk),
	.key(key),
	.key2(key2),
	.data(data),
	.uart_txd(uart_txd),
	.o_data(o_data),
	.over_flag(over_flag)
	);


initial begin
	clk = 1'b0;
	forever begin
	#10	clk = ~clk;
	end
end

initial begin
	#100 data = 8'b01101101;
end

initial begin
	key = 1'b0;
	key2 = 1'b1;
	#300 key2 = 1'b0;	
	#500 key2 = 1'b1;
	#500 key = 1'b1;
	#500 key = 1'b0;
end



endmodule


结束语:很久才想起来这个坑,懒得加注释讲解了,略

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值