FPGA串口发送学习

波特率技术举例:

 

1.串口发送原理:

 设计框图

时序图:bps_clk为波特率时钟

串口发送模块代码:

//时钟频率是50Mhz,也就是周期是20ns
module uart_byte_tx(
    input [7:0] Data, //将要发送的数据
    input En, //发送数据的使能信号
    input clk, //系统时钟
    input rst,  //复位信号
    input [2:0] Baud_set, //8种波特率模式 
    output reg uart_tx, //发送后接受到的串行数据 起始位+数据+停止位
    output reg Tx_Done  //数据发送完成的标志 
    );
reg [17:0] cnt; // 用来分频得到波特率时钟
reg [17:0] Baud; //Baud由Bund_set决定,用来控制波特率  
reg [3:0] counter_1; //对发送的第几位数据进行计数
wire [9:0] data_last;//加上起始位和停止位的数据
assign data_last = {1'd1,Data,1'd0};

//Baud
always@(Baud_set)
case(Baud_set)
    3'd0:Baud=18'd166666;//波特率为300
    3'd1:Baud=18'd41666;//波特率为1200
    3'd2:Baud=18'd20833;//波特率为2400
    3'd3:Baud=18'd5208;//波特率为9600
    3'd4:Baud=18'd2604;//波特率为19200
    3'd5:Baud=18'd1302;//波特率为38400
    3'd6:Baud=18'd868;//波特率为57600
    3'd7:Baud=18'd434;//波特率为115200
endcase 
//波特率分频
always@(posedge clk or negedge rst)  
    if(!rst) cnt <=0; 
    else if(En==1)
    begin
     if (cnt==Baud-1) cnt<=0;
     else cnt<=cnt +1;
    end
    else cnt <=0;   
//always@(posedge clk or negedge rst)  
//    if(!rst) Baud_clk <=0; 
//    else if (cnt==Baud/2-1) Baud_clk<=!Baud_clk;
//    else if (cnt==Baud-1) Baud_clk<=!Baud_clk;
//    else Baud_clk<=Baud_clk ;    

//对发送的数据进行计数
always@(posedge clk or negedge rst)  
    if(!rst) counter_1<=0;
    else if(En==1)
    begin
     if(cnt==Baud-1&&cnt==Baud-1)
        begin
            if(counter_1==9) counter_1<=0;
            else  counter_1<=counter_1+1;
         end
     else counter_1<=counter_1;
     end
     else counter_1<=0; 
//控制Tx_Done        
always@(posedge clk or negedge rst)  
     if(!rst) Tx_Done<=0;
     else if(counter_1==9&&cnt==Baud-1)  Tx_Done<=1;
     else Tx_Done<=0;
//发送数据
always@(posedge clk or negedge rst) 
    if(!rst) begin uart_tx<=1;end
    else if(En==1&&Tx_Done==0) 
        begin
            if(counter_1==9) uart_tx<=1;
            else 
             uart_tx<=data_last[counter_1];
        end
    else
         uart_tx<=1;  
endmodule  

2.完成5个字节的数据发送

因为串口通信协议只能完成8位比特的发送(8bit=1byte),因此发送5个字节的数据需要将5个字节的数据拆分成一个字节一个字节来依次发送。即最先发送[7:0]位,然后发送[15:8]位,直至发送至[39:32]位。

多个 字节发送的模块图:

       

采用状态机的思想来设计多个字节的发送:

     状态0:此时没有接收到发送数据请求信号,该模块处于空闲状态

     状态1:该模块接收到发送数据请求信号(Trans_Go),开始发送数据的第一个字节,第一个字节发送完成后,转移到状态2

     状态2:发送数据[15:8]

     状态3:发送数据[23:16]

    状态4:发送数据[31:24]

    状态5:发送数据[39:32],发送完数据的最后一个字节后,回到零状态,等待数据请求信号(Trans_Go)的来临。

源文件

//采用状态机的思想发送5个字节的数据
//

module top_2(
    input clk,
    input Trans_Go,  //请求发送
    input [39:0] Send_Data,
    input rst,
    output reg Done,  //5个字节发送完成
    output uart_tx
    );

