【FPGA】【Verilog】【基础模块】UART

【FPGA】【Verilog】【基础模块】UART_第1张图片

发送:

module clkdiv(clk_50m, clk_out, reset_n);
	input clk_50m;
	output clk_out;
	input reset_n;
	
	reg clk_out;
	reg [15:0]	counter;
	
	always @(posedge clk_50m or negedge reset_n)
	begin
		if (!reset_n)
			begin
				clk_out <= 0;
				counter <= 0;
			end
		else	if (counter == 16'd162)
			begin	
				clk_out <= 1;
				counter <= counter + 1;
			end 
		else 	if (counter == 16'd325)
			begin 
				clk_out <= 0;
				counter <= 0;
			end 
		else 
			begin
				counter <= counter + 1 ;
			end
	end 
			
endmodule 
module test_uart(clk,reset_n,DATA_out,WriteSignal);
input clk;
input reset_n;
output [7:0] DATA_out;
output WriteSignal;

reg [7:0]	DATA_out;
reg WriteSignal;
reg [7:0]	counter;

always @(posedge clk or negedge  reset_n)
begin
		if (!reset_n)
			begin
				counter <= 0;
				WriteSignal <= 0;
			end 
		else 
			begin 
				if (counter ==254)
					begin 
						DATA_out <= DATA_out + 1;
						WriteSignal <= 1;
						counter <= 0;
					end
				else 
					begin 
						WriteSignal <= 0;
						counter = counter + 1;
					end 
			end
end
endmodule 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name:    uarttx 
// 说明:16个clock发送一个bit, 一个起始位,8个数据位,一个校验位,一个停止位
//////////////////////////////////////////////////////////////////////////////////
module uarttx(clk, rst_n, datain, wrsig, idle, tx);
input clk;                //UART时钟
input rst_n;              //系统复位
input [7:0] datain;       //需要发送的数据
input wrsig;              //发送命令,上升沿有效
output idle;              //线路状态指示,高为线路忙,低为线路空闲
output tx;                //发送数据信号
reg idle, tx;
reg send;
reg wrsigbuf, wrsigrise;
reg presult;
reg[7:0] cnt;             //计数器
parameter paritymode = 1'b0;

////////////////////////////////////////////////////////////////
//检测发送命令wrsig的上升沿
////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
   wrsigbuf <= wrsig;
   wrsigrise <= (~wrsigbuf) & wrsig;  
end

////////////////////////////////////////////////////////////////
//启动串口发送程序
////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
  if (wrsigrise &&  (~idle))  //当发送命令有效且线路为空闲时,启动新的数据发送进程
  begin
     send <= 1'b1;
  end
  else if(cnt == 8'd168)      //一帧数据发送结束
  begin
     send <= 1'b0;
  end
end

////////////////////////////////////////////////////////////////
//串口发送程序, 16个时钟发送一个bit
////////////////////////////////////////////////////////////////
always @(posedge clk or negedge rst_n)
begin
  if (!rst_n) begin
         tx <= 1'b0;
         idle <= 1'b0;
			cnt<=8'd0;
			presult<=1'b0;
  end		
  else if(send == 1'b1)  begin
    case(cnt)                 //产生起始位
    8'd0: begin
         tx <= 1'b0;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd16: begin
         tx <= datain[0];    //发送数据0位
         presult <= datain[0]^paritymode;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd32: begin
         tx <= datain[1];    //发送数据1位
         presult <= datain[1]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd48: begin
         tx <= datain[2];    //发送数据2位
         presult <= datain[2]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd64: begin
         tx <= datain[3];    //发送数据3位
         presult <= datain[3]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd80: begin 
         tx <= datain[4];    //发送数据4位
         presult <= datain[4]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd96: begin
         tx <= datain[5];    //发送数据5位
         presult <= datain[5]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd112: begin
         tx <= datain[6];    //发送数据6位
         presult <= datain[6]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd128: begin 
         tx <= datain[7];    //发送数据7位
      // presult <= datain[7]^presult;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd144: begin
         tx <= presult;      //发送奇偶校验位
         presult <= datain[0]^paritymode;
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd160: begin
         tx <= 1'b1;         //发送停止位            
         idle <= 1'b1;
         cnt <= cnt + 8'd1;
    end
    8'd168: begin
         tx <= 1'b1;             
         idle <= 1'b0;       //一帧数据发送结束
         cnt <= cnt + 8'd1;
    end
    default: begin
         cnt <= cnt + 8'd1;
    end
   endcase
  end
  else  begin
    tx <= 1'b1;
    cnt <= 8'd0;
    idle <= 1'b0;
  end
end
endmodule

(原理图文件)顶层:

【FPGA】【Verilog】【基础模块】UART_第2张图片

结果:

【FPGA】【Verilog】【基础模块】UART_第3张图片

接收:

module uartrx(clock,reset_n,rx,DATAout,ReadSignal,idle,DataError,FrameError);

input clock;
input reset_n;
input rx;

output DATAout;
output ReadSignal;
output DataError;
output FrameError;
output idle;

reg [7:0]	DATAout;
reg ReadSignal,DataError,FrameError;

reg [7:0]	counter;
reg	ReceiveBuffer,ReceiveFall,receive;
reg 	presult,idle;
parameter paritymode = 1'b0;

//检测接受命令rx的下降沿
always @(posedge clock)
	begin
		ReceiveBuffer <= rx;
		ReceiveFall <= ReceiveBuffer &(~rx);
	end 

//接收状态的表示
always @(posedge clock)
begin	
	if(ReceiveFall && (~idle))
		begin
			receive <= 1'b1;
		end 
	else if (counter == 8'd168)
		begin
			receive <= 1'b0;
		end 
end

//串口接收,每16个clock接收同一个bit
always @(posedge clock or negedge reset_n )
begin 
	if (!reset_n)
		begin
			idle <= 1'b0;
			counter <= 8'b0;
			ReadSignal <= 1'b0;
			FrameError <= 1'b0;
			DataError <= 1'b0;
			presult <= 1'b0;
		end 
	else if(receive == 1'b1)
				begin
					case(counter)
						8'd0 :begin 
									idle <= 1'b1;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;
								end
						8'd24:begin 
									idle <= 1'b1;
									DATAout[0] 	<=	rx;
									presult <= paritymode ^ rx;
									counter <= counter  + 8'd1;
									ReadSignal <= 1'b0;
								end 
						8'd40 :begin 
									idle <= 1'b1;
									DATAout[1] <= rx;
									presult <= presult ^rx;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;	
								end 	
						8'd56 :begin 
									idle <= 1'b1;
									DATAout[2] <= rx;
									presult <= presult ^rx;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;
								end 
						8'd72 :begin 
									idle <= 1'b1;
									DATAout[3] <= rx ;
									presult <= presult ^ rx;
									counter <= counter +8'b1;
									ReadSignal <= 1'b0;
								end 
					   8'd88:begin
									idle <= 1'b1;
									DATAout[4] <= rx;
									presult <= presult ^ rx;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;
								end
						8'd104:begin 
									idle <= 1'b1;
									DATAout[5] <= rx;
									presult <= presult ^ rx;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;
								end
						8'd120:begin 
									idle <= 1'b1;
									DATAout[6] <= rx;
									presult <= presult ^ rx;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b0;
								end 
						8'd136:begin 
									idle <= 1'b1;
									DATAout[7] <= rx;
									presult <= presult ^rx;
									counter <= counter + 8'b1;
									ReadSignal  <= 1'b0;
								end 
						8'd152:begin 
									idle <= 1'b1;
									if (presult == rx)
										DataError <= 1'b0;
									else 
										DataError <= 1'b1;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b1;
							 end 
						8'd168:begin 
									idle <= 1'b1;
									if(1'b1 == rx)
										FrameError	<= 1'b0;
									else 
										FrameError 	<=	1'b1;
									counter <= counter + 8'b1;
									ReadSignal <= 1'b1;
							 end 
						default:begin 
								counter <= counter + 8'b1;
								end 
					endcase 
				end 
		else 
			begin 	
				counter <= 8'd0;
				idle <= 1'b0;
				ReadSignal <= 1'b0;
			end 
end 
endmodule 

原理图文件(顶层):

【FPGA】【Verilog】【基础模块】UART_第4张图片

结果:

【FPGA】【Verilog】【基础模块】UART_第5张图片

使用锁相环来加速或者放缓UART的传输速度:

【FPGA】【Verilog】【基础模块】UART_第6张图片

c0是25MHz,c1是100MHz,不知为何无法在串口助手中无结果显示。

你可能感兴趣的:(基础模块,FPGA学习)