精华内容
下载资源
问答
  • FPGA-串口通信协议
    2021-01-31 19:54:36

    FPGA 串口通信协议
     波特率:波特率就是串口的通信速率,常见的波特率有12000bps、4800bps、9600bps、115200bps、256000bps、500000bps,这里波特率的意思是每秒可以传输bit的个数,这里的5207=500000000/9600;传递一个字节需要的时间。
     串口接收模块
    输入为时钟、复位信号、输入数据、输出数据、数据接收完成标志
    源代码:

    module chuanxing_3(clk,rst_n,data_in,po_data,po_en);
    input clk,rst_n;
    input data_in;
    output reg [7:0] po_data;
    output reg po_en;
    
    reg [2:0] state;
    reg [2:0] next_state;
    reg [3:0] cnt_bit;  
    reg [12:0] cnt;
    
    parameter Idle=0,start=1,read=2,stop=3;
    
    parameter TIME=5207;
    
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
       state<=Idle;
     else
      state<=next_state;
    end
    
    //计数模块
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
        cnt<=0;
     else
        begin
         if(state==start||state==read||state==stop)
    	      begin
    	       if(cnt==TIME)
    	          cnt<=0;
    	      else
    			    cnt<=cnt+1;
    			end
    	  else
    	      cnt<=0;
        end
    end
    
    //传递字节
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
      cnt_bit<=0;
    else
       begin
        if(next_state==read)
          begin 
    		 if(cnt_bit==8&&cnt==TIME)
    		     cnt_bit<=0;
    		 else if(cnt_bit==8&&cnt<TIME)
    		      cnt_bit<=8;
    		 else if(cnt_bit<8&&cnt==TIME)
    		      cnt_bit<=cnt_bit+1;
    			else
    			    cnt_bit<=cnt_bit;
    		end 
    	 else	 
    		 cnt_bit<=0;
       end
    end
    
    always @(*)
    begin
    case(state)
     Idle:
           next_state=data_in?Idle:start;
    		 
     start:
           begin
    		  if(cnt==TIME)
    		     next_state=read;
    		  else
    		     next_state=start;
    		 end
    		
     read:
           begin
    		  if(cnt_bit==8&&cnt==TIME)
    		     next_state=stop;
    			else 
    		     next_state=read;
    		 end
    
     stop:
          begin
           if(cnt==TIME/2)
    	       next_state=Idle;
    	    else
              next_state=stop;
          end
      endcase
    end
    
    //串行转并行
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
      po_data<=0;
    else
       begin
        if(next_state==read&&cnt==TIME/2)
           po_data[7:0]<={po_data[6:0],data_in};
       else
            po_data[7:0]<=po_data[7:0];
       end
    end
    
    //数据接收完成标志
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
      po_en<=0;
     else begin
       if(state==stop&&cnt==TIME)
         po_en<=1;
    	 else
    	  po_en<=0;
      end
    end
    endmodule
    

     发送模块

    module chuanxing_3_tx(clk,rst_n,pi_data,pi_en,data_out);
    input clk,rst_n;
    input [7:0] pi_data;
    input pi_en;
    output reg data_out;
    
    
    parameter TIME=5207;
    
    parameter Idle=0,start=1,send=2,stop=3;
    
    reg [3:0] cnt_bit;  //9个字节
    
    reg [12:0] cnt;
    
    reg [2:0] state,next_state;
    
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
       state<=Idle;
     else
       state<=next_state;
    end
    
    always @(*)
    begin
     case(state)
      Idle:
           begin
            if(pi_en)
             next_state=start;
             else
    			next_state=Idle;
    		 end
    		 
    	start:
    	      begin
              if(cnt==TIME)
                 next_state=send;
    	       else
    	          next_state=start;
              end
    	send: begin
              if(cnt_bit==8&&cnt==TIME)
                 next_state=stop;
    			else
    			    next_state=send;
             end
       stop:begin
    			 if(cnt==TIME)
    			     next_state=Idle;
    				else
    				 next_state=stop; 
    		   end
      endcase
    end
    
    //计数模块
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
       cnt<=0;
     else
       begin
        if(next_state==start||next_state==send||next_state==stop)
    	    begin
            if(cnt==TIME)
               cnt<=0;
            else
    	        cnt<=cnt+1;
    	    end
    		else
    		  cnt<=0;
    	end
    end
    
    //字节计数
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
      cnt_bit<=0;
      else begin
       if(next_state==stop)
           cnt_bit<=0;
      else  if(cnt_bit<8&&next_state==send&&cnt==TIME)
           cnt_bit<=cnt_bit+1;
    	else 
            cnt_bit<=cnt_bit;
       end
    end
    
    //
    always @(posedge clk or negedge rst_n)
    begin
     if(!rst_n)
       data_out<=0;
     else begin
       if(next_state==start)
    	    data_out<=0;
    	else if(next_state==stop)
    	     data_out<=1;
      else
       case(cnt_bit)
       4'd1: data_out<=pi_data[cnt_bit-1];
       4'd2: data_out<=pi_data[cnt_bit-1];
       4'd3: data_out<=pi_data[cnt_bit-1];
    	4'd4: data_out<=pi_data[cnt_bit-1];
    	4'd5: data_out<=pi_data[cnt_bit-1];
    	4'd6: data_out<=pi_data[cnt_bit-1];
    	4'd7: data_out<=pi_data[cnt_bit-1];
    	4'd8: data_out<=pi_data[cnt_bit-1];
       endcase
      end
    end
    
    endmodule 
    
    更多相关内容
  • FPGA串口通信(Verilog编写)
  • FPGA串口通信

    千次阅读 2021-07-20 15:38:40
    1 文档简介 本文主要讲解如何编写 FPGA 串口通信的...本文所述的串口指异步串行通信,异步串行是指 UART(Universal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART 是一个并行输入成为串行输出的芯

    1 文档简介
    本文主要讲解如何编写 FPGA 串口通信的收发程序,在程序中使用了状态机,是学习状态机的重要实验。
    2 实验环境
    黑金 FPGA 开发板(AX301 开发板、AX4010 开发板、AX515 开发板、AX530 开发板、AX1025 开发板)
    串口调试助手
    3 实验原理
    3.1 串口通信简介
    本文所述的串口指异步串行通信,异步串行是指 UART(Universal Asynchronous
    Receiver/Transmitter),通用异步接收/发送。UART 是一个并行输入成为串行输出的芯片,通常集成在主板上。UART 包含 TTL 电平的串口和 RS232 电平的串口。 TTL 电平是 3.3V 的,而 RS232 是负逻辑电平,它定义+5~+12V 为低电平,而-12~-5V 为高电平,MDS2710、MDS SD4、EL805 等是RS232 接口,EL806 有 TTL 接口。

    串行接口按电气标准及协议来分包括 RS-232-C、RS-422、RS485 等。RS-232-C、RS-422 与 RS-485 标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议。黑金 FPGA 开发板的串口通信通过 USB 转串口方式,主要是解决很多人电脑不带串口接口的问题,所以这里不涉及到电气协议标准,用法和 TTL 电平串口类似。FPGA 芯片使用 2 个 IO 口和 USB转串口芯片 CP2102 相连。在这里插入图片描述
    3.2 异步串口通信协议
    消息帧从一个低位起始位开始,后面是 7 个或 8 个数据位,一个可用的奇偶位和一个或几个高位停止位。接收器发现开始位时它就知道数据准备发送,并尝试与发送器时钟频率同步。如果选择了奇偶校验,UART 就在数据位后面加上奇偶位。奇偶位可用来帮助错误校验。在接收过程中,UART 从消息帧中去掉起始位和结束位,对进来的字节进行奇偶校验,并将数据字节从串行转换成并行。UART 传输时序如下图所示:在这里插入图片描述
    从波形上可以看出起始位是低电平,停止位和空闲位都是高电平,也就是说没有数据传输时是高电平,利用这个特点我们可以准确接收数据,当一个下降沿事件发生时,我们认为将进行一次数据传输。

    3.3 关于波特率
    常见的串口通信波特率有 2400 、9600、115200 等,发送和接收波特率必须保持一致才能正确通信。波特率是指 1 秒最大传输的数据位数,包括起始位、数据位、校验位、停止位。假如通信波特率设定为 9600,那么一个数据位的时间长度是 1/9600 秒。
    4 程序设计
    4.1 接收模块设计
    串口接收模块是个参数化可配置模块,参数“CLK_FRE”定义接收模块的系统时钟频率,单位是 Mhz,参数“BAUD_RATE”是波特率。接收状态机状态转换图如下:在这里插入图片描述
    “S_IDLE”状态为空闲状态,上电后进入“S_IDLE”,如果信号“rx_pin”有下降沿,我们认为是串口的起始位,进入状态“S_START”,等一个 BIT 时间起始位结束后进入数据位接收状态
    “S_REC_BYTE”,本实验中数据位设计是 8 位,接收完成以后进入“S_STOP”状态,在“S_STOP”没有等待一个 BIT 周期,只等待了半个 BIT 时间,这是因为如果等待了一个周期,有可能会错过下一个数据的起始位判断,最后进入“S_DATA”状态,将接收到的数据送到其他模块。在这个模块我们提一点:为了满足采样定理,在接受数据时每个数据都在波特率计数器的时间中点进行采样,以避免数据出错的情况:

    always@(posedge clk or negedge rst_n)
    begin
    if(rst_n == 1'b0)
    rx_bits <= 8'd0;
    else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
    rx_bits[bit_cnt] <= rx_pin;
    else
    rx_bits <= rx_bits; 
    end
    

    注意:本实验没有设计奇偶校验位。
    在这里插入图片描述
    4.2 发送模块设计
    发送模式设计和接收模块相似,也是使用状态机,状态转换图如下在这里插入图片描述
    上电后进入“S_IDLE”空闲状态,如果有发送请求,进入发送起始位状态“S_START”,起始位发送完成后进入发送数据位状“S_SEND_BYTE”,数据位发送完成后进入发送停止位状态“S_STOP”,停止位发送完成后又进入空闲状态。在数据发送模块中,从顶层模块写入的数据直接传递给寄存器‘tx_reg’,并通过‘tx_reg’寄存器模拟串口传输协议在状态机的条件转换下进行数据传送:

    always@(posedge clk or negedge rst_n)
    begin
    if(rst_n == 1'b0)
    tx_reg <= 1'b1;
    else
    case(state)
     S_IDLE,S_STOP:
    tx_reg <= 1'b1; 
    S_START:
    tx_reg <= 1'b0; 
    S_SEND_BYTE:
    tx_reg <= tx_data_latch[bit_cnt];
    default:
    tx_reg <= 1'b1; 
    endcase
    end
    

    在这里插入图片描述
    4.3 测试程序
    测试程序设计 FPGA 为 1 秒向串口发送一次“HELLO ALINX\r\n”,不发送期间,如果接受到串口数据,直接把接收到的数据送到发送模块再返回。“\r\n”,在这里和 C 语言中表示一致,都是回车换行测试程序分别例化了发送模块和接收模块,同时将参数传递进去,波特率设置为 115200。

    uart_rx# ( .CLK_FRE(CLK_FRE),
    .BAUD_RATE(115200) ) uart_rx_inst
    ( .clk (clk ),
    .rst_n (rst_n ),
    .rx_data (rx_data ),
    .rx_data_valid (rx_data_valid ),
    .rx_data_ready (rx_data_ready ),
    .rx_pin (uart_rx )
    );
    uart_tx# ( .CLK_FRE(CLK_FRE),
    .BAUD_RATE(115200) ) uart_tx_inst
    ( .clk (clk ),
    .rst_n (rst_n ),
    .tx_data (tx_data ),
    .tx_data_valid (tx_data_valid ),
    .tx_data_ready (tx_data_ready ),
    .tx_pin (uart_tx )
    );
    

    5 实验测试
    由于开发板的串口使用 USB 转串口芯片,首先要安装串口驱动程序,正确安装驱动状态如下图所示(当然要连接串口的 USB 到电脑,AX301、AX4010 开发板串口和供电接口为同一个 USB 口,就是 J6 口)。如果没有正确连接请参考本文附录“串口驱动的安装在这里插入图片描述
    串口驱动正常的状态
    从图中可以看出系统给串口分配的串口号是“COM3”,串口号的分配是系统完成的,自动分配情况下每台电脑可能会有差异,笔者这里是“COM3”,使用串口号时要根据自己的分配情况选择。打开串口调试,端口选择“COM3”(根据自己情况选择),波特率设置 115200,检验位选None,数据位选 8,停止位选 1,然后点击“打开串口”。如果找不到这个小软件使用 windows 搜索功能,在黑金给的资料文件夹里搜索“串口调试”。

    打开串口以后,每秒可收到“HELLO ALINX”,在发送区输入框输入要发送的文字,点击“手
    动发送”,可以看到接收到自己发送的字符。在这里插入图片描述

    展开全文
  • FPGA串口通讯代码

    2017-03-06 11:38:24
    用 verilog语言设计的FPGA串口通讯模块,可直接调用
  • FPGA串口通信实验

    2021-03-07 08:41:51
    串口也称串行通信接口或串行通讯接口,是采用串行通信方式的扩展接口。目前人们使用的所有计算机操作系统都支持串行接口,其运用较为广泛。 串行指的是其将发送的数据一位一位的通过数据线传给对方,因此其通信只...

    串口通信是FPGA较为基础的一个实验,本人在初学FPGA后决定将其整理一下并进一步加强自身理解。

    串口简介

    串口也称串行通信接口或串行通讯接口,是采用串行通信方式的扩展接口。目前人们使用的所有计算机操作系统都支持串行接口,其运用较为广泛。

    串行指的是其将发送的数据一位一位的通过数据线传给对方,因此其通信只需要tx、rx两根数据线,从而大大降低了成本,较适合远距离通信。但也正是因为其串行的特点导致其通信速度较慢。

    串口通信简介

    由于其为串行通信,因此串口传送一个字节的数据要分为8次,并且从低到高按顺序一位一位进行传送。因此双方在传送数据时每一位都要有一个固定的时间间隔,以便能正确识别出两位数据;同时接收方也要能确定一个字节数据的开始于结束,因此双方还必须约定开始位与结束位。

    常用的串行通信方式分为同步通信和异步通信。

    同步通信

    同步通信(SYNC:synchronous data communication)是指在约定的通信速率下,发送端和接收端的时钟信号频率和相位始终保持一致(同步),这样就保证了通信双方在发送和接收数据时具有完全一致的定时关系。

    同步通信把许多字符组成一个信息组(信息帧),每帧的开始用同步字符来指示,一次通信只传送一帧信息。在传输数据的同时还需要传输时钟信号,以便接收方可以用时针信号来确定每个信息位。

    同步通信的优点是传送信息的位数几乎不受限制,一次通信传输的数据有几十到几千个字节,通信效率较高。同步通信的缺点是要求在通信中始终保持精确的同步时钟,即发送时钟和接收时钟要严格的同步(常用的做法是两个设备使用同一个时钟源)。

    异步通信

    异步通信(ASYNC:asynchronous data communication),又称为起止式异步通信,是以字符为单位进行传输的,字符之间没有固定的时间间隔要求,而每个字符中的各位则以固定的时间传送。

    在异步通信中,收发双方取得同步是通过在字符格式中设置起始位和停止位的方法来实现的。具体来说就是,在一个有效字符正式发送之前,发送器先发送一个起始位,然后发送有效字符位,在字符结束时再发送一个停止位,起始位至停止位构成一帧。停止位至下一个起始位之间是不定长的空闲位,并且规定起始位为低电平(逻辑值为0),停止位和空闲位都是高电平(逻辑值为1),这样就保证了起始位开始处一定会有一个下跳沿,由此就可以标志一个字符传输的起始。而根据起始位和停止位也就很容易的实现了字符的界定和同步。

    显然,采用异步通信时,发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,可以互不同步。

    串口接头

    常用的串口接头有两种,一种是9针串口(简称DB-9),一种是25针串口(简称DB-25)。每种接头都有公头和母头之分,其中带针状的接头是公头,而带孔状的接头是母头。9针串口的外观如下图所示。
    Alt
    两种接口的管脚说明如下图所示:

    Alt

    协议标准

    常用的串行通信接口标准有RS-232C、RS-422、RS-423和RS-485。其中,RS-232C作为串行通信接口的电气标准定义了数据终端设备(DTE:data terminal equipment)和数据通信设备(DCE:data communication equipment)间按位串行传输的接口信息,合理安排了接口的电气信号和机械要求,在世界范围内得到了广泛的应用。下面简单介绍下RS-232C的相关特性。

    电气特性

    RS-232C对电器特性、逻辑电平和各种信号功能都做了规定,如下:

    在TXD和RXD数据线上:

    (1)逻辑1为-3~-15V的电压

    (2)逻辑0为3~15V的电压

    在RTS、CTS、DSR、DTR和DCD等控制线上:

    (1)信号有效(ON状态)为3~15V的电压

    (2)信号无效(OFF状态)为-3~-15V的电压

    由此可见,RS-232C是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(TTL)以高低电平表示逻辑状态的规定正好相反。

    时序介绍

    起始位: 在发送一个字节的数据前先发出一个逻辑“0”信号,表示传输的开始。
    数据位: 在起始位之后所接的为数据位,注意串口通信是从低位开始传输,由低到高发送数据位。
    奇偶校验位: 可选择是否添加奇偶校验,此位可让接收端验证收到的数据是否有错误。奇校验或偶校验都是判断“1”的个数为奇数或偶数。
    停止位: 它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
    空闲位: 处于逻辑“1”的状态。

    发送过程时序图如下图所示。
    Alt
    TX为发送数据的数据线;SCLK为时钟线,当通信双方约定好波特率之后,双方都将按照此波特率进行传输数据,因此SCLK为FPGA端与接收端进行时钟对准的时钟线,其周期将根据波特率的变化而变化。

    在传输过程中,首先将TX线拉低,此时即发送起始位信号,紧随其后的就是8位数据位,从低到高的数据依次发送,最后将TX拉高传输停止位。

    设计思想

    通过上文分析的时序图后可知数据传输需要SCLK时钟线,因此我们需要一个计数器来根据波特率来产生SCLK信号;由于在不同的时间需要传输不同的数据位因此我们还需要一个计数器来计数已发送的数据bit,并根据此来传输对应的数据。

    发送端代码:

    module uart_tx(
    	input			clk,
    	input			rst,
    	input			data_rdy,
    	input	[7:0]	data,
    	
    	output reg	txd,
    	output reg	tx_busy
    );
    
    	parameter	BAUD = 9600;
    	parameter	CLOCK= 50_000_000;
    	localparam	TIME_BIT = CLOCK / BAUD ;
    	
    	wire			tx_start;
    	
    	reg				flag;
    	reg	[12:0]	cnt_clk;
    	reg	[ 3:0]	cnt_length;
    	
    	always@(posedge clk or negedge rst)begin //计时一个bit
    		if(!rst)begin
    			cnt_clk <= 13'd0;
    		end
    		else if(flag == 1'b1)begin
    			if(cnt_clk == TIME_BIT - 1)begin
    				cnt_clk <= 13'd0;
    			end
    			else begin
    				cnt_clk <= cnt_clk + 1'b1;
    			end
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			cnt_length <= 4'd0;
    		end
    		else begin
    			if(cnt_clk == TIME_BIT - 1 && flag == 1'b1 && cnt_length == 10 - 1)begin
    				cnt_length <= 4'd0;
    			end
    			else if(cnt_clk == TIME_BIT - 1 && flag == 1'b1)begin
    				cnt_length <= cnt_length + 1'b1;
    			end
    		end
    	end
    	
    	assign tx_start = data_rdy & (!flag);
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			flag <= 1'b0;
    		end
    		else if(tx_start)begin
    			flag <= 1'b1;
    		end
    		else if(cnt_clk == TIME_BIT - 1 && flag == 1'b1 && cnt_length == 10 - 1)begin
    			flag <= 1'b0;
    		end
    	end
    	
    	always@(*)begin
    		if(!rst)begin
    			tx_busy = 1'b0;
    		end
    		else if(flag || data_rdy)begin
    			tx_busy = 1'b1;
    		end
    		else begin
    			tx_busy = 1'b0;
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			txd <= 1'b1;
    		end
    		else if(flag == 1'b1)begin
    			case(cnt_length)
    				4'd0:begin
    					txd <= 1'b0;
    				end
    				1,2,3,4,5,6,7,8:begin
    					txd <= data[cnt_length - 1];
    				end
    				9:begin
    					txd <= 1'b1;
    				end
    			endcase
    		end
    	end
    	
    endmodule
    
    

    接收端代码

    module uart_rx(
    	input				clk,
    	input				rst,
    	input				rxd,
    	
    	output reg[7:0]	data,
    	output reg			data_rdy
    );
    
    	parameter	BAUD = 9600;
    	parameter	CLOCK= 50_000_000;
    	localparam	TIME_BIT = CLOCK / BAUD ;
    	
    	reg				rxd_d1;
    	reg				rxd_d2;
    	wire				rxd_negedge;
    	reg				flag/*synthesis noprune*/;
    	reg	[12:0]	cnt_clk;
    	reg	[ 3:0]	cnt_length;
    	reg	[ 7:0]	data_r;
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			rxd_d1 <= 1'b1;
    			rxd_d2 <= 1'b1;
    		end
    		else begin
    			rxd_d1 <= rxd;
    			rxd_d2 <= rxd_d1;
    		end
    	end
    	assign rxd_negedge = rxd_d2 & (!rxd_d1);  //检测下降沿,即为起始位
    	
    	always@(posedge clk or negedge rst)begin //计时一个bit
    		if(!rst)begin
    			cnt_clk <= 13'd0;
    		end
    		else if(flag == 1'b1)begin
    			if(cnt_clk == TIME_BIT - 1)begin
    				cnt_clk <= 13'd0;
    			end
    			else begin
    				cnt_clk <= cnt_clk + 1'b1;
    			end
    		end
    		else begin
    			cnt_clk <= 13'd0;
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			cnt_length <= 4'd0;
    		end
    		else if(flag == 1'b1)begin
    			if(cnt_clk == TIME_BIT - 1 && flag == 1'b1 && cnt_length == 10 - 1)begin
    				cnt_length <= 4'd0;
    			end
    			else if(cnt_clk == TIME_BIT - 1 && flag == 1'b1)begin
    				cnt_length <= cnt_length + 1'b1;
    			end
    		end
    		else begin
    			cnt_length <= 4'd0;
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			flag <= 1'b0;
    		end
    		else begin
    			if(rxd_negedge)begin
    				flag <= 1'b1;
    			end
    			else if(cnt_clk == TIME_BIT - 2 && cnt_length == 10 - 1)begin
    				flag <= 1'b0;
    			end
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			data_r <= 8'd0;
    		end
    		else if(flag == 1'b1 && cnt_clk == 2604 - 1)begin //在中间读取数据
    			case(cnt_length)
    				1,2,3,4,5,6,7,8:begin
    					data_r[cnt_length - 1] <= rxd_d2;
    				end
    				default:;
    			endcase
    		end
    	end
    	
    	always@(posedge clk or negedge rst)begin
    		if(!rst)begin
    			data_rdy <= 1'b0;
    			data <= 8'd4;
    		end
    		else begin
    			if(cnt_clk == 2604 - 1 && flag == 1'b1 && cnt_length == 10 - 1)begin
    				data_rdy <= 1'b1;
    				data <= data_r;
    			end
    			else begin
    				data_rdy <= 1'b0;
    			end
    		end
    	end
    	
    
    
    endmodule
    
    
    展开全文
  • FPGA串口通信程序

    2018-05-27 11:56:48
    实现FPGA与电脑串口通信程序,Quartus II 13.0 上运行无误,所用FPGA芯片型号为Altera Cyclone IV E ,EP4CE15F23C8。烧写进FPGA开发板后,从串口助手向FPGA板发数据,可从串口助手收到发送数据加一后的结果。
  • 参考《你好 fpga》编写的fpga串口通信代码。实现了从上位机发送一个数据立刻回复该数据到上位机的回环测试。其中的tx发送模块可以通过data_pro_gen模块单独测试,一秒发送一次自增数据,适合新手学习。
  • verilog实现串口收发,FPGA串口通信
  • 该代码实现了STM32与FPGA串口通信,调试可用。并且串口的波特率可调整,默认工作频率50M
  • FPGA串口通讯模块

    2018-06-29 20:11:21
    是一个完整的uart模块,两者之间的联合比较好操作,易懂。并且传送和传输之间有明显的控制位和毛刺的消除
  • FPGA平台上,使用verilog语言编写,在quartus ii中编译通过,主要功能是接收串口数据,利用内部的fifo保存数据,然后传输给上位机
  • 单片机部分先对FPGA发送过来的文件头进行确认,正确就接收文件,否则放弃接收的数据。根据FPGA发送模块的协议,对串口控制寄存器SCON和波特率控制寄存器PCON的设置即可实现。
  • 基于Verilog的串口通讯程序,能够实现FPGA与是stm32或PC通信
  • ZYNQ&FPGA 串口通信实验

    2021-11-06 18:33:14
    TX→RX为串行通信,在FPGA内部接收到发送为并行数据。 协议层: 数据位为8位,停止位为1位,无校验位 波特率为115200bps 目的:将上图中数据转换为并行数据并给出标志信号。 串口接收过程示意图: uart_...

    实验任务

     上位机通过串口将数据发送给开发板,开发板通过串口把数据送回上位机。

    TX→RX为串行通信,在FPGA内部接收到发送为并行数据。

    协议层:

    数据位为8位,停止位为1位,无校验位

    波特率为115200bps

     目的:将上图中数据转换为并行数据并给出标志信号。

    串口接收过程示意图:

     uart_rxd接收完成会得到uart_done的8位并行信号;

    接收完成后uart_done会持续一个波特率周期的高电平,表示下方的并行信号为有效数据;

    start_flag为串口接收过程的起始信号,检测到uart_rxd下降沿的时候会给出一个系统时钟周期的高电平。

    rx_flag标志整个接收过程。

    每一个数据传输需要的时间:1/115200(波特率)

    clk_cnt对系统时钟周期计数,计数到一个波特率周期时,就清零,再次开始计数。一个波特率周期计数一次,表示传输一个数据。

    rx_cnt在clk_cnt计数满一个波特率周期后+1,标识出对应的各个位。串并转换或称中,根据该值,把对应的各个位放到并行数据对应的位上面去。

    串口接收代码:

    //串口接收模块
    `timescale 1ns / 1ps
    
    module uart_recv(
    	input 				sys_clk,
    	input 				sys_rst_n,
    	
    	input 				uart_rxd,//串口接收端
    	output reg [7:0] 	uart_data,//串转并
    	output reg			uart_done//代表一帧串口数据接收完成,接收到的并行数据uart_data为有效数据
        );
    
    parameter CLK_FREQ = 50_000_000;
    parameter UART_BPS = 115200;
    parameter BPS_CNT  = CLK_FREQ/UART_BPS;  //clk_cnt需要计数的最大值
    
    reg urat_rxd_d0;
    reg urat_rxd_d1;
    reg rx_flag;//串口接收过程
    reg [3:0] rx_cnt;//计数0-9,4位
    reg [15:0]clk_cnt;//波特率除系统时钟 50000000/115200=434左右,会计数434次左右,9位,考虑不同波特率时会溢出,给大一点
    reg [7:0] rx_data;//
    
    wire start_flag;
    
    assign start_flag = (~urat_rxd_d0)&urat_rxd_d1; //检测串口接收端的下降沿  
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//异步信号同步处理
    	if(!sys_rst_n) begin
    		urat_rxd_d0 <= 1'b1;//串口数据端在默认情况下高电平
    		urat_rxd_d1 <= 1'b1;
    	end
    	else begin//异步数据同步到系统时钟下,不同步可能会产生亚稳态,还能实现下降沿检测功能
    		urat_rxd_d0 <= uart_rxd;
    		urat_rxd_d1 <= urat_rxd_d0;
    	end
    end
    
    always@(posedge sys_clk or negedge sys_rst_n) begin
    	if(!sys_rst_n)
    		rx_flag <= 1'b0;
    	else if(start_flag)//检测到串口接收过程的起始信号
    		rx_flag <= 1'b1;
    	else if((rx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2 - 1'b1))//串口接收过程结束,rx_flag重新拉低
    		rx_flag <= 1'b0;
    end
    	
    always@(posedge sys_clk or negedge sys_rst_n) begin
    	if(!sys_rst_n)
    		clk_cnt <= 16'd0;
    	else if(rx_flag) begin//clk_cnt只在rx_flag位高电平时开始计数
    		if(clk_cnt < BPS_CNT - 1'b1)//只会计数到BPS_CNT - 1'b1
    			 clk_cnt <= clk_cnt + 1'b1;
    		else 
    			 clk_cnt <= 16'd0;
    	end
    	else
    		clk_cnt <= 16'd0;
    end
    		
    always@(posedge sys_clk or negedge sys_rst_n) begin//传输数据计数,标记数据对应位
    	if(!sys_rst_n)
    		rx_cnt <= 4'd0;
    	else if(rx_flag) begin
    		if(clk_cnt == BPS_CNT - 1'b1)
    			rx_cnt <= rx_cnt + 1'b1;
    		else
    			rx_cnt <= rx_cnt;
    	end
    	else
    			rx_cnt <= 4'd0;	 
    end    
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//实现串转并
    	if(!sys_rst_n)
    		rx_data <= 8'd0;
    	else if(rx_flag && (clk_cnt == BPS_CNT/2 )) begin//在计数中间数据最稳定的时候进行寄存
    		 case(rx_cnt)
    		 	4'd1: rx_data[0] <=  urat_rxd_d1;//0位是起始标志位
    		 	4'd2: rx_data[1] <=  urat_rxd_d1;
    		 	4'd3: rx_data[2] <=  urat_rxd_d1;
    		 	4'd4: rx_data[3] <=  urat_rxd_d1;
    		 	4'd5: rx_data[4] <=  urat_rxd_d1;
    		 	4'd6: rx_data[5] <=  urat_rxd_d1;
    		 	4'd7: rx_data[6] <=  urat_rxd_d1;
    		 	4'd8: rx_data[7] <=  urat_rxd_d1;
    		 endcase
    	end
    end
    
    always@(posedge sys_clk or negedge sys_rst_n) begin
    	if(!sys_rst_n) begin
    		uart_done <= 1'b0;
    		uart_data <= 8'd0;
    	end
    	else if(rx_cnt == 4'd9 ) begin
    		uart_done <= 1'b1;
    		uart_data <= rx_data;
    	end
    	else
    		uart_done <= 1'b0;
    		uart_data <= 8'd0;	
    end
    endmodule

    串口发送模块示意图:

     uart_en只拉高没用,必须检测到上升沿;

    代码:

    //串口发送模块
    `timescale 1ns / 1ps
    
    module uart_send(
    	input 				sys_clk,
    	input 				sys_rst_n,
    	input				uart_en,//
    
    	input  [7:0] 		uart_din,//串转并
    
    	output reg			uart_txd//串口发送端
        );
    
    parameter CLK_FREQ = 50_000_000;
    parameter UART_BPS = 115200;
    parameter BPS_CNT  = CLK_FREQ/UART_BPS;  //clk_cnt需要计数的最大值
    
    reg uart_en_d0;
    reg uart_en_d1;
    reg tx_flag;//串口发送过程
    reg [3:0] tx_cnt;//计数0-9,4位
    reg [15:0]clk_cnt;//波特率除系统时钟 50000000/115200=434左右,会计数434次左右,9位,考虑不同波特率时会溢出,给大一点
    reg [7:0] tx_data;//en_flag一拉高立刻开始寄存uart_din信号
    
    wire en_flag;
    
    assign en_flag = uart_en_d0 & (~uart_en_d1); //检测串口发送端的上升沿  
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//异步信号同步处理
    	if(!sys_rst_n) begin
    		uart_en_d0 <= 1'b0;//串口数据端在默认情况下低电平
    		uart_en_d1 <= 1'b0;
    	end
    	else begin//异步数据同步到系统时钟下,不同步可能会产生亚稳态,还能实现下降沿检测功能
    		uart_en_d0 <= uart_en;
    		uart_en_d1 <= uart_en_d0;
    	end
    end
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//把数据寄存到tx_data里面
    	if(!sys_rst_n) 
    		tx_data <= 8'b0;
    	else if(en_flag)
    		tx_data <= uart_din;
    	else
    		tx_data <= tx_data;	
    end
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//在串口发送过程中tx_flag一直保持高电平
    	if(!sys_rst_n)
    		tx_flag <= 1'b0;
    	else if(en_flag)//检测到串口发送过程的起始信号
    		tx_flag <= 1'b1;
    	else if((tx_cnt == 4'd9) && (clk_cnt == BPS_CNT/2 - 1'b1))//串口发送过程结束,tx_flag
    		tx_flag <= 1'b0;
    end
    	
    always@(posedge sys_clk or negedge sys_rst_n) begin//clk_cnt对系统时钟进行计数,计数到波特率周期时清0
    	if(!sys_rst_n)
    		clk_cnt <= 16'd0;
    	else if(tx_flag) begin//clk_cnt只在tx_flag位高电平时开始计数
    		if(clk_cnt < BPS_CNT - 1'b1)//只会计数到BPS_CNT - 1'b1
    			 clk_cnt <= clk_cnt + 1'b1;
    		else 
    			 clk_cnt <= 16'd0;
    	end
    	else
    		clk_cnt <= 16'd0;
    end
    		
    always@(posedge sys_clk or negedge sys_rst_n) begin//传输数据计数,标记数据对应位
    	if(!sys_rst_n)
    		tx_cnt <= 4'd0;
    	else if(tx_flag) begin
    		if(clk_cnt == BPS_CNT - 1'b1)
    			tx_cnt <= tx_cnt + 1'b1;
    		else
    			tx_cnt <= tx_cnt;
    	end
    	else
    			tx_cnt <= 4'd0;	 
    end    
    
    always@(posedge sys_clk or negedge sys_rst_n) begin//实现并转串
    	if(!sys_rst_n)
    		uart_txd <= 1'b1;//串口没有发送数据时为高电平
    	else if(tx_flag && (clk_cnt == 16'd0 )) begin//
    		 case(tx_cnt)
    		 	4'd0: uart_txd <=  1'b0;//0位是起始标志位
    		 	4'd1: uart_txd <=  tx_data[0];
    		 	4'd2: uart_txd <=  tx_data[1];
    		 	4'd3: uart_txd <=  tx_data[2];
    		 	4'd4: uart_txd <=  tx_data[3];
    		 	4'd5: uart_txd <=  tx_data[4];
    		 	4'd6: uart_txd <=  tx_data[5];
    		 	4'd7: uart_txd <=  tx_data[6];
    		 	4'd8: uart_txd <=  tx_data[7];
    		 	4'd9: uart_txd <=  1;
    		 endcase
    	end
    end
    endmodule

    顶层:

    module top_uart(
    	input 				sys_clk,
    	input 				sys_rst_n,
    	
    	input				uart_rxd,
    	output				uart_txd
        );
     
     wire [7:0]				uart_data;
     wire					uart_done;
     
     uart_recv uart_recv_u(   
    .sys_clk			(sys_clk),
    .sys_rst_n			(sys_rst_n),
    
    .uart_rxd			(uart_rxd),
    .uart_data			(uart_data),
    .uart_done			(uart_done)
     );
     
     uart_send uart_send_u(
    .sys_clk				(sys_clk),
    .sys_rst_n				(sys_rst_n),
    .uart_en				(uart_done),
                          
    .uart_din				(uart_data),
                           
    .uart_txd               (uart_txd)
         );
     
     
    endmodule
    

    展开全文
  • FPGA 串口通信RS232

    2020-08-20 09:39:14
    本文主要介绍了FPGA串口通信RS232
  • fpga串口通讯

    2012-10-25 19:02:25
    fpga串口通讯
  • UART_串口_FPGA串口通信_verilog串口通信_FPGA串口.zip
  • FPGA串口通信原理

    2019-10-22 17:36:19
    串行通信串行通信是将数据分成一位一位的形式在一条传输线上逐个传输。 优点是简单、占用资源少。 缺点:传输速度慢。 通信方式 同步通信:带时钟同步信号的数据传输(发送方和接收方在同一时钟的控制下同步传输...
  • 基于 fpga 串口通信代码,verilog代码编写,实现数据收发
  • UART_串口_FPGA串口通信_verilog串口通信_FPGA串口_源码.zip
  • 用VHDL实现的串口通信实验报告,代码绝对好用!!!!!!!
  • fpga串口多字节、数据包发送。该资源是modelsim工程文件,下载后可直接用modelsim打开仿真。作者使用的版本是10.4
  • FPGA串口通信.zip

    2019-08-23 13:37:38
    FPGA串口通信,波特率115200,无校验位,FPGA一直发送数据。
  • 基于fpga串口通信(ch340-fpga

    千次阅读 2022-02-23 13:02:28
    基于fpga串口通信(ch340-fpga) 具体详议设计步骤和解析见: 基于fpga串口通信 设计目标:利用串口调试助手发送一个8位数据data,控制开发板上的8个led灯 关键词:边缘检测电路、异步信号同步化 ...
  • 上传的工程是Quartus 17.1的,Verilog 代码,功能是串口不停发送1-255的数字,然后把串口接收到的数据打印。同时LED1上电后开始1s频率呼吸,当收到“aa”时LED2开始1s频率呼吸,收到“bb”时LED2熄灭。0积分分享给...
  • 摘要:本文针对由FPGA构成的高速数据采集系统数据处理能力弱的问题,提出FPGA与单片机实现数据串行通信的解决方案。在通信过程中完全遵守RS232协议,具有较强的通用性和推广价值。  1 前言  现场可编程逻辑器件...
  • FPGA串行通信的视频叠加系统的设计

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,629
精华内容 3,451
关键字:

fpga串口通信

友情链接: BaseEditBox.rar