基于FPGA的数字钟——(一)串口通信模块

(一)串口通信模块设计

1.串口通信协议

UART通信的一帧一般由11到12位数据组成。1bit的起始位,检测为低电平表示数据开始传输;紧接着8bits的数据;然后是1bit的奇偶校验位,可以是奇校验或者偶校验;最后是1bit或2bits的停止位,必须为高电平,表示一个字符数据的传输结束。

其中校验位是可选的,用来检验数据是否传输正确。如果有校验位,则需要保证收发双方选择同样的一种检验方式。奇校验就是保证数据中的1是奇数,比如如果8bit数据中有3bits的1,校验位置0;如果有4bits的1,校验位置1。偶校验就是保证数据中的1是偶数。

原文链接:https://blog.csdn.net/FPGADesigner/article/details/75201194

波特率:波特率表示数据传输的速率,单位bps,表示位每秒。比如9600bps就表示1s可以传输9600bits的数据。异步收发没有时钟打拍来控制数据的传输,就需要保证收发双方在波特率设置上的一致。确保接收数据的完整性。

在这里插入图片描述

2.串口发送模块实现

默认采用115200的波特率。不使用校验位。设计一个波特率计数器对系统时钟进行分频而实现波特率时钟。
使用三段式状态机进行发送的时序控制,采用BCD码对状态进行编码。
在这里插入图片描述

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2019/12/29 15:55:40
// Design Name: uart_tx
// Module Name: uart_tx
// Project Name: Clock
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_tx
#(
	parameter BAUD_RATE = 115200
)
(
    input clk,
    input rst,
    output reg tx,
    input [7:0] data_in,
	input send_require,
    output reg wr,
	output reg tx_done
    );
	
	localparam baud_cnt_max = 50_000_000/BAUD_RATE-1;
	reg[12:0] baud_cnt;
	reg[3:0] state;
	localparam IDLE     =4'b0000;
	localparam START    =4'b0001;
	localparam SEND_BIT0=4'b0011;
	localparam SEND_BIT1=4'b0010;
	localparam SEND_BIT2=4'b0110;
	localparam SEND_BIT3=4'b0100;
	localparam SEND_BIT4=4'b0101;
	localparam SEND_BIT5=4'b0111;
	localparam SEND_BIT6=4'b1111;
	localparam SEND_BIT7=4'b1110;

	wire sd_rq_pedge;//发送请求上升沿
	reg sd_rq_temp0;
	reg sd_rq_temp1;
	assign sd_rq_pedge = (sd_rq_temp0)&(!sd_rq_temp1);
	
	reg cnt_en;
	reg cnt_full;
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			sd_rq_temp0 <= 1'b0;
			sd_rq_temp1 <= 1'b0;
		end
		else begin
			sd_rq_temp0 <= send_require;
			sd_rq_temp1 <= sd_rq_temp0;
		end
	end
	
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			baud_cnt <= 13'd0;
			cnt_full <= 1'b0;
		end
		else begin
			if(cnt_en)
				if(baud_cnt==baud_cnt_max)begin
					baud_cnt <= 13'd0;
					cnt_full <= 1'b1;
				end
				else begin
					baud_cnt <= baud_cnt + 1'b1;
					cnt_full <= 1'b0;
				end
			else begin
				baud_cnt <= 13'd0;
				cnt_full <= 1'b0;
			end
		end
	end
	
	always@(posedge clk or negedge rst)begin
		if(!rst)
			state <= IDLE;		
		else 
			case(state)
				IDLE:begin
					if(sd_rq_pedge)
						state <= START;
					else
						state <= IDLE;
				end
				START:begin
					if(cnt_full)
						state <= SEND_BIT0;
					else
						state <= START;
				end
				SEND_BIT0:begin
					if(cnt_full)
						state <= SEND_BIT1;
					else
						state <= SEND_BIT0;
				end
				SEND_BIT1:begin
					if(cnt_full)
						state <= SEND_BIT2;
					else
						state <= SEND_BIT1;
				end
				SEND_BIT2:begin
					if(cnt_full)
						state <= SEND_BIT3;
					else
						state <= SEND_BIT2;
				end
				SEND_BIT3:begin
					if(cnt_full)
						state <= SEND_BIT4;
					else
						state <= SEND_BIT3;
				end
				SEND_BIT4:begin
					if(cnt_full)
						state <= SEND_BIT5;
					else
						state <= SEND_BIT4;
				end
				SEND_BIT5:begin
					if(cnt_full)
						state <= SEND_BIT6;
					else
						state <= SEND_BIT5;
				end
				SEND_BIT6:begin
					if(cnt_full)
						state <= SEND_BIT7;
					else
						state <= SEND_BIT6;
				end
				SEND_BIT7:begin
					if(cnt_full)
						state <= IDLE;
					else
						state <= SEND_BIT7;
				end
				default:begin
					state <= IDLE;
				end
			endcase
	end
		always@(posedge clk or negedge rst)begin
		if(!rst)begin
			cnt_en <= 1'b0;	
			tx <= 1'b1;
			wr <= 1'b1;//表明可写
			tx_done <= 1'b0;
		end
		else 
			case(state)
				IDLE:begin
					cnt_en <= 1'b0;	
					tx <= 1'b1;
					wr <= 1'b1;
					tx_done <= 1'b0;
				end
				START:begin
					cnt_en <= 1'b1;	
					tx <= 1'b0;
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT0:begin
					cnt_en <= 1'b1;	
					tx <= data_in[0];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT1:begin
					cnt_en <= 1'b1;	
					tx <= data_in[1];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT2:begin
					cnt_en <= 1'b1;	
					tx <= data_in[2];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT3:begin
					cnt_en <= 1'b1;	
					tx <= data_in[3];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT4:begin
					cnt_en <= 1'b1;	
					tx <= data_in[4];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT5:begin
					cnt_en <= 1'b1;	
					tx <= data_in[5];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT6:begin
					cnt_en <= 1'b1;	
					tx <= data_in[6];
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
				SEND_BIT7:begin
					cnt_en <= 1'b1;	
					tx <= data_in[7];
					wr <= 1'b0;
					tx_done <= 1'b1;
				end
				default:begin
					cnt_en <= 1'b0;	
					tx <= 1'b1;
					wr <= 1'b0;
					tx_done <= 1'b0;
				end
			endcase
	end	
