微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > 大神帮帮忙啊

大神帮帮忙啊

时间:10-02 整理:3721RD 点击:
我写了一个FPGA串口代码和单片机进行通信,可是数据老是不稳定,会出错不知道是哪里的问题,仿真没有问题。
接收部分代码:module jieshou(clk,rst,rxd,rxdata,rxflag);
        input clk;//系统时钟
        input rst;//全局复位高电平复位
        input  rxd;//UART接收信号
        output rxflag;
        reg rxflag;//接收完一个字节标志位
        output [7:0]rxdata;//接受数据
        reg rec1;//检测下降沿
   reg rec2;
       
        wire rec3;//接收信号下降沿
       
        reg rena;//内部接收使能信号
        reg clk_top;//波特率57600时钟
        reg [3:0]cout;
        reg[9:0]dout;//接收数据寄存器
        reg [9:0]cnt_bote;//分频计数器
       
        //reg [9:0]count;
       
        assign rxdata=dout[8:1];//最终数据输出
///////////////////分频模块/////////////////只产生一个时钟的高电平
always @(posedge clk or posedge rst)begin
        if(rst)begin        
       
                cnt_bote<=10'd0;       
                clk_top<=1'b0;
               
        end
        else if(cnt_bote == 10'd867)begin//57600分频数
       
                  clk_top<=1'b1;       
                cnt_bote<=10'd0;       
               
   end
               
        else begin         
       
                clk_top<=1'b0;               
                cnt_bote<=cnt_bote+1'b1;
               
        end
       
end

/*always @(posedge clk or posedge rst)
begin
     if(rst)
      count<=10'd0;
     else  begin
           if((~rxd)&&(cout==0)) count<=count+1'b1;
         else count<=10'd0;
         end
end */
//////////////////////////下降沿检测////////////
always@(posedge clk or posedge rst)begin
        if(rst)
        begin
       
                rec1 <= 1'b1;
                rec2 <= 1'b1;
        end
       
        else begin
       
                rec1 <= rxd;
                rec2 <= rec1;
               
        end
       
end
assign rec3 = !rec1 & rec2;
/////////////////内部接收使能信号////////////
always@(posedge clk or posedge rst)begin
        if(rst)
                rena <= 1'b0;
        else if(rec3)//下降沿到来
                rena <= 1'b1;
                else if(cout == 4'd10)//接受完一个字节接收使能信号复位
                rena <= 1'b0;
        else
                rena <= rena;
               
end
/////////////////////接收完毕信号/////////////////
always@(posedge clk or posedge rst)begin
        if(rst)
                rxflag <= 1'b0;
        else if(cout == 4'd10)//接受完一个字节,将接收完毕标志位置1两个周期
                rxflag <= 1'b1;
        else
                rxflag <= 1'b0;
end
//////////////////////////////////////接收主程序部分/////////////
always @(posedge clk or posedge rst)
   begin        
        if(rst)
          begin //复位信号       
       
                dout<=10'dz;
                                       
          end
               
        else if((rena==1) & (clk_top==1))begin//检测到下降沿到来且波特率时钟为高电平
            
                case(cout)
               
                        4'd0:                   dout[0]<=rxd;//起始位       
                       
                        4'd1:              dout[1]<=rxd;//最低位
                       
                        4'd2:                   dout[2]<=rxd;  
                       
                        4'd3:                        dout[3]<=rxd;       
                       
                        4'd4:                        dout[4]<=rxd;       
                       
                        4'd5:                        dout[5]<=rxd;       
                       
                        4'd6:                        dout[6]<=rxd;       
                       
                        4'd7:                        dout[7]<=rxd;       
                       
                        4'd8:                        dout[8]<=rxd;//最高位
                       
                        4'd9:                  dout[9]<=rxd; //停止位1
                  4'd10:      ;         
                 //rec1<=1'b1;
                 //rec2<=1'b1;
                      //dout<=10'dz;
                        default:;
                       
                endcase
               
        end        
       
end
//////////////////接收逻辑计数部分////////////
always @(posedge clk or posedge rst)begin  
        if(rst)
                cout<=4'd0;//计数器清0
        else if(rena && clk_top)//接收计数器计数
                cout<=cout+4'd1;       
        else if(!rena)               
                cout<=4'd0;
        else                
                cout <= cout;       
               
end
endmodule
发送部分代码:module FS_module(clk,rst,txd,txdata,txflag,txbsy,txcom);
        input clk,rst,txflag;//系统时钟,全局复位高电平复位,发送启动信号
        input [7:0]txdata;//将要发送的数据
        output txcom;//发送完毕信号
        output txd,txbsy;//UART发送信号,发送忙信号
        reg [9:0]txcnt;
        reg txd;
       
        reg rena;//发送使能信号
        reg txClk;//分频时钟波特率57600
        reg txcom;//发送完一个字节
        reg [3:0]txstate;
        reg txbsy;//发送忙
        parameter S0=4'd0;
        parameter S1=4'd1;
        parameter S2=4'd2;
        parameter S3=4'd3;
        parameter S4=4'd4;
        parameter S5=4'd5;
        parameter S6=4'd6;
        parameter S7=4'd7;
        parameter S8=4'd8;
        parameter S9=4'd9;
        parameter S10=4'd10;

        ///////////////////分频模块/////////////////
       
always @(posedge clk or posedge rst)begin
        if(rst)begin
                txcnt<=10'd0;//分频计数器       
               
                txClk<=1'b0;
        end
        else if(txcnt==868)begin //57600波特率
                txClk<=1'b1;//产生一个周期的高电平
                txcnt<=0;
        end
        else
      begin
               
                txClk<=1'b0;
                txcnt<=txcnt+1'b1;
               
                end
end
       
///////////////发送忙信号/////////////////
always@(posedge clk or posedge rst)begin
        if(rst)
       
                txbsy <= 1'b0;
               
        else if(txflag)//当发送信号拉高发送忙标志拉高
       
                txbsy <= 1'b1;
               
        else if(txstate == S0 && !rena)//当发送完毕发送忙标志拉低
       
                txbsy <= 1'b0;
               
        else
       
                txbsy <= txbsy;
               
end
       
///////////////发送使能信号/////////////
always@(posedge clk or posedge rst)begin
        if(rst)
       
                rena <= 1'b0;
               
        else if(txflag)
       
                rena <= 1'b1;
               
        else if(txstate == S1)//起始位发送就复位使能信号
       
                rena <= 1'b0;
               
        else
       
                rena <= rena;
               
end       
////////////////////////////发送数据//////////////////////
always @(posedge clk or posedge rst)begin //
        if(rst)begin
       
                txd<=1'b1;//让TXD为高电平
                txstate<=S0;//状态机指向
                //txbsy<=1'b0;//发送忙清0       
                txcom<=1'b0;//发送完毕复位       
               
        end
               
        else if(txClk)begin
            
                txcom<=1'b0; //发送完毕复位       
               
           case (txstate)
       
                        S0: begin //初始状态,检测发送标志位
                       
                                if (rena)begin//发送使能信号                                          
                                        txstate<=S1;
                                       
                                  end
                                  
                                else
                                        txstate<=S0;  
                                       
                           end
                          
                        S1:begin //起始位发送
                       
                                txd<=1'b0;//起始位               
                                txstate<=S2;
                               
                           end
                               
                        S2:begin
                       
                                txd<=txdata[0];//最低位
                                txstate<=S3;
                               
                           end
                                  
                               
                        S3:begin
                       
                                txd<=txdata[1];//2
            txstate<=S4;
                               
                           end
                       
                        S4:begin
                       
                                txd<=txdata[2];//3
                                txstate<=S5;
                               
                           end
                               
                        S5:begin
                       
                                txd<=txdata[3];//4
                                txstate<=S6;
                               
                           end
                               
                        S6:begin
                       
                                txd<=txdata[4];//5     
                                txstate<=S7;
                               
                           end
                               
                        S7:begin
                                txd<=txdata[5];//6  
            txstate<=S8;
                           end
                                       
                        S8:begin
                       
                                txd<=txdata[6];//7
            txstate<=S9;
                               
                           end
                               
                        S9:begin
                       
                                txd<=txdata[7];//最高位
                                txstate<=S10;
                               
                           end
                               
                        S10:begin
                       
                                txd<=1'b1; //停止位
                                //txbsy<=1'b0;//发送忙清0等待下次发送
                                txcom<=1'b1;//发送完一字节数据       
                                txstate<=S0;
                               
                            end
                       
                        default :;
                       
                endcase
               
        end
end
endmodule
                 
顶层模块代码:module top_tb(
              Clk,TXrst,RXD,TXD,RXdata,
              //pane_data_out,
                                  pane_cmd_en,
                                 // pane_cmd_ack,pane_rd_ack,
                                 // pane_data_in,pane_addr_in,
                                 // pane_cmd_out,pane_addr_out
                                  );
   input Clk;//全局时钟
   input TXrst;//全局复位高电平有效
       
        //input [7:0]pane_data_in;
       
        //input [15:0]pane_addr_in;
       
        //input pane_rd_ack;
       
        //input pane_cmd_ack;
       
   reg [7:0] TXdata;//要发送的数据寄存器
   output [7:0]RXdata;//接收数据输出
       
        //output [7:0]pane_cmd_out;
       
        //output[15:0]pane_addr_out;
       
        //output[7:0]pane_data_out;
       
        output pane_cmd_en;
   input RXD;
   output TXD;
   reg TXflag;//发送启动信号
   reg [3:0] TXstate;//发送状态
   wire TXbsy;//发送忙
       
        reg [7:0] pane_cmd_out;
       
        reg [7:0] pane_cmd;
       
        reg [7:0] pane_cmd0;
       
        reg [7:0] pane_cmd1;
       
        reg [7:0] pane_cmd2;
       
        reg [7:0] pane_cmd3;
       
        reg [7:0] pane_data_out;
       
        wire [15:0]pane_addr_out;
       
        reg [7:0] value;
       
        reg pane_cmd_en;
       
        reg pane_cmd_ack;
       
        reg pane_rd_ack;
       
        //reg[7:0] value1;
       
   parameter s0=4'd0;
   parameter s1=4'd1;
   parameter s2=4'd2;
   parameter s3=4'd3;
   parameter s4=4'd4;
   parameter s5=4'd5;
//这里设置初始值,否则调试会是不定态/////////
   reg [7:0] txone = 8'h5a;
   reg [7:0] txtwo = 8'h11;
   reg [7:0] txthree = 8'h40;
   reg [7:0] txfour = 8'h0b;
   reg [7:0] txfive = 8'hfc;
   reg [7:0] txsix = 8'h00;
   reg [7:0] txseven = 8'hc3;
   reg[2:0] TXcnt;//发送计数器
   wire  RXflag;//接收完一字节数据
   parameter x0=4'd0;
   parameter x1=4'd1;
   parameter x2=4'd2;
   parameter x3=4'd3;
   reg [2:0]RXcnt;//接受计数器
   reg [3:0]RXstate;
       
        assign  pane_addr_out={pane_cmd,pane_cmd1};
FS_module         U1(
              .clk(Clk),
                                  
                                  .txdata(TXdata),
                                  
                                  .txflag(TXflag),
                                  
                                  .txd(TXD),
                                  
                                  .rst(TXrst),
                                  
                                  .txbsy(TXbsy)                  
                                  );       
///////////////////////////////////////////
/////////////////发送主程序////////////////
always @(posedge Clk or posedge TXrst) begin
if(TXrst)begin
         TXstate<=s0;//给初值
         TXflag<=1'b0;//复位清0
         TXcnt<=3'd0;//复位清0
         
               end
  else  begin
          case (TXstate)
          s0:begin
          
           if((pane_cmd_ack==1'b1)&&(pane_rd_ack==1'b1))//接收7个字节数据完成,开始发送
               begin
                         
                TXstate<=s1;
                          
                    end  
           else begin
                    
                          TXstate<=s0;//否则继续等待
                          
                     end
                 end
          s1:
             begin
                    TXflag<=1'b0;//将发送启动标志位清0
                    if(TXbsy==1'b0)begin//判断一字节数据是不是发送完成,完成就让计数器加1.
                        
                         TXcnt<=TXcnt+1'b1;
                    TXstate<=s2;
                                       
                       end
                                 
                   end
          s2:
            begin
                 
                  TXstate<=s3;
                  
             case(TXcnt)
                  
            3'd1: TXdata<=txone;//需要发送的字节
                 
                 3'd2: TXdata<=pane_cmd_out;//读写命令
                 
                 3'd3: TXdata<=pane_cmd;//地址高八位
                 
                 3'd4: TXdata<=pane_cmd1;//地址低八位
                 
                 3'd5: TXdata<=pane_data_out;//数据位
                 
                 3'd6: TXdata<=txsix;//预留位
                 
                 3'd7: begin
                       TXdata<=(txone+pane_cmd+pane_cmd1+pane_data_out+txsix+pane_cmd_out);
                       //TXdata<=value1;//发送校验和
                                 end
                 
                 default:TXcnt<=3'd1;
          endcase
                  
                 end
         s3:
            begin
                 
                    TXflag<=1'b1;
               TXstate<=s4;
                         
            end
                 
        s4:
     begin
          
             if(TXcnt == 3'd7)begin//判断发送完七个字节
                  
                  TXstate<=s5; end
                 
                  
                  else
                  
                  TXstate<=s1;
                  
         end          
                 
        s5:
            begin
                 
              TXcnt<=3'd0;//发送完成计数器清0
              TXstate<=s0;//发送完成状态机指向最初状态,等待下次发送
                        TXflag<=1'b0;//发送启动标志清0
                       
                 end   
                 
                default:
               
                begin TXstate<=s0; end
               
           endcase        
  end
end
/////////////////////调用接收部分///////////////////
//////////////////////////////////////////////////
jieshou U2(
        .clk(Clk),
       
        .rst(TXrst),
       
        .rxd(RXD),
       
        .rxdata(RXdata),
       
        .rxflag(RXflag)
);
/////////////接收主程序//////////////////////////
//////////////////两个开始发送标志位/////////////
always @(posedge Clk or posedge TXrst)begin
if(TXrst)begin
    pane_cmd_ack<=1'b0;
         pane_rd_ack<=1'b0;
               end
             
else if ((RXcnt==3'd7)&&(pane_cmd_en==1'b1)&&(pane_cmd_out==8'h11))//接收完7字节数据,第二字节为11,接收数据正确则让置1
   begin
    pane_cmd_ack<=1'b1;
         pane_rd_ack<=1'b1;       
         end
  else begin
    pane_cmd_ack<=1'b0;
         pane_rd_ack<=1'b0;end
          
end
always @(posedge Clk or posedge TXrst)
begin if(TXrst)
      pane_cmd_en<=1'b0;
               
else if(value==pane_cmd3)//接收的前六个字节之和是不是等于第七个字节
                                          
                 begin
                                                  
                pane_cmd_en<=1'b1;//第7个字节等于前面六个字节之和将pane_cmd_en拉高
                                                  
                        end
        else
                        pane_cmd_en<=1'b0;//不等则不拉高pane_cmd_en
                       
end
               
//////////////////////////////接收////
always @(posedge Clk or posedge TXrst)
begin if(TXrst)
         begin
//        RXflag<=1'b0;
        RXstate<=x0;//接收状态机初值
         end
        else  begin
            case (RXstate)
         x0:begin
            RXcnt=3'd0;
                 RXstate<=x1;
                 end
                 
         x1:begin           
       if(RXflag==1) begin//接受完1字节数据
                          
                     RXcnt<=RXcnt+1'b1;
                          
                     
                 case (RXcnt)
                 
                           3'd0:
                                    begin
                                          
                                           pane_cmd0<=RXdata;//把第一个字节放进去
                                         end
                           3'd1:
                               begin
                                      pane_cmd_out<=RXdata;//把第二个字节放进去
                                         end
                                3'd2:  
                                     begin
                                          pane_cmd<=RXdata;//把第三个字节放进去
                                          end
                                3'd3:   
                                     begin
                                          pane_cmd1<=RXdata;//把第四个字节放进去
                                          end
                                3'd4:   
                                     begin
                                          pane_data_out<=RXdata;//把第五个字节放进去
                                          end
                                3'd5:
                                     begin
                                          pane_cmd2<=RXdata;//把第六个字节放进去
                                          end
                                3'd6:  
                                     begin
                                          
                                          pane_cmd3<=RXdata;//把第七个字节放进去
                                          value<=(pane_cmd0+pane_cmd_out+pane_cmd+pane_cmd1+pane_data_out+pane_cmd2);//校验和
                                          end
                                          
                                3'd7:;
                                     
                                default:;
                                         
                                endcase
                               
                                RXstate<=x2;       
                          
                     end
                 else
                  
                 RXstate<=x1;//没有接收完则继续等待接收完成
                 
            end
        x2:begin                       
                                 if (RXcnt== 3'd7)begin//判断接收完成且接收正确
                                     
                                                  RXstate <= x3;end
                          else  begin //如果没有接收完7字节则等待
                          RXstate <=x1;end
                          
                 end
                 
        x3:begin
       
             RXcnt<=3'd0;
                  RXstate <=x0;
                  
                 end                
default :RXstate <=x0;
endcase
   end
       
end
endmodule


Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top