FPGA入门——串口读写例程(代码)

一、波特率发生器

`timescale 1ns / 1ps
module baud_gen(
						clk_50MHz,
						rst,
						bclk
    );

input clk_50MHz;
input rst;

output bclk;

reg bclk;
reg [8:0] cnt;

always@(posedge clk_50MHz)begin
	if(!rst)begin
			cnt <= 0;
			bclk <= 0;
		end
	else begin
			if(cnt>324)begin
					cnt <= 0;
					bclk <=1 ;
				end
			else begin
					cnt <= cnt + 1'b1;
					bclk <= 0;
				end
		end
end
		
endmodule

二、发送模块

`timescale 1ns / 1ps
module uart_tx(
						bclk,
						rst,
						tx_din,
						tx_cmd,
						tx_ready,
						txd
    );

input bclk;		//发送模块时钟
input rst;
input tx_cmd;	//发送控制信号,高有效
input [7:0] tx_din; //期望发送的字节


output	tx_ready;	//发送完成指示
output	txd;	//串口发送数据

reg 	  tx_ready;

//定义串口参数
parameter [3:0] Lframe = 8;
parameter [2:0] s_idle = 3'b000;
parameter [2:0] s_start = 3'b001;
parameter [2:0] s_wait = 3'b010;
parameter [2:0] s_shift = 3'b011;
parameter [2:0] s_stop = 3'b100;

//定义所需中间变量
//发送模块状态机的状态寄存器
reg [2:0] state = s_idle;
reg [3:0] cnt = 0;
reg [3:0] dcnt = 0;

reg 	txdt ; //没加复位时 为txdt=1

assign txd = txdt; 

