回答

收藏

[评测分享] 【超越者Spartan-6 FPGA开发板】 +4、电容触摸计数器

#板卡评测 #板卡评测 1880 人阅读 | 0 人回复 | 2021-05-16

本帖最后由 TLLED 于 2021-5-16 00:17 编辑

    学习下数码管动态驱动的程序。要实现的功能:按一次触摸按键,数码计数值加1。

    一、硬件电路


    数码管硬件电路
   




   二、驱动程序



    2.1、动态数码管驱动程序seg_led_dynamic.v
    这段是官网驱动的例程。
   

  1. module seg_led_dynamic(
  2.         input            clk  ,        
  3.         input            rst_n,
  4.         
  5.         input         [19:0]    data   ,        // 6位数码管要显示的数值
  6.         input         [5:0]     point  ,        // 小数点具体显示的位置,从高到低,高电平有效
  7.         input                   en     ,        // 数码管使能信号
  8.         input                   sign   ,        // 符号位(高电平显示"-"号)
  9.         
  10.         output  reg  [5:0]  seg_sel ,   // 数码管位选
  11.         output  reg  [7:0]  seg_led     // 数码管段选
  12.         );

  13. //parameter define        
  14. localparam  CLK_DIVIDE = 4'd10     ;        // 时钟分频系数
  15. localparam  MAX_NUM    = 13'd5000  ;        // 对数码管驱动时钟(5MHz)计数1ms所需的计数值

  16. //reg define
  17. reg    [ 3:0]             clk_cnt  ;        // 时钟分频计数器
  18. reg                       dri_clk  ;        // 数码管的驱动时钟,5MHz
  19. reg    [23:0]             num      ;        // 24位bcd码寄存器
  20. reg    [12:0]             cnt0     ;        // 数码管驱动时钟计数器
  21. reg                       flag     ;        // 标志信号(标志着cnt0计数达1ms)
  22. reg    [2:0]              cnt_sel  ;        // 数码管位选计数器
  23. reg    [3:0]              num_disp ;        // 当前数码管显示的数据
  24. reg                       dot_disp ;        // 当前数码管显示的小数点

  25. //wire define
  26. wire   [3:0]              data0    ;        // 个位数
  27. wire   [3:0]              data1    ;        // 十位数
  28. wire   [3:0]              data2    ;        // 百位数
  29. wire   [3:0]              data3    ;        // 千位数
  30. wire   [3:0]              data4    ;        // 万位数
  31. wire   [3:0]              data5    ;        // 十万位数

  32. //提取显示数值所对应的十进制数的各个位
  33. assign  data0 = data % 4'd10;               // 个位数
  34. assign  data1 = data / 4'd10 % 4'd10   ;    // 十位数
  35. assign  data2 = data / 7'd100 % 4'd10  ;    // 百位数
  36. assign  data3 = data / 10'd1000 % 4'd10 ;   // 千位数
  37. assign  data4 = data / 14'd10000 % 4'd10;   // 万位数
  38. assign  data5 = data / 17'd100000;          // 十万位数

  39. //对系统时钟10分频,得到的频率为5MHz的数码管驱动时钟dri_clk
  40. always @(posedge clk or negedge rst_n) begin
  41.    if(!rst_n) begin
  42.        clk_cnt <= 4'd0;
  43.        dri_clk <= 1'b1;
  44.    end
  45.    else if(clk_cnt == CLK_DIVIDE/2 - 1'd1) begin
  46.        clk_cnt <= 4'd0;
  47.        dri_clk <= ~dri_clk;
  48.    end
  49.    else begin
  50.        clk_cnt <= clk_cnt + 1'b1;
  51.        dri_clk <= dri_clk;
  52.    end
  53. end

  54. //将20位2进制数转换为8421bcd码(即使用4位二进制数表示1位十进制数)
  55. always @ (posedge dri_clk or negedge rst_n) begin
  56.     if (!rst_n)
  57.         num <= 24'b0;
  58.     else begin
  59.         if (data5 || point[5]) begin     //如果显示数据为6位十进制数,
  60.             num[23:20] <= data5;         //则依次给6位数码管赋值
  61.             num[19:16] <= data4;
  62.             num[15:12] <= data3;
  63.             num[11:8]  <= data2;
  64.             num[ 7:4]  <= data1;
  65.             num[ 3:0]  <= data0;
  66.         end
  67.         else begin                        
  68.             if (data4 || point[4]) begin //如果显示数据为5位十进制数,则给低5位数码管赋值
  69.                 num[19:0] <= {data4,data3,data2,data1,data0};
  70.                 if(sign)                    
  71.                     num[23:20] <= 4'd11; //如果需要显示负号,则最高位(第6位)为符号位
  72.                 else
  73.                     num[23:20] <= 4'd10; //不需要显示负号时,则第6位不显示任何字符
  74.             end
  75.             else begin                   //如果显示数据为4位十进制数,则给低4位数码管赋值
  76.                 if (data3 || point[3]) begin
  77.                     num[15: 0] <= {data3,data2,data1,data0};
  78.                     num[23:20] <= 4'd10; //第6位不显示任何字符
  79.                     if(sign)             //如果需要显示负号,则最高位(第5位)为符号位
  80.                         num[19:16] <= 4'd11;
  81.                     else                 //不需要显示负号时,则第5位不显示任何字符
  82.                         num[19:16] <= 4'd10;
  83.                 end
  84.                 else begin               //如果显示数据为3位十进制数,则给低3位数码管赋值
  85.                     if (data2 || point[2]) begin
  86.                         num[11: 0] <= {data2,data1,data0};
  87.                                          //第6、5位不显示任何字符
  88.                         num[23:16] <= {2{4'd10}};
  89.                         if(sign)         //如果需要显示负号,则最高位(第4位)为符号位
  90.                             num[15:12] <= 4'd11;
  91.                         else             //不需要显示负号时,则第4位不显示任何字符
  92.                             num[15:12] <= 4'd10;
  93.                     end
  94.                     else begin           //如果显示数据为2位十进制数,则给低2位数码管赋值
  95.                         if (data1 || point[1]) begin
  96.                             num[ 7: 0] <= {data1,data0};
  97.                                          //第6、5、4位不显示任何字符
  98.                             num[23:12] <= {3{4'd10}};
  99.                             if(sign)     //如果需要显示负号,则最高位(第3位)为符号位
  100.                                 num[11:8]  <= 4'd11;
  101.                             else         //不需要显示负号时,则第3位不显示任何字符
  102.                                 num[11:8] <=  4'd10;
  103.                         end
  104.                         else begin       //如果显示数据为1位十进制数,则给最低位数码管赋值
  105.                             num[3:0] <= data0;
  106.                                          //第6、5位不显示任何字符
  107.                             num[23:8] <= {4{4'd10}};
  108.                             if(sign)     //如果需要显示负号,则最高位(第2位)为符号位
  109.                                 num[7:4] <= 4'd11;
  110.                             else         //不需要显示负号时,则第2位不显示任何字符
  111.                                 num[7:4] <= 4'd10;
  112.                         end
  113.                     end
  114.                 end
  115.             end
  116.         end
  117.     end
  118. end

  119. //每当计数器对数码管驱动时钟计数时间达1ms,输出一个时钟周期的脉冲信号
  120. always @ (posedge dri_clk or negedge rst_n) begin
  121.     if (rst_n == 1'b0) begin
  122.         cnt0 <= 13'b0;
  123.         flag <= 1'b0;
  124.      end
  125.     else if (cnt0 < MAX_NUM - 1'b1) begin
  126.         cnt0 <= cnt0 + 1'b1;
  127.         flag <= 1'b0;
  128.      end
  129.     else begin
  130.         cnt0 <= 13'b0;
  131.         flag <= 1'b1;
  132.      end
  133. end

  134. //cnt_sel从0计数到5,用于选择当前处于显示状态的数码管
  135. always @ (posedge dri_clk or negedge rst_n) begin
  136.     if (rst_n == 1'b0)
  137.         cnt_sel <= 3'b0;
  138.     else if(flag) begin
  139.         if(cnt_sel < 3'd5)
  140.             cnt_sel <= cnt_sel + 1'b1;
  141.         else
  142.             cnt_sel <= 3'b0;
  143.     end
  144.     else
  145.         cnt_sel <= cnt_sel;
  146. end

  147. //控制数码管位选信号,使6位数码管轮流显示
  148. always @ (posedge dri_clk or negedge rst_n) begin
  149.     if(!rst_n) begin
  150.         seg_sel  <= 6'b111111;              //位选信号低电平有效
  151.         num_disp <= 4'b0;           
  152.         dot_disp <= 1'b1;                   //共阳极数码管,低电平导通
  153.     end
  154.     else begin
  155.         if(en) begin
  156.             case (cnt_sel)
  157.                 3'd0 :begin
  158.                     seg_sel  <= 6'b111110;  //显示数码管最低位
  159.                     num_disp <= num[3:0] ;  //显示的数据
  160.                     dot_disp <= ~point[0];  //显示的小数点
  161.                 end
  162.                 3'd1 :begin
  163.                     seg_sel  <= 6'b111101;  //显示数码管第1位
  164.                     num_disp <= num[7:4] ;
  165.                     dot_disp <= ~point[1];
  166.                 end
  167.                 3'd2 :begin
  168.                     seg_sel  <= 6'b111011;  //显示数码管第2位
  169.                     num_disp <= num[11:8];
  170.                     dot_disp <= ~point[2];
  171.                 end
  172.                 3'd3 :begin
  173.                     seg_sel  <= 6'b110111;  //显示数码管第3位
  174.                     num_disp <= num[15:12];
  175.                     dot_disp <= ~point[3];
  176.                 end
  177.                 3'd4 :begin
  178.                     seg_sel  <= 6'b101111;  //显示数码管第4位
  179.                     num_disp <= num[19:16];
  180.                     dot_disp <= ~point[4];
  181.                 end
  182.                 3'd5 :begin
  183.                     seg_sel  <= 6'b011111;  //显示数码管最高位
  184.                     num_disp <= num[23:20];
  185.                     dot_disp <= ~point[5];
  186.                 end
  187.                 default :begin
  188.                     seg_sel  <= 6'b111111;
  189.                     num_disp <= 4'b0;
  190.                     dot_disp <= 1'b1;
  191.                 end
  192.             endcase
  193.         end
  194.         else begin
  195.             seg_sel  <= 6'b111111;          //使能信号为0时,所有数码管均不显示
  196.             num_disp <= 4'b0;
  197.             dot_disp <= 1'b1;
  198.         end
  199.     end
  200. end

  201. //控制数码管段选信号,显示字符
  202. always @ (posedge dri_clk or negedge rst_n) begin
  203.     if (!rst_n)
  204.         seg_led <= 8'hc0;
  205.     else begin
  206.         case (num_disp)
  207.             4'd0 : seg_led <= {dot_disp,7'b1000000}; //显示数字 0
  208.             4'd1 : seg_led <= {dot_disp,7'b1111001}; //显示数字 1
  209.             4'd2 : seg_led <= {dot_disp,7'b0100100}; //显示数字 2
  210.             4'd3 : seg_led <= {dot_disp,7'b0110000}; //显示数字 3
  211.             4'd4 : seg_led <= {dot_disp,7'b0011001}; //显示数字 4
  212.             4'd5 : seg_led <= {dot_disp,7'b0010010}; //显示数字 5
  213.             4'd6 : seg_led <= {dot_disp,7'b0000010}; //显示数字 6
  214.             4'd7 : seg_led <= {dot_disp,7'b1111000}; //显示数字 7
  215.             4'd8 : seg_led <= {dot_disp,7'b0000000}; //显示数字 8
  216.             4'd9 : seg_led <= {dot_disp,7'b0010000}; //显示数字 9
  217.             4'd10: seg_led <= 8'b11111111;           //不显示任何字符
  218.             4'd11: seg_led <= 8'b10111111;           //显示负号(-)
  219.             default:
  220.                    seg_led <= {dot_disp,7'b1000000};
  221.         endcase
  222.     end
  223. end


  224. endmodule
复制代码
        2.2、触摸按键驱动数码管部分程序
   
    在按键松开的上升沿,数码计数一次
   
  1. //数码管需要显示的数据,从0累加到999999
  2. always @ (posedge switch or negedge rst_n) begin
  3.     if (!rst_n)begin
  4.         data_t  <= 20'b0;
  5.         point_t <=6'b000000;
  6.         en_t    <= 1'b0;
  7.         sign_t  <= 1'b0;
  8.     end
  9.     else begin
  10.         point_t <= 6'b000000;             //不显示小数点
  11.         en_t    <= 1'b1;                  //打开数码管使能信号
  12.         sign_t  <= 1'b0;                  //不显示负号
  13.         //if (switch) begin                 //显示数值每隔0.01s累加一次
  14.             if(data_t < 20'd999999)
  15.                 data_t <= data_t +1'b1;     
  16.             else
  17.                 data_t <= 20'b0;
  18.         //end
  19.     end
  20. end
复制代码

    2.3、主程序部分
   
    将触摸按键的值传递给数码管驱动子程序
  1. //触摸按键
  2. touch u_touch(
  3.     .clk        (sys_clk  ),
  4.     .rst_n      (sys_rst_n),
  5.     .t_key      (touch_key),
  6.     .switch     (key_val ),
  7.          .beep_val   (beep),
  8.          
  9.          .data_t          (data     ),       // 6位数码管要显示的数值
  10.     .point_t         (point    ),       // 小数点具体显示的位置,高电平有效
  11.     .en_t            (en       ),       // 数码管使能信号
  12.     .sign_t          (sign     )        // 符号位
  13. );
复制代码

    2.4、程序源码   
fpag_test-20210515.rar (2.9 MB, 下载次数: 0)


    三、执行结果


   













分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条