reg [7:0] Data;
reg En;
wire Tx_Done;
reg [2:0] state;

 //例化串口模块
  uart_byte_tx  uart_nux_byte_Inst (
            .Data(Data),
            .En(En),
            .clk(clk),
            .rst(rst),
            .Baud_set(3'd7),
            .uart_tx(uart_tx),
            .Tx_Done(Tx_Done)
            );  
//开始状态转移
            
always@(posedge clk or negedge rst)
    if(!rst) 
        begin 
            Done<=0;
            state<=0;
            Data<=0;
            En<=0;
        end
    else if(state==0)
        begin
          if(Trans_Go) begin 
                        if(Tx_Done) state<=3'd1;
                        else begin En<=1;Data<=Send_Data[7:0]; end
                        end
          else begin state<=state;Data<=0;En<=0; Done<=0;end
        end
    else if(state==3'd1)
        begin
            if(Tx_Done) state<=3'd2;
            else begin
                En<=1;
                Data<=Send_Data[15:8];
                end         
        end
     else if(state==3'd2)
        begin
            if(Tx_Done) state<=3'd3;
            else begin
                En<=1;
                Data<=Send_Data[23:16];
                end
       end      
      else if(state==3'd3)
        begin
            if(Tx_Done) state<=3'd4;
            else begin
                En<=1;
                Data<=Send_Data[31:24];
                end         
        end
        else if(state==3'd4)
        begin
            if(Tx_Done) begin state<=3'd0;Done<=1;En=0;end
            else begin
                En<=1;
                Data<=Send_Data[39:32];
                end         
        end
endmodule

   激励文件

module top_2_test();
   reg clk;
   reg Trans_Go;  //请求发送
   reg rst;
   reg [39:0] Send_Data;
   wire Done;  //5个字节发送完成
   wire uart_tx;
top_2 top_2_test(
    .clk(clk),
    .Trans_Go(Trans_Go),
    .Send_Data(Send_Data),
    .rst(rst),
    . Done(Done),
    .uart_tx(uart_tx)
);

initial
    begin 
    Send_Data = 40'h0;
    Trans_Go=0;
      clk=1;
      rst=0; 
      #10000 rst=1;
      Send_Data = 40'h1234567899;
      #5000 Trans_Go=1;
      @(posedge Done)
     Trans_Go=0;
      #10000
      Send_Data= 40'h1187654321;
      Trans_Go=1;   
      @(posedge Done)
       Trans_Go=0;
end   
always #10 clk=~clk;
endmodule

代码优化:采用2个或者3个状态机发送数据,并且容易修改成发送任意字节的数据。

 状态1:空闲状态,没有发送数据,当数据请求信号Trans_Go来临时,转为状态1 

 状态2:正在发送数据

源文件

//采用2个或者3个状态机实现任意字节数据的发送
//
module top_3(
    clk,
    Trans_Go,  //请求发送
    Send_Data, //最多能发送20个字节的数据
    rst,
    Done,  //5个字节发送完成
    uart_tx
    );
    
parameter Num_Byte  = 7; //发送数据的字节数 
parameter Num_bit = Num_Byte*8;  //发送数据的位数
input [Num_bit-1:0] Send_Data;
input clk;
input Trans_Go; //请求发送
input rst;
output reg Done;  //数据发送完成
output uart_tx;

reg [0:1] state; //状态
reg [Num_bit-1:0] Data_1; 
reg [2:0] counter_byte; //对发送的字节数进行计数

reg [7:0] Data;
reg En;
wire Tx_Done;
 
uart_byte_tx  uart_nux_byte_Inst (
            .Data(Data),
            .En(En),
            .clk(clk),
            .rst(rst),
            .Baud_set(3'd7),
            .uart_tx(uart_tx),
            .Tx_Done(Tx_Done)
            );  

always@(posedge clk or negedge rst)
    if(!rst) begin state<=0;Done<=0;Data<=0;En<=0;Data_1<=0;counter_byte <= 0;end
    else if(state==0)
     begin
        if(Trans_Go==1&&Done==0) begin state<=1;Data_1<=Send_Data;end
        else begin
            Data_1<=0;
            state<=0;
            Done<=0;
            Data<=0;
            En<=0;
            counter_byte <= 0;
            end       
     end
     else if(state==1)
       begin
        if(Tx_Done)
            begin
                     if(counter_byte==Num_Byte-1) begin state<=0; Done<=1;En<=0;counter_byte<=0;end
                     else 
                        begin
                            counter_byte <= counter_byte+1;
                            Data_1 <={Data_1[7:0],Data_1[Num_bit-1:8]};
                            Data <=Data_1[7:0];
                            Done<=0;
                         end
            end    
         else if(!Tx_Done)
          begin
            Data <=Data_1[7:0];
            En<=1;
            Done<=0;
            end      
       end  
endmodule

激励文件

module top_3_test();
parameter Num_Byte  = 7;
parameter Num_bit = Num_Byte*8;
   reg clk;
   reg Trans_Go;  //请求发送
   reg rst;
   reg [Num_bit-1:0] Send_Data;
   wire Done;  //5个字节发送完成
   wire uart_tx;
top_3 top_3_test(
    .clk(clk),
    .Trans_Go(Trans_Go),
    .Send_Data(Send_Data),
    .rst(rst),
    . Done(Done),
    .uart_tx(uart_tx)
);

initial
    begin 
    Send_Data = 56'h0;
    Trans_Go=0;
      clk=1;
      rst=0; 
      #10000 rst=1;
      Send_Data = 56'h12345678991234;
      #5000 Trans_Go=1;
      @(posedge Done)
     Trans_Go=0;
      #10000
      Send_Data= 56'h11876543214321;
      Trans_Go=1;   
      @(posedge Done)
       Trans_Go=0;
end   
always #10 clk=~clk;
endmodule

板级测试文件,实现1分钟发送一个数据

//多个字节发送板级测试文件
//

module top4(
    input clk,
    input rst,
    output uart_tx
    );
    
//例化
wire Done;
reg Trans_Go;
parameter Num_Byte = 7;
parameter Num_bit =Num_Byte*8;
reg [Num_bit-1:0] Send_Data;
reg [Num_bit-1:0] Data_chuzhi=56'h1234567891234;

top_3 top_3_Inst(
    .clk(clk),
    .rst(rst),
    .Send_Data(Send_Data),
    .Trans_Go(Trans_Go),
    .Done(Done),
    .uart_tx(uart_tx)
    );
//10ms计数
parameter MCNT = 33'd3000000000;// 2s计数值   
reg [32:0] counter_10ms;
always@(posedge clk or negedge rst)  
    if(!rst) counter_10ms<=0;
    else if(counter_10ms==MCNT-1)  counter_10ms<=0;
    else counter_10ms<=counter_10ms+1;
    
//每隔10ms发送一个数据
always@(posedge clk or negedge rst)  
    if(!rst)  Trans_Go<=0;
    else if(counter_10ms==1) Trans_Go<=1;
    else if(Done) Trans_Go<=0;
    else Trans_Go<=Trans_Go; 
 
//对发送的数据加1 
 always@(posedge clk or negedge rst) 
    if(!rst) Send_Data<=Data_chuzhi; 
    else if(Done)   Send_Data<=Send_Data+1;
    else Send_Data<=Send_Data;          
endmodule

测试成功

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值