Xilinx FPGA:vivado用串口实现点阵屏状态机

一、项目要求

要求用串口实现状态改变,状态1:静态点亮点阵屏,分别输出数字“1”,“2”,“3”。状态2:动态点亮点阵屏,连续输出数字“1”,“2”,“3”,间隔为1s。

二、信号流向图

根据项目要求分析出我们需要的模块和主要信号的流向。(图是比较高清的,可以放大看)

三、程序设计

接收端模块

`timescale 1ns / 1ps
/串口接收端    串行转并行
module uart_rx(
    input                  sys_clk   ,
    input                  rst_n     ,
    input                  rx_data   ,  //输入串行数据
    output    reg[7:0]     uart_data , // 输出并行数据
    output    reg          rx_done     //数据传输完成结束信号      

    );
    
    parameter         SYSCLK =   50_000_000  ;
    parameter         Baud   =   115200      ;
    parameter         COUNT  =   SYSCLK/Baud ;//434   传输1比特所需要的时钟周期
    parameter         MID    =   COUNT/2     ;
    
    ///产生开始信号(检测下降沿-----二级寄存)
    reg           rx_reg1     ;
    reg           rx_reg2     ;
    
    wire          start_flag    ;  开始信号
    reg           rx_flag       ;
    reg    [3:0]   cnt_bit_rx   ;///0~9
    reg    [9:0]   cnt          ;///434
    reg    [7:0]   data_reg     ;
    
    always@(posedge sys_clk)
          if(!rst_n)begin
          rx_reg1 <= 1 ;  //处于空闲位  数据线上无数据
          rx_reg2 <= 1 ;  //处于空闲位  数据线上无数据
          end
          else
              begin
                  rx_reg1 <= rx_data  ;
                  rx_reg2 <= rx_reg1  ;
              end
     assign start_flag = ~rx_reg1 & rx_reg2  ;  
     //rx_flag
     always@(posedge sys_clk )
           if(!rst_n)
              rx_flag <= 0 ;
           else if (start_flag)
              rx_flag <= 1 ;
           else if ( cnt_bit_rx == 9 && cnt == MID -1 )
              rx_flag <= 0 ;
           else
              rx_flag <= rx_flag ;
   cnt 434  
     always@(posedge sys_clk )
           if(!rst_n)
              cnt <= 0;
           else if ( rx_flag == 1 )begin
                if ( cnt == COUNT -1) ///一定要减一,如果不减一,实际会计到435次,反算回去波特率就不是115200了
                    cnt <= 0;
                else
                    cnt <= cnt +1 ;
           end
           else
               cnt <= 0 ;
   
   /计数器
      always@(posedge sys_clk )
           if(!rst_n)
              cnt_bit_rx <= 0 ;
           else if ( rx_flag )begin
                if ( cnt == COUNT -1)begin
                    if(cnt_bit_rx == 9)
                    cnt_bit_rx <= 0 ;
                    else
                    cnt_bit_rx <= cnt_bit_rx +1 ;
                    end
                else
                cnt_bit_rx <= cnt_bit_rx     ;
                end
           else
           cnt_bit_rx <= 0 ;
           
    [7:0]uart_data
    /*
    cnt_bit = 0 起始位
    cnt_bit = 1-8 数据位
    cnt_bit = 9 停止位
    但是  [7:0]uart_data   没有uart[8]
    所以
    if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
         uart_data[cnt_bit -1] <= rx_data ;
    */
//    always@(posedge sys_clk )
//          if(!rst_n)
//          uart_data <= 0 ;
//          else if ( rx_flag )begin
//                if ( cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9 )
//                uart_data[cnt_bit -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
//                else
//                uart_data <= uart_data ;
//          end
//          else
//          uart_data <= 0 ;
    因为这里要让uart_data只在rx_done的时候有值,所以定义一个中间寄存器data_reg
     always@(posedge sys_clk )
          if(!rst_n)
          data_reg <= 0 ;
          else if ( rx_flag )begin
                if ( cnt == MID -1 && cnt_bit_rx > 0 && cnt_bit_rx < 9 )
                data_reg[cnt_bit_rx -1] <= rx_data ; //这里uart_data是不断随着cnt_bit变化的,只有在第九位的时候才有正确的最终值
                else
                data_reg <= data_reg ;
          end
          else
          data_reg <= 0 ;
//  其他赋值方法1
//      always@(posedge sys_clk )
//          if(!rst_n)
//             uart_data <= 0;
//          else if (cnt == MID -1)begin
//             case(cnt_bit)
//             0:  uart_data  <= 0  ;
//             1:  uart_data [0] <= rx_data  ;
//             2:  uart_data [1] <= rx_data  ;
//             3:  uart_data [2] <= rx_data  ;
//             4:  uart_data [3] <= rx_data  ;
//             5:  uart_data [4] <= rx_data  ;
//             6:  uart_data [5] <= rx_data  ;
//             7:  uart_data [6] <= rx_data  ;
//             8:  uart_data [7] <= rx_data  ;
//             9:  uart_data  <= uart_data  ;  ///停止位的时候数据传完,保持
//             endcase
//             end
//           else
//             uart_data  <= uart_data  ;
   
//   其他赋值方法2
//    always@(posedge sys_clk )
//          if(!rst_n)
//          uart_data <= 0 ;
//          else if (cnt == MID -1 && cnt_bit > 0 && cnt_bit < 9)
//               uart_data <= {rx_data,uart_data[7:1]} ;
//          else
//               uart_data <= uart_data ;
          
   给uart_data赋值
     always@(posedge sys_clk )
          if(!rst_n)     
             uart_data <= 0 ;   
          else if (rx_flag)begin
               if (cnt_bit_rx == 9 && cnt == MID/4 -1)
               uart_data <= data_reg ;
               else
               uart_data <= uart_data ;
          end
          else
          uart_data <= uart_data ; 可以保持到下一个数据到来
          uart_data <= 0 ;  只保持在rx_done处于高电平的时候
  /rx_done
     always@(posedge sys_clk )
          if(!rst_n)           
            rx_done <= 0 ;
          else if (rx_flag)begin
               if ( cnt_bit_rx == 9 && cnt == MID/2 -1)
                   rx_done <= 1 ;
               else
                   rx_done <= 0 ;       
          end
          else
            rx_done <= 0 ; 


      
endmodule

翻译模块:

`timescale 1ns / 1ps
/*
将ASCII码转换成对应的数字或字母或符号
这种转换模块尽量使用组合逻辑去写,让他尽量不产生延时
*/
module translate(
      input                   sys_clk   ,
      input                   rst_n     ,
      input       [7:0]       uart_data ,
      input                   rx_done   ,
      output   reg[7:0]      trans_data
      
    );
    always@(*)
          if(!rst_n)
             trans_data <= 0 ;
          else if (rx_done)
                   case(uart_data)
                   8'h30 : trans_data <= 8'd0 ;
                   8'h31 : trans_data <= 8'd1 ;
                   8'h32 : trans_data <= 8'd2 ;
                   8'h33 : trans_data <= 8'd3 ;
                   8'h41 : trans_data <= "A"  ;
                   8'h40 : trans_data <= "@"  ;
                   endcase
           else
               trans_data <= trans_data  ;
