一 UART串口通信简介
UART(Universal Asynchronous Receiver-Transmitter)是采用异步串行通信方式的通用异步收发传输器,在发送数据时将并行数据转换为串行数据,在接收数据时将串行数据转换为并行数据。发送和接收的一帧数据由起始位、数据位、奇偶校验位和停止位组成,其数据帧格式如下:
串口通信的速率用波特率表示,单位为bps(位/秒),常用的波特率由9600、19200、38400、57600、115200。
针对异步串行通信接口的标准有RS232、RS422、RS485等,其电器特性如下表所示:
接口类型 |
RS232 |
RS422 |
RS485 |
工作方式 |
单端(全双工) |
差分(全双工) |
差分(半双工) |
节点数 |
1发1收 |
1发10收 |
1发32收 |
逻辑特性 |
逻辑1:-5V~-15V 逻辑0:+5V~+15V |
逻辑1:+2V~+6V 逻辑0:-2V~-6V |
逻辑1:+2V~+6V 逻辑0:-2V~-6V |
传输速率 |
20Kbps |
10Mbps |
10Mbps |
传输距离 |
15m |
1200m |
3000m |
二UART串口通信实验
1. 实验内容
UART串口通信实验内容位:当上位机通过串口调试工具发送数据给FPGA,FPGA通过串口接收数据并将接收到的数据发送给上位机,完成串口数据环回。当上位机未发送数据时候,FPGA每隔1s产生Hello World!发送给上位机并通过串口调试工具显示。
2.工程代码
2.1串口发送模块
串口发送模块将输入的8位并行数据进行串行输出。串口发送模块uart_tx代码如下:
1 `timescale 1ns/1ps
2 module uart_tx
3 #(
4 parameter CLK_FREQ = 50_000_000, //系统时钟频率
5 parameter UART_BPS = 9600 //串口波特率
6 )
7 (
8 input clk,
9 input rst_n,
10
11 input [7:0] tx_data, //待发送数据
12 input tx_en, //发送使能信号
13 output uart_tx_busy, //发送忙碌标志信号
14 output reg uart_txd //UART数据发送端口
15
16 );
17
18 localparam BPS_CNT = CLK_FREQ/UART_BPS;//当前波特率需要系统时钟计数BPS_CNT次
19
20 reg tx_en_r1;
21 reg tx_en_r2;
22
23 reg [15:0] clk_cnt; //系统时钟计数器
24 reg [3:0] tx_bit_cnt; //发送数据位计数器
25 reg tx_flag; //发送过程标志位
26 reg bit_flag;
27
28 wire tx_start;
29
30 //uart_tx_busy:串口发送忙碌状态
31 assign uart_tx_busy = tx_flag;
32
33 //tx_start:串口数据开始发送信号,捕获tx_en上升沿
34 assign tx_start = !tx_en_r2 && tx_en_r1;
35 always @(posedge clk or negedge rst_n)
36 begin
37 if(!rst_n)
38 begin
39 tx_en_r1 <= 1'b0;
40 tx_en_r2 <= 1'b0;
41 end
42 else
43 begin
44 tx_en_r1 <= tx_en;
45 tx_en_r2 <= tx_en_r1;
46 end
47 end
48
49 //tx_flag:接收过程标志信号
50 always @(posedge clk or negedge rst_n)
51 begin
52 if(!rst_n)
53 tx_flag <= 1'b0;
54 else if(tx_start)
55 tx_flag <= 1'b1;
56 else if(tx_bit_cnt == 4'd9 && bit_flag == 1'b1)
57 tx_flag <= 1'b0;
58 else
59 tx_flag <= tx_flag;
60 end
61
62 //clk_cnt:系统时钟计数器
63 always @(posedge clk or negedge rst_n)
64 begin
65 if(!rst_n)
66 clk_cnt <= 16'd0;
67 else if(tx_flag == 1'b0 || clk_cnt == BPS_CNT - 1'b1)
68 clk_cnt <= 16'd0;
69 else if(tx_flag)
70 clk_cnt <= clk_cnt + 1'b1;
71 else
72 clk_cnt <= 16'd0;
73 end
74
75 //bit_flag:当clk_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
76 always @(posedge clk or negedge rst_n)
77 begin
78 if(!rst_n)
79 bit_flag <= 1'b0;
80 else if(clk_cnt == 16'd1)
81 bit_flag <= 1'b1;
82 else
83 bit_flag <= 1'b0;
84 end
85
86 //tx_bit_cnt:发送数据位计数器
87 always @(posedge clk or negedge rst_n)
88 begin
89 if(!rst_n)
90 tx_bit_cnt <= 4'd0;
91 else if((tx_bit_cnt == 4'd9) && (bit_flag == 1'b1))
92 tx_bit_cnt <= 4'd0;
93 else if(bit_flag && tx_flag)
94 tx_bit_cnt <= tx_bit_cnt + 1'b1;
95 else
96 tx_bit_cnt <= tx_bit_cnt;
97 end
98
99 //uart_txd:根据发送数据计数器来给uart发送端口赋值
100always @(posedge clk or negedge rst_n)
101begin
102 if(!rst_n)
103 uart_txd <= 1'b1;
104 else if(bit_flag == 1'b1)
105 begin
106 case(tx_bit_cnt)
107 4'd0:uart_txd <= 1'b0; //发送起始位
108 4'd1:uart_txd <= tx_data[0]; //发送数据低位
109 4'd2:uart_txd <= tx_data[1];
110 4'd3:uart_txd <= tx_data[2];
111 4'd4:uart_txd <= tx_data[3];
112 4'd5:uart_txd <= tx_data[4];
113 4'd6:uart_txd <= tx_data[5];
114 4'd7:uart_txd <= tx_data[6];
115 4'd8:uart_txd <= tx_data[7];
116 4'd9:uart_txd <= 1'b1; //发送数据高位
117 default:uart_txd <= 1'b1;
118 endcase
119 end
120 else
121 uart_txd <= uart_txd;
122end
123
124endmodule
125
仿真代码如下:
1 `timescale 1ns/1ps
2 module uart_tx_tb();
3
4 reg clk;
5 reg rst_n;
6 reg [7:0] tx_data;
7 reg tx_en;
8
9 wire uart_tx_busy;
10 wire uart_txd;
11
12 initial
13 begin
14 clk = 1'b1;
15 rst_n = 1'b0;
16 #200
17 rst_n = 1'b1;
18 end
19
20 always #10 clk = ~clk;
21
22 initial begin
23 tx_data <= 8'b0;
24 tx_en <= 1'b0;
25 #200
26 //发送数据0
27 tx_data <= 8'd0;
28 tx_en <= 1'b1;
29 #20
30 tx_en <= 1'b0;
31 //每发送1bit数据需要5208个时钟周期,一帧数据为10bit
32 //所以需要数据延时(5208*20*10)后再产生下一个数据
33 #(5208*20*10);
34 //发送数据1
35 tx_data<= 8'd1;
36 tx_en <= 1'b1;
37 #20
38 tx_en <= 1'b0;
39 #(5208*20*10);
40 //发送数据2
41 tx_data <= 8'd2;
42 tx_en <= 1'b1;
43 #20
44 tx_en <= 1'b0;
45 #(5208*20*10);
46 //发送数据3
47 tx_data<= 8'd3;
48 tx_en <= 1'b1;
49 #20
50 tx_en <= 1'b0;
51 #(5208*20*10);
52 //发送数据4
53 tx_data<= 8'd4;
54 tx_en <= 1'b1;
55 #20
56 tx_en <= 1'b0;
57 #(5208*20*10);
58 //发送数据5
59 tx_data<= 8'd5;
60 tx_en <= 1'b1;
61 #20
62 tx_en <= 1'b0;
63 #(5208*20*10);
64 //发送数据6
65 tx_data<= 8'd6;
66 tx_en <= 1'b1;
67 #20
68 tx_en <= 1'b0;
69 #(5208*20*10);
70 //发送数据7
71 tx_data<= 8'd7;
72 tx_en <= 1'b1;
73 #20
74 tx_en <= 1'b0;
75 end
76
77 uart_tx u_uart_tx(
78 .clk(clk),
79 .rst_n(rst_n),
80
81 .tx_data(tx_data), //待发送数据
82 .tx_en(tx_en), //发送使能信号
83 .uart_tx_busy(uart_tx_busy), //发送忙碌标志信号
84 .uart_txd(uart_txd) //UART数据发送端口
85
86 );
87
88 endmodule
89
仿真结果如下:
仿真结果显示串口发送模块成功将数据0~7以UART数据帧格式进行发送。
2.2串口接收模块
串口接收模块将串行的8位数据转化为并行的8位数据进行输出。串口接收模块uart_rx代码如下:
1 `timescale 1ns/1ps
2 module uart_rx
3 #(
4 parameter CLK_FREQ = 50_000_000, //系统时钟频率
5 parameter UART_BPS = 9600 //串口波特率
6 )
7 (
8 input clk,
9 input rst_n,
10
11 input uart_rxd,
12 output uart_rx_busy,
13 output reg rx_done,
14 output reg [7:0] rx_data
15 );
16
17 localparam BPS_CNT = CLK_FREQ/UART_BPS;//当前波特率需要系统时钟计数BPS_CNT次
18
19 reg uart_rxd_r1;
20 reg uart_rxd_r2;
21 reg [15:0] clk_cnt;
22 reg [3:0] rx_bit_cnt;
23 reg [7:0] rx_data_r;
24 reg rx_flag;
25 reg bit_flag;
26 reg rx_done_r;
27
28
29 assign uart_rx_busy = rx_flag;
30 wire rx_start;
31 //rx_start:接收开始信号
32 assign rx_start = uart_rxd_r2 && !uart_rxd_r1;
33 always @(posedge clk or negedge rst_n)
34 begin
35 if(!rst_n)
36 begin
37 uart_rxd_r1 <= 1'b1;
38 uart_rxd_r2 <= 1'b1;
39 end
40 else
41 begin
42 uart_rxd_r1 <= uart_rxd;
43 uart_rxd_r2 <= uart_rxd_r1;
44 end
45 end
46
47 //rx_flag:接收过程标志位
48 always @(posedge clk or negedge rst_n)
49 begin
50 if(!rst_n)
51 rx_flag <= 1'b0;
52 else if(rx_start)
53 rx_flag <= 1'b1;
54 else if(rx_bit_cnt == 4'd8 && bit_flag == 1'b1)
55 rx_flag <= 1'b0;
56 else
57 rx_flag <= rx_flag;
58 end
59
60 //clk_cnt:系统时钟计数器
61 always @(posedge clk or negedge rst_n)
62 begin
63 if(!rst_n)
64 clk_cnt <= 16'd0;
65 else if(clk_cnt == BPS_CNT - 1'b1)
66 clk_cnt <= 16'd0;
67 else if(rx_flag)
68 clk_cnt <= clk_cnt + 1'b1;
69 else
70 clk_cnt <= 16'd0;
71 end
72
73 //bit_flag:接收过程标志位
74 always @(posedge clk or negedge rst_n)
75 begin
76 if(!rst_n)
77 bit_flag <= 1'b0;
78 else if(clk_cnt == BPS_CNT/2 - 1'b1)
79 bit_flag <= 1'b1;
80 else
81 bit_flag <= 1'b0;
82 end
83
84 //rx_bit_cnt:接收完成标志位
85 always @(posedge clk or negedge rst_n)
86 begin
87 if(!rst_n)
88 rx_bit_cnt <= 4'd0;
89 else if((rx_bit_cnt == 4'd8) && (bit_flag == 1'b1))
90 rx_bit_cnt <= 4'd0;
91 else if(bit_flag == 1'b1)
92 rx_bit_cnt <= rx_bit_cnt + 1'b1;
93 else
94 rx_bit_cnt <= rx_bit_cnt;
95 end
96
97 //rx_data_r:输入数据进行移位
98 always @(posedge clk or negedge rst_n)
99 begin
100 if(!rst_n)
101 rx_data_r <= 8'd0;
102 else if((rx_bit_cnt >= 4'd1) &&(rx_bit_cnt <= 4'd8) && (bit_flag == 1'b1))
103 rx_data_r <= {uart_rxd_r2 , rx_data_r[7:1]};
104 else
105 rx_data_r <= rx_data_r;
106 end
107
108 //rx_done_r:接收完成标志位
109 always @(posedge clk or negedge rst_n)
110 begin
111 if(!rst_n)
112 rx_done_r <= 1'b0;
113 else if((rx_bit_cnt == 4'd8) && (bit_flag == 1'b1))
114 rx_done_r <= 1'b1;
115 else
116 rx_done_r <= 1'b0;
117 end
118
119 //rx_data:输出完整的8位有效数据
120 always @(posedge clk or negedge rst_n)
121 begin
122 if(!rst_n)
123 rx_data <= 8'd0;
124 else if(rx_done_r)
125 rx_data <= rx_data_r;
126 else
127 rx_data <= rx_data;
128 end
129
130 //rx_done:接收完成标志位
131 always @(posedge clk or negedge rst_n)
132 begin
133 if(!rst_n)
134 rx_done <= 1'b0;
135 else
136 rx_done <= rx_done_r;
137 end
138
139 endmodule
仿真代码如下:
1 `timescale 1ns/1ns
2 module uart_rx_tb();
3
4 reg clk;
5 reg rst_n;
6 reg uart_rxd;
7 wire rx_done;
8 wire [7:0] rx_data;
9
10 initial
11 begin
12 clk = 1'b1;
13 rst_n = 1'b0;
14 uart_rxd = 1'b1;
15 #200
16 rst_n = 1'b1;
17 end
18
19 always #10 clk = ~clk;
20
21 initial
22 begin
23 #200
24 rx_bit_data(8'd1);
25 rx_bit_data(8'd2);
26 rx_bit_data(8'd3);
27 rx_bit_data(8'd4);
28 rx_bit_data(8'd5);
29 rx_bit_data(8'd6);
30 rx_bit_data(8'd7);
31 rx_bit_data(8'd8);
32 rx_bit_data(8'd9);
33 end
34
35 task rx_bit_data(
36 input [7:0] data
37 );
38 integer i;
39 for(i = 0; i < 10; i = i + 1'b1)
40 begin
41 case(i)
42 0:uart_rxd <= 1'b0;
43 1:uart_rxd <= data[0];
44 2:uart_rxd <= data[1];
45 3:uart_rxd <= data[2];
46 4:uart_rxd <= data[3];
47 5:uart_rxd <= data[4];
48 6:uart_rxd <= data[5];
49 7:uart_rxd <= data[6];
50 8:uart_rxd <= data[7];
51 9:uart_rxd <= 1'b1;
52 endcase
53 #(5208*20);
54 end
55 endtask
56
57 uart_rx u_uart_rx(
58 .clk(clk),
59 .rst_n(rst_n),
60
61 .uart_rxd(uart_rxd),
62 .rx_done(rx_done),
63 .rx_data(rx_data)
64 );
65
66 endmodule
仿真结果如下:
仿真结果显示,rx_data成功将uart_rxd输入的串行数据转换为8位并行数据输出,rx_done为接收一帧数据完成信号。
2.3控制模块
控制模块uart_ctrl用于控制串口通信发送使能和发送数据信号,当检测到s上位机串口调试工具助手发送数据给FPGA时,FPGA接收模块接收数据后并将发送到上位机完成数据回环。当上位机未发送数据时候,FPGA每隔1s产生Hello World!发送给上位机并通过串口调试工具显示。控制模块uart_ctrl代码如下:
1 `timescale 1ns/1ps
2 module uart_ctrl
3 #(
4 parameter CLK_FREQ = 50_000_000, //系统时钟频率
5 parameter UART_BPS = 9600 //串口波特率
6 )
7 (
8 input clk,
9 input rst_n,
10
11 input rx_done,
12 input [7:0] rx_data,
13
14 input uart_tx_busy,
15 output uart_en,
16 output [7:0] uart_data
17
18 );
19
20 localparam BPS_CNT = CLK_FREQ/UART_BPS;//当前波特率需要系统时钟计数BPS_CNT次
21
22 reg rx_done_r1;
23 reg rx_done_r2;
24 reg tx_start;
25 reg tx_en;
26 reg [7:0] tx_data;
27
28 reg [25:0] uart_wait; //发送等待时间计数器
29 reg [19:0] uart_cnt; //发送时间计数器
30 reg rx_data_valid; //接收数据有效信号
31 reg [7:0] store [14:0]; //存储待发送的8位数据
32 reg [2:0] uart_state; //状态机
33 reg [7:0] bit_cnt; //发送数据计数器
34 reg data_sel; //发送数据选择信号
35 reg tx_en_r;
36 reg [7:0] tx_data_r;
37
38 wire rx_done_flag;
39
40 //rx_done_flag:接收完成标志信号
41 assign rx_done_flag = !rx_done_r2 && rx_done_r1;
42 always @(posedge clk or negedge rst_n)
43 begin
44 if(!rst_n)
45 begin
46 rx_done_r1 <= 1'b0;
47 rx_done_r2 <= 1'b0;
48 end
49 else
50 begin
51 rx_done_r1 <= rx_done;
52 rx_done_r2 <= rx_done_r1;
53 end
54 end
55
56 //tx_en:发送使能信号
57 //tx_data:发送数据
58 always @(posedge clk or negedge rst_n)
59 begin
60 if(!rst_n)
61 begin
62 tx_start <= 1'b0;
63 tx_en <= 1'b0;
64 tx_data <= 8'd0;
65 end
66 else
67 begin
68 if(rx_done_flag)
69 begin
70 tx_start <= 1'b1;
71 tx_en <= 1'b0;
72 tx_data <= rx_data;
73 end
74 else if(tx_start && !uart_tx_busy)
75 begin
76 tx_start <= 1'b0;
77 tx_en <= 1'b1;
78 tx_data <= tx_data;
79 end
80 else
81 begin
82 tx_start <= 1'b0;
83 tx_en <= 1'b0;
84 tx_data <= tx_data;
85 end
86 end
87 end
88
89 //uart_en:串口发送使能信号
90 //uart_data:串口发送数据
91 //发送数据选择:data_sel高,选择存储的字符串,data_sel:低,选择接收的数据
92 assign uart_en = data_sel ? tx_en_r : tx_en ;
93 assign uart_data = data_sel ? tx_data_r : tx_data ;
94
95 //存储待发送的数据
96 always @(*)
97 begin
98 if(!rst_n)
99 begin
100 store[0] = 8'd72; //存储字符H
101 store[1] = 8'd101; //存储字符e
102 store[2] = 8'd108; //存储字符l
103 store[3] = 8'd108; //存储字符l
104 store[4] = 8'd111; //存储字符o
105 store[5] = 8'd32; //存储字符空格
106 store[6] = 8'd87; //存储字符W
107 store[7] = 8'd111; //存储字符o
108 store[8] = 8'd114; //存储字符r
109 store[9] = 8'd108; //存储字符l
110 store[10] = 8'd100; //存储字符d
111 store[11] = 8'd33; //存储字符!
112 store[12] = 8'd32; //存储字符空格
113 store[13] = 8'd10; //换行符
114 store[14] = 8'd13; //回车符
115 end
116 else
117 begin
118 store[0] = store[0];
119 store[1] = store[1];
120 store[2] = store[2];
121 store[3] = store[3];
122 store[4] = store[4];
123 store[5] = store[5];
124 store[6] = store[6];
125 store[7] = store[7];
126 store[8] = store[8];
127 store[9] = store[9];
128 store[10] = store[10];
129 store[11] = store[11];
130 store[12] = store[12];
131 store[13] = store[13];
132 store[14] = store[14];
133 end
134 end
135
136 //串口发送控制,每个一段时间发送字符串的命令
137 always @(posedge clk or negedge rst_n)
138 begin
139 if(!rst_n)
140 begin
141 uart_wait <= 26'd0;
142 rx_data_valid <= 1'b0;
143 end
144 else if(rx_done)
145 begin
146 uart_wait <= 26'd0;
147 rx_data_valid <= 1'b0;
148 end
149 else
150 begin
151 if(uart_wait == 26'd49_999_999)
152 begin
153 uart_wait <= 26'd0;
154 rx_data_valid <= 1'b1;
155 end
156 else
157 begin
158 uart_wait <= uart_wait + 1'b1;
159 rx_data_valid <= 1'b0;
160 end
161 end
162 end
163
164 // //串口发送字符串数据,依次发送存储的字符串
165 always @(posedge clk or negedge rst_n)
166 begin
167 if(!rst_n)
168 begin
169 uart_cnt <= 20'd0;
170 uart_state <= 3'b001;
171 data_sel <= 1'b0;
172 bit_cnt <= 8'd0;
173 tx_data_r <= 8'd0;
174 tx_en_r <= 1'b0;
175 end
176 else
177 begin
178 if(rx_done)
179 begin
180 uart_cnt <= 20'd0;
181 uart_state <= 3'b001;
182 data_sel <= 1'b0;
183 bit_cnt <= 8'd0;
184 tx_data_r <= 8'd0;
185 tx_en_r <= 1'b0;
186 end
187 else
188 begin
189 case(uart_state)
190
191 3'b001:begin
192 if(rx_data_valid)
193 begin
194 uart_state <= 3'b010;
195 data_sel <= 1'b1;
196 end
197 else
198 begin
199 uart_state <= 3'b001;
200 data_sel <= 1'b0;
201 end
202 end
203
204 3'b010:begin
205 if(bit_cnt == 8'd14)
206 begin
207 if(uart_cnt == 20'd0)
208 begin
209 tx_data_r <= store[14];
210 tx_en_r <= 1'b1;
211 uart_cnt <= uart_cnt + 1'b1;
212 end
213 else if(uart_cnt == BPS_CNT*10 - 1'b1)
214 begin
215 uart_state <= 3'b100;
216 tx_en_r <= 1'b0;
217 uart_cnt <= 20'd0;
218 bit_cnt <= 8'd0;
219 end
220 else
221 begin
222 uart_cnt <= uart_cnt + 1'b1;
223 tx_en_r <= 1'b0;
224 end
225 end
226 else
227 begin
228 if(uart_cnt == 20'd0)
229 begin
230 tx_data_r <= store[bit_cnt];
231 tx_en_r <= 1'b1;
232 uart_cnt <= uart_cnt + 1'b1;
233 end
234 else if(uart_cnt == BPS_CNT*10 - 1'b1)
235 begin
236 tx_en_r <= 1'b0;
237 uart_cnt <= 20'd0;
238 bit_cnt <= bit_cnt + 1'b1;
239 end
240 else
241 begin
242 uart_cnt <= uart_cnt + 1'b1;
243 tx_en_r <= 1'b0;
244 end
245
246 end
247 end
248
249 3'b100:begin //发送完成
250 uart_state <= 3'b001;
251 data_sel <= 1'b0;
252 tx_en_r <= 1'b0;
253 end
254
255 default: begin
256 uart_state <= 3'b001;
257 tx_en_r <= 1'b0;
258 uart_cnt <= 20'd0;
259 data_sel <= 1'b0;
260 bit_cnt <= 8'd0;
261 tx_data_r <= 8'd0;
262 end
263
264 endcase
265 end
266 end
267 end
268
269 endmodule
2.4顶层模块
顶层模块uart_top用于完成uart_tx、uart_rx、uart_ctrl模块的例化。
1 `timescale 1ns/1ps
2 module uart_top(
3 input sys_clk,
4 input rst_n,
5
6 input uart_rxd,
7 output uart_txd
8 );
9
10 parameter CLK_FREQ = 50_000_000 ; //时钟频率
11 parameter UART_BPS = 9600 ; //比特率
12
13 wire [7:0] uart_data;
14 wire [7:0] tx_data;
15 wire uart_en;
16 wire uart_tx_busy;
17 wire rx_done;
18
19 uart_tx
20 #(
21 .CLK_FREQ(CLK_FREQ), //系统时钟频率
22 .UART_BPS(UART_BPS) //串口波特率
23 )
24 u_uart_tx(
25 .clk(sys_clk),
26 .rst_n(rst_n),
27
28 .tx_data(tx_data), //待发送数据
29 .tx_en(uart_en), //发送使能信号
30 .uart_tx_busy(uart_tx_busy),//发送忙碌标志信号
31 .uart_txd(uart_txd) //UART数据发送端口
32 );
33
34 uart_rx
35 #(
36 .CLK_FREQ(CLK_FREQ), //系统时钟频率
37 .UART_BPS(UART_BPS) //串口波特率
38 )
39 u_uart_rx(
40 .clk(sys_clk),
41 .rst_n(rst_n),
42
43 .uart_rxd(uart_rxd),
44 .uart_rx_busy(),
45 .rx_done(rx_done),
46 .rx_data(uart_data)
47 );
48
49 uart_ctrl
50 #(
51 .CLK_FREQ(CLK_FREQ), //系统时钟频率
52 .UART_BPS(UART_BPS) //串口波特率
53 )
54 u_uart_ctrl(
55 .clk(sys_clk),
56 .rst_n(rst_n),
57
58 .rx_done(rx_done),
59 .rx_data(uart_data),
60
61 .uart_tx_busy(uart_tx_busy),
62 .uart_en(uart_en),
63 .uart_data(tx_data)
64 );
65
66 endmodule
仿真代码如下:
1 `timescale 1ns/1ps
2 module uart_top_tb();
3
4 reg sys_clk;
5 reg rst_n;
6 reg uart_rxd;
7
8 wire uart_txd;
9
10 initial
11 begin
12 sys_clk = 1'b1;
13 rst_n = 1'b0;
14 uart_rxd = 1'b1;
15 #200
16 rst_n = 1'b1;
17 end
18
19 always #10 sys_clk = ~sys_clk;
20
21 initial
22 begin
23 #400
24 rx_byte();
25 end
26
27 task rx_byte();
28 integer j;
29 for(j = 1; j < 10; j = j + 1'b1)
30 rx_bit_data(j);
31 endtask
32
33 task rx_bit_data(
34 input [7:0] data
35 );
36 integer i;
37 for(i = 0; i < 10; i = i + 1'b1)
38 begin
39 case(i)
40 0:uart_rxd <= 1'b0;
41 1:uart_rxd <= data[0];
42 2:uart_rxd <= data[1];
43 3:uart_rxd <= data[2];
44 4:uart_rxd <= data[3];
45 5:uart_rxd <= data[4];
46 6:uart_rxd <= data[5];
47 7:uart_rxd <= data[6];
48 8:uart_rxd <= data[7];
49 9:uart_rxd <= 1'b1;
50 endcase
51 #(5208*20);
52 end
53 endtask
54
55 uart_top u_uart_top(
56 .sys_clk(sys_clk),
57 .rst_n(rst_n),
58
59 .uart_rxd(uart_rxd),
60 .uart_txd(uart_txd)
61 );
62
63 endmodule
仿真结果如下所示:
首先验证串口通信回环测试,激励模块产生数据1~9,接收模块完成数据接收后,将并行的8位1~9数据传输到uart_tx模块,uart_tx将8位数据进行串行输出,仿真结果显示,回环测试成功。当未检测到rx_done接收信号时,uart_wait计数器每计数到1s,使能rx_data_valid信号,发送store寄存的Helllo World!。
3板级验证
下载代码到Alter Cyclone IV FPGA开发板中,设置波特率为9600,打开串口调试助手,接收区每隔1s接收一个Hello World!,当手动发送123456 数据时,串口接收区显示接收123456 字符。当停止发送123456 字符时,接收区每隔1s会接收到一个Hello World!。
文章来源地址https://www.toymoban.com/news/detail-451434.html
文章来源:https://www.toymoban.com/news/detail-451434.html
到了这里,关于UART串口通信(回环测试)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!