资源描述
多功能出租车运营控制器
学号:61007211
姓名:洪立俊
1、申请题目:多功能出租车运营控制器
这是一个以出租车计费为主要功能的基于FPGA的全数字系统,同时此系统还附加有一些相关的其他功能,比如计时,自动收费,管理员操作等。
2、课题背景:
出租车是人们日常生活中不可或缺的交通工具,但就目前的出租车运营状况来看,仍存在许多问题,比如司机乱收费,不打表现象较多,出租车公司对于运营信息的管理不到位,另外在客运安全方面仍存在较大漏洞,针对以上提到的问题,我觉得开发一个能够高效管理出租车运营的系统。
3、项目规划:
n 系统功能:此系统的功能主要有计时(附有闹钟和日期),运营计价,自动收费,运营信息保存,管理员操作等。
n 指标及规模:时间显示包括时,分,秒,日期显示包括日,月(分大小月,二月假设为29天),闹钟设置精确到秒,闹铃长达30s。收费标准:白天(6时到夜间23点)起步价为9元,3~15公里每公里1元,15公里以上每公里1.5元,每等待1分钟加收2元,夜间起步价10元,超过3公里每公里1.8元,每等待1分钟3元。计价按每100米计价,里程增加。里程最大为99公里,收费最大999.99元,自动收费接受10,5元,1元,自动找零找都是1元。系统涉及密码为6位。
n 面板(显示):6个8段数码管,4×4小键盘,开关若干,LED灯
n 操作及规则:复位后进入计时,按C修改时间,中途按B可退出,完成六位修改后按E确认,按6进入设置闹钟状态,类似于时间的修改。闹钟时间到或者按0关闭,或者30s后自动关闭。按4显示日期,按C修改日期,类似时间修改。按B回到时间显示。按A进入登陆过程,输入6为密码,登录成功进入,管理员操作程序,按D修改里程分配参数,按F可阅读运营记录。按B退出管理员操作,按F键进入运营过程,按方向键可切换里程和费用的显示,按2进入等待。按3保存记录,进入自动收费,通过拨开关进行收费。收完费进入自动找零至零。按E回到时间显示。
n 输入、输出接口:键盘有扫描译码模块,数码管有译码模块及显示驱动模块,相当于数据选择器。
4、实现方案:
n 核心问题:状态的控制及转移,数据处理模块的设计,以及若干显示的分时显示模块的设计。
n 解决方案:FPGA设计顶层文件采用图形化设计,状态机及相关数据处理单元,附加模块部分采用VHDL语言设计,部分采用图形化设计。由于显示部分也是比较复杂的,所以也引进状态的概念对显示内容进行控制。存储器采用数组的形式存储二进制信息,数组元素即为逻辑值向量。
5、系统结构:
n 系统框图:
n 模块功能描述:输入接口用于译码产生相关的控制信号,状态机用于控制不同时刻的相关操作,数据处理单元用来处理相关信号,包括计时模块,相关寄存模块,计费,收费,计程模块,存储器模块等,输出驱动模块用于控制不同时候的输出。
n 模块接口标注:输入模块接口有4位键盘码keyvalue输出,握手信号pressed,以及一些经消抖同步的外部输入,如复位reset,闹钟开关控制alarm_on,收费脉冲输入f10,f5,f1,状态机产生控制信号,修改时间,日期使能timeload, dateload,修改密码使能,存储记录使能store,运营控制信号showXX,阅读记录信号readXX,找零信号等。数据处理模块产生时间time,日期date,密码code,里程kilo,收费charge,存储器记录输出record等。输出模块输入包括显示状态控制信号ss,各数据处理单元的显示输出内容,输出为6个8段数码管的信号,和一个闹钟到信号alarmsignal。
6、状态流程图:
n 系统工作状态流程
由于系统比较庞大,操作过程比较多,所以涉及的状态控制也比较多,为了更加清楚地表示各状态间的控制转移,以及不同状态对应的控制输出信号,现采用多状态机的描述方法。包括主流程图,各子流程图,其中一些具有类似功能的流程就省略了,比如校准日期,设置闹钟,设置参数的流程就和校准时间的流程类似。
1. 总流程图:
2. 出租车运营流程图
3. 校准时间流程图: 4. 管理员登录流程: 5.管理员修改密码流程
6. 管理员阅读运营记录流程图:
7、程序清单
由于本系统的复杂性,所以程序比较多,这里仅列出主要的程序,同一个程序中类似的代码则省略,具有类似功能的代码仅举其一。
--键盘译码,按键动作标志生成模块--
library ieee;
use ieee.std_logic_1164.all;
entity key_decoder is
port(col3,col2,col1,col0:in std_logic;
row3,row2,row1,row0:in std_logic;
clk,scan_clk:in std_logic;
keyvalue:out std_logic_vector(3 downto 0);
pressed,stop:out std_logic);
end key_decoder;
architecture rtl of key_decoder is
signal temp:std_logic_vector(7 downto 0);
signal temp_pressed:std_logic;
signal q1,q2,q3,q4,q5,q6:std_logic;
signal keypressed_asy:std_logic;
begin
temp<=row3&row2&row1&row0&col3&col2&col1&col0;
process(temp) --键盘译码
begin
case temp is
when "11101110"=>keyvalue<="0000";
temp_pressed<='1';
when "11101101"=>keyvalue<="0001";
temp_pressed<='1';
省略部分
when "01111101"=>keyvalue<="1101";
temp_pressed<='1';
when "01111011"=>keyvalue<="1110";
temp_pressed<='1';
when "01110111"=>keyvalue<="1111";
temp_pressed<='1';
when others=>temp_pressed<='0';
end case;
end process;
process(scan_clk) --按键动作标志消抖
begin
if(scan_clk'event and scan_clk='1') then
q1<=temp_pressed;
q2<=q1;
q3<=q2;
q4<=q3;
end if;
keypressed_asy<=q1 or q2 or q3 or q4;
end process;
process(clk) --按键动作标志与全局时钟同步化
begin
if(clk'event and clk='1') then
q5<=keypressed_asy;
q6<=q5;
end if;
pressed<=q5 and not(q6);
end process;
stop<=col3 and col2 and col1 and col0;
end rtl;
--里程计数模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
entity kilocounter is
port(start,mile,pause:in std_logic; --开始计数,里程脉冲输入,暂停使能输入端
kilo:out std_logic_vector(11 downto 0); --公里数输出端
high_3,high_15:out std_logic); --大于三公里,大于15公里的使能输出端
end kilocounter;
architecture rtl of kilocounter is
signal k1,k0,k00:std_logic_vector(3 downto 0);
begin
process(start,pause,mile)
begin
if start='0' then --未进入里程计数时里程数始终保持为零
k1<="0000";k0<="0000";k00<="0000";
high_3<='0';high_15<='0';
else
if pause='1' then --等待状态下保持里程数
k1<=k1;k0<=k0;k00<=k00;
elsif rising_edge(mile) then --在里程脉冲下正常计数
if k00="1001" then
k00<="0000";
if k0="1001" then
k0<="0000";
if k1="1001" then
k1<="0000";
else
k1<=k1+1;
end if;
else
k0<=k0+1;
end if;
else
k00<=k00+1;
end if;
end if;
end if;
if k0>="0011" then --达到里程要求时标志信号有效
high_3<='1';
end if;
if k1>="0010" or (k1="0001" and k0>="0101") then
high_15<='1';
end if;
end process;
kilo(11 downto 8)<=k1;kilo(7 downto 4)<=k0;kilo(3 downto 0)<=k00;
end rtl;
--计时模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity time_counter is
port(clk,reset,timeload:in std_logic; --全局时钟输入,开机复位端,修改时间置数端
buffertime:in std_logic_vector(23 downto 0); --时间并行输入端
time:out std_logic_vector(23 downto 0); --时间输出端
ci:out std_logic); --时间进位进日月模块
end time_counter;
architecture rtl of time_counter is
signal clk1s:std_logic;
signal temp_time5,temp_time4,temp_time3,temp_time2,temp_time1,temp_time0:std_logic_vector(3 downto 0);
component divider_1s --500分频器说明
port(clk:in std_logic;
clk1s:out std_logic);
end component;
begin
divider1s:divider_1s --500分频器实例化
port map(clk=>clk,
clk1s=>clk1s);
process(clk1s,clk,reset,timeload)
begin
if reset='0' then --复位清零
temp_time5<="0000";temp_time4<="0000";temp_time3<="0000";temp_time2<="0000";temp_time1<="0000";temp_time0<="0000";
elsif rising_edge(clk) then
if timeload='1' then --修改时间时置数
temp_time5<=buffertime(23 downto 20);
temp_time4<=buffertime(19 downto 16);
temp_time3<=buffertime(15 downto 12);
temp_time2<=buffertime(11 downto 8);
temp_time1<=buffertime(7 downto 4);
temp_time0<=buffertime(3 downto 0);
else --正常计时
if clk1s='1' then
if temp_time0="1001" then
temp_time0<="0000";
if temp_time1="0101" then
temp_time1<="0000";
if temp_time2="1001" then
temp_time2<="0000";
if temp_time3="0101" then
temp_time3<="0000";
if temp_time4="1001" and temp_time5="0000" then
temp_time4<="0000";temp_time5<="0001";
elsif temp_time4="1001" and temp_time5="0001" then
temp_time4<="0000";temp_time5<="0010";
elsif temp_time4="0011" and temp_time5="0010" then
temp_time4<="0000";temp_time5<="0000";
else
temp_time4<=temp_time4+1;
end if;
else
temp_time3<=temp_time3+1;
end if;
else
temp_time2<=temp_time2+1;
end if;
else
temp_time1<=temp_time1+1;
end if;
else
temp_time0<=temp_time0+1;
end if;
end if;
end if;
end if;
--当计到23:59:59出现进位信号至日月模块--
if temp_time5&temp_time4&temp_time3&temp_time2&temp_time1&temp_time0="001000110101100101011001" then
ci<='1';
else
ci<='0';
end if;
end process;
time(23 downto 20)<=temp_time5;time(19 downto 16)<=temp_time4;time(15 downto 12)<=temp_time3;time(11 downto 8)<=temp_time2;time(7 downto 4)<=temp_time1;time(3 downto 0)<=temp_time0;
end rtl;
--计费模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity total_charge is
port(start,pause,mile,f_wait:in std_logic; --未运营状态,等待暂停状态,里程脉冲,等待时间脉冲
high_3,high_15:in std_logic; --里程标志输入
time:in std_logic_vector(23 downto 0); --时间输入
charge:out std_logic_vector(19 downto 0));--计费总价输出,分别为百,十,个,十分,百分位
end total_charge;
architecture rtl of total_charge is
signal c4,c3,c2,c1,c0:std_logic_vector(3 downto 0);
begin
process(time,pause,start,mile,f_wait,high_3,high_15)
variable hour_h,hour_l:std_logic_vector(3 downto 0);
begin
hour_h:=time(23 downto 20);
hour_l:=time(19 downto 16);
if start='0' then --未运营时价格总为零
c4<="0000";c3<="0000";c2<="0000";c1<="0000";c0<="0000";
else
if (hour_h="0000" and hour_l>="0110") or hour_h="0001" or (hour_h="0010" and hour_l<="0010") then --白天运营
if pause='1' then --等待下的计费
if rising_edge(f_wait) then --即pause='1'进入等待状态
if c2="1001" or c2="1000" then
if c2="1001" then
c2<="0001";
else
c2<="0000";
end if;
if c3="1001" then
c3<="0000";
if c4="1001" then
c4<="0000";
else
c4<=c4+1;
end if;
else
c3<=c3+1;
end if;
else
c2<=c2+2;
end if;
end if;
else
if rising_edge(mile) then --正常运营
if high_3='0' then
c4<="0000";c3<="0000";c2<="1001";c1<="0000";c0<="0000";
elsif high_15='0' then
if c1="1001" then
c1<="0000";
if c2="1001" then
c2<="0000";
if c3="1001" then
c3<="0000";
if c4="1001" then
c4<="0000";
else c4<=c4+1;
end if;
else c3<=c3+1;
end if;
else c2<=c2+1;
end if;
else c1<=c1+1;
end if;
elsif high_3='1' and high_15='1' then
if(c0="0101" and c1="1000")or c1="1001" then
if c1="1001" and c0="0101" then
c0<="0000";c1<="0001";
elsif c1="1001" and c0="0000" then
c0<="0101";c1<="0000";
elsif c1="1000" and c0="0101" then
c0<="0000";c1<="0000";
end if;
if c2="1001" then
c2<="0000";
if c3="1001" then
c3<="0000";
if c4="1001" then
c4<="0000";
else c4<=c4+1;
end if;
else c3<=c3+1;
end if;
else c2<=c2+1;
end if;
elsif c0="0000" then
c0<="0101";c1<=c1+1;
else
c0<="0000";c1<=c1+"0010";
end if;
end if;
end if;
end if;
else --夜间运营模式
if pause='1' then
if rising_edge(f_wait) then
省略部分
end process;
charge(19 downto 16)<=c4;charge(15 downto 12)<=c3;charge(11 downto 8)<=c2;charge(7 downto 4)<=c1;charge(3 downto 0)<=c0;
end rtl;
--铃声产生模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity bell_pro is
port(alarm_on,clk,alarm_load,pressed:in std_logic; --闹钟开关,时钟,修改置数,键盘响应
buffertime:in std_logic_vector(15 downto 0); --修改时间并行输入端
time:in std_logic_vector(23 downto 0); --当前时间并行输入
keyvalue:in std_logic_vector(3 downto 0); --键盘值输入端
alarm_signal:out std_logic); --闹铃信号输出端
end bell_pro;
architecture rtl of bell_pro is
signal alarm:std_logic;
type state is(s0,s1,s2,s3);
signal pre_state:state:=s0;
signal next_state:state:=s0;
signal iner_ala_time:std_logic_vector(15 downto 0);
begin
process(clk) --修改置数进程
begin
if rising_edge(clk) then
if alarm_load='1' then
iner_ala_time<=buffertime;
end if;
end if;
end process;
process(clk,alarm_on) --状态转移进程
begin
if alarm_on='0' then
pre_state<=s0;
elsif rising_edge(clk) then
pre_state<=next_state;
end if;
end process;
process(pre_state,time,iner_ala_time,pressed,keyvalue) --具体的状态机
begin
case pre_state is
when s0=>
if iner_ala_time=time(23 downto 8) then
next_state<=s1;
else
next_state<=pre_state;
end if;
when s1=>
if pressed='1' and keyvalue="0000" then
next_state<=s3;
elsif time(7 downto 4)>="0011" then
next_state<=s2;
else
next_state<=pre_state;
end if;
when s2=>
if time(7 downto 4)="0000" then
next_state<=s0;
else
next_state<=pre_state;
end if;
when s3=>
if time(7 downto 4)>="0011" then
next_state<=s2;
else
next_state<=pre_state;
end if;
when others=>next_state<=s0;
end case;
end process;
process(pre_state) --状态输出
begin
if pre_state=s1 then
alarm<='1';
else
alarm<='0';
end if;
end process;
alarm_signal<=alarm;
end rtl;
--存储器模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity ram_16 is
port(clk:in std_logic;
wr:in std_logic:='0'; --写使能
re:in std_logic:='0'; --读使能
re_address,wr_address:in std_logic_vector(3 downto 0);--读写地址输入端
time:in std_logic_vector(23 downto 0);--时间输入
date:in std_logic_vector(15 downto 0);--日期输入
charge:in std_logic_vector(19 downto 0);--费用输入
kilo:in std_logic_vector(11 downto 0);--里程输入
tra_record:out std_logic_vector(55 downto 0));--运营记录输出
end ram_16;
architecture rtl of ram_16 is
subtype ram_word is std_logic_vector(55 downto 0);
type ram_table is array(0 to 15) of ram_word;
signal ram:ram_table;
begin
process(clk,time,date,charge,re_address,wr_address,kilo,wr,re)
begin
if rising_edge(clk) then
if re='1' then --读出运营记录
tra_record<=ram(conv_integer(re_address));
elsif wr='1' then --写进记录
ram(conv_integer(wr_address))(55 downto 44)<=kilo;
ram(conv_integer(wr_address))(43 downto 28)<=date;
ram(conv_integer(wr_address))(27 downto 12)<=time(23 downto 8);
ram(conv_integer(wr_address))(11 downto 0)<=charge(19 downto 8);
end if;
end if;
end process;
end rtl;
--自动收费模块--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity auto_receive is
port(f10,f5,f1,write,reset,clk,clk1s,en_return:in std_logic; --收费脉冲输入,写使能
charge:in std_logic_vector(19 downto 0); --总收费收入端
展开阅读全文