always@(posedge bclk or posedge rst)begin
	if(!rst)
		begin
			state <= s_idle;
			cnt <= 0;
			tx_ready <= 0;
			txdt <= 1;
		end
	else begin
		case(state)
			//空闲状态,检测发送指令
			s_idle:begin
				tx_ready <= 1; 
				cnt <= 0;
				txdt <= 1'b1;
				if(tx_cmd == 1)
					state <= s_start;
				else 
					state <= s_idle;
			end
		
			//发送模块的开始状态
			s_start:begin
				tx_ready <= 0;
				txdt <= 1'b0;
				state <= s_wait;
			end
			
			//延迟等待状态,使每个有效数据位保持16个bclk周期,从而得到9600的波特率
			s_wait: begin
				tx_ready <= 0;
				if(cnt >= 4'b1110)begin  
					cnt <= 0;
					if(dcnt == Lframe)begin
						state <= s_stop;
						dcnt <= 0;
						txdt <= 1'b1;
					end
					else begin
						state <= s_shift;
						txdt <= txdt;
					end
				end
				else begin
					state <= s_wait;
					cnt <= cnt + 1'b1;
					end
			end
			
			//移位状态,每进入一次就将下一个发送比特移动到发送数据端口上
			s_shift :begin
				tx_ready <=0;
				txdt <= tx_din[dcnt];
				dcnt <= dcnt +1'b1 ;
				state <= s_wait;
			end
			
			//停止状态,发送停止位
			s_stop :begin 
				txdt <= 1'b1;
				if(cnt > 4'b1110)begin
				state <= s_idle;
				cnt <= 0;
				tx_ready <= 1;
			end
			else begin
				state <= s_stop;
				cnt <= cnt + 1'b1;
				end
			end
		endcase
	end
end

endmodule			


三、接收模块

`timescale 1ns / 1ps
module uart_rx(
					bclk,
					rst,
					rxd,
					rx_ready,
					rx_dout
    );

input bclk;
input rst;
input rxd;	//串口接收数据

output rx_ready;	//接收完成指示信号
output [7:0] rx_dout;	//接收到的并行数据,以字节形式输出

parameter [3:0] Lframe = 8;
parameter [2:0] s_idle = 3'b000;		//空闲状态,此状态下rx_ready为1,用于接收起始信号,一旦接收到起始信号立即进入s_sample.
parameter [2:0] s_sample = 3'b010;	//采样状态,此状态下rx_ready为0,对16个采样值进行最大自然判决,得到相应逻辑,重复8次,接收8个数据后进入s_stop状态
parameter [2:0] s_stop = 3'b100;		//检测停止位,为了使接收模块使用范围更广,等待一定时间后转跳回s_idle

reg rx_ready;
reg [2:0] state = s_idle;
reg [3:0] cnt = 0;	//16个周期
reg [3:0] num = 0;	//最大自然判决
reg [3:0] dcnt = 0;	//用来判断是达到8个数据
reg [7:0] rx_doutmp = 0;

assign rx_dout = rx_doutmp;

//接收程序
always@(posedge bclk or posedge rst)
	if(!rst)begin
		state <= s_idle;
		cnt <= 0;
		dcnt <= 0;
		num <= 0;
		rx_doutmp <= 0;
		rx_ready <= 0;
	end
	else begin
		case(state)
			//检测起始条件
			s_idle:begin
				rx_doutmp<=0;
				dcnt<=0;
				rx_ready<=1;   
				if(cnt == 4'b1111)begin
					cnt <= 0;
					if(num > 7)begin
						state <= s_sample;
						num <=0;
					end
					else begin
						state <= s_idle;
						num <= 0;
					end
				end
				else begin
					cnt <= cnt + 1'b1;
					if(rxd == 1'b0)begin
						num <= num + 1'b1 ;
					end
					else begin
						num <= num;
					end 
				end
			end
			
			//接收模块数据采样、判断以及串口并转换模块
			s_sample:begin
				rx_ready <= 1'b0;
				if(dcnt == Lframe)begin
					state <= s_stop;
				end
				else begin
					state <= s_sample;
					if(cnt == 4'b1111)begin
						dcnt <= dcnt + 1'b1;
						cnt <= 0;
						if(num >7)begin
							num <=0;
							rx_doutmp[dcnt] <= 1;
						end
						else begin
							rx_doutmp[dcnt] <= 0;
							num <= 0;
						end
					end
					else begin 
						cnt <= cnt + 1'b1;
						if(rxd == 1'b1)begin
							num <= num + 1'b1;
						end
						else begin 
							num <= num;
						end
					end
				end
			end
			
			//接收模块的停止状态
			s_stop:begin
				rx_ready <= 1'b1;
				if(cnt == 4'b1111)begin
					cnt <= 0;
					state <= s_idle;
				end
				else begin
					cnt <= cnt + 1'b1;
				end
			end
		endcase
	end

endmodule

四、顶层模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    21:42:06 07/08/2019 
// Design Name: 
// Module Name:    top 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description:   发送8位数据时稳定有效 eg:FE    发送FEFE不稳定
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module top(
			clk,rst,rxd,txd
    );

input clk;
input rst;
input rxd;


output txd;

wire bclk;
wire rx_ready;
wire tx_ready;
wire [7:0] rx_dout;

reg [7:0] tx_din;
reg tx_cmd;

reg [2:0] bv1;
//reg [2:0] bv2;

wire bv1_posedge;
//wire bv2_posedge;

always@(posedge bclk)begin
	bv1 <= {bv1[1:0],rx_ready};
//	bv2 <= {bv2[1:0],tx_ready};
	end

assign bv1_posedge = (~bv1[2]) & bv1[1];
//assign bv2_posedge = (~bv2[2]) & bv2[1];

always@(posedge bclk)begin
	if(bv1_posedge == 1'b1)begin
		tx_cmd <= 1;
		tx_din <= rx_dout;
	end
		else tx_cmd <= 0;
//	else if(bv2_posedge == 1'b1)
//		tx_cmd <= 0;
end

baud_gen	 inst_baud_gen(
						.clk_50MHz(clk),
						.rst(rst),
						.bclk(bclk)
    );

uart_rx	inst_uart_rx(
					.bclk(bclk),
					.rst(rst),
					.rxd(rxd),
					.rx_ready(rx_ready),
					.rx_dout(rx_dout)
    );
	 
uart_tx	inst_uart_tx(
						.bclk(bclk),
						.rst(rst),
						.tx_din(tx_din),
						.tx_cmd(tx_cmd),
						.tx_ready(tx_ready),
						.txd(txd)
    );
endmodule

你可能感兴趣的:(FPGA入门例程学习)