串口发送模块设计代码

*********************************************************
独立按键滤波
*********************************************************
*/
module key_filter( 
                  Clk,
                  Rst_n,
                  key_in,
                  key_flag,
                  key_state
                  );
/*********************************************************/
input  Clk;
input  Rst_n;
input  key_in;
output key_flag;
output key_state;
/*********************************************************/
reg  key_sync0;      //外部按键信号进行2级寄存器同步
reg  key_sync1;      //同上,将异步信号同步化.
/*********************************************************/
reg  key_flag;   //按键稳定标志位
reg  key_state;   //按键状态寄存器
reg  key_temp0;      //按键键值寄存器0
reg  key_temp1;      //按键键值寄存器1
reg  [19:0]Delay_cnt;//延时20ms消抖计数器
reg  Delay_full;     //延时计数计满标志位
reg  EN_cnt;         //延时计数开始使能信号
/*********************************************************/
reg  [3:0] state;
localparam   IDLE    = 4'b0001, //初始状态
             Filter0 = 4'b0010, //按键按下抖动滤波状态
             DOWN    = 4'b0100, //按键滤波后稳定状态
             Filter1 = 4'b1000; //按键释放抖动滤波状态
/*********************************************************/
always @(posedge Clk or negedge Rst_n)//异步信号同步化
  begin
    if(!Rst_n)
      begin
        key_sync0 <= 0;
        key_sync1 <= 0;
      end
    else
      begin
        key_sync0<=key_in;     //1级寄存器
 key_sync1<=key_sync0;  //2级寄存器
      end
  end
/*********************************************************/
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
      begin
        key_temp0 <= 0;
        key_temp1 <= 0;
      end
    else
      begin
        key_temp0<=key_sync1;  //1级寄存器
 key_temp1<=key_temp0;  //2级寄存器
      end
  end
assign  pedge =  key_temp0 && (~key_temp1);//检测上升沿
assign  nedge = (~key_temp0) && key_temp1; //检测下降沿  
/*********************************************************/
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  begin
    Delay_cnt <=20'd0;
end
else if(EN_cnt)                 //进入抖动滤波状态,使能信号打开,开始计数
    Delay_cnt<=Delay_cnt+1'b1; 
else
    Delay_cnt<=Delay_cnt;
  end
/*********************************************************/
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  begin
    Delay_full<=1'b0;
end
else if(Delay_cnt==20'd999_999) //产生计数计满标志位,代表消抖结束,键值稳定
    Delay_full<=1'b1; 
else
    Delay_full<=1'b0; //这里一定是0.而不是Delay_full<=Delay_full;
  end
/*********************************************************/
always @(posedge Clk or negedge Rst_n)//1段式状态机
  begin
    if(!Rst_n)
  begin
 state<=IDLE;    //状态机进入初始状态
 key_flag <=1'b0;//按键稳定标志位为0
 key_state<=1'b1;//按键状态为未按下状态为1
 EN_cnt<=1'b0;   //计数使能信号复位
end
else
  begin
 case(state)
   IDLE: begin
        EN_cnt<=1'b0; //只要进入初始状态,计数使能必须关闭,否则一直计数
key_flag<=1'b0;//进入初始状态,稳定值位就清零
        if(nedge)     //检测下降沿,判断按键是否被按下
           begin
   EN_cnt<=1'b1;  //打开计数使能信号
      state<=Filter0;//按下,进入抖动滤波状态
  end
  else
   state<=IDLE;
end
Filter0: if(Delay_full)//判断20ms计数是否完成,完成进入稳定状态
            begin
key_flag <=1'b1;//按键稳定标志位置1
key_state<=1'b0;//按键状态开始跳变
EN_cnt   <=1'b0;//计数使能关闭
state<=DOWN;
end
else if(pedge)//20ms计数未完成,再次检测到上升沿,说明是抖动
   begin
     EN_cnt<=1'b0;//计时关闭
        state<=IDLE; //回到初始状态
end
else
     state<=Filter0;//计数时间未完成,并且没有抖动产生,继续计数
  DOWN : begin
        key_flag<=1'b0;//只产生一个周期的高脉冲
        if(pedge)//检测按键是否被释放,即检测上升沿,检测到上升沿,打开计数使能,开始20ms的计数
  begin
    EN_cnt<=1'b1;
       state<= Filter1;
  end
  else 
     state<=DOWN;//依然是按键被按下稳定状态
  end
Filter1: if(Delay_full)//检测是否计数完成,20m计数完成进入初始状态
            begin
    EN_cnt<=1'b0;
    key_flag<=1'b1;  //这里可以继续输出键值稳定位为1
 key_state<=1'b1; //按键状态是1
                state<=IDLE;
end
else if(nedge)//如果检测到下降沿,说明是抖动,回到DOWN状态
   begin
    EN_cnt<=1'b0;//计时关闭
       state<=DOWN;//回到按键稳定按下状态,等待稳定释放
end
else
       state<=Filter1;
default: begin
            key_flag <=1'b0;
key_state<=1'b1;
EN_cnt   <=1'b0;
            state<=IDLE;
end
 endcase
end
  end

endmodule

/*
*********************************************************
           DATA of UART send  
*********************************************************
*/
module uart_send_tx(
                    Clk,
 Rst_n,
 Baud_set,
 Send_en,
 Send_data_byte,
 Tx_done,
 Rs_232_Tx,
 Uart_state
                    );
/*******************************************************/
input Clk;                //50M clock of  system
input Rst_n;              //reset of system
input Send_en;            //input send enable signal
input [2:0]Baud_set;      //set different baud,max is 8 ways
input [17:0]Send_data_byte;//input 8 bit of send data 
output Tx_done;           //output finish signal of send
output Rs_232_Tx;         //output serial of Rs_232_Tx_ data(1 bit)
output Uart_state;        //output state of  uart
/*******************************************************/
reg  Tx_done;
reg  Rs_232_Tx;
reg  Uart_state;
reg  baud_clk;              //baud clock 
reg  [15:0]div_cnt;         //different baud counter max value
reg  [3: 0]bit_cnt;         //11 bit counter to judge send finish 
reg  [7: 0]r_Send_data_byte;//registerof send byte data
reg  [15:0]div_max;         //max value of frequency division from the LUT
/*******************************************************/
localparam   start = 1'b0; //begin  bit of send data
localparam   stop  = 1'b1; //finish bit of send data
/*******************************************************/
//generate the counter value of different baud_clk.
always @(posedge Clk or negedge Rst_n)
  begin
     if(!Rst_n)
    div_cnt<=16'd0;
 else if(Uart_state)//state is 1,begin the send
    begin
if(div_cnt==div_max)//when counter value is the max, clear div_cnt's value .
div_cnt<=16'd0;
else
div_cnt<=div_cnt+1'b1;
 end
 else
    div_cnt<=16'd0;
  end
/*******************************************************/
//generate the baud_clk.
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
   baud_clk<=1'b0;
else if(div_cnt==16'd1)//duty cycle isn't the 50%,so you can set div_cnt==16'd2 or others .
   baud_clk<=1'b1;     
else
   baud_clk<=1'b0;
  end
/*******************************************************/
//counter value of send data bit
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
   bit_cnt<=4'd0;
else if(bit_cnt==4'd11)//when counter is 11,finish the send data.
   bit_cnt<=4'd0;
else if(baud_clk)//only baud_clk is 1, bit_cnt begin to increase 1.
   bit_cnt<=bit_cnt+1'b1;
else
   bit_cnt<=bit_cnt;
  end 
/******************************************************/
//regsiter the out input signal of send 8 bit data
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  r_Send_data_byte<=8'd0;
else if(Send_en)//enable must open ,the data will regsiter.
  r_Send_data_byte<=Send_data_byte;
else
  r_Send_data_byte<=r_Send_data_byte;
  end
/******************************************************/
//send data of 11 bit to Rs_232_Tx
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  Rs_232_Tx<=1'b1;//when reset is useful,the output is stop bit(high voltage)
else
      case(bit_cnt)
 0: Rs_232_Tx<=1'b1;//first is stop,because the counter begin from 1.
    1: Rs_232_Tx<=start;//begin bit
 2: Rs_232_Tx<=r_Send_data_byte[0];//D0
 3: Rs_232_Tx<=r_Send_data_byte[1];//D1
 4: Rs_232_Tx<=r_Send_data_byte[2];//D2
 5: Rs_232_Tx<=r_Send_data_byte[3];//D3
 6: Rs_232_Tx<=r_Send_data_byte[4];//D4
 7: Rs_232_Tx<=r_Send_data_byte[5];//D5
 8: Rs_232_Tx<=r_Send_data_byte[6];//D6
 9: Rs_232_Tx<=r_Send_data_byte[7];//D7
10: Rs_232_Tx<=stop;//stop bit
 default: Rs_232_Tx<=1'b1;//After when send data finish , Rs_232_Tx must is the high voltage.
  endcase
  end
/*******************************************************/
//look up table of baud clcok's counter value 
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  div_max<=16'd5207;
else
  case(Baud_set)
 3'd0: div_max<=16'd5207;//9600
 3'd1: div_max<=16'd433 ;//115200
 3'd2: div_max<=16'd1301;//38400
 3'd3: div_max<=16'd1162;//43000
 3'd4: div_max<=16'd2603;//19200
 3'd5: div_max<=16'd891 ;//56000
 3'd6: div_max<=16'd867 ;//57600
        default: div_max<=16'd5207;
endcase
  end
/*******************************************************/
//output the Tx_done singal ,it represent the send data has finished.
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  Tx_done<=1'b0;
else if(bit_cnt==4'd11)
  Tx_done<=1'b1;
else
  Tx_done<=1'b0;
  end
/*******************************************************/
//output the uart state   
always @(posedge Clk or negedge Rst_n)
  begin
    if(!Rst_n)
  Uart_state<=1'b0;
else if(Send_en)
  Uart_state<=1'b1;
else if(bit_cnt==4'd11)
  Uart_state<=1'b0;
else
  Uart_state<=Uart_state;
  end
/*******************************************************/
endmodule
/*
****************************************************
         uart send top(use to simulation)
****************************************************
*/
module uart_send_top(
 Clk,
 Rst_n,
 key_in,
 Rs_232_Tx,
 led                
                     );
/**************************************************/
input Clk;              
input Rst_n;              
input key_in;
output Rs_232_Tx;         
output led; 
/**************************************************/           
wire [2:0]Baud_set;
wire Send_en ;    
wire [7:0]Send_data_byte;
wire Tx_done; 
wire key_flag,key_state;
/**************************************************/
assign  Send_en  = key_flag && !key_state;
/**************************************************/
uart_send_tx  uart_send_tx1(
 .Clk       (Clk      ),
 .Rst_n     (Rst_n    ),
 .Baud_set  (3'd0     ),
 .Send_en   (Send_en  ),
 .Tx_done   (         ),
 .Rs_232_Tx (Rs_232_Tx),
 .Uart_state(led      ),
 .Send_data_byte(Send_data_byte)
 );  
key_filter         key_filter( 
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(key_in),
.key_flag(key_flag),
.key_state(key_state)
);  
 issp  issp    (
         .probe(),
         .source(Send_data_byte)
 );

endmodule

说明:这里设计的顶层模块是为了使用ISSP调试工具,没有用到探针,于是就没有连接,综合的时候会被优化掉。

`timescale 1ns/1ps
`define clk_period 20
module uart_send_tx_tb;
   reg  Clk;
reg  Rst_n;
reg [2:0]Baud_set;
reg Send_en;
reg [7:0]Send_data_byte;
wire Tx_done;
wire Rs_232_Tx;
wire Uart_state;
/********************************************/
initial  Clk = 1'b1;
/********************************************/
initial
  begin
    Rst_n = 1'b0;
Baud_set = 3'd0;
Send_data_byte = 8'd0;
Send_en = 1'b0;
#(`clk_period*30+1);
Rst_n = 1'b1;
#(`clk_period*50);
//first send
Send_data_byte = 8'h89;
Baud_set = 3'd1;
Send_en = 1'b1;
#(`clk_period);
 Send_en = 1'b0;
@(posedge Tx_done);//wait the send finish
#500000;
 
//second send
Send_data_byte = 8'hef;
Baud_set = 3'd1;
Send_en = 1'b1;
#(`clk_period);
 Send_en = 1'b0;
@(posedge Tx_done);//wait the send finish
#500000;
#1000 $stop;
  end
/********************************************/
always #(`clk_period/2) Clk = ~Clk;
/********************************************/
uart_send_tx  uart_send_tx0(
 .Clk       (Clk      ),
 .Rst_n     (Rst_n    ),
 .Baud_set  (Baud_set ),
 .Send_en   (Send_en  ),
 .Tx_done   (Tx_done  ),
 .Rs_232_Tx (Rs_232_Tx),
 .Uart_state(Uart_state),
 .Send_data_byte(Send_data_byte)
 );
/********************************************/


endmodule






















































你可能感兴趣的:(串口发送模块设计代码)