小梅哥Xlinx FPGA开发视频布置的作业--基于串口校时的数字时钟

基于串口校时的数字时

刚看完小梅哥的视频,完成了基于串口校时的数字时钟,作业要求如下:
使用ACX720开发板编写一个可通过串口修改时间的简易数字钟
1、使用数码管显示,能够显示时分秒。
2、能够接收串口发送过来的设置时间的信息,并修改时间。
3、能够将当前时间值通过串口以1秒一次的速率发送到电脑。
本工程实现了作业的基本要求

顶层文件

module uart_clock(
    input            clk,
    input            reset_n,
    input            time_rx,//向FPGA输入想显示的时间
    output           ds,
    output           sh_cp,
    output           st_cp,
    output           uart_tx
);
wire rx_done;
wire [7:0] rx_data;
wire ctrl;
wire [31:0] time_set;
uart_byte_rx  uart_byte_rx_u(
   .clk      (clk),
   .reset_n  (reset_n),
   .uart_rx  (time_rx),   
   .baud_set (4),
   .data     (rx_data),
   .rx_done  (rx_done)
);


uart_cmd uart_cmd_u(
     .clk     (clk),
     .reset_n (reset_n),
     .rx_data (rx_data),
     .rx_done (rx_done),
     .ctrl    (ctrl),
     .time_set(time_set)
);

//****一秒产生一个使能信号
    reg [32:0] cnt;//计时一秒钟
    always@(posedge clk or negedge reset_n)begin
        if(!reset_n)
            cnt<=0;
        else if(cnt>=49999999)
            cnt<=0;
        else cnt<=cnt+1;
    end
    reg time_1s;//一秒钟产生一个使能信号
    reg trans_go;
    always @(posedge clk or negedge reset_n) begin
          if(!reset_n)
               time_1s<=0;
          else if(cnt==49999999)begin
               time_1s<=1;
               trans_go<=1;
               end
          else begin  time_1s<=0;   
                      trans_go<=0;   
               end    
    end 
//******//

