关于《深入浅出教你玩转FPGA…

来源:互联网 发布:酷派手机移动数据开关 编辑:程序博客网 时间:2024/06/06 02:00
原文地址:关于《深入浅出教你玩转FPGA》中串口发送的verilog源代码分析作者:SUN_403

[转载]关于《深入浅出教你玩转FPGA》中串口发送的verilog源代码分析

1:num==11只维持一个clk时钟周期。

2:en拉低和num清零是同时的,因为在clk上升沿来之前的那一顺时,en=1,num=11,互相满足要求。

3: req相对en上升沿延迟了一拍,因为采用了边沿提取,相当与加了一个一个D锁存器。

//tx_en脉冲上升沿检测,作为FIFO读使能信号
reg tx_enr1,tx_enr2; //tx_en寄存器
always @(posedge clk or negedge rst_n)
 if(!rst_n) begin
   tx_enr1<= 1'b1;
   tx_enr2<= 1'b1;
  end
 else begin
   tx_enr1<= tx_en;
   tx_enr2<= tx_enr1;
  end

assign fifo232_rdreq = tx_enr1 &~tx_enr2; //tx_en上升沿置高一个时钟周期

4:en也维持一个clk低脉冲时间。

5:数据产生即发生变化,一定要在前一个字符发送完和当前发送字符开始之间的那段高电平之间。

6:一帧发送消耗了10.5个波特率时间+一个clk时钟周期。 

 

发送模块源代码

`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company  :
// Engineer  : 特权franchises3
// Create Date : 2009.05.04
// Design Name :
// Module Name : uart_tx
// Project Name : sdrsvgaprj
// Target Device: Cyclone EP1C3T144C8
// Tool versions: Quartus II 8.1
// Description : 串口数据发送底层模块
//     1bit起始位+8bit数据+1bit停止位
// Revision  : V1.0
// Additional Comments 
//
////////////////////////////////////////////////////////////////////////////////
module  uart_tx(
    clk,rst_n,
    tx_data,tx_start,clk_bps,
    rs232_tx,bps_start,fifo232_rdreq
   );

inputclk;   //25MHz主时钟
input rst_n;  //低电平复位信号
input[7:0] tx_data; //待发送数据
inputtx_start;  //串口发送数据启动标志位,高有效
input clk_bps;  //发送数据标志位,高有效

output rs232_tx; // RS232发送数据信号
output bps_start; //波特率时钟计数器启动信号,高有效
output fifo232_rdreq; //FIFO读请求信号,高有效

//---------------------------------------------------------
regtx_en;   //发送数据使能信号,高有效
reg[3:0] num;

always @ (posedge clk or negedge rst_n)
 if(!rst_n) tx_en <= 1'b0;
 else if(num==4'd11) tx_en <=1'b0; //数据发送完成   
 else if(tx_start) tx_en <=1'b1; //进入发送数据状态中

assign bps_start = tx_en;

//tx_en脉冲上升沿检测,作为FIFO读使能信号
reg tx_enr1,tx_enr2; //tx_en寄存器
always @(posedge clk or negedge rst_n)
 if(!rst_n) begin
   tx_enr1<= 1'b1;
   tx_enr2<= 1'b1;
  end
 else begin
   tx_enr1<= tx_en;
   tx_enr2<= tx_enr1;
  end

assign fifo232_rdreq = tx_enr1 &~tx_enr2; //tx_en上升沿置高一个时钟周期

//---------------------------------------------------------
reg rs232_tx_r;  //RS232发送数据信号

always @ (posedge clk or negedge rst_n)
 if(!rst_n) begin
   num<= 4'd0;
   rs232_tx_r<= 1'b1;
  end
 else if(tx_en) begin
   if(clk_bps) begin
     num<= num+1'b1;
     case(num)
      4'd0:rs232_tx_r <= 1'b0;  //发送起始位
      4'd1:rs232_tx_r <=tx_data[0]; //发送bit0
      4'd2:rs232_tx_r <=tx_data[1]; //发送bit1
      4'd3:rs232_tx_r <=tx_data[2]; //发送bit2
      4'd4:rs232_tx_r <=tx_data[3]; //发送bit3
      4'd5:rs232_tx_r <=tx_data[4]; //发送bit4
      4'd6:rs232_tx_r <=tx_data[5]; //发送bit5
      4'd7:rs232_tx_r <=tx_data[6]; //发送bit6
      4'd8:rs232_tx_r <=tx_data[7]; //发送bit7
      4'd9:rs232_tx_r <= 1'b1; //发送结束位
      default: rs232_tx_r <= 1'b1;
      endcase
    end
   elseif(num==4'd11) num <=4'd0; //复位,实际发送一个数据时间为10.5个波特率时钟周期
  end

assign rs232_tx = rs232_tx_r;

 

endmodule
波特率产生模块

`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company  :
// Engineer  : 特权franchises3
// Create Date : 2009.05.04
// Design Name :
// Module Name : uart_speed_select
// Project Name : sdrsvgaprj
// Target Device: Cyclone EP1C3T144C8
// Tool versions: Quartus II 8.1
// Description : 串口数据发送波特率控制模块
//    
// Revision  : V1.0
// Additional Comments 
//
////////////////////////////////////////////////////////////////////////////////
module uart_speed_select(
    clk,rst_n,
    bps_start,clk_bps
   );

inputclk;   //25MHz时钟
input rst_n;  //低电平复位信号
input bps_start; //波特率时钟计数器启动信号,高有效
outputclk_bps;  //发送数据标志位,高有效

 //以下波特率分频计数值可参照上面的参数进行更改
`define  BPS_PARA  15 //波特率为9600时的分频计数值
`define BPS_PARA_2   //波特率为9600时的分频计数值的一半,用于数据采样

//----------------------------------------------------------
//----------------------------------------------------------
reg[3:0]cnt;   //分频计数器
regclk_bps_r;   //波特率数据改变标志位
// reg[2:0] uart_ctrl;  //uart波特率选择寄存器


always @ (posedge clk or negedge rst_n)
 if(!rst_n) cnt <= 4'd0;
 else if(cnt == `BPS_PARA) cnt <=4'd0; //波特率计数溢出后清零
 else if(bps_start) cnt <=cnt+1'b1;  //波特率时钟计数启动
 else cnt <=4'd0;  //波特率计数停止

always @ (posedge clk or negedge rst_n)
 if(!rst_n) clk_bps_r <=1'b0;
 else if(cnt == `BPS_PARA_2) clk_bps_r<= 1'b1; //clk_bps_r高电平作为发送数据的数据改变点
 else clk_bps_r <= 1'b0;

assign clk_bps = clk_bps_r;

endmodule

数据产生模块

module datagene(clk,rst_n,fifo232_rdreq,tx_data);
input clk;
input rst_n;
input fifo232_rdreq;
output reg [7:0] tx_data;
always@(posedg clk,negedge rst_n)
begin
    if(!rst_n)
     tx_data<=8'd6;
  else if(fifo232_rdreq)
        tx_data<=tx_data+1'b1; 
end
endmodule

数据从7开始发送。

 

 

 

 

 

0 0