quartus Ⅱ 12.1 使用教程(4) uart 测试

开发板使用的是EP4CE15F23C8,软件使用的是quartus  12.1 ,工程实现的功能是使用uart进行回环测试

顶层

module uart_test(
    i_clk,
    i_rst_n,
    rx,
    tx
    
    );
    
input   i_clk;
input   i_rst_n;
input   rx;
output  tx;



wire    clk_out;
wire    wrsig;
wire    idle;
wire    tx;
wire    rx;
wire    [7:0] data_in;
wire    [7:0] data_out;
wire    rdsig;
wire    data_error;
wire    frame_error;

clk_div u1(
    .clk50(i_clk), 
    .rst_n(i_rst_n), 
    .clkout(clk_out)
    );
       
uart_tx u2(
    .clk(clk_out), 
    .rst_n(i_rst_n), 
    .datain(data_out), 
    .wrsig(rdsig), 
    .idle(idle), 
    .tx(tx)
    );
       
uart_rx u3(
    .clk(clk_out), 
    .rst_n(i_rst_n), 
    .rx(rx), 
    .dataout(data_out), 
    .rdsig(rdsig), 
    .dataerror(data_error), 
    .frameerror(frame_error)
    );      
    
endmodule

分频模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name:    clkdiv 
//////////////////////////////////////////////////////////////////////////////////
module clk_div(clk50, rst_n, clkout);
input clk50;              //系统时钟
input rst_n;              //收入复位信号
output clkout;            //采样时钟输出
reg clkout;
reg [15:0] cnt;

/////分频进程, 50Mhz的时钟326分频/////////
always @(posedge clk50 or negedge rst_n)   
begin
  if (!rst_n) begin
     clkout <=1'b0;
	  cnt<=0;
  end	  
  else if(cnt == 16'd162) begin
    clkout <= 1'b1;
    cnt <= cnt + 16'd1;
  end
  else if(cnt == 16'd325) begin
    clkout <= 1'b0;
    cnt <= 16'd0;
  end
  else begin
    cnt <= cnt + 16'd1;
  end
end
endmodule

发送模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name:    uarttx 
// 说明:16个clock发送一个bit, 一个起始位,8个数据位,一个校验位,一个停止位
//////////////////////////////////////////////////////////////////////////////////
module uart_tx(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

接收模块

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module name    uartrx.v
// 说明:          16个clock接收一个bit,16个时钟采样,取中间的采样值
//////////////////////////////////////////////////////////////////////////////////
module uart_rx(clk, rst_n, rx, dataout, rdsig, dataerror, frameerror);
input clk;             //采样时钟
input rst_n;           //复位信号
input rx;              //UART数据输入
output dataout;        //接收数据输出
output rdsig;
output dataerror;      //数据出错指示
output frameerror;     //帧出错指示
reg[7:0] dataout;
reg rdsig, dataerror;
reg frameerror;
reg [7:0] cnt;
reg rxbuf, rxfall, receive;
parameter paritymode = 1'b0;
reg presult, idle;

always @(posedge clk)   //检测线路的下降沿
begin
  rxbuf <= rx;
  rxfall <= rxbuf & (~rx);
end

////////////////////////////////////////////////////////////////
//启动串口接收程序
////////////////////////////////////////////////////////////////
always @(posedge clk)
begin
  if (rxfall && (~idle)) begin//检测到线路的下降沿并且原先线路为空闲,启动接收数据进程  
    receive <= 1'b1;
  end
  else if(cnt == 8'd168) begin //接收数据完成
    receive <= 1'b0;
  end
end

////////////////////////////////////////////////////////////////
//串口接收程序, 16个时钟接收一个bit
////////////////////////////////////////////////////////////////
always @(posedge clk or negedge rst_n)
begin
  if (!rst_n) begin
     idle<=1'b0;
	  cnt<=8'd0;
     rdsig <= 1'b0;	 
	  frameerror <= 1'b0; 
	  dataerror <= 1'b0;	  
	  presult<=1'b0;
  end	  
  else if(receive == 1'b1) begin
		case (cnt)
		8'd0:begin
			idle <= 1'b1;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd24:begin                 //接收第0位数据
			idle <= 1'b1;
			dataout[0] <= rx;
			presult <= paritymode^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd40:begin                 //接收第1位数据  
			idle <= 1'b1;
			dataout[1] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd56:begin                 //接收第2位数据   
			idle <= 1'b1;
			dataout[2] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd72:begin               //接收第3位数据   
			idle <= 1'b1;
			dataout[3] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd88:begin               //接收第4位数据    
			idle <= 1'b1;
			dataout[4] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd104:begin            //接收第5位数据    
			idle <= 1'b1;
			dataout[5] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd120:begin            //接收第6位数据    
			idle <= 1'b1;
			dataout[6] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b0;
		end
		8'd136:begin            //接收第7位数据   
			idle <= 1'b1;
			dataout[7] <= rx;
			presult <= presult^rx;
			cnt <= cnt + 8'd1;
			rdsig <= 1'b1;
		end
		8'd152:begin            //接收奇偶校验位    
			idle <= 1'b1;
			if(presult == rx)
			  dataerror <= 1'b0;
			else
			  dataerror <= 1'b1;       //如果奇偶校验位不对,表示数据出错
			cnt <= cnt + 8'd1;
			rdsig <= 1'b1;
		end
		8'd168:begin
		  idle <= 1'b1;
		  if(1'b1 == rx)
			 frameerror <= 1'b0;
		  else
			 frameerror <= 1'b1;      //如果没有接收到停止位,表示帧出错
		  cnt <= cnt + 8'd1;
		  rdsig <= 1'b1;
		end
		default: begin
			cnt <= cnt + 8'd1;
		end
		endcase
   end	
   else begin
	  cnt <= 8'd0;
	  idle <= 1'b0;
	  rdsig <= 1'b0;	 
	end
end
endmodule

上面四个模块都是黑金提供的,程序比较简单所以也不用进行详细说明,基本能对模块进行仿真,并且

能在硬件上运行就差不多了

分配管脚

quartus Ⅱ 12.1 使用教程(4) uart 测试_第1张图片

点击工具栏快捷按钮进行编译

quartus Ⅱ 12.1 使用教程(4) uart 测试_第2张图片

找到编译后生成的sof文件,点击Open添加进来

quartus Ⅱ 12.1 使用教程(4) uart 测试_第3张图片

将sof文件下载到开发板

quartus Ⅱ 12.1 使用教程(4) uart 测试_第4张图片

连接开发板的串口,发送数据12,可以看到,每发送一次12开发板也同样会将接收到的12这个数据发出来

(这个串口比较简单,只需了解一下原理,并且仿真出来,再在硬件上测试成功就可以了,不用花大

量时间,来进行验证测试,这里仅记录一些简单的步骤)

quartus Ⅱ 12.1 使用教程(4) uart 测试_第5张图片

你可能感兴趣的:(quartus,Ⅱ)