開發板使用的是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
上面四個模塊都是黑金提供的,程序比較簡單所以也不用進行詳細說明,基本能對模塊進行仿真,並且
能在硬件上運行就差不多了
分配管腳
點擊工具欄快捷按鈕進行編譯
找到編譯後生成的sof文件,點擊Open添加進來
將sof文件下載到開發板
連接開發板的串口,發送數據12,可以看到,每發送一次12開發板也同樣會將接收到的12這個數據發出來
(這個串口比較簡單,只需瞭解一下原理,並且仿真出來,再在硬件上測試成功就可以了,不用花大
量時間,來進行驗證測試,這裏僅記錄一些簡單的步驟)