【FPGA】串口收发的verilog实现


2020.8.1

一、叽呱叽呱

作为一名电子专业的小白菜,在大二的暑假终于开博客啦。目前开博客写博文主要是为了在学习的过程中有所输出+能和他人多多交流,也算是自己学习开发的一个记录。

嘛,这个暑假到现在学了一丢丢基础的verilog知识,短期目标是好好把FPGA学下去。

那其他废话也不多说了,本文以串口收发的verilog代码实现为主(基本复现黑金AX301的串口代码),辅以一些必要的原理。

二、实验原理

1.异步串口通信协议

串口传输时序图:

 

从波形来看,在没有数据传输时数据线保持高电平。当一次下降沿事件发生时,我们认为开始一次数据传输。代码中默认一位起始位,八位数据位,无校验位。

 

三、程序设计

1.串口接收模块:

串口接收采用状态机,如下图:

 

 

 

 S_IDLE:空闲状态,表明此时无数据传输,当遇到输入数据下降沿后转换状态至S_START;

S_START:起始状态,此时数据线上为起始位的传输,当一位起始位传输结束后转入S_REC_BYTE;

S_REC_BYTE:接收数据状态,此时数据线接收串行输入的数据,接收完毕后转入S_STOP;

S_STOP:停止状态,此时数据接收完毕,在等待半位数据的时间后(以免错过下一个数据的起始位判断),转入S_IDLE(代码实现中去掉了S_DATA状态)。

 

2.串口发送模块:

 

与接收模块类似,

 S_IDLE:空闲状态,表明此时无数据传输,当遇到输入数据下降沿后转换状态至S_START;

S_START:起始状态,此时数据线上为起始位的传输,当一位起始位传输结束后转入S_REC_BYTE;

S_SEND_BYTE:发送数据状态,此时数据线发送输入的并行八位数据,接收完毕后转入S_STOP;

S_STOP:停止状态,此时数据接收完毕,在等待一位数据的时间后,转入S_IDLE。

 

3.实现功能

其他细节原理不多赘述,我的代码基本与黑金开发板AX301的串口代码一致,只是自己复现了一遍加了些自己理解的注释。

实现串口调试助手发送数据至FPGA开发板,FPGA接收数据后返回对应数据,可在串口调试助手上查看。

 

4.具体代码:

