【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
RS-232 接口设计
一、文档说明
1.1 编写目的
建立通用 RS-232 接口模块,增强移植性。
1.2 适用范围
1.3 版本说明
版本号
V1.0
日期
2016-01-19
作者
Kevin
历史记录
初次版本
1.4 对应程序版本
1.5 参考文档
二、项目说明
2.1 功能概括
串口设置:9600bps,数据位 8 位,停止位 1 位,无校验位。
该项目代码已实现串口的收发功能,可以实现回环测试,并可移植到其他应
用 RS232 接口的项目,可移植性良好。
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
2.2 项目设计思路
2.2.1 串口接收模块设计
1) 串口接收模块时序设计
2) 串口接收模块思路介绍
a.
rx 表示 PC 端的串口发送端(对于 FPGA 端,为串口的接收端),在串口
空闲状态时,rx 一直处于高电平。若 PC 端需要通过串口发送数据,则需
要将 rx 从高拉低,表示串口发送的起始位,接着依次发送 8bit 的数据(最
低位优先),发送完最后 1bit 数据后,rx 保持高电平(无校验位);
b. 由于 PC 端与 FPGA 端处于两个时钟域,所以在 FPGA 端需要进行跨时钟
域处理,即对 rx 进行打两拍处理(rx_t,rx_tt),rx_ttt 是 rx 的 3 级寄存
器;
rx_flag 是串口处于接收状态的标志信号,rx_flag 拉高的条件是 rx 从空闲
状态发送起始位的下降沿,拉低条件是接收完一帧串口数据(8bit);
c.
d. baud_cnt 为波特率计数器,FPGA 使用时钟为 50MHz,所以串口发送 1bit
的数据占用的时钟周期为:(1/9600)x109÷20≈5208,该计数器自加的
条件为 rx_flag 为高,当计数满 5207 时,自动清零;
f.
e. bit_flag 为检测 rx 上串口数据的标志信号,只有当 baud_cnt 计数到 2603
时,bit_flag 才会拉高。选在 baud_cnt 计数器的中间值来检测串口数据,
是为提高检测数据的可靠性;
bit_cnt 为已接收一帧串口数据的 bit 数,其自加条件为 bit_flag,当计数
到 8,即表示接收完一帧数据后清零;
rx_data 是接收串口数据的寄存器,位宽为 8,该寄存器使用了位拼接操
作,其目的是对接收到的串口数据进行移位,将接收到的 1bit 数据构造
成 8bit 的数据,也可以理解成串转并的一个操作;
g.
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
h. po_flag 为接收完一帧串口数据的标志信号,用于提供给外部模块检测接
收到的串口数据,即 rx_data 寄存器的值。
2.2.2 串口发送模块设计
对于串口发送模块,其设计思路与接收模块大同小异,稍微将接收模块的思
想反一下就 OK 了,在此不作介绍,Kevin 将代码分享出来,供读者参考。
2.3 项目代码
1) 顶层模块代码
// ************************************************************************
// Project Name : RS-232
// Author
// E-mail
: Kevin
: deng.kanwen@163.com
// Blog Website : http://dengkanwen.com
// Create Time
: 22:33 2016/01/12
// File Name
:
// Module Name
: uart_top
// Called By
// Abstract
:
:
//
// CopyRight(c) 2016, OpenSoc Studio..
// All Rights Reserved
//
// ************************************************************************
module
uart_top(
// system signals
input
input
// UART interface
input
sclk
s_rst_n
rx_data
,
,
,
output
wire
tx_data
);
//================================================================\
// ========== Define Parameter and Internal Signals ===========
//================================================================/
wire
[ 7:0]
po_data
;
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
wire
po_flag
;
//=============================================================================
//**************
Main Code
**************
//=============================================================================
uart_rx
uart_rx_inst(
(sclk
(s_rst_n
(rx_data
(po_data
(po_flag
(sclk
(s_rst_n
(po_data
(po_flag
(tx_data
.sclk
.s_rst_n
.rx_data
.po_data
.po_flag
);
uart_tx
uart_tx_inst(
.sclk
.s_rst_n
.pi_data
.pi_flag
.tx_data
);
endmodule
2) 串口接收模块代码
),
),
),
),
)
),
),
),
),
)
// ************************************************************************
// Project Name : RS-232
// Author
// E-mail
: Kevin
: deng.kanwen@163.com
// Blog Website : http://dengkanwen.com
// Create Time
: 22:43 2016/01/12
// File Name
:
// Module Name
: uart_top
// Called By
// Abstract
:
:
//
// CopyRight(c) 2016, OpenSoc Studio..
// All Rights Reserved
//
// ************************************************************************
module
uart_rx(
// system signals
input
input
sclk
s_rst_n
,
,
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
// others
input
rx_data
output
output
reg
reg
[7:0]
po_data
po_flag
);
,
,
//================================================================\
// ========== Define Parameter and Internal Signals ===========
//================================================================/
localparam
localparam
BAUD_CNT_END =
5207
BAUD_CNT_M
=
(BAUD_CNT_END+1)/2-1
reg
reg
reg
reg
reg
reg
reg
[12:0]
[ 3:0]
rx1
rx2
rx2_reg
rx_flag
baud_cnt
bit_flag
bit_cnt
;
;
;
;
;
;
;
;
;
//=============================================================================
//**************
Main Code
**************
//=============================================================================
always
@(posedge sclk) begin
rx1
rx2
<=
<=
rx2_reg <=
rx_data;
rx1;
rx2;
end
//定义 rx_flag
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
rx_flag <=
1'b0;
else if(bit_cnt == 4'd8 && bit_flag == 1'b1)
rx_flag <=
1'b0;
else if(rx2 == 1'b0 && rx2_reg == 1'b1)
rx_flag <=
1'b1;
end
//定义 baud_cnt
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
baud_cnt
<=
13'd0;
else if(rx_flag == 1'b1 && baud_cnt == BAUD_CNT_END)
baud_cnt
<=
13'd0;
else if(rx_flag == 1'b1)
else
baud_cnt
baud_cnt
<=
<=
baud_cnt + 1'b1;
13'd0;
end
//定义 bit_flag
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
bit_flag
<=
1'b0;
else if(baud_cnt == BAUD_CNT_M)
else
bit_flag
bit_flag
<=
<=
1'b1;
1'b0;
end
//定义 bit_cnt
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
bit_cnt
<=
4'd0;
else if(bit_cnt == 4'd8 && bit_flag == 1'b1)
bit_cnt
<=
4'd0;
else if(bit_flag == 1'b1)
bit_cnt
<=
bit_cnt + 1'b1;
end
//定义 po_data
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
po_data
<=
8'd0;
else if(bit_flag == 1'b1 && bit_cnt <= 4'd8 && bit_cnt >= 4'd1)
po_data
<=
{rx2, po_data[7:1]};
end
//定义 po_flag
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
po_flag
<=
1'b0;
else if(bit_cnt == 4'd8 && bit_flag == 1'b1)
po_flag
<=
1'b1;
else
新手学习 FPGA 成长日记:http://dengkanwen.com
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
po_flag
<=
1'b0;
end
endmodule
3) 串口发送模块代码
// ************************************************************************
// Project Name : RS-232
// Author
// E-mail
: Kevin
: deng.kanwen@163.com
// Blog Website : http://dengkanwen.com
// Create Time
: 22:43 2016/01/12
// File Name
:
// Module Name
: uart_tx
// Called By
// Abstract
:
:
//
// CopyRight(c) 2016, OpenSoc Studio..
// All Rights Reserved
//
// ************************************************************************
module
uart_tx(
// system signals
input
input
// others
input
input
wire
wire
sclk
s_rst_n
[ 7:0]
pi_data
pi_flag
output
reg
tx_data
);
,
,
,
,
//================================================================\
// ========== Define Parameter and Internal Signals ===========
//================================================================/
localparam
localparam
BAUD_CNT_END
BAUD_CNT_M
=
=
5207
2603
reg
reg
reg
reg
reg
[12:0]
[ 3:0]
[ 7:0]
tx_flag
baud_cnt
bit_flag
bit_cnt
pi_data_reg
新手学习 FPGA 成长日记:http://dengkanwen.com
;
;
;
;
;
;
;
【开源骚客(微信号:OpenSoc)】公众号
免费分享 FPGA 项目
//=============================================================================
//**************
Main Code
**************
//=============================================================================
//定义 pi_data_reg
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
pi_data_reg
<=
8'd0;
else if(pi_flag == 1'b1)
pi_data_reg
<=
pi_data;
end
//定义 tx_flag
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
tx_flag
<=
1'b0;
else if(baud_cnt == BAUD_CNT_END && bit_cnt == 4'd8)
tx_flag
<=
1'b0;
else if(pi_flag == 1'b1)
tx_flag
<=
1'b1;
end
//定义 baud_cnt
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
baud_cnt
<=
13'd0;
else if(baud_cnt == BAUD_CNT_END)
baud_cnt <=
13'd0;
else if(tx_flag == 1'b1)
else
baud_cnt
baud_cnt
<=
<=
baud_cnt + 1'b1;
13'd0;
end
//定义 bit_flag
always
@(posedge sclk or negedge s_rst_n) begin
if(s_rst_n == 1'b0)
bit_flag
<=
1'b0;
else if(baud_cnt == BAUD_CNT_END)
bit_flag <=
1'b1;
else
end
bit_flag
<=
1'b0;
新手学习 FPGA 成长日记:http://dengkanwen.com