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

串口发送、接收字符串

任务内容:

串口的接收与发送,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 

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

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
UART串口通信实验cylone4e FPGA(EP4CE6)Verilog例程quartus11.0工程源码,可以做为你学习设计参考。 /* PC机上开串口调试助手. 发送一个字符(波特率9600,数据位8位,停止位1位) 到开发板(中间通过串口线相连) FPGA收到字符后,回发给PC机上,在串口助手上显示 */ `timescale 1ns / 1ps module my_uart_top( clk,rst_n, rs232_rx,rs232_tx ); input clk; // 50MHz主时钟 input rst_n; //低电平复位信号 input rs232_rx; // RS232接收数据信号 output rs232_tx; // RS232发送数据信号 wire bps_start1,bps_start2; //接收到数据后,波特率时钟启动信号置位 wire clk_bps1,clk_bps2; // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 wire[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 wire rx_int; //接收数据中断信号,接收到数据期间始终为高电平 //---------------------------------------------------- //下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制 //(不是资源共享,和软件中的同一个子程序调用不能混为一谈) //////////////////////////////////////////// speed_select speed_rx( .clk(clk), //波特率选择模块 .rst_n(rst_n), .bps_start(bps_start1), .clk_bps(clk_bps1) ); my_uart_rx my_uart_rx( .clk(clk), //接收数据模块 .rst_n(rst_n), .rs232_rx(rs232_rx), .rx_data(rx_data), .rx_int(rx_int), .clk_bps(clk_bps1), .bps_start(bps_start1) ); /////////////////////////////////////////// speed_select speed_tx( .clk(clk), //波特率选择模块 .rst_n(rst_n), .bps_start(bps_start2), .clk_bps(clk_bps2) ); my_uart_tx my_uart_tx( .clk(clk), //发送数据模块 .rst_n(rst_n), .rx_data(rx_data), .rx_int(rx_int), .rs232_tx(rs232_tx), .clk_bps(clk_bps2), .bps_start(bps_start2) ); endmodule
首先,您需要在51开发板上连接一个AT24C02 EEPROM。然后,您需要编写51单片机的程序以实现串口通信和EEPROM的读写操作。 以下是实现串口通信和EEPROM读写操作的一些基本步骤: 1. 配置串口通信参数,包括波特率、数据位、停止位和校验位等。 2. 在程序中实现串口接收中断,以便在接收PC发送字符串时能够及时处理。 3. 在接收PC发送字符串后,将其存储到一个缓冲区中,然后将缓冲区中的数据写入EEPROM。 4. 实现EEPROM的读取操作,以便在需要时能够读取存储的字符串。 下面是一个简单的示例程序,可以实现串口通信和EEPROM读写操作: ```c #include <reg51.h> #define EEPROM_ADDR 0xA0 sbit SDA = P2^0; sbit SCL = P2^1; void delay(int n) { int i; while(n--) { for(i=0; i<100; i++); } } void i2c_start() { SDA = 1; SCL = 1; delay(5); SDA = 0; delay(5); SCL = 0; } void i2c_stop() { SDA = 0; SCL = 1; delay(5); SDA = 1; delay(5); } void i2c_send(unsigned char dat) { unsigned char i; for(i=0; i<8; i++) { SDA = (dat & 0x80) >> 7; dat <<= 1; SCL = 1; delay(5); SCL = 0; delay(5); } SDA = 1; SCL = 1; delay(5); SCL = 0; } unsigned char i2c_recv() { unsigned char i, dat = 0; SDA = 1; for(i=0; i<8; i++) { SCL = 1; delay(5); dat = (dat << 1) | SDA; SCL = 0; delay(5); } return dat; } void eeprom_write(unsigned char addr, unsigned char dat) { i2c_start(); i2c_send(EEPROM_ADDR); i2c_send(addr); i2c_send(dat); i2c_stop(); delay(10); } unsigned char eeprom_read(unsigned char addr) { unsigned char dat; i2c_start(); i2c_send(EEPROM_ADDR); i2c_send(addr); i2c_start(); i2c_send(EEPROM_ADDR | 0x01); dat = i2c_recv(); i2c_stop(); return dat; } void uart_init() { TMOD = 0x20; TH1 = 0xFD; TL1 = 0xFD; TR1 = 1; SM0 = 0; SM1 = 1; REN = 1; EA = 1; ES = 1; } void uart_send(unsigned char dat) { SBUF = dat; while(!TI); TI = 0; } void uart_recv() interrupt 4 { static unsigned char buf[32]; static unsigned char idx = 0; unsigned char ch = SBUF; if(ch == '\r') { buf[idx] = '\0'; for(unsigned char i=0; i<idx; i++) { eeprom_write(i, buf[i]); } uart_send('\n'); idx = 0; } else { buf[idx++] = ch; } } void main() { uart_init(); while(1); } ``` 这个程序实现了串口通信和EEPROM的读写操作。当接收PC发送字符串后,程序会将其存储到EEPROM中。当需要读取存储的字符串时,可以使用`eeprom_read()`函数来读取指定地址上的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值