新闻中心

EEPW首页 > 手机与无线通信 > 牛人业话 > 小梅哥和你一起深入学习FPGA之串口调试(一)(上)

小梅哥和你一起深入学习FPGA之串口调试(一)(上)

作者: 时间:2015-11-19 来源:网络 收藏

  以上为波特率发生器的代码及分析,波特率发生模块在例化时被分别例化为串口发送波特率发生器和串口接收波特率发生器。接下来我们再来分析串口接收模块的代码。

本文引用地址:https://www.eepw.com.cn/article/283059.htm

  1 module my_uart_rx (

  2 clk, rst_n ,

  3 rs232_rx , rx_data , rx_int ,

  4 clk_bps , bps_start

  5 );

  6

  7 input clk; // 50MHz

  8 input rst_n ; //

  9 input rs232_rx ; // RS232

  10 input clk_bps ; // clk_bps

  11 output bps_start ; //

  12 output [ 7: 0] rx_data ; //

  13 output rx_int ; // ,

  14

  15 //---------------------------------------------------------

  16 reg rs232_rx0 , rs232_rx1 , rs232_rx2 , rs232_rx3 ; //

  17 wire neg_rs232_rx ; //

  18

  19 always @ ( posedge clk or negedge rst_n ) begin

  20 if(! rst_n ) begin

  21 rs232_rx0 <= 1'b0 ;

  22 rs232_rx1 <= 1'b0 ;

  23 rs232_rx2 <= 1'b0 ;

  24 rs232_rx3 <= 1'b0 ;

  25 end

  26 else begin

  27 rs232_rx0 <= rs232_rx ;

  28 rs232_rx1 <= rs232_rx0 ;

  29 rs232_rx2 <= rs232_rx1 ;

  30 rs232_rx3 <= rs232_rx2 ;

  31 end

  32 end

  33 // <20ns-40ns ( )

  34 //

  35 // 40ns

  36 assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0; // neg_rs232_rx

  37

  38 //---------------------------------------------------------

  39 reg bps_start_r ;

  40 reg[ 3: 0] num; //

  41 reg rx_int ; // ,

  42

  43 always @ ( posedge clk or negedge rst_n )

  44 if(! rst_n ) begin

  45 bps_start_r <= 1'bz ;

  46 rx_int <= 1'b0 ;

  47 end

  48 else if( neg_rs232_rx ) begin

  // rs232_rx

  49 bps_start_r <= 1'b1 ; //

  50 rx_int <= 1'b1 ; //

  51 end

  52 else if( num==4'd12 ) begin //

  53 bps_start_r <= 1'b0 ; //

  54 rx_int <= 1'b0 ; //

  55 end

  56

  57 assign bps_start = bps_start_r ;

  58

  59 //---------------------------------------------------------

  60 reg[ 7 : 0] rx_data_r ; //

  61 //---------------------------------------------------------

  62

  63 reg[ 7 : 0] rx_temp_data ; //

  64

  65 always @ ( posedge clk or negedge rst_n )

  66 if(! rst_n ) begin

  67 rx_temp_data <= 8'd0 ;

  68 num <= 4'd0 ;

  69 rx_data_r <= 8'd0 ;

  70 end

  71 else if( rx_int ) begin //

  72 if( clk_bps ) begin

  // , 8bit 1 2

  73 num <= num+1'b1 ;

  74 case ( num)

  75 4'd1:rx_temp_data[0] <= rs232_rx; // 0bit

  76 4'd2:rx_temp_data [1] <= rs232_rx; // 1bit

  77 4'd3:rx_temp_data [2] <= rs232_rx; // 2bit

  78 4'd4:rx_temp_data [3] <= rs232_rx; // 3bit

  79 4'd5:rx_temp_data [4] <= rs232_rx; // 4bit

  80 4'd6:rx_temp_data [5] <= rs232_rx; // 5bit

  81 4'd7:rx_temp_data [6] <= rs232_rx; // 6bit

  82 4'd8:rx_temp_data [7] <= rs232_rx; // 7bit

  83 default : ;

  84 endcase

  85 end

  86 else if( num == 4'd12 ) begin

  // 1+8+1(2)=11bit

  87 num <= 4'd0 ; // STOP ,num

  88 rx_data_r <= rx_temp_data ; // rx_data

  89 end

  90 end

  91

  92 assign rx_data = rx_data_r ;

  93

  94 endmodule

  第19行到第36行为起始位检测部分,19到32行,实现了对rs232_rx端口上电平的连续四个时钟周期的寄存,第36行则对这连续4个时钟上升沿时的rs232_rx端口电平进行逻辑操作,得出rs232_rx端口信号下降沿的到来。neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0,即后两次寄存的状态为低电平而前两次寄存的装填为高电平,则表明该端口上的信号发生了1->0的跳变,即有下降沿出现。neg_rs232_rx信号会产生一个周期的高脉冲。

  第43行至第55行则根据neg_rs232_rx和num计数值来控制串口接收波特率发生器的工作和接收中断信号。第65行至第90行则采用线性序列机的设计方式,进行一个字节的数据的接收。

  以上为对串口接收模块的一个简单分析,接下来,再进行串口发送模块的分析。

  1 module my_uart_tx (

  2 clk, rst_n ,

  3 rx_data , rx_int , rs232_tx ,

  4 clk_bps , bps_start

  5 );

  6

  7 input clk; // 50MHz

  8 input rst_n ; //

  9 input clk_bps ; // clk_bps_r ,

  10 input [ 7 : 0] rx_data ; //

  11 input rx_int ;

  12 output rs232_tx ; // RS232

  13 output bps_start ; //

  14

  15 //---------------------------------------------------------

  16 reg rx_int0 , rx_int1 , rx_int2 ; //rx_int

  17 wire neg_rx_int ; // rx_int

  18

  19 always @ ( posedge clk or negedge rst_n ) begin

  20 if(! rst_n ) begin

  21 rx_int0 <= 1'b0 ;

  22 rx_int1 <= 1'b0 ;

  23 rx_int2 <= 1'b0 ;

  24 end

  25 else begin

  26 rx_int0 <= rx_int ;

  27 rx_int1 <= rx_int0 ;

  28 rx_int2 <= rx_int1 ;

  29 end

  30 end

  31

  32 assign neg_rx_int = ~rx_int1 & rx_int2 ; // neg_rx_int

  33

  34 //---------------------------------------------------------

  35 reg[ 7 : 0] tx_data ; //

  36 //---------------------------------------------------------

  37 reg bps_start_r ;

  38 reg tx_en ; //

  39 reg[ 3: 0] num;

  40

  41 always @ ( posedge clk or negedge rst_n ) begin

  42 if(! rst_n ) begin

  43 bps_start_r <= 1'bz ;

  44 tx_en <= 1'b0 ;

  45 tx_data <= 8'd0 ;

  46 end

  47 else if( neg_rx_int ) begin //

  48 bps_start_r <= 1'b1 ;

  49 tx_data <= rx_data ; //

  50 tx_en <= 1'b1 ; //

  51 end

  52 else if( num==4'd11 ) begin //

  53 bps_start_r <= 1'b0 ;

  54 tx_en <= 1'b0 ;

  55 end

  56 end

  57

  58 assign bps_start = bps_start_r ;

  59

  60 //---------------------------------------------------------

  61 reg rs232_tx_r ;

  62

  63 always @ ( posedge clk or negedge rst_n ) begin

  64 if(! rst_n ) begin

  65 num <= 4'd0 ;

  66 rs232_tx_r <= 1'b1 ;

  67 end

  68 else if( tx_en ) begin

  69 if( clk_bps ) begin

  70 num <= num+1'b1 ;

  71 case ( num)

  72 4'd0 : rs232_tx_r <= 1'b0 ; //

  73 4'd1 : rs232_tx_r <= tx_data [0]; // bit0

  74 4'd2 : rs232_tx_r <= tx_data [1]; // bit1

  75 4'd3 : rs232_tx_r <= tx_data [2];// bit2

  76 4'd4 : rs232_tx_r <= tx_data [3]; // bit3

  77 4'd5 : rs232_tx_r <= tx_data [4];// bit4

  78 4'd6 : rs232_tx_r <= tx_data [5]; // bit5

  79 4'd7 : rs232_tx_r <= tx_data [6]; // bit6

  80 4'd8 : rs232_tx_r <= tx_data [7]; // bit7

  81 4'd9 : rs232_tx_r <= 1'b1 ; //

  82 default : rs232_tx_r <= 1'b1 ;

  83 endcase

  84 end

  85 else if( num==4'd11 ) num <= 4'd0 ; //

  86 end

  87 end

  88

  89 assign rs232_tx = rs232_tx_r ;

  90

  91 endmodule

  代码19行到30行对串口接收模块的接收中断信号进行了3次寄存,第32行则通过对连续两次寄存结果的判断,来检测接收中断信号rx_int的下降沿。如果有下降沿到来,neg_rx_int信号则会产生一个时钟周期的高脉冲信号,第47行则通过对该信号的状态判断,来确定是否启动发送波特率发生器模块。如果检测到了该高脉冲,则使能串口发送(tx_en <= 1'b1),同时将待发送的字节数据(rx_data)寄存到发送寄存器(tx_data)中。第52行,即计数到11后,表明一个字节的数据发送完成,此时停止发送波特率发生器的工作,同时禁止发送模块的工作(tx_en <= 1'b0),即完成一个字节的数据的发送。

  第63行至第87行采用线性序列机设计方式,实现一个字节(自动添加起始位和停止位)的发送操作。

  以上就是对特权同学的串口代码的一个简单分析,顶层模块就只进行了一个简单的例化和连线作用,因此小梅哥就不做分析了。小梅哥个人能力有限,可能存在理解不到位或者表述不专业的地方,不妥之处还望各位多多指出,以促进共同学习。可以说,相对于淘宝网上漫天飞舞的开发板和五花八门的串口例程,特权同学的设计代码相当规范,架构合理,思路清楚,确实是值得我们每一个爱好者学习。

 



关键词: FPGA 串口调试

评论


相关推荐

技术专区

关闭