endmodule


动态模块

`timescale 1ns / 1ps
module DT(
    input               sys_clk   ,
    input               rst_n     ,
    output   reg[63:0]  DT_data  

    );
//   wire [7:0]     rx_data      ,
   向串口发送不同数字,点阵屏出现不同图案,状态机实现
   reg       [3:0]     cur_state    ;
   reg       [3:0]     next_state   ;
   reg       [26:0]    cnt_1s       ;
//   wire      [7:0]     rx_data      ;

   parameter         TIME_1s = 26'd50_000_000 ;
   
   localparam         IDLE = 3'b000  ;
   localparam           S0 = 3'b001  ;
   localparam           S1 = 3'b010  ; 
   localparam           S2 = 3'b100  ; 
   
   state 1
   always@(posedge sys_clk)
         if(!rst_n)
            cur_state <= IDLE   ;
         else 
            cur_state <= next_state ;
   
   state 2
   always@(*)
        case(cur_state)
         IDLE : next_state <= S0  ;
           S0 : 
                begin
                     if( cnt_1s == TIME_1s -1 )
                     next_state <= S1  ;
                     else
                     next_state <= cur_state ;
                end
           S1 :
                begin
                     if( cnt_1s == TIME_1s -1  )
                     next_state <= S2  ;
                     else
                     next_state <= cur_state ;
                end
           S2 :
                begin
                     if( cnt_1s == TIME_1s -1 )
                     next_state <= S0  ;
                     else
                     next_state <= cur_state ;
                end
           default:;
        endcase
    state 3
    always@(posedge sys_clk)
          if (!rst_n)begin
             cnt_1s <= 0 ;
             DT_data <= 0 ;
          end      
          else
             case(cur_state)
             IDLE :
                   begin
                   cnt_1s <= 0 ;
                   DT_data <= 0 ;
                   end
               //0xFF,0xCF,0xEF,0xEF,0xEF,0xEF,0xC7,0xFF,
               //0xFF,0xC7,0xF7,0xE7,0xDF,0xDF,0xC7,0xFF,
               //0xFF,0xC7,0xF7,0xC7,0xF7,0xF7,0xC7,0xFF,
               
               S0 :begin
                         DT_data <= 64'hFF_CF_EF_EF_EF_EF_C7_FF   ;
                         if(cnt_1s == TIME_1s -1)
                            cnt_1s <= 0 ; 
                         else
                            cnt_1s <= cnt_1s +1;
                   end
               S1 : begin
                         DT_data <= 64'hFF_C7_F7_E7_DF_DF_C7_FF  ;
                         if(cnt_1s == TIME_1s -1)
                            cnt_1s <= 0 ; 
                         else
                            cnt_1s <= cnt_1s +1;
                    end
               S2 : begin
                         DT_data <= 64'hFF_C7_F7_C7_F7_F7_C7_FF  ;
                         if(cnt_1s == TIME_1s -1)
                            cnt_1s <= 0 ; 
                         else
                            cnt_1s <= cnt_1s +1;
                    end
               default:;
             endcase
  

endmodule

控制模块

`timescale 1ns / 1ps
module CTRL(
    input                sysclk              ,
    input                rst_n               ,
    input       [7:0]    trans_data          ,
    input       [63:0]   DT_data             ,
    output  reg [63:0]  CTRL_data
    );
/状态机
localparam      IDLE   = 3'b001;
localparam      JT     = 3'b010;
localparam      DT     = 3'b100;
reg     [2:0]   cur_state,next_state;
//state1
always@(posedge sysclk)
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
//state2
always@(*)
    case(cur_state)
        IDLE :begin
            if(trans_data == 1 || trans_data == 2 || trans_data == 3)
                next_state = JT;
            else if(trans_data == "A")
                next_state = DT;
            else
                next_state = cur_state;
        end    
        JT   :begin
            if(trans_data == "A")
                next_state = DT;
            else
                next_state = cur_state;
        end
        DT   :begin
            if(trans_data == 1 || trans_data == 2 || trans_data == 3)
                next_state = JT;
            else
                next_state = cur_state;
        end
        default:;
    endcase
//state3
always@(posedge sysclk)
    if(!rst_n)begin
        CTRL_data <= 0;   
    end
    else
        case(cur_state)
            IDLE : CTRL_data <= 0;     
            JT   : begin
                case(trans_data)  
                    1: CTRL_data <= 64'hFF_CF_EF_EF_EF_EF_C7_FF ; 
                    2: CTRL_data <= 64'hFF_C7_F7_E7_DF_DF_C7_FF ;
                    3: CTRL_data <= 64'hFF_C7_F7_C7_F7_F7_C7_FF ;
                endcase      
            end
            DT   :begin
                CTRL_data <= DT_data;
            end
            
        endcase


    
    endmodule

ctrl_data的数据优化模块

`timescale 1ns / 1ps
module ctrl_data_translate(
       input                  sys_clk    ,
       input                  rst_n      ,
       input    [63:0]        CTRL_data  ,
       output   reg[15:0]    data_screen          

    );
    行扫描 1ms 数据转换 成16位的输出
    parameter                  TIME_1ms = 50_000  ;
    
    reg       [15:0]        cnt_1ms   ;
    reg       [7:0]         number    ;
    
    /计时器
     always@(posedge sys_clk)
           if(!rst_n)
              cnt_1ms <= 0 ;
           else if ( cnt_1ms == TIME_1ms -1)
              cnt_1ms <= 0 ;
           else
              cnt_1ms <= cnt_1ms +1 ;
     
     
     计数器
     always@(posedge sys_clk)
           if(!rst_n)
              number <= 0 ;
           else if ( cnt_1ms == TIME_1ms -1 && number == 7 )
              number <= 0 ;
           else if ( cnt_1ms == TIME_1ms -1)
              number <= number +1 ;
           else
              number <= number  ;
      
     data_screen
     always@(posedge sys_clk)
           if(!rst_n)
              data_screen <= 0 ;
           else
              case(number)
              0:  data_screen <= {8'b0000_0001 ,CTRL_data[63:56]} ;
              1:  data_screen <= {8'b0000_0010 ,CTRL_data[55:48]} ;
              2:  data_screen <= {8'b0000_0100 ,CTRL_data[47:40]} ;
              3:  data_screen <= {8'b0000_1000 ,CTRL_data[39:32]} ;
              4:  data_screen <= {8'b0001_0000 ,CTRL_data[31:24]} ;
              5:  data_screen <= {8'b0010_0000 ,CTRL_data[23:16]} ;
              6:  data_screen <= {8'b0100_0000 ,CTRL_data[15:8]}  ;
              7:  data_screen <= {8'b1000_0000 ,CTRL_data[7:0]}   ;
              default:;
              endcase 
      

     
endmodule

HC595模块

`timescale 1ns / 1ps
module HC595(
     input                     sys_clk    ,
     input                     rst_n      ,
     input   wire[15:0]       data_screen,
     output                    SCK        ,
     output      reg           RCK        ,
     output      reg           DI      

    );

    wire                 locked                ;
    wire                 en                    ;
    reg     [3:0]        cnt                   ;
    reg     [3:0]        cnt_bit               ;//16位


    
    assign  en = ( locked & rst_n )? 1 : 0 ;
    
    /DI模块  需要赋初值/15位的cnt_bit/
    在SCK的上升沿赋值
    always@(posedge SCK)
          if(!rst_n)
             cnt_bit <= 0 ;
          else if ( en == 1 )begin
               if ( cnt_bit == 4'd15 )
                    cnt_bit <= 0 ;
               else
                    cnt_bit <= cnt_bit +1 ;
          end
          else
             cnt_bit <= 0 ;
    
    always@(negedge SCK)
          if(!rst_n)
             DI <= 0 ;
          else if ( en == 1 )
             DI <= data_screen[ cnt_bit ] ;
          else
             DI <= 0 ;
    
    
    ///RCK模块,每一个16位数据传输完毕后都会拉高3~5个时钟周期
       always@(posedge sys_clk)
             if(!rst_n)
                cnt <= 0 ;
                else if ( en == 1 )begin
                     if ( cnt_bit == 0 )begin
                         if ( cnt == 9 )
                              cnt <= 0 ;
                         else
                              cnt <= cnt +1 ;
                     end
                 else
                 cnt <= 0 ;               
                end 
                else
                cnt <= 0 ;
    
    always@(posedge sys_clk )
          if (!rst_n)
              RCK <= 0 ;
          else if ( en == 1 )begin
               if (cnt_bit == 0 && cnt >= 5 && cnt <= 7 )
               RCK <= 1 ;
               else
               RCK <= 0 ;
          end
         else
               RCK <= 0 ;
     

          
    clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_5M(SCK),     // output clk_5M
    // Status and control signals
    .resetn(rst_n), // input resetn
    .locked(locked),       // output locked
   // Clock in ports
    .sys_clk(sys_clk));      // input sys_clk            
    
  
 

endmodule

顶层模块

`timescale 1ns / 1ps
module TOP(
     input               sys_clk   ,
     input               rst_n     ,
     input               rx_data   ,  //输入串行数据
     output              SCK       ,
     output      wire     RCK      ,
     output      wire     DI      
    );

    wire[7:0]         uart_data ; // 输出并行数据
    wire              rx_done   ; //数据传输完成结束信号 
    wire[15:0]       data_screen;   

   wire     [7:0]     trans_data      ;
 
 接收端模块例化
  uart_rx  uart_rx_u2(
          .     sys_clk   (sys_clk  )   ,
          .     rst_n     (rst_n    )   ,
          .     rx_data   (rx_data  )   ,  //输入串行数据
          .     uart_data (uart_data)   , // 输出并行数据
          .     rx_done   (rx_done  )     //数据传输完成结束信号      

    );  

翻译模块例化   
translate translate_u1(
           .       sys_clk   ( sys_clk  )  ,
           .       rst_n     ( rst_n    )  ,
           .       uart_data ( uart_data)  ,
           .       rx_done   ( rx_done  )  ,
           .      trans_data (trans_data)  
      
    );    

///动态模块例化
     wire[63:0]       DT_data   ;
DT DT_u1(
            .  sys_clk (sys_clk)  ,
            .  rst_n   (rst_n  )  ,
            .  DT_data (DT_data) 

    );

CTRL模块例化
    wire     [63:0]    CTRL_data  ;
CTRL CTRL_u1(
                .   sysclk       (  sys_clk    )       ,
                .   rst_n        (  rst_n     )       ,
                .   trans_data   (  trans_data)       ,
                .   DT_data      (  DT_data   )       ,
                .  CTRL_data     ( CTRL_data  )
    );

CTRL_data 的翻译模块例化
ctrl_data_translate  ctrl_data_translate_u1(
                 .     sys_clk    (  sys_clk   )   ,
                 .     rst_n      (  rst_n     )   ,
                 .     CTRL_data  (  CTRL_data )   ,
                 .    data_screen ( data_screen)            

    );

HC595 HC595_u1(
                  .      sys_clk    ( sys_clk   )  , 
                  .      rst_n      ( rst_n     )  , 
                  .     data_screen (data_screen)  , 
                  .      SCK        ( SCK       )  ,    
                  .      RCK        ( RCK       )  ,  
                  .      DI         ( DI        )

    );
    
    
      endmodule

四、仿真程序

时间太长了,大家慢慢跑吧。。。

`timescale 1ns / 1ps
module test_bench(  );

     reg           sys_clk   ;
     reg           rst_n     ;
     reg          rx_data   ;    //输入串行数据
     wire          SCK       ;
     wire          RCK       ;
     wire          DI        ;
     
     
    parameter         SYSCLK =   50_000_000  ;
    parameter         Baud   =   115200      ;
    parameter         COUNT  =   SYSCLK/Baud ;//434   传输1比特所需要的时钟周期
    parameter         MID    =   COUNT/2     ;
    

initial
      begin
           sys_clk = 0 ;
           rst_n   = 0 ;
           #10
           rst_n   = 1 ;
      end
  always #1 sys_clk = ~sys_clk ; //2ns
  

  initial
        begin

            uart_out (8'h31);
            uart_out (8'h32);
            uart_out (8'h33);
            uart_out (8'h41);
            uart_out (8'h40);
        end              
  
  
  //任务函数
  task     uart_out   ;
     input      [7:0]    DATA   ;
         begin
              rx_data = 1 ;///空闲位初始
              #20 
              rx_data = 0 ;///起始位
               ///传输1bit的计时次数*1周期时间=总时间
               #(COUNT*2)  rx_data = DATA[0] ;///数据位第一位
               #(COUNT*2)  rx_data = DATA[1] ;///数据位第二位
               #(COUNT*2)  rx_data = DATA[2] ;
               #(COUNT*2)  rx_data = DATA[3] ;
               #(COUNT*2)  rx_data = DATA[4] ;
               #(COUNT*2)  rx_data = DATA[5] ;
               #(COUNT*2)  rx_data = DATA[6] ;
               #(COUNT*2)  rx_data = DATA[7] ;
               #(COUNT*2)  rx_data = 1       ;
               #(COUNT*2)                    ;//停止位也需要时间
               #2000_000                     ;//2ms数据发送的时间至少要大于点阵屏切换数据的时间(1ms)
         end
  
  
  
  endtask


TOP TOP_u1(
           .    sys_clk (sys_clk)  ,
           .    rst_n   (rst_n  )  ,
           .    rx_data (rx_data)  ,  //输入串行数据
           .    SCK     (SCK    )  ,
           .     RCK    ( RCK   )  ,
           .     DI     ( DI    ) 
    );
endmodule

五、实验结果:

0621

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值