FPGA入门——串口发送模块与验证

编程入门 行业动态 更新时间:2024-10-22 17:23:19

ISSP调试工具
串口(异步串行通信接口):IIC(集成电路总线)、SPI(串行外围总线)、UART(通用异步收发器)

UART发送

UART发送

FPGA通过URAT串口发送协议向PC发送数据。发送:并行数据转串行数据

UART发送一个字节时序图:
串口发送总模块


Clk时钟信号,Rst_n复位信号,Bps_set四位选择波特率信号,Con_en使能信号,Data_in8位输入信号. Rs232_tx输出信号,Done_tx输出一次完整11位Rs232_tx数据完成信号,Uart_state输出完所有信号完成标志信号.

数字设计图

串口发送模块
 module UART_TX(
    Clk,
	Rst_n,
	Bps_set,
	Con_en,
	Data_in,
    
	Rs232_tx,
	Done_tx,
	Uart_state 
  );
input Clk;
input Rst_n;
input [2:0]Bps_set;
input Con_en;
input [7:0]Data_in;
output reg Rs232_tx;
output reg Done_tx;
output reg Uart_state;

reg [15:0]count; //计数器定值
reg [15:0]high_count; //计数值 
reg [7:0]Data_in_r;
reg bps_clk;
reg [3:0]bps_count;

localparam start_bite = 1'b0;
localparam stop_bite = 1'b1;
	
//查找表输出计数值
 always @(posedge Clk or negedge Rst_n)
  if(!Rst_n) 
	count <= 16'd5207;
	else begin   
	case(Bps_set)
	  0: count <= 16'd5207;         //波特率9600
	  1: count <= 16'd2603;         //波特率19200
	  2: count <= 16'd1301;         //波特率38400
	  3: count <= 16'd865;          //波特率57600
	  4: count <= 16'd433;          //波特率115200
	default : count <= 16'd5207;
	endcase
	end
	