①串口接收模块

  1 module uart_rx
  2 #(
  3     parameter                 CLK_FRE = 50, //系统时钟频率 50(MHz)
  4      parameter                 UART_BPS = 115200 //波特率为115200
  5   )
  6 (
  7    input                       clk,
  8     input                       rst_n,
  9     input                       rx_in,
 10     output reg[7:0]        rx_out,
 11     output reg                rx_data_valid
 12 );
 13 
 14 localparam              CYCLE            = CLK_FRE * 1000000 / UART_BPS; //传输一位数据需几个时钟
 15 localparam                     S_IDLE         = 3'd1; //输入信号空闲状态
 16 localparam                     S_START         = 3'd2; //输入信号检测到下降沿后,开始接收起始位
 17 localparam                    S_REC_BYTE     = 3'd3; //接收到一位起始位,开始接受数据
 18 localparam                     S_STOP         = 3'd4; //八位数据接收完毕
 19 
 20 
 21 reg                             rx_in_0;  //接收的数据延时一个时钟
 22 reg                             rx_in_1; //接收的数据延时两个时钟
 23 wire                            rx_negedge; //rx_in下降沿判断
 24 reg [2:0]                    state;  //当前输入信号状态
 25 reg [2:0]                    next_state; //输入信号下一个状态
 26 reg [8:0]                    cycle_cnt; //传输一位数据时,时钟计数
 27 reg [3:0]                     bit_cnt; //接收数据时,每位数据计数
 28 reg [7:0]                    rx_bits; //接收数据的临时存储
 29 
 30 
 31 //判断输入信号rx_in是否遇到下降沿
 32 assign rx_negedge = rx_in_1 && (!rx_in_0); //输入信号rx_in下降沿边沿检测
 33 
 34 always@(posedge clk or negedge rst_n)
 35 begin
 36    if(rst_n == 1'b0)
 37     begin
 38        rx_in_0 <= 1'b0;
 39         rx_in_1 <= 1'b0;
 40    end
 41     else
 42     begin
 43        rx_in_0 <= rx_in;
 44         rx_in_1 <= rx_in_0;
 45     end
 46 end
 47 
 48 //输入信号状态转换
 49 always@(posedge clk or negedge rst_n)
 50 begin
 51     if(rst_n == 1'b0)
 52         state <= S_IDLE;
 53     else
 54         state <= next_state;
 55 end
 56 
 57 //输入信号状态机
 58 always@(*)
 59 begin
 60     case(state)
 61     S_IDLE:
 62         if(rx_negedge == 1'b1) //检测输入信号下降沿
 63             next_state = S_START;
 64         else
 65            next_state = S_IDLE;
 66     S_START:
 67        if(cycle_cnt == CYCLE - 1) //等到一位起始位后
 68             next_state = S_REC_BYTE;
 69         else
 70            next_state = S_START;
 71     S_REC_BYTE:
 72        if(cycle_cnt == CYCLE - 1 && bit_cnt == 3'd7) //接收完八位数据后转换状态
 73            next_state = S_STOP;
 74       else
 75             next_state = S_REC_BYTE;
 76     S_STOP:
 77         if(cycle_cnt == CYCLE/2 -1) //等待半位以免错过下一个数据的起始位判断
 78             next_state = S_IDLE;
 79         else
 80             next_state = S_STOP;        
 81     default:
 82         next_state = S_IDLE;
 83     endcase
 84 end
 85 
 86 //接收一位数据时,时钟计数
 87 always@(posedge clk or negedge rst_n)
 88 begin
 89     if(rst_n == 1'b0)
 90         cycle_cnt <= 9'b0;
 91     else if(next_state != state || (state == S_REC_BYTE && cycle_cnt == CYCLE - 1)) //每当状态转变或接收数据时接收完一位数据,需要重新计数
 92        cycle_cnt <= 9'b0; 
 93     else 
 94        cycle_cnt <= cycle_cnt + 9'b1;
 95 end
 96 
 97 //接收数据时,判断接收了几位数据的计数
 98 always@(posedge clk or negedge rst_n)
 99 begin
100     if(rst_n == 1'b0)
101         bit_cnt <= 3'b0;
102     else if(state == S_REC_BYTE) //当计数一位的时钟完成,bit_cnt + 1
103     begin
104        if(cycle_cnt == CYCLE - 1)
105             bit_cnt <= bit_cnt + 3'b1;
106         else
107             bit_cnt <= bit_cnt;
108     end
109     else
110         bit_cnt <= 3'b0;
111 end
112 
113 //接收数据临时存储,串转并
114 always@(posedge clk or negedge rst_n)
115 begin
116     if(rst_n == 1'b0)
117         rx_bits <= 8'b0;
118     else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 -1)
119         rx_bits[bit_cnt] <= rx_in;
120     else
121         rx_bits <= rx_bits;
122 end
123 
124 //输出接收到的数据
125 always@(posedge clk or negedge rst_n)
126 begin
127     if(rst_n == 1'b0)
128         rx_out <= 8'b0;
129     else if(state == S_STOP && next_state != state)
130         rx_out <= rx_bits;
131 end
132 
133 //判断接收到的数据是否有效    
134 always@(posedge clk or negedge rst_n)
135 begin
136     if(rst_n == 1'b0)
137         rx_data_valid <= 1'b0;
138     else if(state == S_STOP && next_state!=state)
139         rx_data_valid <= 1'b1;
140     else if(state == S_IDLE)
141         rx_data_valid <= 1'b0;
142 end    
143     
144 endmodule    
View Code

 

②串口发送模块

  1 module uart_tx
  2 #( parameter CLK_FRE = 50,
  3    parameter UART_BPS = 115200
  4 )
  5 (  input             clk,
  6     input             rst_n,
  7     input [7:0]        tx_data_in,
  8     input             tx_data_valid,
  9     output             tx_data_out,
 10     output reg        tx_data_ready
 11 );
 12 
 13 localparam             CYCLE = CLK_FRE * 1000000 / UART_BPS; //传输一位数据需要几个时钟
 14 localparam             S_IDLE = 3'd1;
 15 localparam             S_START = 3'd2;
 16 localparam             S_SEND_BYTE = 3'd3;
 17 localparam             S_STOP = 3'd4;
 18 
 19 reg[2:0]             state;
 20 reg[2:0]                next_state;
 21 reg[8:0]                cycle_cnt;
 22 reg[3:0]                bit_cnt;
 23 reg                    tx_data_reg; //串行输出数据
 24 reg[7:0]                tx_data_latch; //输入的要发送的数据锁存
 25 
 26 //发送状态转换
 27 always@(posedge clk or negedge rst_n)
 28 begin
 29     if(rst_n == 1'b0)
 30         state <= S_IDLE;
 31     else
 32         state <= next_state;
 33 end
 34 
 35 //发送状态机
 36 always@(*)
 37 begin
 38     case(state)
 39         S_IDLE:
 40             if(tx_data_valid == 1'b1) //发送请求有效时
 41                 next_state <= S_START;
 42             else
 43                 next_state <= S_IDLE;
 44         S_START:
 45            if(cycle_cnt == CYCLE - 1) //发送完一位起始位后
 46                 next_state <= S_SEND_BYTE;
 47             else
 48                 next_state <= S_START;
 49         S_SEND_BYTE:
 50             if(bit_cnt == 3'd7 && cycle_cnt == CYCLE - 1) //发送完八位数据后
 51                 next_state <= S_STOP;
 52             else
 53                 next_state <= S_SEND_BYTE;
 54         S_STOP:
 55             if(cycle_cnt == CYCLE - 1) //等一位数据的时间转到空闲状态
 56                 next_state <= S_IDLE;
 57             else
 58                 next_state <= S_STOP;
 59         default:
 60             next_state <= S_IDLE;            
 61     endcase
 62 end
 63 
 64 //发送一位数据时,时钟计数
 65 always@(posedge clk or negedge rst_n)
 66 begin
 67     if(rst_n == 1'b0)
 68         cycle_cnt <= 0;
 69     else if(next_state != state ||(state == S_SEND_BYTE && cycle_cnt == CYCLE - 1))
 70         cycle_cnt <=0;
 71     else
 72         cycle_cnt <= cycle_cnt + 9'b1;
 73 end
 74 
 75 //发送数据时,判断发送了几位数据的计数
 76 always@(posedge clk or negedge rst_n)
 77 begin    
 78     if(rst_n == 1'b0)
 79         bit_cnt <= 0;
 80     else if(state == S_SEND_BYTE)
 81     begin
 82         if(cycle_cnt == CYCLE - 1)
 83             bit_cnt <= bit_cnt + 3'b1;
 84         else
 85             bit_cnt <= bit_cnt;
 86     end
 87     else
 88         bit_cnt <= 0;
 89 end
 90 
 91 //输入数据锁存
 92 always@(posedge clk or negedge rst_n)
 93 begin
 94     if(rst_n == 1'b0)
 95         tx_data_latch <= 8'b0;
 96     else if(state == S_IDLE && tx_data_valid == 1'b1) //当输入数据线处于空闲状态且输入数据有效时
 97         tx_data_latch <= tx_data_in;
 98 end
 99 
100 //输出数据,并入转串出
101 always@(posedge clk or negedge rst_n)
102 begin
103     if(rst_n == 1'b0)
104         tx_data_reg <= 1'b1; 
105     else 
106         case(state)
107             S_IDLE,S_STOP:
108                 tx_data_reg <= 1'b1;
109             S_START:
110                 tx_data_reg <= 1'b0;
111             S_SEND_BYTE:
112                tx_data_reg <= tx_data_latch[bit_cnt];
113             default:
114                 tx_data_reg <= 1'b1;
115         endcase
116 end
117 assign tx_data_out = tx_data_reg;
118 
119 //输出数据完毕标志的检验
120 always@(posedge clk or negedge rst_n)
121 begin
122     if(rst_n == 1'b0)
123         tx_data_ready <= 1'b0;
124     else if(state == S_STOP && cycle_cnt == CYCLE - 1) //仅在输出数据完毕后的一段时间,该标志置1
125         tx_data_ready <= 1'b1;
126     else if(state == S_IDLE) //我的理解是:使输出数据完毕的标志的时间保持一段时间,以免数据的错发漏发
127         if(tx_data_valid == 1'b1)
128             tx_data_ready <= 1'b0;
129         else
130             tx_data_ready <= 1'b1;
131 end
132 
133 endmodule
View Code

 

③顶层模块

 1 module uart_top(
 2     input clk,
 3     input rst_n,
 4     input uart_rx,
 5     output uart_tx
 6 );
 7 
 8 parameter CLK_FRE = 50;
 9 parameter BAUD_RATE = 115200;
10 localparam IDLE = 2'd1;
11 localparam WAIT = 2'd2;
12 
13 
14 wire            rx_data_valid;
15 wire[7:0]    rx_data_out;
16 reg[7:0]        tx_data_in;
17 reg            tx_data_valid;
18 wire            tx_data_ready;    
19 reg[1:0]        state;        
20 reg[8:0]        wait_cnt;
21 
22 always@(posedge clk or negedge rst_n)
23 begin
24     if(rst_n == 1'b0)
25     begin
26         wait_cnt <= 9'b0;
27         state <= IDLE;
28         tx_data_valid <= 1'b0;
29         tx_data_in <= 8'b0;
30     end
31     else
32         case(state)
33             IDLE:
34                 state <= WAIT;
35             WAIT:
36             begin
37                 if(rx_data_valid == 1'b1) //当数据接收完毕后,发送有效位置1
38                 begin
39                     tx_data_valid = 1'b1;
40                     tx_data_in <= rx_data_out;
41                 end
42                 else if(tx_data_valid == 1'b1 && tx_data_ready == 1'b1) //如果数据发送完成,发送有效位置0
43                     tx_data_valid <= 1'b0;
44                 else
45                     wait_cnt <= wait_cnt + 1;
46                 if(wait_cnt >= CLK_FRE * 1000000) //如果等待超过一秒
47                 begin
48                     state <= IDLE;
49                     wait_cnt <= 9'b0;
50                 end
51             end
52             default:
53                 state <= IDLE;
54         endcase
55                 
56         
57 end
58 
59 uart_rx
60 #( 
61     .CLK_FRE             (CLK_FRE),
62     .UART_BPS             (BAUD_RATE)
63 )uart_rx_inst
64 (    
65     .clk                    (clk),
66     .rst_n                (rst_n),
67     .rx_in                (uart_rx),
68     .rx_out                (rx_data_out),
69     .rx_data_valid     (rx_data_valid)
70 );
71 
72 uart_tx
73 #( 
74     .CLK_FRE             (CLK_FRE),
75     .UART_BPS             (BAUD_RATE)
76 )uart_tx_inst
77 (    
78     .clk                    (clk),
79     .rst_n                (rst_n),    
80     .tx_data_in         (tx_data_in),
81     .tx_data_valid        (tx_data_valid),
82     .tx_data_out        (uart_tx),
83     .tx_data_ready        (tx_data_ready)
84 );
85 
86 
87 
88 endmodule
View Code

 

5.调试结果

 

 成功!

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM