UART介绍:
是一种串行、异步、全双工的通信协议,在UART通信协议中信号线上的状态为高电平时代表‘1’,信号线上的状态为低电平时代表‘0’。串行通信是指利用一条传输线将数据一位位地顺序传送,也可以用两个信号线组成全双工通信,如rs232。特点是通信线路简单,利用简单的线缆就可实现通信,
接线图:
时序图:
实验目的:设计一个回传数据的UART模块
(本实验以rs232进行设计)
模块框图:
(本实验参考了野火的UART)
链接:5. 串口rs232 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档 (embedfire.com)
uart_rx模块代码
module uart_rx
(
input wire clk_50Mhz , //系统时钟50Mhz
input wire rst_n , //全局复位
input wire rx , //输入uart_rx信号
output reg flag , //输出一个字节处理完成的标志
output reg [7:0] data //输出一个字节的uart_rx并行数据
);
//定义波特率
parameter UART_BPS = 'd9600 ;
parameter CLK_FPEQ = 'd50_000_000 ;
parameter BAUD_CNT_MAX = CLK_FPEQ/UART_BPS;
reg rx1;
reg rx2;
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;
//对输入信号进行时钟同步
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
rx1<=1'b0;
end
else begin
rx1<=rx;
end
end
//对rx1信号进行同步,防止亚稳态现象
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
rx2<=1'b0;
end
else begin
rx2<=rx1;
end
end
//产生数据处理开始标志
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
start_flag <=1'b0;
end
else if ((rx2 == 1'b1)&&(rx1 == 1'b0)
&&(work_en == 1'b0)) begin
start_flag <=1'b1;
end
else begin
start_flag <=1'b0;
end
end
//产生工作使能信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
work_en <= 1'b0;
end
else if(start_flag==1'b1) begin
work_en <= 1'b1;
end
else if((bit_cnt==4'd8)&&(bit_flag==1'b1)) begin
work_en <= 1'b0;
end
else begin
work_en <= work_en;
end
end
//计数到对应波特率的bit产生一次内部触发信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
baud_cnt <= 13'd0;
end
else if((baud_cnt == BAUD_CNT_MAX -1)
||(work_en ==1'b0)) begin
baud_cnt <= 13'd0;
end
else begin
baud_cnt <= baud_cnt +1'b1;
end
end
//产生一个bit的触发信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
bit_flag <=1'b0;
end
else if(baud_cnt==BAUD_CNT_MAX/2-1) begin
bit_flag <=1'b1;
end
else begin
bit_flag <=1'b0;
end
end
//计数bit信号的个数
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
bit_cnt <=4'b0;
end
else if((bit_cnt == 4'd8)&&(bit_flag==1'b1)) begin
bit_cnt <=4'd0;
end
else if(bit_flag == 1'b1) begin
bit_cnt <=bit_cnt + 1'b1;
end
else begin
bit_cnt <=bit_cnt;
end
end
//得到并行数据
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
rx_data <=8'd0;
end
else if ((bit_cnt>=4'd1)&&(bit_cnt<=4'd8)&&(bit_flag==1'b1)) begin
rx_data <= {rx2,rx_data[7:1]};
end
else begin
rx_data <= rx_data;
end
end
//得到数据处理结束标志
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
rx_flag <=1'b0;
end
else if((bit_cnt==4'd8)&&(bit_flag==1'b1)) begin
rx_flag <=1'b1;
end
else begin
rx_flag <=1'b0;
end
end
//对数据输出
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
data <=8'd0;
end
else if(rx_flag==1'b1) begin
data <=rx_data;
end
else begin
data <=data;
end
end
//对数据输出数据处理结束标志
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n == 1'b0) begin
flag <=1'b0;
end
else begin
flag <=rx_flag;
end
end
endmodule
uart_tx模块代码
module uart_tx
(
input wire clk_50Mhz , //系统时钟50Mhz
input wire rst_n , //全局复位
input wire [7:0] data , //输入一个字节的uart_rx并行数据
input wire flag , //输入一个字节处理开始的标志
output reg tx //输出一个字节的uart_tx串行信号
);
//定义波特率
parameter UART_BPS = 'd9600 ;
parameter CLK_FPEQ = 'd50_000_000 ;
parameter BAUD_CNT_MAX = CLK_FPEQ/UART_BPS;
reg bit_flag ,//数据处理标志
work_en ;
reg[12:0] baud_cnt ;//延时计数
reg[3:0] bit_cnt ;//数据处理计数
//产生工作使能信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
work_en <=1'b0;
end
else if (flag ==1'b1) begin
work_en <=1'b1;
end
else if((bit_cnt ==4'd9)&&(bit_flag == 1'b1)) begin
work_en <=1'b0;
end
else begin
work_en <=work_en;
end
end
//计数到对应波特率的bit产生一次内部触发信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
baud_cnt <= 13'd0;
end
else if((baud_cnt ==BAUD_CNT_MAX-1)||(work_en ==1'b0)) begin
baud_cnt <=13'd0;
end
else if(work_en ==1'b1) begin
baud_cnt <=baud_cnt +1'b1;
end
else begin
baud_cnt <= baud_cnt;
end
end
//产生一个bit的触发信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
bit_flag <=1'b0;
end
else if((work_en==1'b1)&&(baud_cnt==13'd0)) begin
bit_flag <=1'b1;
end
else begin
bit_flag <=1'b0;
end
end
//计数bit信号的个数
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
bit_cnt <=4'b0;
end
else if((bit_cnt ==4'd9)&&(bit_flag ==1'b1)) begin
bit_cnt <=4'b0;
end
else if((work_en ==1'b1)&&(bit_flag ==1'b1)) begin
bit_cnt <=bit_cnt + 1'b1;
end
else begin
bit_cnt <=bit_cnt;
end
end
//输出串行信号
always@(posedge clk_50Mhz or negedge rst_n) begin
if(rst_n==1'b0) begin
tx <=1'b1;
end
else if(bit_flag ==1'b1) begin
case(bit_cnt)
0 : tx <= 1'b0;
1 : tx <= data[0];
2 : tx <= data[1];
3 : tx <= data[2];
4 : tx <= data[3];
5 : tx <= data[4];
6 : tx <= data[5];
7 : tx <= data[6];
8 : tx <= data[7];
9 : tx <= 1'b1;
default :tx <=1'b1;
endcase
end
end
endmodule
uart232模块代码
module uart232(
input wire clk_50Mhz ,//系统时钟50Mhz
input wire rst_n ,//全局复位
input wire rx ,//输入uart_rx信号
output wire tx //输出uart_tx信号
);
wire [7:0] data;
wire flag;
uart_rx uart_rx_inst
(
.clk_50Mhz (clk_50Mhz) , //系统时钟50Mhz
.rst_n (rst_n) , //全局复位
.rx (rx) , //输入uart_rx信号
.flag (flag) , //输出一个字节处理完成的标志
.data (data) //输出一个字节的uart_rx并行数据
);
uart_tx uart_tx_inst
(
.clk_50Mhz (clk_50Mhz) , //系统时钟50Mhz
.rst_n (rst_n) , //全局复位
.data (data) , //输入一个字节的uart_rx并行数据
.flag (flag) , //输入一个字节处理开始的标志
.tx (tx) //输出一个字节的uart_tx串行信号
);
endmodule