• EDA项目 出租车计价器 赏析


    祝青春不虚度,充实,饱满,热烈。

    1.0项目简介:

    本项目是一个出租车计价器(taxi_fee.vhd)
    满足以下要求:

    –(1)起步8元/3公里,此后2元/公里;
    –(2)里程指示信号为每前进50米一个高电平脉冲,上升沿有效;显示行公里数,精确到0.1公里。(为了方便运算,模拟时速100m/s)也就是说,3km之后,每0.1km,更新价格,上涨0.2元。
    –(3)前进里程开始之前显示价钱,精确到0.1元;
    –(4)用两个按键分别表示开始行程和结束行程。

    1.1项目整体结构

    本项目由三个部分:脉冲产生模块Speed_pulse.vhd, 计费模块taxi_state.vhd, 显示模块display.vhd
    下面对每个模块的具体介绍,请按照显示模块display.vhd,脉冲产生模块Speed_pulse.vhd, 计费模块taxi_state.vhd的顺序阅读,因为我就是按照这个顺序写的,但是我懒得调整顺序了,因为模块的先后顺序是按照数据的流向排列的。

    输入:
    reset:计价器复位。
    start: 下降沿时刻,开始行程,模拟开始开车
    stop: 下降沿时刻,结束行程,模拟停车
    隐含的输入:模拟时速100m/s。

    输出:
    数码管HEX0,HEX1,HEX2:显示里程
    数码管HEX3,HEX4,HEX5: 显示金额

    信号:
    totel_money: 金额
    mileage:里程(项目里粗心了,totel写错了英文单词,正确的是total,只好将错就错了)
    在这里插入图片描述


    2.速度脉冲产生模块Speed_pulse.vhd

    模块功能:为每前进50米一个高电平脉冲,模拟汽车前进了50米;
    显示行公里数,精确到0.1公里。(模拟时速)

    输入:clk --时钟
    reset–复位信号,低有效

    输出: one_pulse --50米一个高电平脉冲

    模块结构
    本部分大部分采用process语句,使用算法(顺序语句)描述硬件行为,是行为描述风格
    在这里插入图片描述

    1,只要敏感信号(本部分的敏感信号为时钟clk)在变化,就会运行,由于敏感信号往往一直在变化,包括本部分的时钟clk一直在随时间变化,所以process也在无限循环运行
    2. process语句内部是顺序执行的,但是和其他的process相比,则是并行运行,两个process各自运行,而不是顺序先运行一个process再运行另外一个,所以是并行运行。

    2.1声明部分

    	  clk             : IN STD_LOGIC;--时钟,两次clk=1的中间,间隔了0.1s
          reset           : IN STD_LOGIC;--复位信号,低有效 
          one_pulse   : OUT STD_LOGIC--50米一个高电平脉冲,即每过50米,one_pulse=1,其余时间one_pulse=0
    
    • 1
    • 2
    • 3

    2.2进程process语句

       SIGNAL one_pulse_cnt   : integer := 0;   --用于计数的integer,由于clk是、0.1s从10再到1,但是one_pulse是0.5s从10再到1,表示0.5s走了50米。所以用one_pulse_cnt来计时,每过0.1s,one_pulse_cnt就加1,但是one_pulse_cnt不等于5,所以one_pulse。当one_pulse_cnt加到5的时候,就表示过去了0.5s,one_pulse就会变成1,然后one_pulse_cnt就会被重新赋值为0,进入下一个循环。详细过程间下面process代码
       
    
        PROCESS (clk)--括号里的clk是敏感信号,只要敏感信号在变化,就会不断运行。
       --下面代码请按照注释的甲乙丙的顺序阅读。
       --
       BEGIN
          IF (clk'EVENT AND clk = '1') THEN--甲 两次clk=1的中间,间隔了0.1s
    		 IF (reset = '0') THEN--如果reset是0则复位,下面的elsif和else都是reset不为0,就不用复位。
                one_pulse_cnt <= 0;
                one_pulse <= '0';
             ELSIF (one_pulse_cnt >= 5) THEN--丙 每0.5秒走50m。
                   one_pulse_cnt <= 0;
                   one_pulse <= '1';--走了50米,出现一个高电平脉冲
             ELSE --乙 过去的时间不足0.5s,暂时让one_pulse=0,表示还没走50米
                   one_pulse_cnt <= one_pulse_cnt + 1;
                   one_pulse <= '0';
             END IF;
          END IF;
       END PROCESS;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.计费模块taxi_state.vhd

    模块功能
    –(1)起步8元/3公里,此后2元/公里;
    –(2)里程指示信号为每前进50米一个高电平脉冲,上升沿有效;显示行公里数,精确到0.1公里。(模拟时
    –速100m/s)也就是说,3km之后,每100米,更新价格,上涨0.2元。
    –(3)前进里程开始之前显示价钱,精确到0.1元;
    –(4)用两个按键分别表示开始行程和结束行程。

    输入:clk:时钟
    reset:复位信号 低有效
    stop --本次行程结束,停止计费,低有效
    start-启动信号,行程开始,低有效
    one_pulse --50米一个高电平脉冲,这个输入来自速度脉冲产生模块Speed_pulse.vhd的输出

    输出:mileage_out 里程
    totel_money_out 车费

    本部分主要采用process语句,同上不再赘述

    3.1 process语句

    --这一部分将从 速度脉冲产生模块Speed_pulse.vhd 获得的50m一次的脉冲one_pulse,换算为100m一次脉冲two_pulse
    PROCESS (clk)
       BEGIN
          IF (clk'EVENT AND clk = '1') THEN
             IF (reset = '0') THEN
                flag_pulse <= '0';
    	     ELSIF(one_pulse='1')THEN
    				flag_pulse <= not flag_pulse;--本部分将50m脉冲one_pulse转换为100m一次电平变化flag_pulse。
    				--也就是说,one_pulse从1变成0再变成1,表示走了50m,然而flag_pulse从1变成0再变成1,走了100m
    			END IF;
    		END IF;
    	END PROCESS;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    two_pulse<=	 flag_pulse and one_pulse;--获得100m脉冲two_pulse
    
    • 1
    --这一部分是出租车的状态转换,和不同状态下,根据里程,进行价格计算。注意state有000空闲,001起步价,010两元每三公里,110停车几种状态。
    PROCESS (clk)
       BEGIN
          IF (clk'EVENT AND clk = '1') THEN
             IF (reset = '0') THEN--重置
                state <= "000";
                totel_money <= "0000000000000000";
                totel_money_out <= "0000000000000000";
             ELSIF (stop = '0') THEN--注意,下面三句话是同时进行的,所以totel_money_out是车费,不是"0000000000000000"
             --因为停下来了,所以totel_money也要重置为0000000000000000。
                state <= "110";
                totel_money <= "0000000000000000";
                totel_money_out <= totel_money;--输出合计费用
             ELSE--没有停下来,只是输出车费。
                totel_money_out <= totel_money;--输出合计费用
                CASE state IS`--注意state有000空闲,001起步价,010两元每三公里,110停车几种状态。
                   WHEN "000" =>--空闲状态 注意state有000空闲,001起步价,010两元每三公里,110停车几种状态。
                      totel_money <= totel_money;
                      IF (start = '0') THEN --如果开始开车,那么进入下一个阶段。
                         state <= "001";--变成起步价阶段
                      ELSE
                         state <= "000";--否则停留在空闲阶段
                      END IF;
                   WHEN "001" =>--起步价
                      totel_money <= "0000_0000_0101_0000";--起步费为 8.0 元(800.1元)
                      IF (mileage >= "0000_0000_0001_1110") THEN--大于3.0公里(300.1km)后按公里计费
                         state <= "010";
                      ELSE
                         state <= "001";
                      END IF;
                   WHEN "010" =>--车行驶3公里后按每公里2元计费
                      IF (two_pulse = '1') THEN--走了0.1km
                         totel_money <= totel_money + "0000000000000010";--0.1公里 0.2元计费
                      END IF;
                         state <= "010";
                   WHEN OTHERS =>
                      state <= "000";
                END CASE;
             END IF;
          END IF;
       END PROCESS;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    --这一部分是里程计算
    PROCESS (clk)
       BEGIN
          IF (clk'EVENT AND clk = '1') THEN
             IF (reset = '0') THEN
                mileage <= "0000000000000000";
             ELSIF (state = "001" OR state = "010" OR state = "100") THEN--如果汽车处于正在开的状态
                IF (two_pulse = '1') THEN--0.1公里脉冲
                   mileage <= mileage + "0000000000000001";--0.1公里里程加1
                ELSE
                   mileage <= mileage;
                END IF;
             ELSIF (stop = '0') THEN
                mileage <= "0000000000000000";
             ELSE
                mileage <= mileage;
             END IF;
          END IF;
       END PROCESS;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4. 显示模块display.vhd

    模块功能:将里程和价格显示到LED屏幕上

    输入:reset: 重置 复位信号,低有效 ?
    clk 标准时钟
    totel_money 车费 来自计费模块taxi_state.vhd
    mileage 里程 来自计费模块taxi_state.vhd

    输出
    HEX0,1,2
    HEX3,4,5

    此部分采用了元件例化语句 端口映射方式为名字关联方式 是组件描述风格
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

    4.1 Component声明部分

    结构体trans描述了2种component:

    b_to_bcd:

    将二进制转BCD码(BCD码是指用4bit来表示十进制的一位的方式,其中一种4bit与十进制一位的映射方法如下)
    在这里插入图片描述

    SIGNAL Kmmoney_H : STD_LOGIC_VECTOR(3 DOWNTO 0); --费用的百位,注意他的数据类型是4个LOGIC类型的数组,因为这个数组表示十进制的一位,用4bit(1个Logic类型是1bit)表示。
    SIGNAL BCD_mileage_out   :  STD_LOGIC_VECTOR(15 DOWNTO 0);--路程的输出,共16个LOGIC,所以是4位十进制数。
    
    • 1
    • 2

    LED7s:

    例化显示模块

    --一个LED7S接收一个4bit的BCD码,也就是十进制的1位,然后输出7bit,刚好作为LED显示屏上每一个“杠”是亮是暗,从而显示一个数字。
    COMPONENT LED7S is
    Port(din: in std_logic_vector(3 downto 0);
    	 y: out std_logic_vector(6 downto 0));
    END COMPONENT;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    LED
    上图为LED显示数字,可以看到有7个杠,通过各自的亮暗决定显示什么数字。

    4.2 功能描述部分

    --二进制表示的里程 转BCD码,使用了b_to_bcd  component
    --=>左边是 b_to_bcd  component的引脚,右边是这些引脚链接的外部引脚。
    --下面这一部分交代了b_to_bcd的各个引脚的连接关系
    BCD_mileage : b_to_bcd 
       PORT MAP (      
          clk       =>clk,
          rst_n     =>reset,
          binary    =>mileage_exd,
          state_en  =>'1',
          BCD       =>BCD_mileage_out
       );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    BCD_totel_money也使用了b_to_bcd component,不赘述

    --信号BCD_totel_money_out从BCD_totel_money的BCD 输出口获得车费的BCD码,然后根据BCD码的规则,将最高4位分给Kmmoney_H作为十进制的百位,以此类推。
       Kmmoney_H <= BCD_totel_money_out(11 downto 8);--百位
       Kmmoney_M <= BCD_totel_money_out(7 downto 4);--十位
       Kmmoney_L <= BCD_totel_money_out(3 downto 0);--个位
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    BUUCTF·[WUSTCTF2020]B@se1·WP
    通过ELRepo修改CentOS 7内核版本的详细步骤
    儿科医生教你做好“过敏三级预防”,孩子过敏不要怕
    php健身房教练预约系统网站
    openGauss 列存表PSort索引
    9月8日作业
    嵌入式Qt-做一个秒表
    asp.net docker-compose添加kafka和redis和zookeeper
    AI天后,在线飙歌,人工智能AI孙燕姿模型应用实践,复刻《遥远的歌》,原唱晴子(Python3.10)
    hiveSql 跨N天最大连续统计
  • 原文地址:https://blog.csdn.net/ZnS_oscar/article/details/127857941