赞
踩
串口的接收与发送,PC 端发送特定指令后,开发板可发送相应指令到 PC 端显示。
指令一:PC 端发送 I like FPGA,开发板回应 ILke FPGA, too 在 PC 端显示。
指令二:PC 端发送 I like verilog,开发板回应 ILke verilog, too 在 PC 端显示。
顶层代码:顶层代码主要负责各个模块的例化,本次任务由3个模块组成,分别是rx模块(字符串的读取)、tx模块(字符串的发送)和ctrl模块(根据接收到的字符串,控制需要发送的字符串)。
module top( input wire clk, input wire rst_n, input wire rx, output wire tx ); wire [7:0]po_data; wire po_flag; wire [111:0]str; wire [7:0]tx_str; wire tx_flag; wire tx_start; wire [4:0]tx_cnt; uart_rx inst_uart_rx ( .sclk (clk), .rst_n (rst_n), .rx (rx), .po_data (po_data), .po_flag (po_flag), .str(str) ); uart_tx inst_uart_tx ( .sclk (clk), .rst_n (rst_n), .tx (tx), .pi_data (tx_str), .tx_start(tx_start), .tx_down(tx_flag), .tx_cnt(tx_cnt), .str(str) ); ctrl inst_uart_trcl ( .clk (clk), .rst_n (rst_n), .str (str), .tx_start (tx_start), .tx_str (tx_str), .po_data(po_data), .tx_flag(tx_flag), .tx_cnt(tx_cnt) ); endmodule
仿真图:
rx部分代码:将上位机发送的串行数据转换为并行数据,供fpga进一步处理。
注:上位机发送过来的数据是串行的、且由高到低发送
module uart_rx( input wire sclk, input wire rst_n, input wire rx, //上位机发送的数据,1bit output reg [7:0] po_data, //接收到的字符 output reg po_flag, //接收完1个字符标志位 output reg [111:0]str//14*8,拼接成的字符串 ); parameter CNT_BAUD_MAX = 5207; //9600波特率,时钟周期20ns parameter CNT_HALF_BAUD_MAX = 2603; //5208的一半 reg rx1,rx2,rx2_reg; reg rx_flag; reg [12:0] cnt_baud; reg bit_flag; reg [3:0] bit_cnt; //打拍 always @(posedge sclk) begin {rx2_reg,rx2,rx1}<={rx2,rx1,rx}; end //控制开始读取上位机发来的数据 always @(posedge sclk) begin if (rst_n == 1'b0) begin rx_flag <= 1'b0; end else if (bit_cnt == 4'd8 && bit_flag == 1'b1) begin //接收完一个字符(1bit起始位+8bit数据位) rx_flag <= 1'b0; end else if (rx2_reg == 1'b1 && rx2 == 1'b0) begin //检测到起始位(下降沿) rx_flag <= 1'b1; end end //当rx_flag == 1'b1时,cnt_baud循环计数 always @(posedge sclk) begin if (rst_n == 1'b0) begin cnt_baud <= 'd0; end else if (rx_flag == 1'b0) begin cnt_baud <= 'd0; end else if (rx_flag == 1'b1 && cnt_baud == CNT_BAUD_MAX) begin //1bit数据接收完成 cnt_baud <= 'd0; end else if (rx_flag == 1'b1) begin cnt_baud <= cnt_baud + 1'b1; end end //1bit数据的中间时刻标志位(中间时刻数据最稳定) always @(posedge sclk) begin if (rst_n == 1'b0) begin bit_flag <= 1'b0; end else if (rx_flag == 1'b1 && cnt_baud == CNT_HALF_BAUD_MAX) begin //计数到1bit数据的中间时刻 bit_flag <= 1'b1; end else begin bit_flag <= 1'b0; end end //对bit_flag计数,0-8循环 always @(posedge sclk) begin if (rst_n == 1'b0) begin bit_cnt <= 'd0; end else if (bit_flag == 1'b1 && bit_cnt == 'd8) begin //1bit发送位和8bi数据位结束完毕 bit_cnt <= 'd0; end else if (bit_flag == 1'b1) begin bit_cnt <= bit_cnt + 1'b1; end end //拼接rx2_reg,串行数据转并行数据 always @(posedge sclk ) begin if (rst_n == 1'b0) begin po_data <='d0; end else if (bit_cnt >= 4'd1 && bit_flag == 1'b1) begin po_data <= {rx2_reg,po_data[7:1]}; end end //拼接完8bit数据时,拉高一个clk的高电平 always @(posedge sclk) begin if (rst_n == 1'b0) begin po_flag <= 1'b0; end else if (bit_cnt == 4'd8 && bit_flag == 1'b1) begin po_flag <= 1'b1; end else begin po_flag <= 1'b0; end end //将接受到的字符拼接成字符串 always @(posedge sclk) begin if (rst_n == 1'b0) begin str <= 0; end else if (po_flag==1) begin //一个字符接收完毕 str <= {str[103:0],po_data}; end end endmodule
仿真图:细节放大:
tx部分:将fpga的并行数据转成串行数据发送给上位机。
注:由高位到低位发送。
module uart_tx( input wire sclk, input wire rst_n, input wire tx_start, //触发fpga开始发送,与ctrl模块相连 input wire [7:0] pi_data, //需要发送的字符,与ctrl模块相连 input wire [4:0]tx_cnt, //控制发送第几个字符,与ctrl模块相连 input wire[111:0] str, //rx接收到的字符串 output reg tx, //发送的字符 output reg tx_down //发送完一个字符的标志位 ); parameter CNT_BAUD_MAX = 5207; reg [7:0] data_reg; reg tx_flag; reg [12:0] cnt_baud; reg bit_flag; reg [3:0] bit_cnt; //缓存数据,避免上一个模块发生变化而影响需要发送的数据 always @(posedge sclk) begin if (rst_n == 1'b0) begin data_reg <='d0; end else data_reg <= pi_data; end //tx_flag=1时开始发送 always @(posedge sclk) begin if (rst_n == 1'b0) begin tx_flag <= 1'b0; end //首先,每发送完一个字符tx_flag <= 1'b0;其次,需要发送的字符串发送完tx_flag <= 1'b0 else if((bit_flag == 1'b1 && bit_cnt == 4'd9)||(str[87:0]=="I Like FPGA"&&tx_cnt==12&&tx_down==1)||(str[111:0]=="I Like verilog"&&tx_cnt==15&&tx_down==1)) begin tx_flag <= 1'b0; end //首先,接收到‘I Like FPGA’或‘I Like verilog’,tx_flag <= 1'b1;其次,每发送完一个字符,tx_flag <= 1'b1 else if (tx_start== 1'b1 || tx_down==1) begin tx_flag <= 1'b1; end end //当tx_flag == 1'b1时,cnt_baud循环计数(0-5207) always @(posedge sclk) begin if (rst_n == 1'b0) begin cnt_baud <= 'd0; end else if(tx_flag == 1'b0)begin cnt_baud <='d0; end else if (tx_flag == 1'b1 && cnt_baud == CNT_BAUD_MAX) begin cnt_baud <= 'd0; end else if (tx_flag == 1'b1) begin cnt_baud <= cnt_baud + 1'b1; end end //接收到1bit数据标志位 always @(posedge sclk) begin if (rst_n == 1'b0) begin bit_flag <= 1'b0; end else if (cnt_baud == CNT_BAUD_MAX -1 && tx_flag == 1'b1) begin bit_flag <= 1'b1; end else begin bit_flag <= 1'b0; end end //对bit_flag计数,0-9循环 always @(posedge sclk) begin if (rst_n == 1'b0) begin bit_cnt <= 'd0; end else if(bit_flag == 1'b1 && bit_cnt == 4'd9) begin //1bit发送位+8bit数据位+1bit停止位发送完 bit_cnt <= 'd0; end else if (bit_flag == 1'b1) begin bit_cnt <= bit_cnt + 1'b1; end end //往上位机发送的串行数据 always @(posedge sclk ) begin if (rst_n == 1'b0) tx <= 1'b1; //需要发送的字符串发送完, tx <= 1'b1 else if ((str[87:0]=="I Like FPGA"&&tx_cnt==12&&tx_down==1)||(str[111:0]=="I Like verilog"&&tx_cnt==15&&tx_down==1)) tx <= 1'b1; // 1bit起始位。首先,接收到正确指令,tx <= 1'b0;其次,每发送完一个字符,tx <= 1'b0 else if (tx_start == 1'b1 || tx_down==1) begin tx <= 1'b0; end else if (bit_cnt<=7 && bit_flag == 1'b1) begin //8位数据位,并转串 tx <= data_reg[bit_cnt]; end else if (bit_flag == 1'b1 && bit_cnt == 4'd8) //1bit起始位+8位数据位发送完毕,产生1bit停止位 tx <= 1'b1; end //一个字符发送完毕,tx_down <= 1'b1 always @(posedge sclk) if (rst_n == 1'b0) tx_down <= 1'b0; else if (bit_flag == 1'b1 && bit_cnt == 4'd9) tx_down <= 1'b1; else tx_down <= 1'b0; endmodule
仿真图:
ctrl部分:根据接收到的字符串,控制发送出去的字符串
module ctrl( input wire clk, input wire rst_n, input wire [111:0]str, //接收到的字符串 input wire tx_flag, //一个字符发送完毕 input wire[7:0]po_data, //接收到的字符 output reg [7:0]tx_str, //需要发送的字符 output reg tx_start, //当接受完正确的字符串时,控制开始发送字符串 output reg [4:0]tx_cnt //发送第几个字符 ); reg [2:0]flag_send; //判断是什么字符串 always @(posedge clk) if (rst_n==0) begin flag_send<=3'b000; end else if(str[87:0]=="I Like FPGA") begin flag_send<=3'b001; end else if(str[111:0]=="I Like verilog") begin flag_send<=3'b010; end else begin flag_send<=3'b000; end //tx_start<=1时开始发送字符串 always @(posedge clk) if (rst_n==0) tx_start<=0; else if((str[79:0]=="I Like FPG"&&po_data=="A")||(str[103:0]=="I Like verilo"&&po_data=="g")) //接收到正确的字符串 tx_start<=1; else tx_start<=0; //判断发送第几个字符 always @(posedge clk) if (rst_n==0) tx_cnt<=0; else if(tx_cnt==12&&str[87:0]=="I Like FPGA"&&tx_flag==1) tx_cnt<=0; else if(tx_cnt==15&&str[111:0]=="I Like verilog"&&tx_flag==1) tx_cnt<=0; else if(tx_flag==1) tx_cnt<=tx_cnt+1; //确定发送的字符 always @(posedge clk) if (rst_n==0) tx_str<=1; else case(tx_cnt) 'd0:tx_str<="I"; 'd1:tx_str<="L"; 'd2:tx_str<="k"; 'd3:tx_str<="e"; 'd4:tx_str<=" "; 'd5:if(flag_send==3'b001) tx_str<="F"; else if(flag_send==3'b010) tx_str<="v"; 'd6:if(flag_send==3'b001) tx_str<="P"; else if(flag_send==3'b010) tx_str<="e"; 'd7:if(flag_send==3'b001) tx_str<="G"; else if(flag_send==3'b010) tx_str<="r"; 'd8:if(flag_send==3'b001) tx_str<="A"; else if(flag_send==3'b010) tx_str<="i"; 'd9:if(flag_send==3'b001) tx_str<=","; else if(flag_send==3'b010) tx_str<="l"; 'd10:if(flag_send==3'b001) tx_str<="t"; else if(flag_send==3'b010) tx_str<="o"; 'd11:if(flag_send==3'b001) tx_str<="o"; else if(flag_send==3'b010) tx_str<="g"; 'd12:if(flag_send==3'b001) tx_str<="o"; else if(flag_send==3'b010) tx_str<=","; 'd13:if(flag_send==3'b010) tx_str<="t"; 'd14:if(flag_send==3'b010) tx_str<="o"; 'd15:if(flag_send==3'b010) tx_str<="o"; default:tx_str<=0; endcase endmodule
仿真图:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。