使用 ZYNFPGA 序列通信进行实验

      最后更新:2021-11-07 09:20:00 手机定位技术交流文章

      实验任务

      数据从顶端机器通过序列端口传送到开发面板,数据通过序列端口返回顶端机器。

      TXRX是FPGA收到的一份系列来文,送交平行数据。

      协议层:

      有8个数据点,1个站点,没有检查点。

      波特定在115,200公尺

      目标是将上图中的数据转换成平行数据并生成信号。

      序列摄入的流程图 :

      uart_rxd收到了来自 uart_done 的八个平行信号。

      当收到 uart_done 信号时,该信号将保持高度的港口利率周期,表明以下平行信号是合法数据。

      Start_flag 是序列接收过程的起始信号, 当 uart_rxd 坠落时, 序列接收过程会提供高电高度系统时钟周期 。

      Rx-flag 表示接收程序结束 。

      1/115200(时速)是每次数据传输所需的时间。

      clk_cn 计时系统时钟周期,最多一个端口速率周期,然后是零,然后又开始计数。一个波特时钟率一次计数,表示数据传输。

      rx_ 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
      

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/12900.html

          热门文章

          文章分类