reg [31:0] time_set_r;//time_set_r[7:0] time_set_r[15:8] time_set_r[23:16] time_set_r[31:24]
always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           time_set_r<=0;
      else if(ctrl)begin
           time_set_r<=time_set;
           end
      else if(time_1s)begin
           time_set_r[3:0]<=time_set_r[3:0]+1;//秒位加一
           
           if(time_set_r[3:0]==4'd9)begin//秒位的个位和十位
                if((time_set_r[7:4]==4'd5))begin//59->00,分的个位加一
                    time_set_r[7:4]<=4'd0;
                    time_set_r[3:0]<=4'd0;
                    time_set_r[11:8]<=time_set_r[11:8]+1;
                    end
                else begin //秒的个位9->0,秒的十位加一
                     time_set_r[7:4]<=time_set_r[7:4]+1;
                     time_set_r[3:0]<=4'd0;
                     end
           end
           
           if(time_set_r[11:8]==4'd9)begin//分位的个位和十位
                if((time_set_r[15:12]==4'd5)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin//59->00,小时的个位加一
                    time_set_r[15:12]<=4'd0;
                    time_set_r[11:8]<=4'd0;
                    time_set_r[19:16]<=time_set_r[19:16]+1;
                    end
                else if ((time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin //分的个位9->0,分的十位加一
                     time_set_r[15:12]<=time_set_r[15:12]+1;
                     time_set_r[11:8]<=4'd0;
                     end
           end
           
           if(time_set_r[19:16]==4'd3)begin//小时位清零
                if((time_set_r[23:20]==4'd2)&&(time_set_r[15:12]==4'd5)&&(time_set_r[11:8]==4'd9)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin
                    time_set_r[23:20]<=4'd0;
                    time_set_r[19:16]<=4'd0;
                    end
           end
           
           if (time_set_r[19:16]==4'd9)begin //小时位十位加一
                if((time_set_r[15:12]==4'd5)&&(time_set_r[11:8]==4'd9)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin
                    time_set_r[23:20]<=time_set_r[23:20]+1;
                    time_set_r[19:16]<=4'd0;
                    end
           end 
      end        
end 


//**输入32位的数据(8个4位的数据)显示
//reg [31:0] disp_data;
wire ds,sh_cp,st_cp;
hex8_test hex8_test_u(
 .clk       (clk),
 .reset_n   (reset_n), 
 .disp_data (time_set_r), 
 .ds        (ds),    
 .sh_cp     (sh_cp), 
 .st_cp     (st_cp)      
 );

//**发送到串口助手
wire  [31:0] data40;
assign  data40={time_set_r[7:0],time_set_r[15:8],time_set_r[23:16],time_set_r[31:24]};是
wire trans_done;
uart_tx_data4 uart_tx_data4_u(
  .clk          (clk),
  .reset_n      (reset_n),
  .data40       (data40),
  .trans_go     (trans_go),
  .uart_tx      (uart_tx),
  .trans_done   (trans_done)
);
endmodule

以下是顶层文件中需要的子程序。

串口接受单个字节的程序

module uart_byte_rx(
    input           clk,
    input           reset_n,
    input           uart_rx,
    input      [2:0]baud_set,
    output reg [7:0]data,
    output reg      rx_done  
);
reg [2:0]sta_bit;
reg [2:0]sto_bit;
reg [1:0] uart_rx_r;
always@(posedge clk ) begin
     uart_rx_r[0]<=uart_rx;
     uart_rx_r[1]<=uart_rx_r[0];     
end
wire pedge_uart_rx;
wire nedge_uart_rx;
assign pedge_uart_rx=(uart_rx_r==2'b01);
assign nedge_uart_rx=(uart_rx_r==2'b10);

reg [8:0] bps_dr;
always @(*)
    case(baud_set)
        0: bps_dr=1000000000/9600/16/20-1;
        1: bps_dr=1000000000/19200/16/20-1;
        2: bps_dr=1000000000/38400/16/20-1;
        3: bps_dr=1000000000/57600/16/20-1;
        4: bps_dr=1000000000/115200/16/20-1;
        default:bps_dr=1000000000/9600/16/20-1;
     endcase
wire bps_clk_16x;
reg [8:0] div_cnt;
assign bps_clk_16x=(div_cnt==bps_dr/2);

reg rx_en;
always@(posedge clk or negedge reset_n)begin
    if(!reset_n)
        rx_en<=0;
    else if(nedge_uart_rx)
        rx_en<=1;
    else if(rx_done||(sta_bit>=4))
        rx_en<=0;
end


always@(posedge clk or negedge reset_n)begin
    if(!reset_n)
        div_cnt<=0;
    else if(rx_en)begin
        if(div_cnt==bps_dr)
            div_cnt<=0;
        else  div_cnt<=div_cnt+1;
    end
    else div_cnt<=div_cnt;  
end

reg [7:0] bps_cnt;
always@(posedge clk or negedge reset_n)begin
    if(!reset_n)
        bps_cnt<=0;
    else if(rx_en)begin
       if(bps_clk_16x) begin
        if(bps_cnt==160)
             bps_cnt<=0;
        else
             bps_cnt<=bps_cnt+1;
        end
     else 
        bps_cnt<=bps_cnt;
     end
     else bps_cnt<=0;
end

// reg width name number
reg [2:0]r_data[7:0];

always@(posedge clk or negedge reset_n)begin
    if(!reset_n)begin
        sta_bit<=0;
        sto_bit<=0;
        r_data[0]<=0;
        r_data[1]<=0;
        r_data[2]<=0;
        r_data[3]<=0;
        r_data[4]<=0;
        r_data[5]<=0;
        r_data[6]<=0;
        r_data[7]<=0;
    end
    else if(bps_clk_16x)begin
          case(bps_cnt)
              0:begin
                    sta_bit<=0;
                    sto_bit<=0;
                    r_data[0]<=0;
                    r_data[1]<=0;
                    r_data[2]<=0;
                    r_data[3]<=0;
                    r_data[4]<=0;
                    r_data[5]<=0;
                    r_data[6]<=0;
                    r_data[7]<=0;
              end
              5,6,7,8,9,10,11     :sta_bit<=sta_bit+uart_rx;
              21,22,23,24,25,26,27:r_data[0] <=r_data[0]+uart_rx;
			  37,38,39,40,41,42,43:r_data[1] <= r_data[1] + uart_rx;
			  53,54,55,56,57,58,59:r_data[2] <= r_data[2] + uart_rx;
			  69,70,71,72,73,74,75:r_data[3] <= r_data[3] + uart_rx;
			  85,86,87,88,89,90,91:r_data[4] <= r_data[4] + uart_rx;
			  101,102,103,104,105,106,107:r_data[5] <= r_data[5] + uart_rx;
			  117,118,119,120,121,122,123:r_data[6] <= r_data[6] + uart_rx;
			  133,134,135,136,137,138,139:r_data[7] <= r_data[7] + uart_rx;
			  149,150,151,152,153,154,155:sto_bit <= sto_bit + uart_rx;
            default:;
           endcase
    end
end

always@(posedge clk or negedge reset_n)begin
    if(!reset_n)
        data<=0;
    else if(bps_clk_16x&&(bps_cnt==160))begin
        data[0]<=(r_data[0]>=4);
        data[1]<=(r_data[1]>=4);
        data[2]<=(r_data[2]>=4);
        data[3]<=(r_data[3]>=4);
        data[4]<=(r_data[4]>=4);
        data[5]<=(r_data[5]>=4);
        data[6]<=(r_data[6]>=4);
        data[7]<=(r_data[7]>=4);  
     end   
end

always@(posedge clk or negedge reset_n)begin
    if(!reset_n)
        rx_done<=0;
    else if((div_cnt==bps_dr/2)&&(bps_cnt==160))
        rx_done<=1;
    else rx_done<=0;
end
endmodule

串口接受一帧数据(多字节)的控制程序

module uart_cmd(
    input            clk,
    input            reset_n,
    input      [7:0] rx_data,
    input            rx_done,
    output reg       ctrl,
    output reg [31:0]time_set
); 
reg r_rx_done;   
always@(posedge clk)
    r_rx_done<= rx_done;
 
// reg width   name    number
   reg [7:0] data_str [5:0];
 always@(posedge clk ) begin
    if(rx_done)begin
        data_str[5]<=#1 rx_data;
        data_str[4]<=#1data_str[5];
        data_str[3]<=#1data_str[4];
        data_str[2]<=#1data_str[3];
        data_str[1]<=#1data_str[2];
        data_str[0]<=#1data_str[1];
    end
 end 
 
 always@(posedge clk or negedge reset_n ) begin
    if(!reset_n)begin
        ctrl<=#1 0;
        time_set<=#1 0;
    end   
    else if(r_rx_done) begin
        if((data_str[0]==8'h55)&&(data_str[5]==8'hF0))begin
            time_set[7:0]<=#1 data_str[4];
            time_set[15:8]<=#1 data_str[3];
            time_set[23:16]<=#1data_str[2];
            time_set[31:24]<=#1 data_str[1];
            ctrl<=#1 1; 
        end
     end
     else begin
         ctrl<=#1 0;
     end
  end
endmodule

数码管显示的顶层程序(例化两个程序来驱动数码管显示)

module hex8_test(
  input              clk,
  input              reset_n, 
  input      [31:0]  disp_data, 
  output             ds,    
  output             sh_cp, 
  output             st_cp     
 );
wire [7:0]   sel;
wire [7:0]   seg;
//assign disp_data=32'h23579bdf;
hex8_2  hex8_2_u(
  clk,
  reset_n,
  disp_data,
  sel, 
  seg    
);  

wire [15:0]data;
assign data={seg,sel};
wire s_en;
assign s_en=1;
hc595_driver hc595_driver_u(
     clk,
     reset_n,
     data, 
     s_en,
     ds,
     sh_cp,
     st_cp   
);  
  
endmodule

数码管例化的程序——1.数码管数据

module hex8_2 (
  input              clk,
  input              reset_n,
  input      [31:0]  disp_data,
  output reg [7:0]   sel, 
  output reg [7:0]   seg    
);
  reg clk_1k;
  reg [15:0] div_cnt;
  always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           div_cnt<=0;
      else if(div_cnt>=49999)
           div_cnt<=0;
      else div_cnt<=div_cnt+1;
   end   
   
  always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           clk_1k<=0;
      else if(div_cnt==49999)
           clk_1k<=1;
      else 
           clk_1k<=0;          
   end 
   
 reg[2:0] num_cnt;
  always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           num_cnt<=0;
      else if(clk_1k)
           num_cnt<=num_cnt+1;
   end 
  always @(posedge clk)
     case(num_cnt)
            0:sel<=8'b0000_0001;
            1:sel<=8'b0000_0010;
            2:sel<=8'b0000_0100;
            3:sel<=8'b0000_1000;
            4:sel<=8'b0001_0000;
            5:sel<=8'b0010_0000;
            6:sel<=8'b0100_0000;
            7:sel<=8'b1000_0000;
            default:;
      endcase

  reg [3:0] disp_tmp;
  always @(posedge clk)
     case(num_cnt)
            7:disp_tmp<=disp_data[31:28];
            6:disp_tmp<=disp_data[27:24];
            5:disp_tmp<=disp_data[23:20];
            4:disp_tmp<=disp_data[19:16];
            3:disp_tmp<=disp_data[15:12];
            2:disp_tmp<=disp_data[11:8];
            1:disp_tmp<=disp_data[7:4];
            0:disp_tmp<=disp_data[3:0];
            default:;
      endcase 

  always @(posedge clk)
     case(disp_tmp)
         4'h0:seg=8'hc0;
         4'h1:seg=8'hf9;
         4'h2:seg=8'ha4;
         4'h3:seg=8'hb0;
         4'h4:seg=8'h99;
         4'h5:seg=8'h92;
         4'h6:seg=8'h82;
         4'h7:seg=8'hf8;
         4'h8:seg=8'h80;
         4'h9:seg=8'h90;
         4'ha:seg=8'h88;
         4'hb:seg =8'h83;
         4'hc:seg =8'hc6;
         4'hd:seg =8'ha1;
         4'he:seg =8'h86;
         4'hf:seg =8'h8e;
         default:;
      endcase        
endmodule


数码管例化的程序——2.驱动HC595

module hc595_driver(
  input             clk,
  input             reset_n,
  input     [15:0]  data, 
  input             s_en,
  output  reg       ds,
  output  reg       sh_cp,
  output  reg       st_cp   
);
reg [15:0] r_data;
  always @(posedge clk ) begin
      if(s_en)
           r_data<=data;
   end

reg [7:0] divider_cnt;
  always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           divider_cnt<=0;
      else if(divider_cnt==1)
           divider_cnt<=0;
      else 
           divider_cnt<=divider_cnt+1;
   end
wire sck_plus;
assign sck_plus=(divider_cnt==1);
  
reg [5:0] shcp_edge_cnt;
  always @(posedge clk or negedge reset_n) begin
      if(!reset_n)
           shcp_edge_cnt<=0;
      else if(sck_plus)begin
            if(shcp_edge_cnt==32)
             shcp_edge_cnt<=0;
           else 
             shcp_edge_cnt<=shcp_edge_cnt+1;
           end
   end

   always @(posedge clk or negedge reset_n) begin
       if(!reset_n)begin
          ds<=0;  
          sh_cp<=0;
          st_cp<=0;
       end
       
       else begin
          case(shcp_edge_cnt)
            0:begin sh_cp<=0;st_cp<=0;ds<=r_data[15];end
            1:begin sh_cp<=1;end
            2:begin sh_cp<=0;ds<=r_data[14];end
            3:begin sh_cp<=1;end
            4:begin sh_cp<=0;ds<=r_data[13];end
            5:begin sh_cp<=1;end
            6:begin sh_cp<=0;ds<=r_data[12];end
            7:begin sh_cp<=1;end
            8:begin sh_cp<=0;ds<=r_data[11];end
            9:begin sh_cp<=1;end
            10:begin sh_cp<=0;ds<=r_data[10];end
            11:begin sh_cp<=1;end
            12:begin sh_cp<=0;ds<=r_data[9];end
            13:begin sh_cp<=1;end
            14:begin sh_cp<=0;ds<=r_data[8];end
            15:begin sh_cp<=1;end
            16:begin sh_cp<=0;ds<=r_data[7];end
            17:begin sh_cp<=1;end
            18:begin sh_cp<=0;ds<=r_data[6];end
            19:begin sh_cp<=1;end
            20:begin sh_cp<=0;ds<=r_data[5];end
            21:begin sh_cp<=1;end
            22:begin sh_cp<=0;ds<=r_data[4];end
            23:begin sh_cp<=1;end
            24:begin sh_cp<=0;ds<=r_data[3];end
            25:begin sh_cp<=1;end
            26:begin sh_cp<=0;ds<=r_data[2];end
            27:begin sh_cp<=1;end
            28:begin sh_cp<=0;ds<=r_data[1];end
            29:begin sh_cp<=1;end
            30:begin sh_cp<=0;ds<=data[0];end
            31:begin sh_cp<=1;end
            32:st_cp<=1;
          default: begin ds<=0;  
                         sh_cp<=0;
                         st_cp<=0;
                    end
          endcase
       end

   end
endmodule

串口发送多个字节到上位机的程序


module uart_tx_data4(
  input clk,
  input reset_n,
  input [31:0]data40,
  input trans_go,
  
  output uart_tx,
  output reg trans_done
);

  reg [7:0] data;
  reg send_go;
  wire tx_done; 
  reg [3:0] cnt;
  reg [1:0] state;
    
uart_byte_tx uart_byte_tx11(
.data      (data)     ,
.send_go   (send_go)  ,
.clk       (clk)      ,
.reset_n   (reset_n)  ,
.baud_set  (4) ,
          
.uart_tx   (uart_tx)  ,
.tx_done   (tx_done)
);
  
  always@(posedge clk or negedge reset_n )begin
      if(!reset_n)begin
         trans_done<=0;  
         send_go<=0;
         state<=0;
         data<=0;
         cnt<=0;end
      else begin
      case(state)
           0: begin
               trans_done<=0;  
               if(trans_go)begin
               data<=data40[7:0];
               send_go<=1;
               state<=1;
               end
               end
           1 :begin
              cnt<=1;
              send_go<=0;
               if(tx_done)begin
                  if(cnt==3)begin
                    state<=0; 
                    send_go<=0;
                    trans_done<=1;
                    cnt<=0;  
                   end
                  else begin
                       data<=data40[8*cnt+8+:8];
                       cnt<=cnt+1;
                       send_go<=1;
                       state<=1;
                   end end
                else begin
                      send_go<=0;
                      cnt<=cnt;
                      data<=data;
                      end
               end
      default:;
      endcase
      end
  end
endmodule

串口发送单个字节到上位机的程序(串口发送多个字节需要例化的程序)

module uart_byte_tx(
   input [7:0] data,
   input send_go,
   input clk,
   input reset_n,
   input [2:0] baud_set,
   
   output  reg uart_tx,
   output  reg tx_done
);

   reg [20:0]bps_dr;
   always @(*)
        case(baud_set)
            0:bps_dr=1000000000/9600/20;
            1:bps_dr=1000000000/19200/20;
            2:bps_dr=1000000000/38400/20;
            3:bps_dr=1000000000/57600/20;
            4:bps_dr=1000000000/115200/20;
            default: bps_dr=1000000000/9600/20;
          endcase

   reg send_en; 
   reg [7:0] r_data;           
   always @(posedge clk or negedge reset_n )begin
       if(!reset_n)
             send_en<=0;
       else if(send_go)
             send_en<=1;
       else if(tx_done)
             send_en<=0;
    end

     
   always @(posedge clk or negedge reset_n)begin
       if(!reset_n)
             r_data<=0;
       else if(send_go)
             r_data<=data;
        else r_data<=r_data;
    end   


   wire bps_clk;
   assign bps_clk=(div_cnt==1);
   reg [20:0] div_cnt;
   always @(posedge clk or negedge reset_n )begin
       if(!reset_n)
            div_cnt<=0;
       else if(send_en)
            if(div_cnt==bps_dr-1)
                 div_cnt<=0;
            else div_cnt<=div_cnt+1;
       else div_cnt<=0;
    end 
    
   reg [3:0] bps_cnt;
   always @(posedge clk or negedge reset_n )begin
       if(!reset_n)
            bps_cnt<=0;
       else if(send_en)begin
           if(bps_clk)begin
            if(bps_cnt==11)
               bps_cnt<=0;
            else
                bps_cnt<=bps_cnt+1;
            end
        end 
        else
             bps_cnt<=0;
   end

   always@(posedge clk or negedge reset_n ) 
       if(!reset_n)begin
            uart_tx<=1;
            end
       else begin
            case(bps_cnt)
            0:; 
            1:uart_tx<=0;
            2:uart_tx<=r_data[0];
            3:uart_tx<=r_data[1];
            4:uart_tx<=r_data[2];
            5:uart_tx<=r_data[3];
            6:uart_tx<=r_data[4];
            7:uart_tx<=r_data[5];
            8:uart_tx<=r_data[6];
            9:uart_tx<=r_data[7];
            10:uart_tx<=1;
            11:begin uart_tx<=1;end
            default:uart_tx<=1;
            endcase
       end
       
    always@(posedge clk or negedge reset_n ) 
       if(!reset_n)
            tx_done<=0;
       else if((bps_clk==1) &&(bps_cnt==10))
            tx_done<=1;
       else if(bps_cnt==0)
            tx_done<=0;
       else
            tx_done<=0;
endmodule
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值