基于FPGA的数字钟——(一)串口通信模块
发布日期:2021-05-07 22:56:09 浏览次数:23 分类:精选文章

本文共 10220 字,大约阅读时间需要 34 分钟。

(一)串口通信模块设计

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;//保持	endendmodule

状态机转移图

在这里插入图片描述
仿真波形图
在这里插入图片描述
接收后data_out数据
在这里插入图片描述

上一篇:基于FPGA的数字钟——(二)按键消抖模块设计
下一篇:详解C++继承(普通继承,菱形继承与虚拟继承)

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年03月23日 00时36分30秒