开发板使用的是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这个数据发出来
(这个串口比较简单,只需了解一下原理,并且仿真出来,再在硬件上测试成功就可以了,不用花大
量时间,来进行验证测试,这里仅记录一些简单的步骤)