本(běn)文(wén)为(wèi)明(míng)德揚原創及(jí)录(lù)用(yòng)文(wén)章(zhāng),轉(zhuǎn)载請注明(míng)出(chū)处!
1.1 總(zǒng)體(tǐ)設計(jì)
1.1.1 概述
学習了(le)明(míng)德揚至(zhì)簡設計(jì)法和(hé)明(míng)德揚設計(jì)規範,本(běn)人(rén)設計(jì)了(le)一(yī)个(gè)基于(yú)FPGA的(de)出(chū)租車計(jì)費系(xì)統。該系(xì)統由(yóu)一(yī)个(gè)按鍵表(biǎo)示出(chū)租車上(shàng)是(shì)否有(yǒu)乘客,再通(tòng)过(guò)檢测出(chū)租車的(de)檔位和(hé)轮胎的(de)轉(zhuǎn)速来(lái)獲得乘客所(suǒ)需支付的(de)總(zǒng)費用(yòng)。在(zài)本(běn)案(àn)例的(de)設計(jì)过(guò)程中(zhōng),包(bāo)含了(le)按鍵定(dìng)義和(hé)消抖、計(jì)數器、數碼管(guǎn)顯示等技術(shù)。經(jīng)过(guò)逐步改進(jìn)、調試等一(yī)系(xì)列操作之後(hòu),完成(chéng)了(le)此(cǐ)設計(jì),下(xià)面(miàn)将完整的(de)設計(jì)記(jì)录(lù)與(yǔ)大家(jiā)分(fēn)享。
本(běn)工程使用(yòng)VIVADO進(jìn)行仿真(zhēn),未進(jìn)行上(shàng)板。
1.1.2 設計(jì)目标(biāo)
此(cǐ)設計(jì)可(kě)以(yǐ)完成(chéng)出(chū)租車計(jì)費的(de)功能(néng)。在(zài)按鍵按下(xià)後(hòu)(乘客上(shàng)車),開(kāi)始按如(rú)下(xià)規則計(jì)費:
起步價5元(yuán),超过(guò)3KM以(yǐ)每公里(lǐ)2元(yuán)計(jì)費,如(rú)果(guǒ)遇到(dào)紅(hóng)綠(lǜ)燈(dēng)、堵車等需要(yào)停車等待时(shí),則以(yǐ)每20分(fēn)鐘(zhōng)1元(yuán)計(jì)費。
再按一(yī)下(xià)按鍵(乘客下(xià)車)則計(jì)費結束(shù),算出(chū)乘客所(suǒ)需支付的(de)總(zǒng)費用(yòng),并在(zài)數碼管(guǎn)上(shàng)顯示。
1.1.3 系(xì)統結構框图(tú)
系(xì)統結構框图(tú)如(rú)下(xià)所(suǒ)示:
1.1.4 模块(kuài)功能(néng)
key模块(kuài)实現(xiàn)功能(néng)
由(yóu)于(yú)按鍵信(xìn)号(hào)是(shì)异(yì)步信(xìn)号(hào),所(suǒ)以(yǐ)对(duì)該将信(xìn)号(hào)打(dǎ)两(liǎng)拍处理,将异(yì)步信(xìn)号(hào)同(tóng)步化(huà);
实現(xiàn)10ms按鍵消抖功能(néng),并輸出(chū)按鍵信(xìn)号(hào)key_flag,每按一(yī)次(cì)按鍵,key_flag取(qǔ)反(fǎn)
其中(zhōng)key_flag=1表(biǎo)示有(yǒu)乘客,key_flag=0表(biǎo)示沒(méi)有(yǒu)乘客。
speed模块(kuài)实現(xiàn)功能(néng)
通(tòng)过(guò)按鍵信(xìn)号(hào)key_flag有(yǒu)效,对(duì)轮胎轉(zhuǎn)速進(jìn)行每秒(miǎo)取(qǔ)樣(yàng),進(jìn)而(ér)獲得乘客行駛總(zǒng)的(de)路(lù)程和(hé)判斷按时(shí)計(jì)費的(de)使能(néng)信(xìn)号(hào)en_0是(shì)否有(yǒu)效。
fare模块(kuài)实現(xiàn)功能(néng)
通(tòng)过(guò)speed模块(kuài)的(de)總(zǒng)路(lù)程和(hé)按时(shí)計(jì)費有(yǒu)效使能(néng)信(xìn)号(hào)来(lái)獲得乘客所(suǒ)需支付的(de)總(zǒng)費用(yòng),再取(qǔ)得總(zǒng)費用(yòng)的(de)个(gè)位、十(shí)位和(hé)百(bǎi)位數值并輸出(chū)。
show模块(kuài)实現(xiàn)功能(néng)
采用(yòng)動(dòng)态掃描3个(gè)數碼管(guǎn)的(de)方(fāng)式顯示fare模块(kuài)中(zhōng)獲得的(de)三(sān)个(gè)數值即为(wèi)乘客所(suǒ)需支付的(de)總(zǒng)費用(yòng)。
1.1.5 頂层信(xìn)号(hào)
| | |
| | |
| | |
| | 出(chū)租車的(de)檔位信(xìn)号(hào),空挡为(wèi)0,其他(tā)檔位为(wèi)1 |
| | 出(chū)租車轮胎轉(zhuǎn)速信(xìn)号(hào)。通(tòng)过(guò)該信(xìn)号(hào),可(kě)以(yǐ)用(yòng)来(lái)計(jì)算汽車行駛的(de)距離。 |
| | 乘客上(shàng)、下(xià)車指示信(xìn)号(hào)。 使用(yòng)按鍵来(lái)表(biǎo)示。 |
| | 3个(gè)數碼管(guǎn)的(de)位選信(xìn)号(hào),在(zài)低電(diàn)平是(shì)該位置數碼管(guǎn)亮(liàng)。 |
| | 段(duàn)選信(xìn)号(hào),共(gòng)8位。由(yóu)低到(dào)高(gāo),分(fēn)别表(biǎo)示數碼管(guǎn)的(de)a,b,c,d,e,f,g,點(diǎn)。當該比特(tè)为(wèi)0时(shí),表(biǎo)示點(diǎn)亮(liàng)相應(yìng)位置;为(wèi)1时(shí)熄滅。 |
1.1.6 頂层代(dài)碼
module taxi_fare( clk , rst_n , d_w , rev , key_in ,
seg_sel , segment );
input clk ; input rst_n ; input d_w ; //檔位 input [15:0] rev ; //轉(zhuǎn)速 input key_in ; //按鍵,表(biǎo)示乘客是(shì)否上(shàng)車
output seg_sel ; //位選信(xìn)号(hào),在(zài)低電(diàn)平是(shì)該位置數碼管(guǎn)亮(liàng)。 output segment ; //段(duàn)選信(xìn)号(hào),共(gòng)8位。由(yóu)低到(dào)高(gāo),分(fēn)别表(biǎo)示數碼管(guǎn)的(de)a,b,c,d,e,f,g,點(diǎn)。當該比特(tè)为(wèi)0时(shí),表(biǎo)示點(diǎn)亮(liàng)相應(yìng)位置;为(wèi)1时(shí)熄滅。
wire [3-1:0] seg_sel ; wire [8-1:0] segment ;
//中(zhōng)間(jiān)量(liàng) wire key_flag ; //有(yǒu)乘客为(wèi)1,无乘客为(wèi)0 wire en_0 ; //按时(shí)間(jiān)計(jì)費使能(néng)信(xìn)号(hào) wire [19:0] distance ; //行駛路(lù)程 wire [3:0] x_g ; //總(zǒng)費用(yòng)的(de)个(gè)位值 wire [3:0] x_s ; //總(zǒng)費用(yòng)的(de)十(shí)位值 wire [3:0] x_b ; //總(zǒng)費用(yòng)的(de)百(bǎi)位值
key_litter key_litter_0( .clk (clk) , .rst_n (rst_n) , .key_in (key_in) ,
.key_flag (key_flag) );
speed speed_0( .clk (clk) , .rst_n (rst_n) , .d_w (d_w) , .rev (rev) , .key_flag (key_flag) , //輸出(chū)信(xìn)号(hào) .en_0 (en_0) , .distance (distance) );
fare fare_0( .clk (clk) , .rst_n (rst_n) , .distance (distance) , .en_0 (en_0) , .key_flag (key_flag) ,
.x_g (x_g) , .x_s (x_s) , .x_b (x_b) );
show show_0( .clk (clk) , .rst_n (rst_n) , .din ({x_b,x_s,x_g}) , .din_vld (3'b111) , .disp_en (1) ,
.seg_sel (seg_sel) , .segment (segment) );
endmodule |
1.2 key模块(kuài)設計(jì)
1.2.1 接口(kǒu)信(xìn)号(hào)
| | |
| | |
| | |
| | 按鍵輸入(rù)。使用(yòng)按鍵来(lái)表(biǎo)示乘客上(shàng)、下(xià)車。 |
| | 輸出(chū)表(biǎo)示有(yǒu)无乘客。1为(wèi)有(yǒu)乘客,0为(wèi)沒(méi)有(yǒu)乘客 |
1.2.2 設計(jì)思(sī)路(lù)
此(cǐ)模块(kuài)通(tòng)过(guò)一(yī)个(gè)按鍵来(lái)表(biǎo)示車上(shàng)是(shì)否有(yǒu)乘客,複位时(shí)輸出(chū)信(xìn)号(hào)key_flag为(wèi)0,當乘客上(shàng)車时(shí),司機(jī)按一(yī)下(xià)按鍵,key_flag由(yóu)0變(biàn),1,表(biǎo)明(míng)乘客已上(shàng)車,系(xì)統開(kāi)始計(jì)費。到(dào)达(dá)目的(de)地(dì)时(shí),司機(jī)再按一(yī)下(xià)按鍵,key_flag由(yóu)1變(biàn)0,表(biǎo)明(míng)到(dào)达(dá)目的(de)地(dì)乘客下(xià)車,系(xì)統結束(shù)計(jì)費。
独立式按鍵工作原理如(rú)上(shàng)图(tú)所(suǒ)示,4条(tiáo)輸入(rù)線(xiàn)接到(dào)FPGA的(de)IO口(kǒu)上(shàng),當按鍵K1按下(xià)时(shí),VCC通(tòng)过(guò)電(diàn)阻R1再通(tòng)过(guò)按鍵K1最(zuì)終(zhōng)進(jìn)入(rù)GND形成(chéng)一(yī)条(tiáo)通(tòng)路(lù),这(zhè)条(tiáo)線(xiàn)路(lù)的(de)全(quán)部(bù)電(diàn)壓都加在(zài)R1上(shàng),則引脚P14是(shì)低電(diàn)平。當松開(kāi)按鍵後(hòu),線(xiàn)路(lù)斷開(kāi),就(jiù)不(bù)会(huì)有(yǒu)電(diàn)流通(tòng)过(guò),P14和(hé)VCC就(jiù)應(yìng)該是(shì)等電(diàn)位,为(wèi)高(gāo)電(diàn)平。我(wǒ)们(men)可(kě)以(yǐ)通(tòng)过(guò)P14这(zhè)个(gè)IO口(kǒu)的(de)高(gāo)低電(diàn)平狀态来(lái)判斷是(shì)否有(yǒu)按鍵按下(xià)。其它(tā)按鍵原理與(yǔ)K1一(yī)致(zhì),當然本(běn)实验(yàn)只(zhī)需要(yào)一(yī)个(gè)按鍵即可(kě),任選一(yī)个(gè)按鍵都可(kě)以(yǐ)。
從图(tú)中(zhōng)可(kě)以(yǐ)看(kàn)出(chū),如(rú)果(guǒ)我(wǒ)们(men)按下(xià)按鍵,那(nà)麼(me)按鍵就(jiù)会(huì)接通(tòng)并連(lián)接到(dào)低電(diàn)平GND,如(rú)果(guǒ)我(wǒ)们(men)沒(méi)有(yǒu)按下(xià),那(nà)麼(me)按鍵就(jiù)会(huì)斷開(kāi)并接到(dào)VCC,因(yīn)此(cǐ)按鍵为(wèi)低電(diàn)平有(yǒu)效。通(tòng)常的(de)按鍵所(suǒ)用(yòng)開(kāi)關(guān)为(wèi)機(jī)械弹性(xìng)開(kāi)關(guān),當機(jī)械觸點(diǎn)斷開(kāi)或(huò)者(zhě)閉合时(shí),由(yóu)于(yú)機(jī)械觸點(diǎn)的(de)弹性(xìng)作用(yòng),一(yī)个(gè)按鍵開(kāi)關(guān)在(zài)閉合时(shí)不(bù)会(huì)马上(shàng)稳定(dìng)地(dì)接通(tòng),在(zài)斷開(kāi)时(shí)也(yě)不(bù)会(huì)一(yī)下(xià)子斷開(kāi)。因(yīn)而(ér)機(jī)械式按鍵在(zài)閉合及(jí)斷開(kāi)的(de)瞬間(jiān)均伴随有(yǒu)一(yī)連(lián)串的(de)抖動(dòng),如(rú)果(guǒ)不(bù)進(jìn)行处理,会(huì)使系(xì)統識别到(dào)抖動(dòng)信(xìn)号(hào)而(ér)進(jìn)行不(bù)必要(yào)的(de)反(fǎn)應(yìng),導致(zhì)模块(kuài)功能(néng)不(bù)正(zhèng)常,为(wèi)了(le)避免这(zhè)種(zhǒng)現(xiàn)象(xiàng)的(de)産生(shēng),需要(yào)進(jìn)行按鍵消抖的(de)操作。
按鍵消抖主(zhǔ)要(yào)分(fēn)为(wèi)硬(yìng)件(jiàn)消抖和(hé)软(ruǎn)件(jiàn)消抖。两(liǎng)个(gè)“與(yǔ)非(fēi)”門(mén)構成(chéng)一(yī)个(gè)RS觸發(fà)器为(wèi)常用(yòng)的(de)硬(yìng)件(jiàn)消抖。软(ruǎn)件(jiàn)方(fāng)法消抖,即檢测出(chū)鍵閉合後(hòu)執行一(yī)个(gè)延时(shí)程序,抖動(dòng)时(shí)間(jiān)的(de)长短(duǎn)由(yóu)按鍵的(de)機(jī)械特(tè)性(xìng)決定(dìng),一(yī)般为(wèi)5ms~20ms,讓前(qián)沿抖動(dòng)消失後(hòu)再一(yī)次(cì)檢测鍵的(de)狀态,如(rú)果(guǒ)仍保持(chí)閉合狀态電(diàn)平,則确認按下(xià)按鍵操作有(yǒu)效。當檢测到(dào)按鍵釋放(fàng)後(hòu),也(yě)要(yào)給(gěi)5ms~20ms的(de)延时(shí),待後(hòu)沿抖動(dòng)消失後(hòu)才能(néng)轉(zhuǎn)入(rù)該鍵的(de)处理程序。經(jīng)过(guò)按鍵消抖的(de)行人(rén)优先(xiān)按鍵,判斷按鍵有(yǒu)效後(hòu),按鍵信(xìn)号(hào)傳遞給(gěi)控制系(xì)統,控制系(xì)統再進(jìn)入(rù)相應(yìng)的(de)处理程序。如(rú)還(huán)不(bù)明(míng)白之处,見(jiàn)实验(yàn)的(de)PDF。
图(tú)5.1.2按鍵消抖示意(yì)图(tú)
1.2.3 參考代(dài)碼
使用(yòng)明(míng)德揚的(de)計(jì)數器模板,可(kě)以(yǐ)很快(kuài)速很熟練地(dì)写出(chū)按鍵消抖模块(kuài)。
每10ms掃描一(yī)次(cì)按鍵輸入(rù)key_in,可(kě)以(yǐ)达(dá)到(dào)消抖的(de)目的(de),再用(yòng)寄存器緩存一(yī)下(xià),按鍵为(wèi)低電(diàn)平有(yǒu)效;但本(běn)实验(yàn)是(shì)需要(yào)按鍵按下(xià)松開(kāi)这(zhè)樣(yàng)一(yī)次(cì)完整的(de)按按鍵操作後(hòu)輸出(chū)key_flag才發(fà)生(shēng)變(biàn)化(huà),所(suǒ)以(yǐ)檢测當檢测到(dào)按鍵有(yǒu)上(shàng)升(shēng)沿變(biàn)化(huà)时(shí),代(dài)表(biǎo)該按鍵被(bèi)按下(xià)松開(kāi),按鍵輸出(chū)key_flag才發(fà)生(shēng)變(biàn)化(huà)。
本(běn)模块(kuài)設計(jì)了(le)一(yī)个(gè)狀态機(jī),用(yòng)于(yú)按鍵的(de)檢测。該狀态機(jī)共(gòng)包(bāo)括4个(gè)狀态。
其各(gè)个(gè)狀态的(de)含義如(rú)下(xià)。
空閑狀态(IDLE):表(biǎo)示按鍵沒(méi)有(yǒu)被(bèi)按下(xià),檢测到(dào)低電(diàn)平進(jìn)入(rù)下(xià)一(yī)狀态。
延时(shí)确認狀态(S1):開(kāi)始10ms延时(shí)計(jì)數,若計(jì)數完成(chéng)且依然为(wèi)低電(diàn)平則進(jìn)入(rù)下(xià)一(yī)狀态,若計(jì)數期(qī)間(jiān)按鍵出(chū)現(xiàn)高(gāo)電(diàn)平说(shuō)明(míng)为(wèi)抖動(dòng)回(huí)到(dào)初始狀态。
檢测釋放(fàng)狀态(S2):表(biǎo)示按鍵按下(xià)未松開(kāi),檢测到(dào)高(gāo)電(diàn)平進(jìn)入(rù)下(xià)一(yī)狀态。
延时(shí)确認狀态(S3):開(kāi)始10ms延时(shí)計(jì)數,若計(jì)數完成(chéng)且依然为(wèi)高(gāo)電(diàn)平視为(wèi)有(yǒu)效松手(shǒu)行为(wèi)進(jìn)入(rù)初始狀态再檢测下(xià)一(yī)次(cì)按鍵按下(xià),若計(jì)數期(qī)間(jiān)按鍵出(chū)現(xiàn)低電(diàn)平说(shuō)明(míng)为(wèi)抖動(dòng)回(huí)到(dào)S2狀态。
代(dài)碼如(rú)下(xià):
module key_litter( clk , rst_n , key_in ,
key_flag );
//消抖的(de)狀态 parameter IDLE = 4'b0000 ; parameter S1 = 4'b0001 ; parameter S2 = 4'b0010 ; parameter S3 = 4'b0100 ; parameter S4 = 4'b1000 ;
//輸入(rù)信(xìn)号(hào)定(dìng)義 input clk ; input rst_n ; input key_in ;
//輸出(chū)信(xìn)号(hào)定(dìng)義 output key_flag; //輸出(chū),表(biǎo)示是(shì)否有(yǒu)乘客
//輸出(chū)信(xìn)号(hào)reg定(dìng)義 reg key_flag;
//中(zhōng)間(jiān)信(xìn)号(hào)定(dìng)義 reg [19:0] cnt ;
reg key_in_1; //寄存器 reg key_in_2; //寄存器
reg [3:0] state_c ; reg [3:0] state_n ;
wire idl2s1_start ; wire s12s2_start ; wire s12s2_end ; wire s22s3_start ; wire s32s4_start ; wire s32s4_end ;
wire add_cnt ; //計(jì)數進(jìn)行 wire end_cnt ; //計(jì)數清(qīng)零(líng) wire cnt_during ; //計(jì)數过(guò)程中(zhōng)
//打(dǎ)两(liǎng)拍 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin key_in_1 <= 0; key_in_2 <= 0; end else begin key_in_1 <= key_in; key_in_2 <= key_in_1; end end
//消抖 //四(sì)段(duàn)式狀态機(jī)
//第(dì)一(yī)段(duàn):同(tóng)步时(shí)序always模块(kuài),格式化(huà)描述次(cì)态寄存器遷移到(dào)現(xiàn)态寄存器(不(bù)需更(gèng)改) always@(posedge clk or negedge rst_n)begin if(!rst_n)begin state_c <= IDLE; end else begin state_c <= state_n; end end //第(dì)二(èr)段(duàn):組合邏輯always模块(kuài),描述狀态轉(zhuǎn)移条(tiáo)件(jiàn)判斷 always@(*)begin case(state_c) IDLE:begin if(idl2s1_start)begin state_n = S1; end else begin state_n = state_c; end end S1:begin if(s12s2_start)begin state_n = S2; end else if(s12s2_end)begin state_n = IDLE ; end else begin state_n = state_c; end end S2:begin if(s22s3_start)begin state_n = S3; end else begin state_n = state_c; end end S3:begin if(s32s4_start)begin state_n = IDLE; end else if(s32s4_end)begin state_n = S2; end else begin state_n = state_c; end end default:begin state_n = IDLE; end endcase end //第(dì)三(sān)段(duàn):設計(jì)轉(zhuǎn)移条(tiáo)件(jiàn) assign idl2s1_start = key_in_2 == 0; assign s12s2_start = key_in_2==0 && end_cnt == 1; assign s12s2_end = key_in_2==1 && cnt_during ; assign s22s3_start = key_in_2 == 1; assign s32s4_start = key_in_2 == 1 && end_cnt == 1; assign s32s4_end = key_in_2 == 0 && cnt_during ; //第(dì)四(sì)段(duàn):同(tóng)步时(shí)序always模块(kuài),格式化(huà)描述寄存器輸出(chū)(可(kě)有(yǒu)多(duō)个(gè)輸出(chū)) always @(posedge clk or negedge rst_n)begin if(!rst_n)begin key_flag <=1'b0 ; //初始化(huà) end else if(s32s4_start)begin key_flag = ~key_flag; end else begin key_flag <= key_flag; end end
//計(jì)數器,計(jì)數10ms always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end else cnt <= 0; end assign add_cnt = state_c == S1 || state_c == S3; assign end_cnt = add_cnt && cnt== /*仿真(zhēn)时(shí)使用(yòng)以(yǐ)減少(shǎo)仿真(zhēn)时(shí)間(jiān)5 - 1;*/ 500000-1; assign cnt_during = add_cnt && end_cnt == 0;
endmodule |
1.3 speed模块(kuài)設計(jì)
1.3.1 接口(kǒu)信(xìn)号(hào)
| | |
| | |
| | |
| | 出(chū)租車檔位信(xìn)号(hào),空挡为(wèi)0、其他(tā)檔位为(wèi)1 |
| | 出(chū)租車轮胎轉(zhuǎn)速信(xìn)号(hào)。通(tòng)过(guò)該信(xìn)号(hào),可(kě)以(yǐ)用(yòng)来(lái)計(jì)算汽車行駛的(de)距離。 |
| | 表(biǎo)示有(yǒu)无乘客上(shàng)車,有(yǒu)乘客为(wèi)1,沒(méi)有(yǒu)为(wèi)0 |
| | 表(biǎo)示出(chū)租車按时(shí)間(jiān)計(jì)費信(xìn)号(hào),1位按时(shí)間(jiān)計(jì)費,0則不(bù)按时(shí)間(jiān)計(jì)費。等待紅(hóng)綠(lǜ)燈(dēng)或(huò)堵車等需要(yào)停車过(guò)程中(zhōng),使用(yòng)时(shí)間(jiān)計(jì)費;行駛过(guò)程中(zhōng),使用(yòng)距離計(jì)費。 |
| | 輸出(chū)乘客乘坐的(de)總(zǒng)路(lù)程 |
1.3.2 設計(jì)思(sī)路(lù)
消抖後(hòu)的(de)按鍵信(xìn)号(hào)輸入(rù)到(dào)本(běn)模块(kuài)中(zhōng),同(tóng)樣(yàng)使用(yòng)明(míng)德揚至(zhì)簡設計(jì)法和(hé)計(jì)數器模板,可(kě)以(yǐ)快(kuài)速写出(chū)計(jì)算總(zǒng)路(lù)程和(hé)獲得按时(shí)計(jì)費信(xìn)号(hào)en_0有(yǒu)效的(de)代(dài)碼。當key_flag为(wèi)1有(yǒu)效且轉(zhuǎn)速rev>=3r/s时(shí),計(jì)數器開(kāi)始計(jì)數,每計(jì)一(yī)秒(miǎo)鐘(zhōng)对(duì)轉(zhuǎn)速信(xìn)号(hào)rev取(qǔ)樣(yàng),獲得每秒(miǎo)行駛路(lù)程并累加,當key_flag为(wèi)0时(shí),計(jì)數停止,累加也(yě)停止,此(cǐ)时(shí)獲得的(de)累加值即为(wèi)總(zǒng)路(lù)程。當key_flag为(wèi)1有(yǒu)效且rev<3r/s时(shí),en_0拉高(gāo)为(wèi)1,表(biǎo)示此(cǐ)时(shí)需要(yào)按时(shí)計(jì)費。
1.3.3 參考代(dài)碼
module speed( clk , rst_n , d_w , rev , key_flag, //輸出(chū)信(xìn)号(hào) en_0 , distance );
//參數定(dìng)義 parameter DATA_W = 20;
//輸入(rù)信(xìn)号(hào)定(dìng)義 input clk ; input rst_n ; input d_w ; //檔位 input rev ; //轉(zhuǎn)速 input key_flag; //有(yǒu)无乘客信(xìn)号(hào)
//輸入(rù)信(xìn)号(hào)定(dìng)義 wire [15:0] rev ; //輸出(chū)信(xìn)号(hào)定(dìng)義 output[DATA_W-1:0] distance ; //路(lù)程 output en_0 ; //按时(shí)計(jì)費信(xìn)号(hào)
//輸出(chū)信(xìn)号(hào)reg定(dìng)義 reg [DATA_W-1:0] distance ; reg en_0 ;
//中(zhōng)間(jiān)信(xìn)号(hào)定(dìng)義 reg [15:0] rev_1 ; //每秒(miǎo)取(qǔ)樣(yàng)轉(zhuǎn)速信(xìn)号(hào) reg [25:0] cnt ; //一(yī)秒(miǎo)的(de)計(jì)數器
wire high_en_0 ; //拉高(gāo)按时(shí)計(jì)費信(xìn)号(hào)的(de)信(xìn)号(hào) wire add_cnt ; wire end_cnt ;
//按时(shí)計(jì)費 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin en_0 <= 0; end else if(high_en_0) begin en_0 <= 1; end else en_0 <= 0; end assign high_en_0 = ( d_w == 0 && rev < 3 || rev < 3 ) && key_flag == 1;
//計(jì)數1秒(miǎo) always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end else if(key_flag == 0) cnt <= 0; end assign add_cnt = rev >= 3 && key_flag == 1; assign end_cnt = add_cnt && cnt == /*仿真(zhēn)时(shí)使用(yòng)以(yǐ)节(jié)省(shěng)仿真(zhēn)时(shí)間(jiān)500-1;*/50000000-1 ;
//每秒(miǎo)取(qǔ)樣(yàng)rev always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin rev_1 <= 0; end else if(end_cnt) begin rev_1 <= rev; end end
//distance always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin distance <= 0; end else if(end_cnt) begin distance <=distance + rev_1/3; end end
endmodule |
1.4 fare模块(kuài)設計(jì)
1.4.1 接口(kǒu)信(xìn)号(hào)
| | |
| | |
| | |
| | |
| | 按时(shí)間(jiān)計(jì)費信(xìn)号(hào),1为(wèi)按时(shí)間(jiān)計(jì)費,0为(wèi)不(bù)按时(shí)間(jiān)計(jì)費 |
| | 表(biǎo)示是(shì)否有(yǒu)乘客,有(yǒu)为(wèi)1,沒(méi)有(yǒu)为(wèi)0,且在(zài)沒(méi)有(yǒu)乘客时(shí),所(suǒ)有(yǒu)信(xìn)号(hào)歸0 |
| | 輸出(chū)總(zǒng)費用(yòng)的(de)个(gè)位數值 |
| | 輸出(chū)總(zǒng)費用(yòng)的(de)十(shí)位數值 |
| | 輸出(chū)總(zǒng)費用(yòng)的(de)百(bǎi)位數值 |
1.4.2 設計(jì)思(sī)路(lù)
從speed模块(kuài)中(zhōng)得到(dào)乘客乘坐總(zǒng)路(lù)程distance和(hé)按时(shí)計(jì)費使能(néng)信(xìn)号(hào)en_0,然後(hòu)以(yǐ)5元(yuán)起步價,超过(guò)3KM以(yǐ)每滿1公里(lǐ)2元(yuán)的(de)計(jì)費方(fāng)式計(jì)算出(chū)按路(lù)程計(jì)費的(de)總(zǒng)費用(yòng),再通(tòng)过(guò)en_0按20分(fēn)鐘(zhōng)1元(yuán)的(de)計(jì)費方(fāng)式計(jì)算出(chū)按时(shí)間(jiān)計(jì)費的(de)總(zǒng)費用(yòng),再求和(hé)獲得總(zǒng)費用(yòng),最(zuì)後(hòu)得到(dào)總(zǒng)費用(yòng)得个(gè)位、十(shí)位、百(bǎi)位,分(fēn)别是(shì)x_g、x_s、x_b。
1.4.3 參考代(dài)碼
module fare( clk , rst_n , distance, en_0 , key_flag,
x_g , x_s , x_b );
//參數定(dìng)義 parameter DATA_W = 4;
//輸入(rù)信(xìn)号(hào)定(dìng)義 input clk ; input rst_n ;
input en_0 ; //按时(shí)計(jì)費 input [19:0] distance; //路(lù)程 input key_flag; //有(yǒu)无乘客
//輸出(chū)信(xìn)号(hào)定(dìng)義 output[DATA_W-1:0] x_g ; //數碼管(guǎn)顯示个(gè)位 output[DATA_W-1:0] x_s ; //數碼管(guǎn)顯示十(shí)位 output[DATA_W-1:0] x_b ; //數碼管(guǎn)顯示百(bǎi)位
//輸出(chū)信(xìn)号(hào)reg定(dìng)義 reg [DATA_W-1:0] x_g ; reg [DATA_W-1:0] x_s ; reg [DATA_W-1:0] x_b ;
//中(zhōng)間(jiān)信(xìn)号(hào)定(dìng)義 reg [9:0] taxi_fare ; //總(zǒng)車費 reg [9:0] taxi_fare_1; //按路(lù)程車費 reg [9:0] taxi_fare_2; //按时(shí)間(jiān)車費 reg [35:0] cnt ; //計(jì)數20分(fēn)鐘(zhōng) reg key_flag1 ; //寄存器 reg key_flag2 ; //寄存器 reg key_flag_low ; //乘客下(xià)車信(xìn)号(hào) reg key_flag_low1 ; //乘客下(xià)車後(hòu)隔一(yī)个(gè)时(shí)鐘(zhōng)周期(qī)信(xìn)号(hào) reg [2:0] state ;
wire add_taxi_fare_1; wire add_taxi_fare_2; wire add_cnt ; wire end_cnt ;
//獲取(qǔ)key_flag下(xià)降沿,表(biǎo)示乘客下(xià)車 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin key_flag1 <= 0; end else begin key_flag1 <= key_flag; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin key_flag2 <= 0; end else begin key_flag2 <= key_flag1; end end always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin key_flag_low <= 0; end else if(key_flag2==1&&key_flag1==0)begin key_flag_low <= 1; end else begin key_flag_low <= 0; end end
always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin key_flag_low1 <= 0; end else key_flag_low1 <= key_flag_low; end
//按路(lù)程計(jì)費 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin taxi_fare_1 <= 0; end else if(add_taxi_fare_1)begin if(distance<=3000)begin taxi_fare_1 <= 5; end else if(distance>3000)begin taxi_fare_1 <= 3'd5+ (distance-3000) / 500;//* 0.002; end end end assign add_taxi_fare_1 = key_flag_low && en_0 == 0 ;
//按时(shí)間(jiān)計(jì)費 always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin taxi_fare_2 <= 0; end else if(add_taxi_fare_2)begin taxi_fare_2 <= taxi_fare_2 + 1; end end assign add_taxi_fare_2 = end_cnt == 1;
//計(jì)數20分(fēn)鐘(zhōng) always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 0; end else if(add_cnt)begin if(end_cnt) cnt <= 0; else cnt <= cnt + 1; end end assign add_cnt = en_0 == 1 && key_flag == 1; assign end_cnt = add_cnt && cnt== /*仿真(zhēn)时(shí)使用(yòng)以(yǐ)节(jié)省(shěng)仿真(zhēn)时(shí)間(jiān)500*1200-1;*/ 50000000*1200-1;
//獲得總(zǒng)車費 always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin taxi_fare <= 0; end else if(key_flag_low1==1)begin taxi_fare <= taxi_fare_1+ taxi_fare_2; end end
//輸出(chū) always @(*)begin if(rst_n == 1'b0)begin x_g <= 0; x_s <= 0; x_b <= 0; state <= 1; end else if(taxi_fare != 0)begin case(state) 1: begin x_g <= taxi_fare%10;taxi_fare <= taxi_fare/10;state <= 2;end 2: begin x_s <= taxi_fare%10;taxi_fare <= taxi_fare/10;state <= 3;end 3: begin x_b <= taxi_fare%10;taxi_fare <= taxi_fare/10;state <= 1;end endcase end end
endmodule |
1.5 show模块(kuài)設計(jì)
1.5.1 接口(kǒu)信(xìn)号(hào)
| | |
| | |
| | |
| | 打(dǎ)開(kāi)數碼管(guǎn)顯示的(de)使能(néng)信(xìn)号(hào)。1表(biǎo)示打(dǎ)開(kāi)顯示,0表(biǎo)示不(bù)顯示。 |
| | 輸入(rù)總(zǒng)費用(yòng){x_b,x_s,x_g} |
| | 數碼管(guǎn)顯示數據(jù)刷新使能(néng)信(xìn)号(hào)。當其值为(wèi)1有(yǒu)效时(shí),刷新要(yào)顯示的(de)數據(jù)值。 |
| | 3个(gè)數碼管(guǎn)的(de)位選信(xìn)号(hào),在(zài)低電(diàn)平是(shì)該位置數碼管(guǎn)亮(liàng)。 |
| | 段(duàn)選信(xìn)号(hào),共(gòng)8位。由(yóu)低到(dào)高(gāo),分(fēn)别表(biǎo)示數碼管(guǎn)的(de)a,b,c,d,e,f,g,點(diǎn)。當該比特(tè)为(wèi)0时(shí),表(biǎo)示點(diǎn)亮(liàng)相應(yìng)位置;为(wèi)1时(shí)熄滅。 |
1.5.2 設計(jì)思(sī)路(lù)
由(yóu)于(yú)在(zài)fare模块(kuài)中(zhōng)已經(jīng)獲得總(zǒng)費用(yòng)的(de)个(gè)位、十(shí)位和(hé)百(bǎi)位的(de)值,所(suǒ)以(yǐ)在(zài)本(běn)模块(kuài)只(zhī)需要(yào)控制3个(gè)數碼管(guǎn)对(duì)其數值進(jìn)行顯示即可(kě)。
本(běn)模块(kuài)在(zài)設計(jì)过(guò)程中(zhōng)采用(yòng)動(dòng)态掃描3个(gè)數碼管(guǎn)的(de)方(fāng)式進(jìn)行顯示,并且直(zhí)接使用(yòng)明(míng)德楊提(tí)供的(de)數碼管(guǎn)顯示規範代(dài)碼。動(dòng)态掃描方(fāng)式相比于(yú)使用(yòng)3个(gè)独立的(de)數碼管(guǎn)顯示会(huì)节(jié)約資源,硬(yìng)件(jiàn)電(diàn)路(lù)更(gèng)簡單,且數碼管(guǎn)越多(duō)优勢越明(míng)顯。
1.5.3 參考代(dài)碼
接口(kǒu)定(dìng)義: clk : 时(shí)鐘(zhōng)信(xìn)号(hào),頻率是(shì)50MHz rst_n : 複位信(xìn)号(hào),在(zài)低電(diàn)平时(shí)有(yǒu)效 seg_sel : 位選信(xìn)号(hào),在(zài)低電(diàn)平是(shì)該位置數碼管(guǎn)亮(liàng)。 segment : 段(duàn)選信(xìn)号(hào),共(gòng)8位。由(yóu)低到(dào)高(gāo),分(fēn)别表(biǎo)示數碼管(guǎn)的(de)a,b,c,d,e,f,g,點(diǎn)。當該比特(tè)为(wèi)0时(shí),表(biǎo)示點(diǎn)亮(liàng)相應(yìng)位置;为(wèi)1时(shí)熄滅。 **********old.mdy-edu.com 明(míng)德揚科教注釋結束(shù)****************/
module show( rst_n , clk , disp_en , din , din_vld ,
seg_sel , segment );
/*********old.mdy-edu.com 明(míng)德揚科教注釋開(kāi)始**************** 參數定(dìng)義,明(míng)德揚規範要(yào)求,verilog內(nèi)的(de)用(yòng)到(dào)的(de)數字(zì),都使用(yòng)參數表(biǎo)示。 參數信(xìn)号(hào)全(quán)部(bù)大写 **********old.mdy-edu.com 明(míng)德揚科教注釋結束(shù)****************/
parameter SEG_WID = 8; parameter SEG_NUM = 3; parameter COUNT_WID = 26; parameter TIME_20US = 20'd1000;
parameter NUM_0 = 8'b1100_0000; parameter NUM_1 = 8'b1111_1001; parameter NUM_2 = 8'b1010_0100; parameter NUM_3 = 8'b1011_0000; parameter NUM_4 = 8'b1001_1001; parameter NUM_5 = 8'b1001_0010; parameter NUM_6 = 8'b1000_0010; parameter NUM_7 = 8'b1111_1000; parameter NUM_8 = 8'b1000_0000; parameter NUM_9 = 8'b1001_0000; parameter NUM_F = 8'b1011_1111; parameter NUM_ERR = 8'b1000_0110;
input clk ; input rst_n ; input disp_en ; input [SEG_NUM*4-1:0] din ; input [SEG_NUM-1:0] din_vld ; output [SEG_NUM-1:0] seg_sel ; output [SEG_WID-1:0] segment ;
reg [SEG_NUM-1:0] seg_sel ; reg [SEG_WID-1:0] segment ; reg [COUNT_WID-1:0] cnt0 ; wire add_cnt0 ; wire end_cnt0 ; reg [SEG_NUM-1:0] cnt1 ; wire add_cnt1 ; wire end_cnt1 ; reg [4*SEG_NUM-1:0] din_ff0 ; reg [ 4-1:0] seg_tmp ; wire flag_20us ; integer ii ;
always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt0 <= 0; end else if(add_cnt0)begin if(end_cnt0) cnt0 <= 0; else cnt0 <= cnt0 + 1; end end
assign add_cnt0 = 1; assign end_cnt0 = add_cnt0 && cnt0==TIME_20US-1 ;
always @(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt1 <= 0; end else if(add_cnt1)begin if(end_cnt1) cnt1 <= 0; else cnt1 <= cnt1 + 1; end end
assign add_cnt1 = end_cnt0; assign end_cnt1 = add_cnt1 && cnt1==SEG_NUM-1 ;
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin seg_sel <= {SEG_NUM{1'b1}}; end else if(disp_en) seg_sel <= ~(1'b1 << cnt1); else seg_sel <= {SEG_NUM{1'b1}}; end
always @(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin din_ff0 <= 0; end else begin for(ii=0;ii<SEG_NUM;ii=ii+1)begin if(din_vld[ii]==1'b1)begin din_ff0[(ii+1)*4-1 -:4] <= din[(ii+1)*4-1 -:4]; end else begin din_ff0[(ii+1)*4-1 -:4] <= din_ff0[(ii+1)*4-1 -:4]; end end end end
always @(*)begin seg_tmp = din_ff0[(cnt1+1)*4-1 -:4]; end
always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin segment<=NUM_0; end else if(seg_tmp==0)begin segment<=NUM_0; end else if(seg_tmp==1)begin segment<=NUM_1; end else if(seg_tmp==2)begin segment<=NUM_2; end else if(seg_tmp==3)begin segment<=NUM_3; end else if(seg_tmp==4)begin segment<=NUM_4; end else if(seg_tmp==5)begin segment<=NUM_5; end else if(seg_tmp==6)begin segment<=NUM_6; end else if(seg_tmp==7)begin segment<=NUM_7; end else if(seg_tmp==8)begin segment<=NUM_8; end else if(seg_tmp==9)begin segment<=NUM_9; end else if(seg_tmp==4'hf)begin segment<=NUM_F; end else begin segment<=NUM_ERR; end end
endmodule |
1.6 效果(guǒ)和(hé)總(zǒng)結
由(yóu)于(yú)本(běn)系(xì)統涉及(jí)1秒(miǎo)、20分(fēn)鐘(zhōng)等时(shí)間(jiān)节(jié)點(diǎn),时(shí)間(jiān)很长,所(suǒ)以(yǐ)在(zài)仿真(zhēn)时(shí)有(yǒu)一(yī)定(dìng)的(de)困難,为(wèi)此(cǐ)我(wǒ)将系(xì)統中(zhōng)的(de)时(shí)間(jiān)节(jié)點(diǎn)全(quán)部(bù)乘上(shàng)10^(-5),讓所(suǒ)有(yǒu)狀态提(tí)前(qián)到(dào)达(dá),方(fāng)便我(wǒ)们(men)仿真(zhēn)验(yàn)證。
由(yóu)于(yú)乘上(shàng)了(le)10^(-5),所(suǒ)以(yǐ)原消抖10ms在(zài)仿真(zhēn)中(zhōng)为(wèi)100ns;
系(xì)統中(zhōng)原1s取(qǔ)樣(yàng)轉(zhuǎn)速rev在(zài)仿真(zhēn)中(zhōng)为(wèi)10us;
原按时(shí)計(jì)費20分(fēn)鐘(zhōng)/元(yuán)在(zài)仿真(zhēn)中(zhōng)为(wèi)12ms/元(yuán);
在(zài)测試文(wén)件(jiàn)中(zhōng)轉(zhuǎn)速rev>=3r/s的(de)时(shí)間(jiān)是(shì)50000000ns;
總(zǒng)路(lù)程distance=15/3*50000000/10000=25km;
由(yóu)于(yú)在(zài)测試文(wén)件(jiàn)中(zhōng)按鍵消抖有(yǒu)一(yī)段(duàn)时(shí)間(jiān)且这(zhè)一(yī)段(duàn)时(shí)間(jiān)在(zài)rev>=3r/s的(de)时(shí)間(jiān)內(nèi),所(suǒ)以(yǐ)系(xì)統实際对(duì)速度(dù)采樣(yàng)的(de)次(cì)數会(huì)少(shǎo)一(yī)次(cì),所(suǒ)以(yǐ)最(zuì)終(zhōng)的(de)總(zǒng)路(lù)程会(huì)少(shǎo)5m;
所(suǒ)以(yǐ),按路(lù)程計(jì)費的(de)總(zǒng)費用(yòng)taxi_fare_1=5+(25 - 3)*2 – 0.005*2=48.99(元(yuán));
去(qù)除小數部(bù)分(fēn)taxi_fare_1=48(元(yuán));
在(zài)测試文(wén)件(jiàn)中(zhōng)轉(zhuǎn)速rev<3r/s的(de)时(shí)間(jiān)是(shì)24000000ns;
按时(shí)間(jiān)計(jì)費的(de)總(zǒng)費用(yòng)taxi_fare_2=24000000/12000000=2(元(yuán));
所(suǒ)以(yǐ)總(zǒng)車費taxi_fare_1=taxi_fare_1+taxi_fare_2=50(元(yuán));
`define clk_period 20 module taxi_fare_tb(
);
reg clk ; reg rst_n ; reg d_w ; reg [15:0] rev ; reg key_in ;
wire [3-1:0] seg_sel ; wire [8-1:0] segment ;
taxi_fare taxi_fare_0( .clk (clk) , .rst_n (rst_n) , .d_w (d_w) , .rev (rev) , .key_in (key_in) ,
.seg_sel (seg_sel) , .segment (segment) );
initial clk = 1; always#(`clk_period/2) clk = ~clk;
initial begin rst_n = 0; #100; rst_n = 1; end
initial begin d_w = 0; #10000; d_w = 1; #200000000; d_w = 0; end
initial begin rev = 0; #10000; rev = 15; #50000000; rev = 1; #24000000; rev = 0; end
initial begin key_in = 1; #1000; key_in = 0; #10; key_in = 1; #10; key_in = 0; #10; key_in = 1; #10; key_in = 0; #9000; key_in = 1; #10; key_in = 0; #10; key_in = 1; #74000000; key_in = 0; #9000; key_in = 1; end
endmodule |
由(yóu)仿真(zhēn)結果(guǒ)可(kě)以(yǐ)看(kàn)到(dào)seg_sel=110第(dì)1位數碼管(guǎn)顯示时(shí)segment=11000000、seg_sel=101第(dì)2位數碼管(guǎn)顯示时(shí)segment=10010010、seg_sel=011第(dì)3位數碼管(guǎn)顯示时(shí)segment=11000000,在(zài)數碼管(guǎn)上(shàng)分(fēn)别对(duì)應(yìng)數值为(wèi)0、5、0,表(biǎo)示为(wèi)50元(yuán)。
仿真(zhēn)結果(guǒ)和(hé)理論結構都是(shì)50元(yuán),符合我(wǒ)们(men)的(de)預期(qī),验(yàn)證成(chéng)功。
在(zài)这(zhè)个(gè)設計(jì)中(zhōng),使用(yòng)明(míng)德楊的(de)至(zhì)簡設計(jì)法,讓我(wǒ)的(de)思(sī)路(lù)非(fēi)常清(qīng)晰,邏輯非(fēi)常嚴谨,虽然沒(méi)有(yǒu)做到(dào)一(yī)遍(biàn)成(chéng)功,但在(zài)調試过(guò)程中(zhōng)我(wǒ)都比較快(kuài)速的(de)找(zhǎo)到(dào)問(wèn)題(tí),并快(kuài)速解(jiě)決。对(duì)于(yú)学習FPGA的(de)同(tóng)学,我(wǒ)非(fēi)常推薦使用(yòng)明(míng)德楊至(zhì)簡設計(jì)法和(hé)明(míng)德楊模块(kuài)進(jìn)行学習和(hé)設計(jì)。
感(gǎn)興趣的(de)朋友也(yě)可(kě)以(yǐ)訪問(wèn)明(míng)德揚論壇(http://www.fpgabbs.cn/)進(jìn)行FPGA相關(guān)工程設計(jì)学習,也(yě)欢迎大家(jiā)在(zài)評論與(yǔ)我(wǒ)们(men)進(jìn)行讨論!
温(wēn)馨提(tí)示:明(míng)德揚2023推出(chū)了(le)全(quán)新課程——邏輯設計(jì)基本(běn)功修煉課,降低学習FPGA門(mén)檻的(de)同(tóng)时(shí),增加了(le)学習的(de)趣味性(xìng),并組織了(le)考試赢積分(fēn)活動(dòng)
http://www.minyingyiyuan.com/ffkc/415.html
(點(diǎn)擊→了(le)解(jiě)課程詳情(qíng)☝)感(gǎn)興趣請聯系(xì)易老(lǎo)师(shī):13112063618(微信(xìn)同(tóng)步)
本(běn)文(wén)TAG: