1、串口又叫通用异步收发传输器,即UART;是一种通用的数据通信协议。
2、接受数据时:将接收到的串行数据转换成并行数据;(涉及到串转并)
发送数据时:将并行数据转换成串行数据来传输;(涉及到并转串)
3、串口常见总线包括:RS232、RS499、RS423、RS422、RS485;
4、在信息传输通道中,携带数据信息的信号单元叫码元(因为串口是 1bit 进行传输的,所以其码元就是代表一个二进制数)
5、波特率:每秒钟通过信号传输的码元数称为码元的传输速率,简称波特率;单位为Bps;
6、比特率:每秒钟通信信道传输的信息量称为位传输速率,简称比特率;单位为bps;且可由波特率算出。公式为:比特率=波特率 * 单个调制状态对应的二进制位数。例如使用的是9600的波特率,则其串口的比特率为:9600Bps*1bit=9600bps;
7、串口发送和接收数据的格式:1bit起始位(高电平)+8bit数据位+1bit停止位(高电平)
例子:串口回环(电脑通过串口发送数据到FPGA,FPGA接收串口的数据并将接收的数据通过串口回传给电脑)
整体模块划分:
点击查看代码
module rs232
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output wire tx
);
wire [7:0] rx_data;
wire rx_flag;
uart_rx
#(
.UART_BPS(9600 ),
.CLK_FREQ(50_000_000 )
)
uart_rx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n(sys_rst_n),
.rx (rx ),
.po_data (rx_data ),
.po_flag (rx_flag )
);
uart_tx
#(
.UART_BPS(9600 ),
.CLK_FREQ(50_000_000)
)
uart_tx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n(sys_rst_n),
.pi_data (rx_data ),
.pi_flag (rx_flag ),
.tx (tx )
);
endmodule
其中,接收模块如下:
波形图如下:
点击查看代码
module uart_rx
#(
parameter UART_BPS = 'd9600,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output reg [7:0] po_data,
output reg po_flag
);
parameter BAUD_CNT_MAX=CLK_FREQ/UART_BPS;
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;
reg start_flag;
reg work_en;
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt;
reg [7:0] rx_data;
reg rx_flag;
//打一拍(rx_reg1)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_reg1<=1'b1;
else
rx_reg1<=rx;
//打二拍(rx_reg2)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_reg2<=1'b1;
else
rx_reg2<=rx_reg1;
//打三拍(rx_reg3)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_reg3<=1'b1;
else
rx_reg3<=rx_reg2;
//start_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
start_flag<=1'b0;
else if((rx_reg2==1'b0)&&(rx_reg3==1'b1))
start_flag<=1'b1;
else
start_flag<=1'b0;
//work_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
work_en<=1'b0;
else if((bit_cnt==4'd8)&&(bit_flag==1'b1))
work_en<=1'b0;
else if(start_flag==1'b1)
work_en<=1'b1;
//baud_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
baud_cnt<=13'd0;
else if((baud_cnt==BAUD_CNT_MAX-1)||(work_en==1'b0))
baud_cnt<=13'd0;
else
baud_cnt<=baud_cnt+1'b1;
//bit_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
bit_flag<=1'b0;
else if(baud_cnt==BAUD_CNT_MAX/2-1)
bit_flag<=1'b1;
else
bit_flag<=1'b0;
//bit_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_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;
//rx_data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_data<=8'd0;
else if((bit_cnt>=4'd1)&&(bit_cnt<=4'd8)&&(bit_flag==1'b1))
rx_data<={rx_reg3,rx_data[7:1]};
//rx_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rx_flag<=1'b0;
else if((bit_cnt==4'd8)&&(bit_flag==1'b1))
rx_flag<=1'b1;
else
rx_flag<=1'b0;
//po_data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_data<=8'd0;
else if(rx_flag==1'b1)
po_data<=rx_data;
//po_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
po_flag<=1'b0;
else
po_flag<=rx_flag;
endmodule
发送模块如下:
波形图如下:
点击查看代码
module uart_tx
#(
parameter UART_BPS = 'd9600,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk,
input wire sys_rst_n,
input wire [7:0] pi_data,
input wire pi_flag,
output reg tx
);
parameter BAUD_CNT_MAX=CLK_FREQ/UART_BPS;
reg work_en;
reg [12:0] baud_cnt;
reg bit_flag;
reg [3:0] bit_cnt;
//work_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
work_en<=1'b0;
else if((bit_cnt==4'd9)&&(bit_flag==1'b1))
work_en<=1'b0;
else if(pi_flag==1'b1)
work_en<=1'b1;
//baud_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
baud_cnt<=13'd0;
else if((baud_cnt==BAUD_CNT_MAX-1)||(work_en==1'b0))
baud_cnt<=13'd0;
else if(work_en==1'b1)
baud_cnt<=baud_cnt+1'd1;
//bit_flag
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
bit_flag<=1'b0;
else if(baud_cnt==13'd1)
bit_flag<=1'b1;
else
bit_flag<=1'b0;
//bit_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
bit_cnt<=4'd0;
else if((bit_flag==1'b1)&&(work_en==1'b1))
bit_cnt<=bit_cnt+1'b1;
else if((bit_flag==1'b1)&&(bit_cnt==4'd9))
bit_cnt<=4'd0;
//tx
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
tx<=1'b1;
else if(bit_flag==1'b1)
case(bit_cnt)
0: tx<=1'b0;
1: tx<=pi_data[0];
2: tx<=pi_data[1];
3: tx<=pi_data[2];
4: tx<=pi_data[3];
5: tx<=pi_data[4];
6: tx<=pi_data[5];
7: tx<=pi_data[6];
8: tx<=pi_data[7];
9: tx<=1'b1;
default:tx<=1'b1;
endcase
endmodule
关于接收模块中的打拍的问题:单比特信号从慢速时钟域同步到快速时钟域需要使用打两拍的方式消除亚稳态;超过两拍后效果就不明显了。
标签:wire,UART,总线,rx,sys,flag,rst,reg,三大 From: https://www.cnblogs.com/haogegedeboke/p/16844045.html