当前位置:   article > 正文

【FPGA串口发送、接收字符串】串口的接收与发送,PC 端发送特定指令后,开发板可发送相应指令到 PC 端显示。 指令一:PC 端发送 I like FPGA,开发板回应 ILke FPGA, to_verilog 串口发送字符串

verilog 串口发送字符串

串口发送、接收字符串

任务内容:

串口的接收与发送,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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

仿真图:
在这里插入图片描述

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102

仿真图:在这里插入图片描述细节放大:
在这里插入图片描述

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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

仿真图:
在这里插入图片描述
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 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98

仿真图:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/516599
推荐阅读
相关标签
  

闽ICP备14008679号