1、系统硬件方案设计
如下图所示,出租车计费的标准是起步价是12元,2公里之内里程费用不变,当超过2公里时,每行驶1公里,每公里加收2.4元。通过按键模块来控制系统的显示模块,不同的按键可以显示不同的功能,当按键1按下时出租车计费系统开始进行计费,数码管此时显示总费用,计时模块和计里程模块开始运行,同时LED1会亮起,表示出租车正在计费中;当按键2按下时,数码管会显示里程数;当按键3按下时数码管会显示时长;当按键4按下时出租车计费系统会进行复位操作;当按键5按下时会对出租车计费系统暂停计费。出租车设定时速为36KM/H,换算得10秒出租车行驶里程100米,计费模块会增加0.24元。同时对乘坐的时长也会进行收费,每1分钟加收1.2元,换算得每2秒计费模块会增加0.04元。出租车计费系统得总费用等于起步价加上公里数乘以2.4元再加上所乘坐得时间,其计算的公式为:总费用=起步价+(所驾驶里程数-2)*2.4+(乘坐的时间)*1.2。
2、 FPGA芯片选择
本次毕业设计使用的芯片是Altera公司 Cyclone V系列的5CEBA4F23C7N芯片。Cyclone系列是Altera公司简化版的FPGA芯片,该芯片拥有低功耗,低成本,和相对高的集成度等优点,非常适合进行较小的系统设计使用。使用的开发板是E0-CV开发板,如下图所示,该开发板的主要元件有9K可编程逻辑元件;3080kbits嵌入式内存;4分数锁相环;10个发光二极管;10个滑动开关;4个按钮;1个CPU复位按钮;6个7段数码管;串行配置设备-在FPGA上的EPCS64模式配置;车载USB Blaster(普通B型USB连接器);支持JTAG和AS;64MB SDRAM, x16位数据总线;2 x20的GPIO;使用4位电阻网络DAC;使用高密度D-sub连接器;该DE0-CV板带有一个控制面板程序,允许用户访问各种主板上来自主机的部件。主机与主板通信通过USB连接。该程序可以用来验证组件上的功能。
本次毕业设计使用的芯片是Altera公司 Cyclone V系列的5CEBA4F23C7N芯片。Cyclone系列是Altera公司简化版的FPGA芯片,该芯片拥有低功耗,低成本,和相对高的集成度等优点,非常适合进行较小的系统设计使用。使用的开发板是E0-CV开发板,如下图所示,该开发板的主要元件有9K可编程逻辑元件;3080kbits嵌入式内存;4分数锁相环;10个发光二极管;10个滑动开关;4个按钮;1个CPU复位按钮;6个7段数码管;串行配置设备-在FPGA上的EPCS64模式配置;车载USB Blaster(普通B型USB连接器);支持JTAG和AS;64MB SDRAM, x16位数据总线;2 x20的GPIO;使用4位电阻网络DAC;使用高密度D-sub连接器;该DE0-CV板带有一个控制面板程序,允许用户访问各种主板上来自主机的部件。主机与主板通信通过USB连接。该程序可以用来验证组件上的功能。
3、计时设计
时钟信号一直都是设计一个同步系统的核心信号,如果没有一个准确的时钟信号,一个系统的运行就不可能会准确,所以时钟信号的好坏以及是否稳定决定了一个同步电路的性能如何。通常使用高性能的信号,一般都会调用FPGA内部属于自己的时钟资源——布线资源和锁相环(PLL)。如下图所示,5CEBA4F23C7N芯片是50 MHz 缓冲至四个 50MHz时钟。
时钟信号一直都是设计一个同步系统的核心信号,如果没有一个准确的时钟信号,一个系统的运行就不可能会准确,所以时钟信号的好坏以及是否稳定决定了一个同步电路的性能如何。通常使用高性能的信号,一般都会调用FPGA内部属于自己的时钟资源——布线资源和锁相环(PLL)。如下图所示,5CEBA4F23C7N芯片是50 MHz 缓冲至四个 50MHz时钟。
通过分频得50Mhz,在数码管中,时间的显示为00:00,对四个数码管分好位置,0~1数码管对应时钟的秒数,2~3数码管对应时间的分钟数,通过不同的进制可以精确的显示出所用的时间,由于秒到分的进制是6进制,所以数码管1要设置成6进制,其余的都是10进制,调用好时钟后即可开始编写代码,设计时钟的主要流程图如下图所示。
计时代码主要程序如下:
ELSIF (clk'EVENT AND clk = '1')THEN --判断时钟信号为上升沿;
IF (en_1hz = '1') THEN --使能为1开始计时;
IF (data0(3 DOWNTO 0) ="1001") THEN --数码管0为9时下次数值加1为0;其他情况都加1
IF (data1 = "0101") THEN--数码管1为5时下次数值加1变成0;其他情况都加1
IF (data2 = "1001") THEN--数码管2为9时下次数值加1变成0;其他情况都加1
IF (data3 = "0101") THEN--数码管3为5时下次数值加1变成0;其他情况都加1
data3 <= "0000";ELSEdata3 <= data3 + "0001";
END IF;
data2 <= "0000";ELSEdata2 <= data2 + "0001";
END IF;
data1 <= "0000"; ELSEdata1 <= data1 + "0001";
END IF;
data0 <= "0000"; ELSEdata0 <= data0 + "0001"
time_total <= (data3 & data2& data1 & data0);--总时间就是data0~3连接到一起的量
4、 计程设计
出租车的速度设置为36km/h,换算得10m/s,既每秒行驶0.1km,设置数码管中显示000.0km。每过10s就向前一位进1,后一位清零,即可计算得出出租车走过的总路程为多少。设计里程计算的主要流程图如下图所示。
DE0-CV开发板的按键都是每个按钮开关在未按下时高电平,按下时是处于低电平模式,一般这种按键模式称之为共阳极连接。在VHDL中按键值得获取可以采用二进制进行描述。开发板的按键示意图如下所示。
出租车的速度设置为36km/h,换算得10m/s,既每秒行驶0.1km,设置数码管中显示000.0km。每过10s就向前一位进1,后一位清零,即可计算得出出租车走过的总路程为多少。设计里程计算的主要流程图如下图所示。
计算里程的主要代码如下:
ELSIF (clk'EVENT AND clk = '1')THEN --判断时钟信号为上升沿;
IF (en_1hz = '1') THEN --使能为1开始计程;
IF (data0 = "1001") THEN
data0 <= "0000"; -- 0号位为9时下次数值加1为0,其他情况都加1;
IF (data1 = "1001") THEN
data1 <= "0000"; -- 1号位为9时下次数值加1为0,其他情况都加1;
IF (data2 = "1001") THEN-- 2号位为9时下次数值加1为0,其他情况都加1;
IF (data3 = "1001") THEN-- 3号位为9时下次数值加1为0,其他情况都加1;
data3 <= "0000";ELSE data3<= data3 + "0001";
END IF;
data2 <= "0000"; ELSE data2<= data2 + "0001";
END IF;
ELSE data1 <= data1 +"0001";
END IF;
ELSE data0 <= data0 +"0001";
Mile_dec <= (data4 & data3& data2 & data1); --总里程就是data0~3连接到一起的量
5、计费设计
出租车的费用为起步价12元,每分钟加收1.2元,前两公里不收而外里程费,两公里后每公里加收2.4元,由于设置了出租车的行驶速度为36km/h,既每秒10m,每10s走100m收费0.24元。设计程序里就是前200s只进行对乘坐时间的计算收费,不对出租车行走的里程数进行收费,200s后出租车行走了2km以上,总费用就开始加上里程费用。如下图所示:
费用计算代码如下:
cnt_2s <= (conv_integer(time_total(3 DOWNTO 0)) + conv_integer(time_total(7DOWNTO 4)) * 10) / 2;
-- 将时间的秒数设置成cnt_2s,时间的费用是两秒一跳;
IF ((NOT(rst)) = '1') THEN --判断复位取反后是否等于1,与其他时钟错开
Q1 <= 1200;
--总费用就为12元;
ELSIF (clk'EVENT AND clk = '1')THEN
IF (Mile_in <="0000000000100000") THEN --当里程小于2KM时;
Q1 <= 1200+4 * cnt_2s+( (conv_integer(time_total(11 DOWNTO 8)) + conv_integer(time_total(15 DOWNTO 12)) * 10) * 100);
--总费用等于12加上0.04乘以总时间的秒数再加上所用多少分钟;
ELSE
Q1 <= 1200+ 4 * cnt_2s+((conv_integer(time_total(11 DOWNTO 8)) + conv_integer (time_total(15 DOWNTO 12))* 10) * 100) + 24 *(conv_integer( Mile_in(15 DOWNTO 12)) *1000+conv_integer(Mile_in(11 DOWNTO 8)) *100 +conv_integer(Mile_in(7 DOWNTO 4))*10 +conv_integer(Mile_in(3 DOWNTO 0)) - 20);
--总费用等于12加上0.04乘以总时间的秒数再加上所用多少分钟再加上计程所显示的距离
END IF;
--rem A/B的运算结果是向0的方向取整
--将费用的每个位置分出
T10 <= (Q1 rem 10);
T20 <= (Q1 /10) rem 10;
T30 <= (Q1 / 100) rem 10;
T40 <= (Q1 /1000) rem 10;
--将每个位置的费用数值都拉长4位,方便后面转换
T1<=conv_std_logic_vector(T10,4);
T2<=conv_std_logic_vector(T20,4);
T3<=conv_std_logic_vector(T30,4);
T4<=conv_std_logic_vector(T40,4);
T_fare <= (T4 & T3 & T2& T1);
-- 总费用的数值就用二进制替换出来
6、 按键设计
对按键进行设计都要进行消抖操作,因为在对按键进行扫描的过程中,按键会经常出现扫描不正常,按下按键没反应或者反应不灵敏的情况,原因就是按键按下或者抬起时会产生抖动,会在回路中产生不稳定的信号,这段不稳定的信号中如果采集到的按键值就会产生误判,进而影响系统的运作。按键抖动的示意图如下所示。所以在对按键进行操作的时候就要对按键进行消抖操作。
按键消抖的流程图如下图所示:
按键消抖的主要代码如下:
IF ((NOT(rst_n)) = '1') THEN --复位键为0则按键采样都为0
count2 <="00000000000000";
key_reg1 <= '0';
key_reg2 <= '0';
button_posedge <= '0';
ELSIF (clk'EVENT AND clk = '1')THEN --检测到时钟上升沿时
count2 <= count2 +"00000000000001";
IF (count2 ="00000011111010") THEN – 延迟时间
key_reg1 <= button_in; --键位输入
count2 <="00000000000000";
END IF;
key_reg2 <= key_reg1;
button_posedge <= (key_reg2) AND(NOT(key_reg1)); --按键状态
7、按键的编写与功能分配DE0-CV开发板的按键都是每个按钮开关在未按下时高电平,按下时是处于低电平模式,一般这种按键模式称之为共阳极连接。在VHDL中按键值得获取可以采用二进制进行描述。开发板的按键示意图如下所示。
出租车计费系统的开始是由按键1进行操作的,当按键1按下时,出租车计费系统开始计费,计时和计程模块开始运行;当按键2按下时,数码管上显示的是出租车所行驶的里程数;当按键3按下时,数码管显示的是出租车所用的时间;当按键4按下时,数码管显示出租车所要收取的费用;当按键5按下时,出租车计费系统暂停计费,重新按下按键1会继续计费;当按键6按下时,出租车计费系统进行复位操作。如下图所示。
Led数码管是由七个发光二极管0、1、2、3、4、5、6构成,根据数码管之间相互连接的情况,一共有两种数码管,一种是共阴极数码管:把所有负极端全部接一块接负极,即公共端为负极。另外一种是共阳极数码管:把所有正极端全部接一块接正极,即公共端为正极。只要控制好数码管每段的显示,就能使数码管显示出不同的数字以及简单的英文字母。DE0-CV 开发板有 6 个 7 段数码管。这6个数码管都是共阳极数码管,可以通过低电平或者高电平来控制开发板数码管每段的显示。
按键的设计代码如下:
--先调用好在消抖的例化程序中写好的按键端口,在顶层文件中分配给每个需要用到的按键端口;
ax_debounce_m7 : ax_debounce --启动按键;
PORT MAP (
clk => clk,rst_n=> rst_n,button_in => btn1,button_posedge=> start_posedge
);
ax_debounce_m1 : ax_debounce --里程按键;
PORT MAP (
clk=>clk,rst_n=>rst_n,button_in=>btn2,button_posedge=>distance_posedge
);
ax_debounce_m2 : ax_debounce --计时按键;
PORT MAP (
clk=> clk,rst_n=>rst_n,button_in => btn3,button_posedge => time_posedge
);
ax_debounce_m3 : ax_debounce --暂停按键;
PORT MAP (
clk=>clk,rst_n=>rst_n,button_in=>btn5,button_posedge=>stop_posedge
);
ax_debounce_m4 : ax_debounce --费用按键;
PORT MAP (
clk=> clk,rst_n=>rst_n,button_in => btn6,button_posedge=> fare_posedge
);
--相应的端口的主要功能如下面代码所示:
IF ((NOT(rst_n)) = '1')THEN --复位键功能
stop_en <= '0';
ELSIF (clk'EVENT AND clk= '1') THEN
IF (stop_posedge = '1')THEN --暂停
stop_en <= '1';
PROCESS (clk, rst_n)
BEGIN
IF ((NOT(rst_n)) = '1')THEN --复位键按下数码管显示的时间
dist_en <='0';time_en <= '1';fare_en <= '0';
ELSIF (clk'EVENT AND clk= '1') THEN
IF (distance_posedge ='1') THEN --里程按键按下数码管显示里程
dist_en <='1';time_en <= '0';fare_en <= '0';
ELSIF (time_posedge ='1') THEN --时间按键按下数码管显示时间
dist_en <='0';time_en <= '1';fare_en <= '0';
ELSIF (fare_posedge ='1') THEN --费用按键按下数码管显示费用
dist_en <= '0';time_en<= '0';fare_en <= '1';
8、数码管的设计Led数码管是由七个发光二极管0、1、2、3、4、5、6构成,根据数码管之间相互连接的情况,一共有两种数码管,一种是共阴极数码管:把所有负极端全部接一块接负极,即公共端为负极。另外一种是共阳极数码管:把所有正极端全部接一块接正极,即公共端为正极。只要控制好数码管每段的显示,就能使数码管显示出不同的数字以及简单的英文字母。DE0-CV 开发板有 6 个 7 段数码管。这6个数码管都是共阳极数码管,可以通过低电平或者高电平来控制开发板数码管每段的显示。
在编写代码中,代码中的电路信号通常是以BCD码的形式进行表示或者进行编写,例如:在代码中写出判断出该数值为0000,此时在代码中的电信号为二进制,假设该数码管为共阳极数码管,那么相应的字形码应该是1000000,对应的数码管段码,如图3.8所示,6号段高电平不亮,其他段位正常亮起,此时数码管显示为0,符合要求。这两者之间的转换就需要使用到BCD码到数码管显示的字形码之间的转换模块。
BCD译码的相应代码显示:
CASE bin_data IS
WHEN "0000"=>seg_data <= "1000000"; --0
WHEN "0001"=>seg_data <= "1111001"; --1
WHEN "0010"=>seg_data <= "0100100"; --2
WHEN "0011"=>seg_data <= "0110000"; --3
WHEN "0100"=>seg_data <= "0011001"; --4
WHEN "0101"=>seg_data <= "0010010"; --5
WHEN "0110"=>seg_data <= "0000010"; --6
WHEN "0111"=>seg_data <= "1111000"; --7
WHEN "1000"=>seg_data <= "0000000"; --8
WHEN "1001"=>seg_data <= "0010000"; --9
WHEN OTHERS=>seg_data <= "1111111"; --其他情况数码管不亮