赞
踩
verilog实现UART:RS232串口的收发。
RTL代码及仿真代码100%每行全注释,不用担心看不懂。
FPGA:开发工具ISE,或者QUARTUS。
功能:将电脑上使用串口调试助手发送的数据进行接收,再将接收到的数据发送回去,在串口调试助手界面显示。
RS232协议:1位起始位+8位数据位+1位停止位。
顶层模块和分模块均有modelsim仿真文件及仿真结果波形,便于学习验证及应用。
已下载到板验证通过。
本文将介绍如何使用Verilog语言实现UART协议,实现RS232串口的收发功能。本文提供的RTL代码及仿真代码100%每行全注释,方便读者理解和学习。读者可以使用FPGA开发工具ISE或者QUARTUS进行开发。最终实现的功能是将电脑上使用串口调试助手发送的数据进行接收,再将接收到的数据发送回去,并在串口调试助手界面显示。本文还将介绍RS232协议,并提供了顶层模块和分模块的modelsim仿真文件及仿真结果波形,方便读者进行学习和验证。
一、介绍
UART是一种通讯协议,用于串行数据传输,通常用于将数据发送到计算机或其他设备。UART通常使用RS232协议进行通讯,它是一种标准的串行通信协议,用于连接计算机和串口设备。在这篇文章中,我们将介绍如何使用Verilog语言实现UART协议,以实现串口通讯功能。
二、RS232协议
在实现UART协议之前,我们需要了解一下RS232协议。RS232协议使用一个异步传输的串行通信信道,用于在计算机和串口设备之间传输数据。该协议使用1位起始位、8位数据位和1位停止位,以及可选的奇偶校验位。在本文中,我们将实现基本的RS232协议,即使用1位起始位、8位数据位和1位停止位进行通讯。
三、Verilog实现UART
接下来,我们将介绍如何使用Verilog语言实现UART协议。具体实现过程如下:
1.顶层模块
首先,我们需要创建一个顶层模块,用于接收和发送数据。该模块包括以下子模块:接收模块、发送模块、时钟模块和UART控制模块。其中,接收模块和发送模块分别负责接收和发送数据,时钟模块负责产生时钟信号,并将时钟信号传递给UART控制模块。UART控制模块负责控制接收和发送模块,并将接收到的数据发送给计算机,并将计算机发送的数据发送给接收模块。
以下是一个示例顶层模块的代码:
- module uart_top(
- input clk,
- input rst_n,
- input uart_rx,
- output uart_tx
- );
-
- reg [7:0] rx_data;
- reg [7:0] tx_data;
- reg rx_flag;
- reg tx_flag;
- reg [3:0] bit_cnt;
- reg [3:0] rx_bit_cnt;
- reg [3:0] tx_bit_cnt;
- reg stop_bit;
-
- parameter CLK_DIV = 26; // 9600 baud
-
- uart_receiver u_receiver(
- .clk(clk),
- .rst_n(rst_n),
- .data_in(uart_rx),
- .data_out(rx_data),
- .data_valid(rx_flag),
- .bit_cnt(rx_bit_cnt),
- .stop_bit(stop_bit)
- );
-
- uart_transmitter u_transmitter(
- .clk(clk),
- .rst_n(rst_n),
- .data_out(uart_tx),
- .data_in(tx_data),
- .data_valid(tx_flag),
- .bit_cnt(tx_bit_cnt),
- .stop_bit(stop_bit)
- );
-
- uart_control u_control(
- .clk(clk),
- .rst_n(rst_n),
- .data_in(rx_data),
- .data_valid_in(rx_flag),
- .bit_cnt_in(rx_bit_cnt),
- .stop_bit_in(stop_bit),
- .data_out(tx_data),
- .data_valid_out(tx_flag),
- .bit_cnt_out(tx_bit_cnt)
- );
-
- endmodule
该模块中包含了三个子模块:uart_receiver、uart_transmitter和uart_control模块。顶层模块负责将这些模块连接起来,实现UART通讯功能。
2.接收模块
接下来,我们需要实现接收模块。接收模块负责接收从计算机发送过来的数据,并将数据存储到缓存中。在接收模块中,我们需要使用计数器来计算每个位的时长,并在停止位到达时将数据存储到缓存中。
以下是一个示例接收模块的代码:
- module uart_receiver(
- input clk,
- input rst_n,
- input data_in,
- output reg [7:0] data_out,
- output reg data_valid,
- output reg [3:0] bit_cnt,
- output reg stop_bit
- );
-
- parameter CLK_DIV = 26; // 9600 baud
-
- reg [23:0] bit_timer;
- reg [7:0] shift_reg;
- reg sync_cnt;
- reg sync_flag;
- reg [3:0] cnt;
- reg data_ready;
-
- always @(posedge clk or negedge rst_n) begin
- if (~rst_n) begin
- bit_timer <= 0;
- shift_reg <= 0;
- sync_cnt <= 0;
- sync_flag <= 0;
- cnt <= 0;
- data_ready <= 0;
- bit_cnt <= 0;
- stop_bit <= 0;
- end else begin
- if (sync_flag) begin
- if (bit_timer == CLK_DIV) begin
- bit_timer <= 0;
- if (cnt < 8) begin
- shift_reg <= {shift_reg[6:0], data_in};
- cnt <= cnt + 1;
- end else if (cnt == 8) begin
- stop_bit <= data_in;
- cnt <= cnt + 1;
- end else if (cnt == 9) begin
- data_valid <= 1;
- cnt <= 0;
- data_out <= shift_reg;
- sync_flag <= 0;
- data_ready <= 1;
- end
- end else begin
- bit_timer <= bit_timer + 1;
- end
- end else if (data_in == 0) begin
- sync_cnt <= sync_cnt + 1;
- end else if (sync_cnt > 3) begin
- sync_flag <= 1;
- sync_cnt <= 0;
- bit_cnt <= 0;
- cnt <= 0;
- data_valid <= 0;
- data_ready <= 0;
- end else begin
- sync_cnt <= 0;
- end
- end
- end
-
- endmodule
在该模块中,我们使用了一个计时器来计算每个位的时长,并使用一个移位寄存器来存储数据。当停止位到达时,我们将数据存储到缓存中,并将数据有效标志设为1,表示接收到了有效数据。接收模块还使用了一个同步计数器来检测信号的同步状态。
3.发送模块
接下来,我们需要实现发送模块。发送模块负责将数据从缓存中发送到计算机。在发送模块中,我们需要使用计数器来计算每个位的时长,并在停止位到达时停止发送。
以下是一个示例发送模块的代码:
- module uart_transmitter(
- input clk,
- input rst_n,
- output reg data_out,
- input [7:0] data_in,
- input data_valid,
- input [3:0] bit_cnt,
- input stop_bit
- );
-
- parameter CLK_DIV = 26; // 9600 baud
-
- reg [23:0] bit_timer;
- reg [7:0] shift_reg;
- reg [3:0] cnt;
- reg tx_ready;
- reg [3:0] bit_num;
-
- always @(posedge clk or negedge rst_n) begin
- if (~rst_n) begin
- bit_timer <= 0;
- shift_reg <= 0;
- cnt <= 0;
- tx_ready <= 1;
- bit_num <= 0;
- end else begin
- if (data_valid && tx_ready) begin
- shift_reg <= data_in;
- tx_ready <= 0;
- cnt <= 0;
- bit_num <= 0;
- end else if (~tx_ready && (bit_timer == CLK_DIV)) begin
- bit_timer <= 0;
- if (cnt < 8) begin
- data_out <= shift_reg[bit_num];
- bit_num <= bit_num + 1;
- cnt <= cnt + 1;
- end else if (cnt == 8) begin
相关代码,程序地址:http://lanzouw.top/692092879411.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。