//产生Uart_state使能信号
always @(posedge Clk or negedge Rst_n)
 if(!Rst_n)
  Uart_state <= 1'b0;
  else  if(Con_en)
 Uart_state <= 1'b1;
  else if(bps_count == 4'd11)
  Uart_state <= 1'b0;
   else Uart_state <= Uart_state; 
	
  //计数满产生bps_clk信号  
 always @(posedge Clk or negedge Rst_n)
  if(!Rst_n)
    high_count <= 0;
	  else if(Uart_state) begin
	     if(high_count == count)
	         high_count <= 0;
		    else high_count <= high_count + 1'b1;
			 end
		else high_count <= 0;
 
always @(posedge Clk or negedge Rst_n)
   if(!Rst_n)
	 bps_clk <= 1'b0;
	  else if(high_count == 16'b1)
	   bps_clk <= 1'b1;
		 else bps_clk <= 1'b0;
		 
//计数bps_clk的高电平到11计数满为0	产生Done_tx高点平信号   
always @(posedge Clk or negedge Rst_n)
  if(!Rst_n)
   bps_count <= 4'b0;
	 else if(bps_count == 4'd11)
	  bps_count <= 4'b0;
	  else if(bps_clk )
	   bps_count <= bps_count + 4'b1; 
	    else bps_count <= bps_count;
		 
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
 Done_tx <= 1'b0;
 else  if(bps_count == 4'd11) 
  Done_tx <= 1;
   else Done_tx <= 0;
	
always @(posedge Clk or negedge Rst_n )
 if(!Rst_n)
  Data_in_r <= 0;
   else if(Con_en)
	 Data_in_r <= Data_in ;
	 else Data_in_r <= Data_in_r; 
	
//十选一多路选择器	
always @(posedge Clk or negedge Rst_n)
 if(!Rst_n)
  Rs232_tx <= 1'b1;
 else begin
   case(bps_count)
	0: Rs232_tx <=  1'b1;
	1: Rs232_tx <=  start_bite;
	2: Rs232_tx <=  Data_in_r[0];
	3: Rs232_tx <=  Data_in_r[1];
	4: Rs232_tx <=  Data_in_r[2];
    5: Rs232_tx <=  Data_in_r[3];
	6: Rs232_tx <=  Data_in_r[4];
	7: Rs232_tx <=  Data_in_r[5];
	8: Rs232_tx <=  Data_in_r[6];
	9: Rs232_tx <=  Data_in_r[7];
	10: Rs232_tx <=  stop_bite;
	default : Rs232_tx <=  1'b1;
	 endcase 
 end

endmodule 
串口发送仿真模块
`timescale 1ns/1ns
`define clk_period 20
module UART_TX_tb;

    reg Clk;
    reg Rst_n;
    reg [2:0]Bps_set;
	 reg Con_en;
	 reg [7:0]Data_in;
	  wire Rs232_tx;
	  wire Done_tx;
	  wire Uart_state;
UART_TX UART_TX0(
    .Clk(Clk),
	 .Rst_n(Rst_n),
	 .Bps_set(Bps_set),
	 .Con_en(Con_en),
	 .Data_in(Data_in),
	 .Rs232_tx(Rs232_tx),
	 .Done_tx(Done_tx),
	 .Uart_state(Uart_state) 
  );
 
 initial Clk = 1;
 always#(`clk_period/2) Clk = ~Clk;
 
 initial begin
  Rst_n = 1'b0;
  Data_in = 8'b0;
  Con_en = 1'b0;
  Bps_set = 3'd4;
  #(`clk_period*20+1);
  Rst_n = 1'b1;
 #(`clk_period*20+1);
  Data_in = 8'hae;
  Con_en = 1'b1;
 #(`clk_period);
 Con_en = 1'b0;
 
 
 @(posedge Done_tx)
  #(`clk_period*2000);
   Data_in = 8'h5b;
   Con_en = 1'b1;
   #(`clk_period);
   Con_en = 1'b0;
	 
 @(posedge Done_tx)
	#(`clk_period*2000);
	$stop;
 end
 
 
endmodule 
仿真结果


可以看到bps_count为2时Rs232_tx为Data_in最低位0,bps_count为3时Rs232_tx为Data_in次位1,以此类推。

按键消抖模块
module Key_shake(Clk,Rst_n,Key_in,Key_flag,Key_data);
   input Clk;
	input Rst_n;
	input Key_in;
	output reg Key_flag; //当按键按下20ms消除抖动成功后产生一个脉冲flag信号,检测到产生flag信号后产生按键按下低电平。
	output reg Key_data;
	
   reg [3:0]state; 
   reg  [19:0]count; //寄存器计数	
	reg   count_start;//时能计时
	reg  count_full;//计满脉冲信号
	reg reg0,reg1;
	reg key_in_now0,key_in_now1;
	wire rise,fall;
	
	localparam 
	High_pulse      =   4'b0001, //高电平稳定状态
	Low_eliminate   = 4'b0010, //键下降沿稳定状态
	Low_pulse       = 4'b0100, //低电平稳定状态
	High_eliminate  = 4'b1000; //键上升沿稳定状态
	
		always @(posedge Clk or negedge Rst_n)    //对输入按键信号做同步处理,消除异步信号亚稳态的影响。
	 if(!Rst_n) begin
       key_in_now0 <= 1'b0;
		 key_in_now1 <=1'b0;
		 end
      else   begin 
		 key_in_now0 <= Key_in;
	    key_in_now1 <= key_in_now0; 	
	end
	
	
	always @(posedge Clk or negedge Rst_n)    //脉冲边沿检测   两个寄存器
	 if(!Rst_n) begin
       reg0 <= 1'b0;
		 reg1 <=1'b0;
		 end
      else   begin 
		 reg0 <= key_in_now1;
	    reg1 <= reg0; 	
	end
	
	assign fall = !reg0 & reg1;  //检测到下降沿
	assign rise = reg0 & !reg1;  //检测到上升沿  
	
	 always @(posedge Clk  or negedge Rst_n)    //20ms计数器
       if(!Rst_n)
          count <= 20'b0;            	
	      else  if(count_start)
			  count <= count + 20'b1;
             else  count <= 20'b0;		  	
				 
	 always @(posedge Clk  or negedge Rst_n)     //20ms计数器计数满标志脉冲信号
       if(!Rst_n)
          count_full <= 1'b0;            	
	      else  if(count == 99_9999)
			  count_full <= 1'b1;
             else  count_full <= 1'b0;	
				 
	always @(posedge Clk or negedge Rst_n)
	 if(!Rst_n) begin
	  Key_data <= 1'b1;
	  state <= High_pulse;
	  Key_flag <= 1'b0;
	  count_start <= 1'b0;
         end		
	  else  case(state) 
	          High_pulse : begin  Key_flag <= 0;  
				                     Key_data <= 1'b1;
				   if(fall) begin
					    state <= Low_eliminate;
						 count_start <= 1'b1;   //使能开始20ms计数
	              end
					  else   state <= High_pulse;
					      end
				 Low_eliminate :  
   				if(count_full) begin
					     state <= Low_pulse;
						  Key_flag <= 1'b1;
				        Key_data <= 1'b0;
						  count_start <= 1'b0;   //关闭使能20ms计数
						 end
					 else begin  
					     if(rise) begin
						 state <= High_pulse;
						 count_start <= 1'b0;   //关闭使能20ms计数
						               end
					      else 
							 state <= Low_eliminate;
						         end
              
              Low_pulse:  begin Key_flag <= 1'b0;
                 if(rise) begin
					    state <= High_eliminate;
						 count_start <= 1'b1; //开始计时
						 end
					  else  state <= Low_pulse;
				            end
			     High_eliminate : 
				     if(count_full) begin
					   Key_data <= 1'b1;
						Key_flag <= 1'b1;
						state <= High_pulse;
					  end
					   else begin
						  if(fall) begin
						   state <= Low_pulse;
							count_start <= 1'b0;
							   end else 
								 state <= High_eliminate;
						            end		
		
		default : begin 
		               state <= High_pulse; //默认状态
							count_start <= 1'b0;
							Key_data <= 1'b1;
					    	Key_flag <= 1'b0;
		     end
	  endcase 

endmodule 
顶层模块

调用IP核。

module UART_tx_top(
   Clk,
   Rst_n,	
   Rs232_tx,
   Key_in0,
	led
			);
 input  Clk;
 input  Rst_n;
 input Key_in0;
 output Rs232_tx;	
 output led;
 
 wire Con_en;
 wire [7:0]Data_in;
 wire Key_flag0;
 wire Key_data0;
 
 assign Con_en = Key_flag0 & !Key_data0;
 
   Key_shake   Key_shake0(
  .Clk(Clk),
  .Rst_n(Rst_n),
  .Key_in(Key_in0),
  .Key_flag(Key_flag0),
  .Key_data(Key_data0)
  );

UART_TX UART_TX0(
    .Clk(Clk),
	 .Rst_n(Rst_n),
	 .Bps_set(3'd0),
	 .Con_en(Con_en),
	 .Data_in(Data_in),
	 .Rs232_tx(Rs232_tx),
	 .Done_tx(),
	 .Uart_state(led) 
  );
issp issp0(
	.probe(),
	.source(Data_in)
	);



endmodule

FPGA发送信号PC端

更多推荐

FPGA入门——串口发送模块与验证

本文发布于:2023-06-14 00:00:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1416080.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:串口   模块   入门   FPGA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!