当前位置:   article > 正文

FPGA出租车计费系统设计_fpga出租车计价器的设计与实现

fpga出租车计价器的设计与实现

一、需求分析

        设计一个简易的出租车计费系统,实现计价功能,计费标准为按里程收费,起步价为6.00元,当里程小于3公里时,按起步价收费,超过3公里后按1.2元/公里收费。

        实现车辆行驶的模拟:能模拟汽车的启动,暂停,停止等状态。

        计费显示部分设计:用LED数码管实时显示车费和汽车行驶里程,用一个按键切换车费和里程的显示,里程单位km,记程范围为0-99km。

二、输入输出端口

输入:系统时钟、系统复位、行驶模拟按键(启动、暂停、停止)、显示切换按键

输出:①数码管段选位选(没有驱动芯片

           ②ds数据、oe使能、shcp移位时钟、stcp寄存时钟(74hc595串并转换数码管驱动芯片)

三、模块介绍

1.计费逻辑状态机:

        状态机的核心是一个case语块,是一种编程思想。case的条件是不同的状态(state),每个状态下分别进行各种操作,状态的切换由输入信号条件控制。在写法上可以只定义一个状态(state),或者定义两个状态(now_state、next_state)现态和次态。再写一个状态转移,让次态不断传递给现态,完成状态的切换。

        在本项目中,使用状态机思想,描述汽车的启动、暂停、停止几种状态。

        停止状态:此状态下对车费和里程清零,并判断启动键是否按下,进入启动状态

        启动状态:让里程自增(模拟汽车行驶)让车费为6元,当里程大于等于3公里,车费开始每公里1.2元增加。

        暂停状态:不进行操作,只判断启动和停止键是否按下进行跳转。

2.数码管动态显示:

        数码管一般是由7个led灯组成,称为7段数码管,加上dp小数点称为8段。  

        如图,要显示数字“1”,bc亮,其他不亮,段码则为1001_1111,转为16进制从低位到高位数,为F9。开发板上有6位数码管,即6个这样的数码管连接在一起,通过位选来控制让哪一个数码管有效,再通过段选控制显示的内容。

        所以,动态显示=位选信号从1-6扫描为周期,例如要显示数字“2023”,在选通1号数码管亮的时候,段选为“3”;接着选通2号数码管亮,段选输出“2”;接着让3号数码管亮,段选“0”;4号数码管亮,段选“2”,这样通过高速4次扫描,由于人眼暂留效应,看到的就是“2023”同时亮起的效果。

3.bcd_8421模块:

        明白了数据的获取(计费逻辑)与显示(动态数码管),但实际上要想把一个数字的不同数位分别显示出来,还需要一个拆分功能把一个数拆成小数位、个位、十位、百位等,然后把不同位分别送入不同数码管动态显示。

        起初我是自己用除法写了拆分逻辑,进行电路综合后发现,在FPGA芯片中,除法非常占用资源,导致我的资源块超出(下图报错信息),无法进行布局布线设计。FPGA有硬件乘法器,但没有除法器。如果非要用除法,建议使用ip核除法软核,不过ip核也是使用“+,-,移位”实现的。所以不如自己写一个拆分模块。

  1. assign fare_g[7:4] = (fare/10) % 10;
  2. assign fare_g[11:8] = (fare/100) % 10;
  3. assign fare_g[15:12] = (fare/1000) % 10;

        拆分思想是,先补零,移位判断是否大于4,大于就加3再判断。对于十进制数的位数进行判断,例如“234”,3位,补3x4=12个0,进行如下操作后,“2”“3”“4”就被拆开分别放入3组4位二进制里了。(下图取自野火FPGA教程)

        对费用数据、里程数据进行拆分后,分别放入段选寄存器中,按位把数据组一个一个送入595芯片,595芯片将串行传入的数据,进行移位存入寄存器,当一组8位数据存好,再复制到输出寄存器并行输出,编写控制移位时钟和寄存器时钟的时序,送入595芯片,即可实现串并转换。

        如果没有595芯片,就需要编写动态扫描周期进程,按照位选段选时序要求,依次让数码管不同位显示不同数据。

四、代码

1.计费逻辑与显示数据生成模块

  1. module data_gen //数据生成模块
  2. #(
  3. parameter CNT_MAX = 26'd49_999_999,
  4. )
  5. (
  6. input wire sys_clk , // 系统时钟
  7. input wire sys_rst_n , // 系统复位
  8. input wire start , // 启动
  9. input wire stop , // 停止
  10. input wire pause , // 暂停
  11. input wire key_switch , // 切换显示,
  12. output reg [19:0] data, //数据输出
  13. output reg [5:0] point, //小数点
  14. output wire sign, //正负号
  15. output reg seg_en //显示使能
  16. );
  17. parameter STOP = 4'b0000 , //停止
  18. START = 4'b0001 , //启动
  19. PAUSE = 4'b0010 ; //暂停,三个状态值
  20. reg [25:0] cnt_100ms;
  21. reg cnt_flag;
  22. reg [10:0] fare; // 车费
  23. reg [6:0] total_distance; // 总行驶里程
  24. reg [3:0] state; // 车辆状态
  25. //100ms的计费自增周期产生
  26. always@(posedge sys_clk or negedge sys_rst_n)
  27. if(sys_rst_n == 1'b0)
  28. cnt_100ms <= 26'd0;
  29. else if(cnt_100ms == CNT_MAX)
  30. cnt_100ms <= 26'd0;
  31. else
  32. cnt_100ms <= cnt_100ms + 1'b1;
  33. always@(posedge sys_clk or negedge sys_rst_n)
  34. if(sys_rst_n == 1'b0)
  35. cnt_flag <= 1'b0;
  36. else if(cnt_100ms == CNT_MAX - 1'b1)
  37. cnt_flag <= 1'b1;
  38. else
  39. cnt_flag <= 1'b0;
  40. //计费逻辑状态机进程
  41. always@(posedge sys_clk or negedge sys_rst_n)
  42. if(!sys_rst_n)
  43. begin
  44. fare <= 11'b0; //初始化车费、路程等清零
  45. total_distance <= 7'b0;
  46. state <= 4'b0;
  47. end
  48. else
  49. begin //状态机各个状态转换
  50. case (state)
  51. STOP: // 停止状态
  52. if(start == 1'b0)
  53. begin
  54. state <= START; // 切换到启动状态
  55. end
  56. else
  57. begin
  58. total_distance <= 7'b0;
  59. fare <= 11'b0;
  60. end
  61. START: // 启动状态
  62. if(pause == 1'b0)
  63. begin
  64. state <= PAUSE; // 切换到暂停状态
  65. end
  66. else if(cnt_flag == 1'b1)
  67. begin
  68. total_distance <= total_distance + 1'b1; // 模拟行驶
  69. if(total_distance <= 7'd2)
  70. begin
  71. fare <= 11'd60; // 起步价6.00元
  72. end // 这里用60代表6元,12代表1.2元
  73. else
  74. begin
  75. fare <= fare + 11'd12; // 超过3公里,每公里1.2元
  76. end
  77. end
  78. else if(stop == 1'b0) begin
  79. state <= STOP; // 切换到停止状态
  80. end
  81. PAUSE: // 暂停状态
  82. if(start == 1'b0)
  83. begin
  84. state <= START; // 切换到启动状态
  85. end
  86. else if(stop == 1'b0)
  87. begin
  88. state <= STOP; // 切换到停止状态
  89. end
  90. endcase
  91. end
  92. //显示切换进程
  93. always@(posedge sys_clk or negedge sys_rst_n)
  94. if(!sys_rst_n)
  95. begin
  96. data <= 20'd0;
  97. point <= 6'b000_000;
  98. end
  99. else if(key_switch == 1'b0) //显示费用模式
  100. begin
  101. data <= fare;
  102. point <= 6'b000_010;
  103. end
  104. else //显示里程模式
  105. begin
  106. data <= total_distance;
  107. point <= 6'b000_000;
  108. end
  109. assign sign = 1'b0;
  110. always@(posedge sys_clk or negedge sys_rst_n)
  111. if(sys_rst_n == 1'b0)
  112. seg_en <= 1'b0;
  113. else
  114. seg_en <= 1'b1;
  115. endmodule

2.595芯片驱动控制模块

  1. module hc595_ctrl
  2. (
  3. input wire sys_clk , //系统时钟
  4. input wire sys_rst_n, //系统复位
  5. input wire [7:0] seg , //数码管段选
  6. input wire [5:0] sel , //数码管位选
  7. output reg shcp , //移位时钟
  8. output reg stcp , //寄存器时钟
  9. output reg ds , //数据
  10. output wire oe //使能
  11. );
  12. wire [13:0] data ;
  13. reg [1:0] cnt ;
  14. reg [3:0] cnt_bit ;
  15. assign data = {seg[0],seg[1],seg[2],seg[3],
  16. seg[4],seg[5],seg[6],seg[7],sel}; //把段位数据放入data
  17. //产生周期扫描信号
  18. always@(posedge sys_clk or negedge sys_rst_n)
  19. if(sys_rst_n == 1'b0)
  20. cnt <= 2'd0;
  21. else if(cnt == 2'd3)
  22. cnt <= 2'd0;
  23. else
  24. cnt <= cnt + 2'd1;
  25. always@(posedge sys_clk or negedge sys_rst_n)
  26. if(sys_rst_n == 1'b0)
  27. cnt_bit <= 4'd0;
  28. else if((cnt_bit == 4'd13) && (cnt == 2'd3))
  29. cnt_bit <= 4'd0;
  30. else if(cnt == 2'd3)
  31. cnt_bit <= cnt_bit + 1'b1;
  32. else
  33. cnt_bit <= cnt_bit;
  34. //按周期扫描信号,依次把数据传入595芯片ds
  35. always@(posedge sys_clk or negedge sys_rst_n)
  36. if(sys_rst_n == 1'b0)
  37. ds <= 1'b0;
  38. else if(cnt == 2'd0)
  39. ds <= data[cnt_bit];
  40. else
  41. ds <= ds;
  42. always@(posedge sys_clk or negedge sys_rst_n)
  43. if(sys_rst_n == 1'b0)
  44. shcp <= 1'b0;
  45. else if(cnt == 2'd2)
  46. shcp <= 1'b1;
  47. else if(cnt == 1'b0)
  48. shcp <= 1'b0;
  49. else
  50. shcp <= shcp;
  51. always@(posedge sys_clk or negedge sys_rst_n)
  52. if(sys_rst_n == 1'b0)
  53. stcp <= 1'b0;
  54. else if((cnt == 1'b0) && (cnt_bit == 4'd0))
  55. stcp <= 1'b1;
  56. else if((cnt ==2'd2) && (cnt_bit ==4'd0))
  57. stcp <= 1'b0;
  58. else
  59. stcp <= stcp;
  60. assign oe = 1'b0;
  61. endmodule

3.bcd_8421数据拆分模块

  1. module bcd_8421
  2. (
  3. input wire sys_clk ,
  4. input wire sys_rst_n ,
  5. input wire [11:0] data , //要拆分的数据
  6. output reg [3:0] unit , //拆分后的个位
  7. output reg [3:0] ten , //十位
  8. output reg [3:0] hun , //百位
  9. output reg [3:0] tho //千位
  10. );
  11. reg [3:0] cnt_shift;
  12. reg [27:0] data_shift;
  13. reg shift_flag;
  14. //循环移位次数
  15. always@(posedge sys_clk or negedge sys_rst_n)
  16. if(sys_rst_n == 1'b0)
  17. cnt_shift <= 4'd0;
  18. else if((cnt_shift == 4'd13)&& (shift_flag == 1'b1))
  19. cnt_shift <= 4'd0;
  20. else if(shift_flag == 1'b1)
  21. cnt_shift <= cnt_shift + 1'b1;
  22. else
  23. cnt_shift <= cnt_shift;
  24. //4位一组进行判断>4否? 大于就加3
  25. always@(posedge sys_clk or negedge sys_rst_n)
  26. if(sys_rst_n == 1'b0)
  27. data_shift <= 27'd0;
  28. else if(cnt_shift == 4'd0)
  29. data_shift <= {16'b0,data};
  30. else if((cnt_shift <= 12) && (shift_flag == 1'b0))
  31. begin
  32. data_shift[15:12] <= (data_shift[15:12] > 4) ? (data_shift[15:12] +2'd3) : (data_shift[15:12]);
  33. data_shift[19:16] <= (data_shift[19:16] > 4) ? (data_shift[19:16] +2'd3) : (data_shift[19:16]);
  34. data_shift[23:20] <= (data_shift[23:20] > 4) ? (data_shift[23:20] +2'd3) : (data_shift[23:20]);
  35. data_shift[27:24] <= (data_shift[27:24] > 4) ? (data_shift[27:24] +2'd3) : (data_shift[27:24]);
  36. end
  37. else if((cnt_shift <= 12) && (shift_flag == 1'b1))
  38. data_shift <= data_shift << 1;
  39. else
  40. data_shift <= data_shift;
  41. always@(posedge sys_clk or negedge sys_rst_n)
  42. if(sys_rst_n == 1'b0)
  43. shift_flag <= 1'b0;
  44. else
  45. shift_flag <= ~shift_flag;
  46. //移位判断一个周期后,进行数据输出
  47. always@(posedge sys_clk or negedge sys_rst_n)
  48. if(sys_rst_n == 1'b0)
  49. begin
  50. unit <= 4'd0;
  51. ten <= 4'd0;
  52. hun <= 4'd0;
  53. tho <= 4'd0;
  54. end
  55. else if(cnt_shift == 5'd13)
  56. begin
  57. unit <= data_shift[15:12];
  58. ten <= data_shift[19:16];
  59. hun <= data_shift[23:20];
  60. tho <= data_shift[27:24];
  61. end
  62. endmodule

4.数码管段选位选数据产生模块

  1. `timescale 1ns/1ns
  2. module seg_dynamic
  3. (
  4. input wire sys_clk ,
  5. input wire sys_rst_n,
  6. input wire [19:0] data ,
  7. input wire [5:0] point ,
  8. input wire sign ,
  9. input wire seg_en ,
  10. output reg [7:0] seg ,
  11. output reg [5:0] sel
  12. );
  13. parameter CNT_MAX = 16'd49_999;
  14. wire [3:0] unit ;
  15. wire [3:0] ten ;
  16. wire [3:0] hun ;
  17. wire [3:0] tho ;
  18. wire [3:0] t_tho ;
  19. wire [3:0] h_hun ;
  20. reg [23:0] data_reg ;
  21. reg [15:0] cnt_1ms ;
  22. reg flag_1ms ;
  23. reg [2:0] cnt_sel ;
  24. reg [5:0] sel_reg ;
  25. reg [3:0] data_disp ;
  26. reg dot_disp ;
  27. always@(posedge sys_clk or negedge sys_rst_n)
  28. if(sys_rst_n == 1'b0)
  29. data_reg <= 24'd0;
  30. else if((h_hun) || (point[5])) //最高位非零,则全显示
  31. data_reg <= {h_hun,t_tho,tho,hun,ten,unit};
  32. //次高位非零,少显示一位最高位
  33. else if(((t_tho) || (point[4])) && (sign == 1'b1))
  34. data_reg <= {4'd10,t_tho,tho,hun,ten,unit};
  35. else if(((t_tho) || (point[4])) && (sign == 1'b0))
  36. data_reg <= {4'd11,t_tho,tho,hun,ten,unit};
  37. else if(((tho) || (point[3])) && (sign == 1'b1))
  38. data_reg <= {4'd11,4'd10,tho,hun,ten,unit};
  39. else if(((tho) || (point[3])) && (sign == 1'b0))
  40. data_reg <= {4'd11,4'd11,tho,hun,ten,unit};
  41. else if(((hun) || (point[2])) && (sign == 1'b1))
  42. data_reg <= {4'd11,4'd11,4'd10,hun,ten,unit};
  43. else if(((hun) || (point[2])) && (sign == 1'b0))
  44. data_reg <= {4'd11,4'd11,4'd11,hun,ten,unit};
  45. else if(((ten) || (point[1])) && (sign == 1'b1))
  46. data_reg <= {4'd11,4'd11,4'd11,4'd10,ten,unit};
  47. else if(((ten) || (point[1])) && (sign == 1'b0))
  48. data_reg <= {4'd11,4'd11,4'd11,4'd11,ten,unit};
  49. //只显示最低位一位
  50. else if(((unit) || (point[0])) && (sign == 1'b1))
  51. data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd10,unit};
  52. else
  53. data_reg <= {4'd11,4'd11,4'd11,4'd11,4'd11,unit};
  54. //1ms循环计数
  55. always@(posedge sys_clk or negedge sys_rst_n)
  56. if(sys_rst_n == 1'b0)
  57. cnt_1ms <= 16'd0;
  58. else if(cnt_1ms == CNT_MAX)
  59. cnt_1ms <= 16'd0;
  60. else
  61. cnt_1ms <= cnt_1ms +1'b1;
  62. always@(posedge sys_clk or negedge sys_rst_n)
  63. if(sys_rst_n == 1'b0)
  64. flag_1ms <= 1'b0;
  65. else if(cnt_1ms == CNT_MAX -1'b1)
  66. flag_1ms <= 1'b1;
  67. else
  68. flag_1ms <= 1'b0;
  69. //从0到5循环数,选择当前显示的数码管
  70. always@(posedge sys_clk or negedge sys_rst_n)
  71. if(sys_rst_n == 1'b0)
  72. cnt_sel <= 3'd0;
  73. else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
  74. cnt_sel <= 3'd0;
  75. else if(flag_1ms == 1'b1)
  76. cnt_sel <= cnt_sel + 3'd1;
  77. else
  78. cnt_sel <= cnt_sel;
  79. //根据上面进程,让位选信号移位
  80. always@(posedge sys_clk or negedge sys_rst_n)
  81. if(sys_rst_n == 1'b0)
  82. sel_reg <= 6'b000_000;
  83. else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
  84. sel_reg <= 6'b000_001;
  85. else if(flag_1ms == 1'b1)
  86. sel_reg <= sel_reg << 1;
  87. else
  88. sel_reg <= sel_reg;
  89. //六个数码管轮流显示
  90. always@(posedge sys_clk or negedge sys_rst_n)
  91. if(sys_rst_n == 1'b0)
  92. data_disp <= 4'd0;
  93. else if((seg_en == 1'b1) &&(flag_1ms == 1'b1))
  94. case(cnt_sel)
  95. 3'd0: data_disp <= data_reg[3:0];
  96. 3'd1: data_disp <= data_reg[7:4];
  97. 3'd2: data_disp <= data_reg[11:8];
  98. 3'd3: data_disp <= data_reg[15:12];
  99. 3'd4: data_disp <= data_reg[19:16];
  100. 3'd5: data_disp <= data_reg[23:20];
  101. default:data_disp <= 4'd0;
  102. endcase
  103. else
  104. data_disp <= data_disp;
  105. always@(posedge sys_clk or negedge sys_rst_n)
  106. if(sys_rst_n == 1'b0)
  107. dot_disp <= 1'b1;
  108. else if(flag_1ms == 1'b1)
  109. dot_disp <= ~point[cnt_sel];
  110. else
  111. dot_disp <= dot_disp;
  112. //数码管显示数字与段码映射
  113. always@(posedge sys_clk or negedge sys_rst_n)
  114. if(sys_rst_n == 1'b0)
  115. seg <= 8'b1111_1111;
  116. else
  117. case(data_disp)
  118. 4'd0: seg <= {dot_disp,7'b100_0000};
  119. 4'd1: seg <= {dot_disp,7'b111_1001};
  120. 4'd2: seg <= {dot_disp,7'b010_0100};
  121. 4'd3: seg <= {dot_disp,7'b011_0000};
  122. 4'd4: seg <= {dot_disp,7'b001_1001};
  123. 4'd5: seg <= {dot_disp,7'b001_0010};
  124. 4'd6: seg <= {dot_disp,7'b000_0010};
  125. 4'd7: seg <= {dot_disp,7'b111_1000};
  126. 4'd8: seg <= {dot_disp,7'b000_0000};
  127. 4'd9: seg <= {dot_disp,7'b001_0000};
  128. 4'd10: seg <= 8'b1011_1111;
  129. 4'd11: seg <= 8'b1111_1111;
  130. default: seg <= 8'b0000_0000;
  131. endcase
  132. always@(posedge sys_clk or negedge sys_rst_n)
  133. if(sys_rst_n == 1'b0)
  134. sel <= 6'b000_000;
  135. else
  136. sel <= sel_reg;
  137. bcd_8421 bcd_8421_inst
  138. (
  139. .sys_clk (sys_clk ),
  140. .sys_rst_n (sys_rst_n),
  141. .data (data ),
  142. .unit (unit ),
  143. .ten (ten ),
  144. .hun (hun ),
  145. .tho (tho ),
  146. .t_tho (t_tho ),
  147. .h_hun (h_hun )
  148. );
  149. endmodule

5.不使用595芯片版本,产生数码管扫描信号

  1. //数据与数码管段码映射关系
  2. always@(posedge sys_clk or negedge sys_rst_n)
  3. if(!sys_rst_n)
  4. begin
  5. seg_data <= 8'd0;
  6. end
  7. else
  8. begin
  9. case (seg_cache)
  10. 4'd0: seg_data <= {point,SEG_0};
  11. 4'd1: seg_data <= {point,SEG_1};
  12. 4'd2: seg_data <= {point,SEG_2};
  13. 4'd3: seg_data <= {point,SEG_3};
  14. 4'd4: seg_data <= {point,SEG_4};
  15. 4'd5: seg_data <= {point,SEG_5};
  16. 4'd6: seg_data <= {point,SEG_6};
  17. 4'd7: seg_data <= {point,SEG_7};
  18. 4'd8: seg_data <= {point,SEG_8};
  19. 4'd9: seg_data <= {point,SEG_9};
  20. default: seg_data <= 8'b1111_1111;
  21. endcase
  22. end
  23. //产生数码管位选扫描更新1ms刷新
  24. always@(posedge clk_1ms or negedge sys_rst_n)
  25. if(!sys_rst_n)
  26. cnt_dig <= 1'b0;
  27. else if(cnt_dig == 2'd3)
  28. cnt_dig <= 1'b0;
  29. else
  30. cnt_dig <= cnt_dig + 1'b1;
  31. //数码管段选位选数据扫描1ms刷新
  32. always@(posedge clk_1ms or negedge sys_rst_n)
  33. if(!sys_rst_n)
  34. begin
  35. seg_cache <= 8'b1111_1111;
  36. seg_dig <= 4'b0000;
  37. end
  38. else if(key_switch == 1'b0) //显示费用模式
  39. begin
  40. case (cnt_dig)
  41. 2'd0: begin
  42. seg_dig <= 4'b1110; //点亮第1位数码管
  43. seg_cache <= fare_g[3:0]; //费用的第1位
  44. point <= 1'b0; //小数点不亮
  45. end
  46. 2'd1: begin
  47. seg_dig <= 4'b1101; //点亮第2位数码管
  48. seg_cache <= fare_g[7:4]; //费用的第2位
  49. point <= 1'b1; //小数点亮
  50. end
  51. 2'd2: begin
  52. seg_dig <= 4'b1011; //点亮第3位数码管
  53. seg_cache <= fare_g[11:8]; //费用的第3位
  54. point <= 1'b0; //小数点不亮
  55. end
  56. 2'd3: begin
  57. seg_dig <= 4'b0111; //点亮第4位数码管
  58. seg_cache <= fare_g[15:12]; //费用的第4位
  59. point <= 1'b0; //小数点不亮
  60. end
  61. default:;
  62. endcase
  63. end
  64. else //显示里程模式
  65. begin
  66. case (cnt_dig)
  67. 2'd0: begin
  68. seg_dig <= 4'b1110; //同上
  69. seg_cache <= distance_g[3:0];
  70. end
  71. 2'd1: begin
  72. seg_dig <= 4'b1101;
  73. seg_cache <= distance_g[7:4];
  74. end
  75. 2'd2: begin
  76. seg_dig <= 4'b1011;
  77. seg_cache <= 4'd0;
  78. end
  79. 2'd3: begin
  80. seg_dig <= 4'b0111;
  81. seg_cache <= 4'd0;
  82. end
  83. default:;
  84. endcase
  85. end

五、仿真与实物效果演示

1.费用与里程关系

        60代表6元,12代表1.2元。由图可见:在里程从1km到3km递增时,费用固定60也即起步价6元;当里程4km,5km递增时,费用递增1.2元。符合设计要求。

2.数码管动态显示

Seg_data为数码管段选,seg_dig为数码管位选。由图可见:在费用fare为168,16.8元

位选1110,第1位数码管点亮,段码为00000000,显示数字8;

位选1101,第2位数码管点亮,段码为10000010,显示数字6;

位选1011,第3位数码管点亮,段码为01111001,显示数字1;

位选0111,第4位数码管点亮,段码为01000000,显示数字0。

其中第二位的小数点dp点亮,即代表第一位为小数,实际显示“016.8”,符合设计。

同上分析,在显示里程的时候,total_distance为35km,四位数码管依次显示“0035”。

3.上板演示

出租车计费系统演示

六、总结

        通过本次项目实战,巩固了数码管动态显示知识,提高了代码编写思路,在编写逻辑算法时,没有年初刚开始学习FPGA时的那种无从下手。也遇到很多bug,仿真时没有关掉modelsim,仿真报错,原因要关掉才能重新仿真。数据更新与数码管显示的频率要有合理的区分度,不然数据已经变化了,数码管还没动态刷新一个周期。在例化模块的时候,该用wire线型还是reg寄存器型,需要考虑清楚对这个信号进行了时序逻辑操作还是组合逻辑。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/443090?site
推荐阅读
相关标签
  

闽ICP备14008679号