基于FPGA的出租车计费系统设计---第一版--郝旭帅电子设计团队

news2025/1/16 13:45:30

欢迎各位朋友关注“郝旭帅电子设计团队”,本篇为各位朋友介绍基于FPGA的出租车计费系统设计—第一版

功能说明:

  1. 收费标准(里程):起步价5元,包括三公里;三公里之后,每公里2元(不到一公里,不收费)。

  2. 收费标准(低速等待费):当计费开始,车辆速度低于某一速度时,开始收取低速等待费,三分钟收取2元,不足三分钟不收费

  3. 整体收费=里程计费+低速等待费

  4. 设置有计费开始/停止按钮。

  5. 设置有档位控制按钮,0档(停止不动),1档(3分钟一公里),2档(1分钟一公里)。当计费开始,0档和1档位需要累加低速等待计费。

  6. 利用六个数码管显示信息。

  7. 显示模式一:第一个数码管显示是否计费(A:计费停止, C:计费开始),第二个数码管显示档位(0、1、2),第三个至六个显示应收钱数。

  8. 显示模式二:总计运行时间

  9. 显示模式三:前三个里程,后三个里程收费

  10. 显示模式四:前三个低速等待时长(分钟),后三个低速等待费。

  11. 设置有显示模式切换按钮。

  12. 计费停止后,重新按下计费开始,上述所有统计从0开始。

  13. 为了下板后,能够比较快速显示出效果,所有的时间加速30倍.

使用平台:本次设计应用Altera的平台设计(芯片:EP4CE10F17C8N)。

仿真平台:Modelsim。

作者QQ:746833924

说明:本篇设计中不涉及到IP和原语,代码在其他平台依然可以适用;当其他板卡电路不同时,会导致不同的现象出现,如有需要修改代码请联系作者;如需作者使用的板卡,请联系作者;

设计思想如下:

图片

key_ctrl模块负责将外部输入的按键进行消抖,产生按键按下时的脉冲。

taxi_meter_ctrl模块负责根据外部输入的三个脉冲和出租车计费的规则产生对应的输出数据。

seven_tube_drive模块负责将taxi_meter_ctrl产生的数据显示到数码管上。

key_ctrl模块设计思想为:按键信号是由外部机械式按键产生,每次按下或者抬起时,会产生一定的抖动。如果直接对其进行边沿检测就会导致多次触发。故而需要设计按键消抖,进而对消抖之后的波形进行边沿检测。消抖原理为:外部按键信号发生改变后,如果能够持续20ms,没有新的改变,就认为此次改变不是抖动,而是真正的按下,然后进行采样即可。

// 记录任意边沿之后没有遇到新的边沿的时间长度是否达到20Ms 

//---------------------------------------------------------------------------------------  

