該可編程器件實(shí)驗(yàn)板是以 Altera 公司的 MAX II 系列可編程器件
EPM1270T144C5 為核心芯片,是一款具有多種外部接口和顯示器件的通用數(shù)字電路實(shí)驗(yàn)平臺。選用1kHz。
一、 設(shè)計(jì)課題的任務(wù)要求
1、 智能藥盒有三個(gè)藥格,分別對應(yīng)老年人每天早中晚的三次服藥,每個(gè)藥格有對應(yīng)的提醒燈。按下BTN0 鍵進(jìn)入開機(jī)初始狀態(tài),三個(gè)藥格的提醒燈在 8×8 點(diǎn)陣中顯示紅、綠、黃圖案。
2、 三個(gè)藥格可通過 BTN7 鍵切換設(shè)定服藥時(shí)間,切換到哪個(gè)藥格,相應(yīng)藥格的提醒圖案以 2Hz 的頻率進(jìn)行閃爍顯示。服藥時(shí)間的設(shè)定采用 BTN6 和 BTN5 鍵,BTN6 每按 1 下,時(shí)間加 1 秒,BTN5 每按 1 下,時(shí)間減 1 秒,每個(gè)藥格可設(shè)定一個(gè)時(shí)間,設(shè)定時(shí)間范圍在 0~59 秒之間,在設(shè)定過程中采用數(shù)碼管 DISP1 和 DISP0 顯示所設(shè)定的服藥時(shí)間。
3、 服藥時(shí)間設(shè)定結(jié)束后,按下智能藥盒工作鍵 BTN2 后,藥格提醒圖案停止閃爍,藥 盒開始工作,并從 0 開始進(jìn)行 60 秒計(jì)時(shí),數(shù)碼管 DISP1 和 DISP0 顯示計(jì)時(shí)時(shí)間。當(dāng)計(jì)時(shí)計(jì)到各個(gè)藥格所設(shè)定的服藥時(shí)間時(shí),點(diǎn)陣上相應(yīng)藥格的提醒圖案以 4Hz 的頻率進(jìn)行閃爍提醒,同時(shí)蜂鳴器報(bào)警,按 BTN1 鍵后報(bào)警和閃爍停止。
4、 智能藥盒計(jì)到 60 秒后重復(fù)開始服藥計(jì)時(shí)和提醒,直到按下 BTN0 鍵后智能藥盒關(guān)閉,點(diǎn)陣全滅,計(jì)時(shí)停止。
提高要求:
1、 用 4*4 小鍵盤設(shè)定服藥時(shí)間;
2、 采用液晶 LCD1602 顯示設(shè)定的服藥時(shí)間;
3、 增加高級模式,每個(gè)藥格可設(shè)定 1~2個(gè)服藥時(shí)間進(jìn)行提醒; 4、 自擬其他功能。
二、 系統(tǒng)設(shè)計(jì)
設(shè)計(jì)思路
該智能藥盒類似于一個(gè)鬧鐘,也就是計(jì)時(shí)器。核心內(nèi)容就是設(shè)定幾個(gè)時(shí)間,然后計(jì)時(shí)到所設(shè)定的時(shí)間時(shí)報(bào)警。8×8 點(diǎn)陣用于顯示藥格,數(shù)碼管顯示時(shí)間,蜂鳴器報(bào)警。
總體框圖
分塊設(shè)計(jì)
1). 計(jì)時(shí)與計(jì)數(shù):這是實(shí)驗(yàn)的核心內(nèi)容。由于計(jì)時(shí)和計(jì)數(shù)都涉及到對時(shí)間的操作,因此這兩個(gè)功能必須集合到同一個(gè)模塊并且是同一個(gè)always塊里。剛開機(jī)后,藥盒應(yīng)處于計(jì)數(shù)狀態(tài),用來設(shè)定時(shí)間;按下BTN2后進(jìn)入計(jì)時(shí)狀態(tài),開始60秒循環(huán)計(jì)時(shí)。所以使用一個(gè)work信號來控制計(jì)時(shí)與計(jì)數(shù)的切換。work初始為0,對應(yīng)計(jì)數(shù)狀態(tài),按BTN2使work翻轉(zhuǎn),狀態(tài)切換。計(jì)數(shù)時(shí)按BTN4獲取當(dāng)前時(shí)間值并輸出,在這個(gè)模塊的外部會有其他模塊負(fù)責(zé)將這個(gè)獲取的時(shí)間存起來。這里需要注意獲取時(shí)間和存儲時(shí)間的先后問題,否則會存入無效時(shí)間。因此,選擇在時(shí)鐘上升沿獲取時(shí)間,然后在按鍵信號下降沿存儲,二者相差一個(gè)時(shí)鐘周期。
2). 8*8點(diǎn)陣顯示:點(diǎn)陣用紅、綠、黃分別表示3個(gè)藥格。在設(shè)定時(shí)間以及報(bào)警時(shí)都要求對應(yīng)的點(diǎn)陣要閃爍,因此,它可以分為4種狀態(tài):都不閃,紅色閃,綠色閃,黃色閃。這樣我們就可以用一個(gè)2位的二進(jìn)制數(shù)來表示它們:00,01,10,11.同時(shí)選用BTN7驅(qū)動(dòng)模4計(jì)數(shù)器,按一下,二進(jìn)制數(shù)加一,狀態(tài)切換,這樣就實(shí)現(xiàn)了藥格切換。藥格的顯示是采用行掃描的形式,由于只掃描2行,所以將行掃描信號和時(shí)鐘信號綁定,當(dāng)時(shí)鐘為高電平時(shí),掃第3行,時(shí)鐘為低電平時(shí)掃第4行,這樣之后就不用重復(fù)對行信號進(jìn)行處理了。
3). 數(shù)碼管顯示:由于只用兩個(gè)數(shù)碼管,所以將數(shù)碼管的陰極信號與時(shí)鐘綁定,當(dāng)時(shí)鐘為高電平時(shí),亮十位的數(shù)碼管,同時(shí)陽極信號賦值為時(shí)間的十位,時(shí)鐘為低電平時(shí)亮個(gè)位的數(shù)碼管,同時(shí)陽極信號賦值為時(shí)間的個(gè)位,這樣就完成了數(shù)碼管的顯示。
三、 功能說明及資源利用情況
1.功能說明
該藥盒實(shí)現(xiàn)了課題要求的基本功能,包括按BTN0開機(jī)關(guān)機(jī),按BTN7切換設(shè)定服藥時(shí)間,切換時(shí),對應(yīng)的藥格會以2Hz閃爍。按BTN6和BTN5可分別實(shí)現(xiàn)加計(jì)數(shù)和減計(jì)數(shù),按下BTN4即可保存時(shí)間。之后,按下BTN2便可進(jìn)入計(jì)時(shí)工作狀態(tài)。藥盒能夠循環(huán)進(jìn)行60秒計(jì)時(shí),當(dāng)?shù)竭_(dá)設(shè)定的時(shí)間后,對應(yīng)藥格4Hz閃爍,同時(shí)蜂鳴器報(bào)警。報(bào)警和閃爍可按下BTN1手動(dòng)關(guān)閉,或者計(jì)時(shí)到60秒后自動(dòng)關(guān)閉。按下BTN2又可切換到設(shè)定時(shí)間狀態(tài),設(shè)定新的時(shí)間。再按下BTN0后,藥盒關(guān)機(jī),數(shù)據(jù)清空。此外,還實(shí)現(xiàn)了提高功能之一,即每個(gè)藥盒可以設(shè)定一到兩個(gè)時(shí)間。
2.資源利用情況
總共使用了200個(gè)邏輯門和50個(gè)管腳。
四、 故障及問題分析
1.在代碼編寫過程中,運(yùn)行代碼調(diào)試時(shí),經(jīng)常報(bào)錯(cuò)說重復(fù)賦值。比如計(jì)數(shù)與計(jì)時(shí)重復(fù)對時(shí)間負(fù)值;關(guān)機(jī)將數(shù)據(jù)清零時(shí),又對這些數(shù)據(jù)重復(fù)進(jìn)行了賦值。所以,需要將這些對變量的賦值都綜合到對應(yīng)的同一個(gè)模塊里,以此避免沖突。
2.在測試功能的時(shí)候,發(fā)現(xiàn)保存的時(shí)間總是會出現(xiàn)錯(cuò)位。分析發(fā)現(xiàn)是獲取時(shí)間與存儲時(shí)間同時(shí)進(jìn)行導(dǎo)致的。在獲取時(shí)間的同時(shí)存時(shí)間,存儲的并不是獲取的時(shí)間,而是初始化的0時(shí)間,然后在下一次存時(shí)間時(shí),才會存儲這次獲取的時(shí)間,也就是發(fā)生了錯(cuò)位。因此,選擇在時(shí)鐘上升沿獲取時(shí)間,然后在按鍵信號下降沿存儲,二者相差一個(gè)時(shí)鐘周期。這樣錯(cuò)開后,功能正常實(shí)現(xiàn)。
3.在測試功能時(shí),發(fā)現(xiàn)在剛開始計(jì)時(shí)時(shí)就報(bào)警。分析發(fā)現(xiàn),原本能設(shè)置兩個(gè)時(shí)間的藥格,如果只設(shè)置一個(gè)時(shí)間,剩下的那個(gè)時(shí)間就會保持初始化的0時(shí)間,這樣剛開始計(jì)時(shí)就會報(bào)警。因此,增加一個(gè)判斷條件,來取消對初始0時(shí)間的報(bào)警。
module imbox( //上層模塊 input clk, //時(shí)鐘信號,需選用1kHz input btn0, //開機(jī)關(guān)機(jī)鍵 input btn1, //關(guān)閉報(bào)警鍵 input btn2, //開始或停止計(jì)時(shí) input btn4, //保存時(shí)間 input btn5, //減計(jì)數(shù)鍵 input btn6, //加計(jì)數(shù)鍵 input btn7, //切換藥格鍵 output [7:0]col_r, //8*8點(diǎn)陣的列信號,紅色 output [7:0]col_g, //8*8點(diǎn)陣的列信號,綠色 output beep, //蜂鳴器 output [7:0] seg, //數(shù)碼管陽極信號 output reg [7:0] row, //8*8點(diǎn)陣的行信號,用于進(jìn)行行掃描 output reg [7:0] cat, //數(shù)碼管陰極信號 output led //led燈,在BTN4按下時(shí)響應(yīng) );wire [1:0] change; //藥格切換信號 reg [1:0] remind; //報(bào)警狀態(tài)下的藥格信號 wire clk_2, clk_4,clk_500; //不同頻率的時(shí)鐘 wire key0, key1, key2, key4, key5, key6, key7; //消抖后的按鍵信號 reg clk_2_r,clk_500_r, work,start,rmd; //生成時(shí)鐘的中間量;工作、開始、提醒信號 wire [5:0] total; //計(jì)數(shù)與計(jì)時(shí) wire [5:0] time_e; //獲取設(shè)定時(shí)間 reg [11:0] timee [2:0]; //存儲設(shè)定時(shí)間 reg [3:0] data; //數(shù)碼管顯示的數(shù)據(jù) wire [3:0] data1, data2; //時(shí)間的十位和個(gè)位 always@(posedge key0) //開機(jī)于關(guān)機(jī) begin start<=~start; end divide d0(clk,clk_4); //時(shí)鐘分頻 always@(posedge clk_4) clk_2_r<=~clk_2_r; assign clk_2=clk_2_r; always@(posedge clk) clk_500_r<=~clk_500_r; assign clk_500=clk_500_r; always@(clk) if(~start) //關(guān)機(jī)狀態(tài) begin row<=8'b11111111; cat<=8'b11111111; end else if(clk) //將row,cat,data與時(shí)鐘綁定,隨時(shí)鐘變化而自動(dòng)掃描 begin row<=8'b11101111; cat<=8'b11111101; data<=data1; end else begin row<=8'b11110111; cat<=8'b11111110; data<=data2; end always@(negedge clk) if(~start) work<=0; else if(key2) //非工作工作(計(jì)數(shù)與計(jì)時(shí)切換) work<=~work; else work<=work; always@(negedge key4 or posedge key0) if(key0) begin timee[0][11:0]<=0; timee[1][11:0]<=0; timee[2][11:0]<=0; end else if(change>0) timee[change-1][11:0]<={timee[change-1][5:0],time_e}; //移位寄存設(shè)定的時(shí)間 //按鍵消抖 debounce d1(clk,{btn0,btn1,btn2,btn4,btn5,btn6,btn7},{key0,key1,key2,key4,key5,key6,key7});//切換藥格 counter4 c1(start,key7,change); //8*8點(diǎn)陣顯示 show s0(col_r,col_g,clk,clk_500,((work&rmd)?clk_4:clk_2),((work&rmd)?remind:change));//計(jì)數(shù)與計(jì)時(shí) timer t0(start,work,clk,key6,key5,key4,key2,led,total,time_e); //計(jì)算十位和個(gè)位 div_rill d2(total,data1,data2); //數(shù)碼管顯示 segment s1(clk,data,seg); //控制報(bào)警 always@(posedge clk ) if(key1|key0|(~start)|(~work)) rmd<=0; else case(total) timee[0][11:6]:begin remind<=2'b01;rmd<=timee[0][11:6];end// timee[0][5:0] :begin remind<=2'b01;rmd<=1;end timee[1][11:6]:begin remind<=2'b10;rmd<=timee[1][11:6];end// timee[1][5:0] :begin remind<=2'b10;rmd<=1;end timee[2][11:6]:begin remind<=2'b11;rmd<=timee[2][11:6];end// timee[2][5:0] :begin remind<=2'b11;rmd<=1;end default:begin remind<=remind;rmd<=rmd;end endcase assign beep=rmd&clk; //蜂鳴器報(bào)警 endmodule //計(jì)數(shù)與計(jì)時(shí) module timer ( input start, //開始信號(開機(jī)或關(guān)機(jī)) input work, //工作信號(計(jì)數(shù)或計(jì)時(shí)) input clk1, //時(shí)鐘 input key6, //加計(jì)數(shù) input key5, //減計(jì)數(shù) input key4, //保存時(shí)間 input key2, //切換計(jì)數(shù)與計(jì)時(shí) output reg led, //用于響應(yīng)key4 output reg [5:0]total, //時(shí)間 output reg [5:0]time_e //獲取設(shè)定的時(shí)間用以保存 ); reg [9:0] cnt; always @(posedge clk1) if((~start)|key2) total<=6'b000000; else if(~work) begin if (key6&(total<59)) total <= total+1'b1; //計(jì)數(shù) else if (key5&(total>0)) total <= total-1'b1; else if(key4&(total>0)) begin time_e<=total; //獲取設(shè)定的時(shí)間用以保存 led<=key4; end else begin total <= total; led<=0; end end else if (cnt==999) begin cnt<=0; if(total==60) total<=1'b0; else total<=total+1'b1; //計(jì)時(shí) end else cnt<=cnt+1; endmodule //數(shù)碼管顯示 module segment( input clk, //時(shí)鐘 input [3:0]data, //數(shù)碼管陽極 output reg [7:0]seg //數(shù)碼管 ); always @(clk) case (data) //將陽極的數(shù)據(jù)譯碼顯示為數(shù)字 4'b0000: begin seg<=8'h3f;end 4'b0001: begin seg<=8'h06;end 4'b0010: begin seg<=8'h5b;end 4'b0011: begin seg<=8'h4f;end 4'b0100: begin seg<=8'h66;end 4'b0101: begin seg<=8'h6d;end 4'b0110: begin seg<=8'h7d;end 4'b0111: begin seg<=8'h07;end 4'b1000: begin seg<=8'h7f;end 4'b1001: begin seg<=8'h6f;end endcase endmodule //除法和取余(二進(jìn)制轉(zhuǎn)十進(jìn)制) module div_rill ( input [5:0] a, //需要處理的二進(jìn)制數(shù) output reg [3:0] yshang, //十位(除以十后的商) output reg [3:0] yyushu //個(gè)位(除以十后的余數(shù)) ); reg[5:0] tempa; reg[8:0] temp_a; integer i; always @(a ) tempa <= a; always @(tempa) begin temp_a = {3'b000,tempa}; for(i = 0;i < 3;i = i + 1) begin temp_a = {temp_a[7:0],1'b0}; if(temp_a[8:3] >= 4'b1010) temp_a = temp_a - 7'b1010000 + 1'b1; else temp_a = temp_a; end yshang <= {1'b0,temp_a[2:0]}; yyushu <= temp_a[6:3]; end endmodule //8*8點(diǎn)陣顯示 module show( output reg[7:0]col_r, //8*8點(diǎn)陣的列信號,紅色 output reg[7:0]col_g, //8*8點(diǎn)陣的列信號,綠色 input clk, //1kHz時(shí)鐘 input clk500, //500Hz,讓橙色和綠色交替,從而調(diào)出黃色 input clkout, //閃爍時(shí)鐘,調(diào)用時(shí)的參數(shù)可在2Hz和4Hz間切換 input [1:0]cnt //藥格信號,切換藥格 ); always @ (clk) if(clkout) case (clk500) 0: begin col_r<=8'b00000011;col_g<=8'b11011000; end //綠|綠|紅 1: begin col_r<=8'b11000011;col_g<=8'b11011000; end //橙|綠|紅(上面的綠色與下面的橙色疊加出黃色) endcase else case(cnt) 2'b00:begin case (clk500) //初始狀態(tài) 0: begin col_r<=8'b00000011;col_g<=8'b11011000; end 1: begin col_r<=8'b11000011;col_g<=8'b11011000; end endcase end 2'b01:begin case (clk500) //紅燈閃爍 0: begin col_r<=8'b00000000;col_g<=8'b11011000; end 1: begin col_r<=8'b11000000;col_g<=8'b11011000; end endcase end 2'b10:begin case (clk500) //綠燈閃爍 0: begin col_r<=8'b00000011;col_g<=8'b11000000; end 1: begin col_r<=8'b11000011;col_g<=8'b11000000; end endcase end 2'b11:begin case (clk500) //黃燈閃爍 0: begin col_r<=8'b00000011;col_g<=8'b00011000; end 1: begin col_r<=8'b00000011;col_g<=8'b00011000; end endcase end endcase endmodule //模4計(jì)數(shù)(分別對應(yīng)3個(gè)藥格和初始狀態(tài),用來控制切換藥格) module counter4 ( input start, //開機(jī)信號 input btn, //按鍵計(jì)數(shù) output reg [1:0]count //模4計(jì)數(shù) ) ; always @ (posedge btn or negedge start) if(~start) count<=2'b00; else if(count==2'b11) count<=2'b00; else count<=count+1'b1; endmodule //時(shí)鐘分頻 module divide (clk,clkout); input clk; //輸入時(shí)鐘 output clkout; //輸出時(shí)鐘 reg [6:0] cnt_p; //cnt_p為上升沿觸發(fā)的計(jì)數(shù)器 reg clk_p; //clk_p為上升沿觸發(fā)的分頻時(shí)鐘 always @ (posedge clk ) begin if (cnt_p==124) //250分頻,1kHz轉(zhuǎn)4Hz begin cnt_p<=0; clk_p<=~clk_p; end else cnt_p<=cnt_p+1; end assign clkout = clk_p; endmodule //按鍵消抖 module debounce ( input clk, //時(shí)鐘 input [6:0] key, //需要消抖的按鍵 output [6:0] key_pulse //消抖后的按鍵信號 ); reg [6:0] key_rst_pre; //按鍵前一狀態(tài) reg [6:0] key_rst; //按鍵當(dāng)前狀態(tài) wire [6:0] key_edge; //按鍵上升沿檢測 reg [6:0] key_sec_pre; //按鍵前一電平狀態(tài) reg [6:0] key_sec; //按鍵后一電平狀態(tài) reg [3:0] cnt; //計(jì)數(shù) always @(posedge clk ) begin key_rst <= key; key_rst_pre <= key_rst; end assign key_edge = (~key_rst_pre) & key_rst; //檢測上升沿 always @(posedge clk ) begin if(key_edge) cnt <= 4'b0000; else cnt <= cnt + 1'b1; end always @(posedge clk) if (cnt==4'b1010) //延時(shí)10ms后檢測電平 key_sec <= key; else key_sec<=key_sec; always @(posedge clk) key_sec_pre <= key_sec; assign key_pulse = (~key_sec_pre) & key_sec; endmodule
總結(jié)
以上是生活随笔為你收集整理的【Verilog智能药盒的设计与实现】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。