我是靠谱客的博主 内向荷花,这篇文章主要介绍FPGA学习之UART串口通信(当UART控制器从上位机接收到数据后,立即将数据输出,并发送回上位机,完成“回环测试”),现在分享给大家,希望可以做个参考。
FPGA需要控制的仅为两条信号线:RXD和TXD,即数据接收线和数据发送线,因此我们只需要关注数据接收和发送时的时序图。传送的一帧数据里面包括起始位(0),8位数据位,奇偶校验位,停止位(1)。当空闲时,10位数据均为高电平,在检测到起始位低电平时,开始传输。
波特率是衡量数据传输速率的指标,表示每秒传输的二进制位数,在此例中设为9600,所以50M/9600==5207,所以分频时要计数到5207.
1.串口接收数据的速率控制模块:用于控制串口接收的速率
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52module bps_rx( input clk, input rst_n, input rx_en, //bps_rx开始计数的使能信号 output reg rx_sel_data, //控制数据采集的尖峰脉冲信号 output reg [3:0] rx_num //有效数据位的计数值 ); parameter bps_div_1 = 13'd5207; //50M/5207=9600频率(波特率) parameter bps_div_2 = 13'd2603; //数据在波特率的中间值时采集 reg flag; //接收标志位,当接收到rx_en时,拉高 reg [12:0] cnt; //波特率计数 always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 13'b0; else if(flag && cnt < bps_div_1) cnt <= cnt + 1'b1; else cnt <= 13'b0; always@(posedge clk or negedge rst_n) if(!rst_n) flag <= 0; else if(rx_en) flag <= 1; else if (rx_num == 4'd10) //当数据接收完毕时,标志位清零 flag <= 0; always @(posedge clk or negedge rst_n) //规定接收数据的范围,即一帧数据 两个起始位 8位数据位 if(!rst_n) rx_num = 4'd0; else if(rx_sel_data && flag) rx_num = rx_num + 1'b1; else if (rx_num == 4'd10) rx_num = 4'd0; always @(posedge clk or negedge rst_n) //数据在波特率的中间值时采集 if(!rst_n) rx_sel_data = 1'b0; else if(cnt == bps_div_2) //生成尖峰脉冲,尖峰脉冲为采集数据的使能信号 rx_sel_data = 1'b1; else rx_sel_data = 1'b0; endmodule
2.串口串行数据的接收模块:用于接收串口串行数据
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57module uart_rx( input clk, input rst_n, input rx_sel_data, //控制数据采集的尖峰脉冲信号 input [3:0] rx_num, //有效数据位的计数值 input rs232_rx, //输入串行数据 output rx_en, //使能信号:启动接收波特率计数 output reg tx_en, //使能信号:在接收完数据后,开始发送数据 output reg [7:0] rx_d //将采集的8位数据转换为并行数据 ); reg in_1, in_2; reg [7:0] rx_d_r; //数据寄存器 always @(posedge clk or negedge rst_n) if (!rst_n) begin in_1 <= 1'b1; //因为起始位为0,所以初值设为1 in_2 <= 1'b1; end else begin in_1 <= rs232_rx; in_2 <= in_1; end assign rx_en = in_2 && (~in_1); //当in_1变为0时,说明已经开始接收数据,就可以拉高接收使能信号 //确保在一帧数据的中间8位进行数据读取 always @(posedge clk or negedge rst_n) if (!rst_n) begin rx_d_r <= 8'b0; rx_d <= 8'b0; end else if (rx_sel_data) //数据采集的尖峰脉冲信号来的时候开始接收数据 case (rx_num) 0:; //起始位不处理 1: rx_d_r[0] <= rs232_rx; 2: rx_d_r[1] <= rs232_rx; 3: rx_d_r[2] <= rs232_rx; 4: rx_d_r[3] <= rs232_rx; 5: rx_d_r[4] <= rs232_rx; 6: rx_d_r[5] <= rs232_rx; 7: rx_d_r[6] <= rs232_rx; 8: rx_d_r[7] <= rs232_rx; 9: rx_d <= rx_d_r; //将数据传给输出 default :; endcase always @(posedge clk or negedge rst_n) if(!rst_n) tx_en <= 0; else if (rx_num == 9 && rx_sel_data) //在接收完停止位后 把发送标志位拉高 tx_en <= 1; else tx_en <= 0; endmodule
3.串口发送数据的速率控制模块:用于控制串口发送的速率
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53module bps_tx( input clk, input rst_n, input tx_en, //bps_tx开始计数的使能信号 output reg tx_sel_data, //控制数据采集的尖峰脉冲信号 output reg [3:0] tx_num //有效数据位的计数值 ); parameter bps_div_1 = 13'd5207; //50M/5207=9600频率(波特率) parameter bps_div_2 = 13'd2603; //数据在波特率的中间值时采集 reg flag; //接收标志位,当接收到tx_en时,拉高 reg [12:0] cnt; //波特率计数 always@(posedge clk or negedge rst_n) if(!rst_n) flag <= 0; else if(tx_en) flag <= 1; else if (tx_num == 4'd10) //当数据接收完毕时,标志位清零 flag <= 0; always @(posedge clk or negedge rst_n) if(!rst_n) cnt <= 13'b0; else if(flag && cnt < bps_div_1) cnt <= cnt + 1'b1; else cnt <= 13'b0; always @(posedge clk or negedge rst_n) //规定接收数据的范围,即一帧数据 两个起始位 8位数据位 if(!rst_n) tx_num = 4'd0; else if(tx_sel_data && flag) tx_num = tx_num + 1'b1; else if (tx_num == 4'd10) tx_num = 4'd0; always @(posedge clk or negedge rst_n) //数据在波特率的中间值时采集 if(!rst_n) tx_sel_data = 1'b0; else if(cnt == bps_div_2) //生成尖峰脉冲,尖峰脉冲为采集数据的使能信号 tx_sel_data = 1'b1; else tx_sel_data = 1'b0; endmodule
4.串口串行数据的发送模块:用于发送串口串行数据
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31module uart_tx( input clk, input rst_n, input tx_sel_data, //控制数据采集的尖峰脉冲信号 input [3:0] tx_num, //有效数据位的计数值 input [7:0] rx_d, //输入8wei数据 output reg rs232_tx //发送数据 ); //确保在一帧数据的中间8位进行数据读取 always @(posedge clk or negedge rst_n) if (!rst_n) rs232_tx <= 1'b1; else if (tx_sel_data) //数据采集的尖峰脉冲信号来的时候开始接收数据 case (tx_num) 0:rs232_tx <= 1'b0; //起始位为0 1: rs232_tx <= rx_d[0]; 2: rs232_tx <= rx_d[1]; 3: rs232_tx <= rx_d[2]; 4: rs232_tx <= rx_d[3]; 5: rs232_tx <= rx_d[4]; 6: rs232_tx <= rx_d[5]; 7: rs232_tx <= rx_d[6]; 8: rs232_tx <= rx_d[7]; 9: rs232_tx <= 1'b1; //停止位1 default :rs232_tx <= 1'b1; endcase endmodule
5.顶层模块:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50module uart( input clk, input rst_n, input rs232_rx, output rs232_tx ); wire rx_en; wire tx_en; wire [7:0] rx_d; wire [3:0] rx_num,tx_num; //模块例化 bps_rx bps_rx( .clk(clk), .rst_n(rst_n), .rx_en(rx_en), .rx_num(rx_num), .rx_sel_data(rx_sel_data) ); uart_rx uart_rx( .clk(clk), .rst_n(rst_n), .rx_en(rx_en), .rx_num(rx_num), .rx_sel_data(rx_sel_data), .rx_d(rx_d), .rs232_rx(rs232_rx), .tx_en(tx_en) ); bps_tx bps_tx( .clk(clk), .rst_n(rst_n), .tx_en(tx_en), .tx_num(tx_num), .tx_sel_data(tx_sel_data) ); uart_tx uart_tx( .clk(clk), .rst_n(rst_n), .rx_d(rx_d), .tx_num(tx_num), .rs232_tx(rs232_tx), .tx_sel_data(tx_sel_data) ); endmodule
6.测试文件
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46`timescale 1 ns/ 1 ns module uart_tb(); parameter T = 20; reg clk; reg rst_n; reg rs232_rx; wire rs232_tx; initial begin clk = 1'b0; rst_n = 1'b0; rs232_rx = 1; #200 rst_n = 1'b1; //模拟发送一帧数据 #200 rs232_rx = 0; //起始位 #110000 rs232_rx = 0; #110000 rs232_rx = 1; #110000 rs232_rx = 1; #110000 rs232_rx = 0; #110000 rs232_rx = 0; #110000 rs232_rx = 1; #110000 rs232_rx = 0; #110000 rs232_rx = 1; //停止位 #1500000 $stop; end always #(T/2) clk = ~clk; uart i1 ( .rs232_rx(rs232_rx), .rs232_tx(rs232_tx), .clk(clk), .rst_n(rst_n) ); endmodule
7.RTL图:
仿真图:
工程文件上传至qq群:868412045
最后
以上就是内向荷花最近收集整理的关于FPGA学习之UART串口通信(当UART控制器从上位机接收到数据后,立即将数据输出,并发送回上位机,完成“回环测试”)的全部内容,更多相关FPGA学习之UART串口通信(当UART控制器从上位机接收到数据后内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复