endmodule

仿真波形图
uart_tb

串口接收模块设计

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: NanJing University of Information Science & Technology
// Engineer: Yang Cheng Yu
// 
// Create Date: 2019/12/29 15:55:40
// Design Name: uart_rx
// Module Name: uart_rx
// Project Name: Clock
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_rx
#(
	parameter BAUD_RATE = 115200
)
(
    input clk,
    input rst,
	input rx,
	output reg rd,
	output reg[7:0] data_out,
	output rx_done
    );
	reg rx_done;
	localparam baud_cnt_max = 50_000_000/BAUD_RATE-1;
	localparam baud_cnt_half = (50_000_000/BAUD_RATE)/2-1;
	wire rx_pin_nedge;//rx_pin下降沿
	reg rx_pin_temp0;
	reg rx_pin_temp1;
	reg[3:0] state;
	reg[12:0] baud_cnt;
	reg cnt_en;
	reg cnt_half;
	reg cnt_full;
	reg rx_over;
	reg[7:0] data_out_reg;
	localparam IDLE			=4'b0000;
	localparam GET_START_BIT=4'b0001;
	localparam GET_BIT0		=4'b0011;
	localparam GET_BIT1		=4'b0010;
	localparam GET_BIT2		=4'b0110;
	localparam GET_BIT3		=4'b0100;
	localparam GET_BIT4		=4'b0101;
	localparam GET_BIT5		=4'b0111;
	localparam GET_BIT6		=4'b1111;
    localparam GET_BIT7     =4'b1110;
	assign rx_pin_nedge = (!rx_pin_temp0)&(rx_pin_temp1);//下降沿
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			rx_pin_temp0 <= 1'b1;
			rx_pin_temp1 <= 1'b1;
		end
		else begin
			rx_pin_temp0 <= rx;
			rx_pin_temp1 <= rx_pin_temp0;
		end
	end
	
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			baud_cnt <= 13'd0;
			cnt_full <= 1'b0;
			cnt_half <= 1'b0;
		end
		else begin
			if(cnt_en)
				if(baud_cnt==baud_cnt_max)begin
					baud_cnt <= 13'd0;
					cnt_full <= 1'b1;
					cnt_half <= 1'b0;
				end
				else if(baud_cnt==baud_cnt_half)begin
					baud_cnt <= baud_cnt + 1'b1;
					cnt_full <= 1'b0;
					cnt_half <= 1'b1;	
				end
				else begin
					baud_cnt <= baud_cnt + 1'b1;
					cnt_full <= 1'b0;
					cnt_half <= 1'b0;
				end
			else begin
				baud_cnt <= 13'd0;
				cnt_full <= 1'b0;
				cnt_half <= 1'b0;
			end
		end
	end
	
	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			state <= IDLE;
		end
		else begin
			case(state)
				IDLE:begin
					if(rx_pin_nedge)
						state <= GET_START_BIT;
					else
						state <= IDLE;
				end
				GET_START_BIT:begin
					if(cnt_full)
						state <= GET_BIT0;
					else
						state <= GET_START_BIT;
				end
				GET_BIT0:begin
					if(cnt_full)
						state <= GET_BIT1;
					else
						state <= GET_BIT0;
				end
				GET_BIT1:begin
					if(cnt_full)
						state <= GET_BIT2;
					else
						state <= GET_BIT1;
				end
				GET_BIT2:begin
					if(cnt_full)
						state <= GET_BIT3;
					else
						state <= GET_BIT2;
				end
				GET_BIT3:begin
					if(cnt_full)
						state <= GET_BIT4;
					else
						state <= GET_BIT3;
				end
				GET_BIT4:begin
					if(cnt_full)
						state <= GET_BIT5;
					else
						state <= GET_BIT4;
				end
				GET_BIT5:begin
					if(cnt_full)
						state <= GET_BIT6;
					else
						state <= GET_BIT5;
				end
				GET_BIT6:begin
					if(cnt_full)
						state <= GET_BIT7;
					else
						state <= GET_BIT6;
				end
				GET_BIT7:begin
					if(cnt_full)
						state <= IDLE;
					else
						state <= GET_BIT7;
				end
				default:state <= IDLE;
			endcase
		end
	end

	always@(posedge clk or negedge rst)begin
		if(!rst)begin
			data_out_reg <= 8'b0000_0000;
			cnt_en <= 1'b0;
			rx_over <= 1'b0;
			rd <= 1'b1;
			rx_done <= 1'b0;
		end
		else begin
			case(state)
				IDLE:begin
					data_out_reg <= 8'b0000_0000;
					cnt_en <= 1'b0;
					rx_over <= 1'b0;
					rd <= 1'b1;
					rx_done <= 1'b0;
				end
				GET_START_BIT:begin
					data_out_reg <= 8'b0000_0000;
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
				end
				GET_BIT0:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[0] <= rx_pin_temp0;
					else
						data_out_reg[0] <= data_out_reg[0];
				end
				GET_BIT1:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[1] <= rx_pin_temp0;
					else
						data_out_reg[1] <= data_out_reg[1];
				end
				GET_BIT2:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[2] <= rx_pin_temp0;
					else
						data_out_reg[2] <= data_out_reg[2];
				end
				GET_BIT3:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[3] <= rx_pin_temp0;
					else
						data_out_reg[3] <= data_out_reg[3];
				end
				GET_BIT4:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[4] <= rx_pin_temp0;
					else
						data_out_reg[4] <= data_out_reg[4];
				end
				GET_BIT5:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[5] <= rx_pin_temp0;
					else
						data_out_reg[5] <= data_out_reg[5];
				end
				GET_BIT6:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
					if(cnt_half)
						data_out_reg[6] <= rx_pin_temp0;
					else
						data_out_reg[6] <= data_out_reg[6];
				end
				GET_BIT7:begin
					cnt_en <= 1'b1;
					rx_over <= 1'b1;
					rd <= 1'b0;
					rx_done <= 1'b1;
					if(cnt_half)
						data_out_reg[7] <= rx_pin_temp0;
					else
						data_out_reg[7] <= data_out_reg[7];
				end
				default:begin
					data_out_reg <= data_out_reg;
					cnt_en <= 1'b0;
					rx_over <= 1'b0;
					rd <= 1'b0;
					rx_done <= 1'b0;
				end
			endcase
		end
	end
	always@(posedge clk or negedge rst)begin
		if(!rst)
			data_out <= 8'b0000_0000;
		else
			if(rx_over)
				data_out <= data_out_reg;
			else
				data_out <= data_out;//保持
	end
endmodule

状态机转移图
在这里插入图片描述
仿真波形图
在这里插入图片描述
接收后data_out数据
在这里插入图片描述

发布了5 篇原创文章 · 获赞 10 · 访问量 161

猜你喜欢

转载自blog.csdn.net/qq_43650722/article/details/103766793
今日推荐