完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
我写了一个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 |
|
相关推荐
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
1512 浏览 1 评论
1295 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
1503 浏览 0 评论
922 浏览 0 评论
2300 浏览 0 评论
1451 浏览 35 评论
5640 浏览 113 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 21:21 , Processed in 0.561120 second(s), Total 73, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号