always@(posedgeclk)begin

   if(rst_n ==1'b0)

     cnt_20ms <=20'd0;

   else

     if(pulse_key_negedge ==1'b1||pulse_key_posedge ==1'b1)

       cnt_20ms <=20'd1;

     else

       if(cnt_20ms >20'd0&&cnt_20ms <T_20ms)

         cnt_20ms <=cnt_20ms +1'b1;

       else

           cnt_20ms <=20'd0;

 end

// --------------------------------------------------------------------------------------- 

// 任意边沿之后没有遇到新的边沿的时间长度达到20Ms,认为按键稳定,此时采样 

//--------------------------------------------------------------------------------------    

always@(posedgeclk)begin

   if(rst_n ==1'b0)

     key_wave <=1'b1;

   else

     if(cnt_20ms ==T_20ms)

       key_wave <=key_rr;

     else

       key_wave <=key_wave;

 end

//--------------------------------------------------------------------------------------

// 对消抖之后的按键信号进行边沿检测 

//---------------------------------------------------------------------------------------------

initialkey_wave_r =1'b1;

always@(posedgeclk)key_wave_r <=key_wave;

assignflag_neg =(key_wave_r ==1'b1&&key_wave ==1'b0)?1'b1:1'b0;

assignflag_pos =(key_wave_r ==1'b0&&key_wave ==1'b1)?1'b1:1'b0;

//--------------------------------------------------------------------------------------------  

taxi_meter_ctrl模块的设计原理如下:

根据flag_start_stop的信号,确定运行状态。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      state_run <= 1'b0;
    else
      if (flag_start_stop == 1'b1)
        state_run <= ~state_run;
      else
        state_run <= state_run;
  end

根据flag_gear的信号,确定出租车的档位。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      gear <= 2'd0;
    else
      if (flag_gear == 1'b1)  
        if (gear < 2'd2)
          gear <= gear + 1'b1;
        else
          gear <= 2'd0;
      else
        gear <= gear;
  end

确定公里数,以及根据规则,确定钱数。

停止运行了后,公里数不要清除(也需要翻看),公里数需要在下一次启动时,清除;

flag_mileage_add是公里数递增的脉冲。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      mileage <= 10'd0;
    else
      if (state_run == 1'b0 && flag_start_stop == 1'b1)
        mileage <= 10'd0;
      else
        if (state_run == 1'b1)
          if (flag_mileage_add == 1'b1)
            if (mileage < 10'd999)
              mileage <= mileage + 1'b1;
            else
              mileage <= mileage;
          else
            mileage <= mileage;
        else
          mileage <= mileage;
  end
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      money_mileage <= 10'd0;
    else
      if (mileage < 10'd4)
        money_mileage <= 10'd5;
      else
        money_mileage <= (mileage - 10'd3) * 2 + 5;
  end

产生flag_mileage_add的逻辑为:记录三分钟,如果是0档,则计数器不动;如果是1档,则计数器加1(由于加速30倍,所以加30);如果是2档,则计数器加3(由于加速30倍,所以加90);由于每次并不是加1,所以最大值并一定正好能达到,所以超过最大值时,减去最大值。

 always @ (posedge clk) begin
    if (rst_n == 1'b0) begin
      counter <= 64'd0;
      flag_mileage_add <= 1'b0;
    end
    else
      if (state_run == 1'b1)
          if (gear == 2'd1)
            if (counter < 34'd9_000_000_000 - 1'b1)  begin
              counter <= counter + 30;
              flag_mileage_add <= 1'b0;
            end
            else begin
              counter <= counter - (34'd9_000_000_000 - 1'b1);
              flag_mileage_add <= 1'b1;
            end
          else
            if (gear == 2'd2)
              if (counter < 34'd9_000_000_000 - 1'b1)  begin
                counter <= counter + 90;
                flag_mileage_add <= 1'b0;
              end
              else begin
                counter <= counter - (34'd9_000_000_000 - 1'b1);
                flag_mileage_add <= 1'b1;
              end
            else begin
              counter <= counter;
              flag_mileage_add <= 1'b0;
            end
      else begin
        counter <= 64'd0;
        flag_mileage_add <= 1'b0;
      end
  end

记录整体的运行时间;加速30倍;

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      cnt_1s_all_timer <= 26'd0;
    else
      if (state_run == 1'b1)
        
          if (cnt_1s_all_timer < T_1s - 1'b1)
            cnt_1s_all_timer <= cnt_1s_all_timer + 30;
          else
            cnt_1s_all_timer <= cnt_1s_all_timer - (T_1s - 1'b1);
      else
        cnt_1s_all_timer <= 26'd0;
  end
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      sec_counter_all_timer <= 32'd0;
    else
      if (state_run == 1'b0 && flag_start_stop == 1'b1)
        sec_counter_all_timer <= 32'd0;
      else
        if (cnt_1s_all_timer >= T_1s - 1'b1)
          sec_counter_all_timer <= sec_counter_all_timer + 1'b1;
        else
          sec_counter_all_timer <= sec_counter_all_timer;
  end

确定低速等待时间;加速30倍;计数器为1分钟的计数器;

然后根据1分钟的计数器,确定等待了多长时间;

  always @ (posedge clk) begin
    if (rst_n == 1'b0)  
      min_wait_timer <= 32'd0;
    else
      if (state_run == 1'b1)  
          if (gear == 2'd0 || gear == 2'd1)
            if (min_wait_timer < T_60s - 1'b1)
              min_wait_timer <= min_wait_timer + 30;
            else
              min_wait_timer <= min_wait_timer - (T_60s - 1'b1);
          else
            min_wait_timer <= min_wait_timer;
      else
        min_wait_timer <= 32'd0;
  end
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      wait_min <= 32'd0;
    else
      if (state_run == 1'b0 && flag_start_stop == 1'b1)   
        wait_min <= 32'd0;
      else
        if (state_run == 1'b1 && (gear == 2'd0 || gear == 2'd1) && min_wait_timer >= T_60s - 1'b1)
          wait_min <= wait_min + 1'b1;
        else
          wait_min <= wait_min;
  end

根据低速等待时间,确定低速等待费。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      money_wait <= 32'd0;
    else
      money_wait <= (wait_min/3) * 2;
  end 

最终的费用等于里程费用加上低速等待费。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      money_all <= 11'd0;
    else
      money_all <= money_mileage + money_wait;
  end

根据切换显示的脉冲,确定需要显示的模式;

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      state_show <= 2'd0;
    else
      if (flag_show == 1'b1)
        state_show <= state_show + 1'b1;
      else
        state_show <= state_show;
  end

一个模式:显示车辆运行状态,档位和收费。

  initial data0[23:20] = 4'ha;
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data0[23:20] <= 4'ha;
    else
      if (state_run == 1'b1)
        data0[23:20] <= 4'hc;
      else
        data0[23:20] <= 4'ha;
  end
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data0[19:16] <= 4'h0;
    else
      data0[19:16] <= {2'd0,gear};
  end

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data0[15:0] <= 16'd0;
    else
      data0[3:0] <= money_all % 10;
      data0[7:4] <= money_all/10 % 10;
      data0[11:8] <= money_all/100 % 10;
      data0[15:12] <= money_all/1000 % 10;
  end

第二个模式:显示整体的运行时间(换算成为时分秒)。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data1 <= 24'd0;
    else
      data1[23:20] <= sec_counter_all_timer / 3600 / 10 % 10;
      data1[19:16] <= sec_counter_all_timer / 3600  % 10;
      
      data1[15:12] <= sec_counter_all_timer % 3600 / 60 / 10 % 10;
      data1[11:8] <= sec_counter_all_timer % 3600  / 60 % 10;
      
      data1[7:4] <= sec_counter_all_timer % 60 / 10 % 10;
      data1[3:0] <= sec_counter_all_timer % 60 % 10;
  end

第三个模式:显示历程,历程计费。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data2 <= 24'd0;
    else
      data2[23:20] <= mileage / 100;
      data2[19:16] <= mileage / 10 % 10;
      data2[15:12] <= mileage % 10;
      
      data2[11:8] <= money_mileage / 100;
      data2[7:4] <= money_mileage / 10 % 10;
      data2[3:0] <= money_mileage % 10;
  end

第四个模式:显示低速等待计费和低速等待时间。

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data3 <= 24'd0;
    else
      data3[23:20] <= wait_min / 100;
      data3[19:16] <= wait_min / 10 % 10;
      data3[15:12] <= wait_min % 10;
      
      data3[11:8] <= money_wait / 100;
      data3[7:4] <= money_wait / 10 % 10;
      data3[3:0] <= money_wait % 10;
  end

根据外部的显示脉冲,确定需要显示的模式;

  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      state_show <= 2'd0;
    else
      if (flag_show == 1'b1)
        state_show <= state_show + 1'b1;
      else
        state_show <= state_show;
  end
  
  always @ (posedge clk) begin
    if (rst_n == 1'b0)
      data <= 23'd0;
    else  
      case (state_show)
        2'd0    :   data <= data0;
        2'd1    :   data <= data1;
        2'd2    :   data <= data2;
        2'd3    :   data <= data3;
        default :   data <= data0;
      endcase
  end

以上为taxi_meter_crtl的设计思想;

七段数码管为普通六位一体的共阳极数码,采用动态驱动的方式,在此不再赘述。

下板后,我们就可以看到出租车计费系统的运行情况。

图片

图片

讲解和演示视频(链接)如下:

https://www.bilibili.com/video/BV184421D7MT/?vd_source=b5405faeab8632f02533bcbfc5e52e55

本设计所有内容(设计代码、设计工程)链接为:

链接:https://pan.baidu.com/s/1vLDLaQckYVFUMS8hQolcaQ
提取码:01v6

本篇内容中有部分资源来源于网络,如有侵权,请联系作者。

如果您觉得本公众号还不错的话,可以推给身边的朋友们,感谢并祝好!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JVM: 堆上的数据存储

文章目录 一、对象在堆中的内存布局1、对象在堆中的内存布局 - 标记字段2、JOL打印内存布局 二、元数据指针 一、对象在堆中的内存布局 对象在堆中的内存布局&#xff0c;指的是对象在堆中存放时的各个组成部分&#xff0c;主要分为以下几个部分&#xff1a; 1、对象在堆中的…

Java SpringTask定时自动化处理

目录 一、自动化处理 1.1 什么是自动化处理 1.2 SpringTask介绍 二、SpringTask的基本使用 2.1 引入依赖 2.2 通过控制台加入注解启用SpringTask 2.3 使用Cron表达式规定时间 2.4 通过Schedule(Cron表达式) 实现定时任务&#xff08;每两秒执行一次&#xff09; 三、实…

【完美解决】 TypeError: ‘str’ object does not support item assignment

【完美解决】 TypeError: ‘str’ object does not support item assignment 在Python编程中&#xff0c;遇到TypeError: str object does not support item assignment这样的错误通常意味着你试图修改字符串中的某个字符&#xff0c;但字符串是不可变类型&#xff0c;不支持这…

【每日一题 | 组成原理】补码溢出判断

题目 题型总结 带符号的定点数表示方式有4种&#xff0c;分别是原码、反码、补码和移码&#xff0c;他们都由两部分组成&#xff0c;分别是符号位和数值位&#xff0c;这四种编码方式非常重要&#xff0c;要熟练掌握他们之间的转换和与真值间的转换。这里我们重点看一下补码&a…

408-部分知识点笔记(自用)

一、操作系统部分 1.内中断&#xff08;异常&#xff09;和外中断&#xff08;中断&#xff09; 1.1 异常&#xff08;内中断&#xff09; 异常就是指CPU内部发生的中断&#xff0c;与当前正在执行的程序有关。类似的内中断有&#xff1a;缺页中断、算法溢出、除以0错误、存…

可视化目标检测算法推理部署(三)YOLOv8模型视频推理

在上一章节中博主利用Gradio完成了YOLOv8模型的图像推理&#xff0c;那么在本章节中将进行视频推理&#xff0c;其代码十分简单&#xff0c;只需要将原本的视频切分为一帧帧图像再去检测即可&#xff0c;代码如下&#xff1a; def detectio_video(input_path):output_path&quo…

[C++]多态与虚函数

一、多态的概念 顾名思义&#xff0c;多态的意思就是一个事物有多种形态&#xff0c;在完成某个行为的时候&#xff0c;当不同的对象去完成时会产生不同的状态。在面向对象方法中一般是这样表示多态的&#xff1a;向不同的对象发送同一条消息&#xff0c;不同的对象在接收时会产…

记录|Stock编程

目录 前言一、Stock编程&#xff1f;二、聊天工具开发1. 目的2. 服务器端开启对端口的监听3. VS创建服务器端ServiceStep1. 创建Step2. Listener对象监听事件Step1~2效果展示 4. 创建客户端&#xff0c;与服务器端链接5. VS创建客户端ClientStep1. 创建Step2. Client对象Step1~…

二维码门楼牌管理应用平台建设:实有人口采集管理

文章目录 前言一、移动快采&#xff0c;精准定位&#xff0c;高效管理二、新增与注销&#xff0c;灵活管理人口信息三、多维度查询&#xff0c;精准锁定目标人群四、信息核实&#xff0c;确保数据准确无误 前言 在智慧城市建设的大潮中&#xff0c;二维码门楼牌管理应用平台以…

POI 快速入门 Excel导入导出

Excel导入导出 1 什么是POI POI简介&#xff08;Apache POI&#xff09;&#xff0c;Apache POI是Apache软件基金会的开放源码函式库&#xff0c;POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 Apache POI官网http://poi.apache.org/ HSSF &#xff0d; 提…

Ubuntu22.04 Docker更换阿里云镜像

由于运营商网络原因&#xff0c;会导致您拉取Docker Hub镜像变慢&#xff0c;甚至下载失败。那么可以更换阿里云镜像加速器&#xff0c;从而加速官方镜像的下载。 1.获取镜像加速器地址 登录容器镜像服务控制台&#xff0c;在左侧导航栏选择镜像工具 > 镜像加速器&#xf…

课题项目结题测试的作用

课题项目结题测试是课题项目研究过程中的一个重要环节&#xff0c;它对于确保课题项目的质量和成果具有重要的作用。本文将详细介绍课题项目结题测试的作用。 一、确保课题项目质量 课题项目结题测试是对课题项目研究成果的全面评估和检测。通过结题测试&#xff0c;可以对课…

使用Echarts来实现数据可视化

目录 一.什么是ECharts? 二.如何使用Springboot来从后端给Echarts返回响应的数据&#xff1f; eg:折线图&#xff1a; ①Controller层&#xff1a; ②service层&#xff1a; 一.什么是ECharts? ECharts是一款基于JavaScript的数据可视化图标库&#xff0c;提供直观&…

生产力工具|vscode for mac安装及过程留存

一、安装vscode 在官网下载.zip 文件&#xff1a; Visual Studio Code - Code Editing. Redefined 第一步&#xff1a;下载后解压后&#xff0c;直接双击种类为应用程序的文件,将vscode显示在启动台的程序中; 第二步:将文件拖到应用程序中&#xff0c;打开启动…

中国工商银行长春分行开展“工驿幸福 健康财富”长辈客群康养活动

中国工商银行长春分行作为国有大行&#xff0c;持续完善有温度、专业化、安全稳健的养老场景服务&#xff0c;以工行驿站为依托、以长辈客群养老需求为中心&#xff0c;积极对接社区构建敬老、康养的“金融泛金融”工行驿站服务生态&#xff0c;进一步提升长辈客群的到店体验。…

APP逆向 day25unidbg中

一.前言 昨天我们讲了unidbg的上篇&#xff0c;都是一些之前讲过的简单案例&#xff0c;末尾还单独说了一个新案例海南航空&#xff0c;今天我们来讲的案例都是之前讲过的&#xff0c;主要是和大家说补环境 二.唯品会skey 大家如果不记得了&#xff0c;可以去看看前面的文章…

一个函数统一238个机器学习R包,这也太赞了吧

Caret 是一个试图标准化机器学习过程的一个包。Caret 对 R 中最常用的机器学习方法 (目前支持238个R包)提供了统一的接口。 进行数据预处理 实现机器学习方法流程化模型构建 通过参数组合和交叉验证评估模型的参数 选择最优模型 评估模型性能 一键满足各种掉包&#xff0c…

带通采样定理

一、采样定理 1.1 低通采样定理(奈奎斯特采样) 低通采样定理&#xff08;奈奎斯特采样&#xff09;是要求大于信号的最高上限频率的两倍 1.2 带通采样定理 带通信号的采样频率在某个时间小于采样频率也能无失真恢复原信号 二、频谱混叠 对一个连续时域信号&#xff0c;采…

【网络安全】CVSS 10信息披露+图片元数据不适当处理

未经许可,不得转载。 文章目录 漏洞1漏洞2漏洞1 app.redacted.com,是一个在线学习应用程序,适用于企业。但其仅限于会员。尝试使用wappalyzer分析其技术堆栈。 首先想到的是对敏感文件进行目录模糊测试。主要使用 dirsearch 和 ffuf 进行此操作。 首先,我运行了 dirsear…