<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 矩陣鍵盤(pán)鍵入系統設計

矩陣鍵盤(pán)鍵入系統設計

作者: 時(shí)間:2023-12-06 來(lái)源:電子森林 收藏

實(shí)驗任務(wù)

  • 任務(wù):基于核心板 和 底板 設計鍵入系統并觀(guān)察調試結果
  • 要求:按動(dòng)按鍵,通過(guò)核心板上的數碼管顯示按鍵的鍵值。
  • 解析:通過(guò)編程驅動(dòng)電路,獲取矩陣鍵盤(pán)鍵入的信息,然后通過(guò)編碼將鍵盤(pán)輸出的信息譯碼成對應的鍵值信息,最后通過(guò)驅動(dòng)核心板獨立數碼管,將鍵盤(pán)按鍵的鍵值顯示在數碼管上。

實(shí)驗目的


在基礎數字電路實(shí)驗部分我們已經(jīng)掌握了驅動(dòng)獨立顯示數碼管的原理及方法,掌握了有限狀態(tài)機的設計實(shí)現思想,本實(shí)驗主要學(xué)習矩陣鍵盤(pán)的原理及驅動(dòng)設計。

本文引用地址:http://dyxdggzs.com/article/202312/453589.htm
  • 熟悉獨立顯示數碼管驅動(dòng)模塊的應用
  • 熟悉狀態(tài)機FSM的編程方法
  • 掌握矩陣鍵盤(pán)的工作原理
  • 完成驅動(dòng)矩陣鍵盤(pán)的設計實(shí)現

設計框圖


根據前面的實(shí)驗解析我們可以得知,該設計可以拆分成三個(gè)功能模塊實(shí)現,

  • ArrayKeyBoard:通過(guò)驅動(dòng)矩陣鍵盤(pán)工作獲取鍵盤(pán)的操作信息數據。 * Decoder:通過(guò)編碼方式將鍵盤(pán)的操作信息譯碼成對應的鍵值信息。 * Segmentled:通過(guò)驅動(dòng)核心板獨立數碼管將鍵盤(pán)按鍵的鍵值顯示在數碼管上。

頂層模塊Type_system通過(guò)實(shí)例化三個(gè)子模塊并將對應的信號連接,最終實(shí)現矩陣鍵盤(pán)鍵入系統的總體設計。

top-down層次設計

模塊結構設計


實(shí)驗原理


鍵盤(pán)類(lèi)型

嵌入式設計中常見(jiàn)的鍵盤(pán)有兩種類(lèi)型,獨立鍵盤(pán)與矩陣鍵盤(pán),

獨立鍵盤(pán)

 

矩陣鍵盤(pán)

  • 獨立式按鍵:每個(gè)按鍵單獨連接到一個(gè)I/O口上,通過(guò)判斷按鍵端口的電位識別按鍵的操作,編程簡(jiǎn)單,需要更多I/O資源
  • 矩陣式按鍵:通過(guò)行列交叉編碼連接,通過(guò)分時(shí)掃描的方法識別按鍵的操作,節約I/O資源,編程相對復雜 關(guān)于獨立鍵盤(pán)的驅動(dòng)設計,我們在基礎數字電路實(shí)驗部分已經(jīng)系統學(xué)習過(guò),這里主要介紹一下矩陣鍵盤(pán)的原理及驅動(dòng)方法。 在鍵盤(pán)中按鍵數量較多時(shí),為了減少I(mǎi)/O口的占用,通常將按鍵排列成矩陣形式,使用行線(xiàn)和列線(xiàn)分別連接到按鍵開(kāi)關(guān)的兩端,這樣我們就可以通過(guò)4根行線(xiàn)和4根列線(xiàn)(共8個(gè)I/O口)連接16個(gè)按鍵,而且按鍵數量越多優(yōu)勢越明顯,比如再多加一條線(xiàn)就可以構成20鍵的鍵盤(pán),而直接用端口線(xiàn)則只能多出一鍵(9鍵)。由此可見(jiàn),在需要的鍵數比較多時(shí),采用矩陣法來(lái)做鍵盤(pán)是更加合適的。
矩陣鍵盤(pán)連接

這里我們以底板上的4×4矩陣鍵盤(pán)為例,其電路圖如下: 

4x4矩陣鍵盤(pán)電路

上圖為4×4矩陣按鍵的硬件電路圖,可以看到4根行線(xiàn)(ROW1、ROW2、ROW3、ROW4)和4根列線(xiàn)(COL1、COL2、COL3、COL4),同時(shí)列線(xiàn)通過(guò)上拉電阻連接到VCC電壓(3.3V),對于矩陣按鍵來(lái)講:

  • 4根行線(xiàn)是輸入的,是由FPGA控制拉高或拉低,
  • 4根列線(xiàn)數輸出的,是由4根行線(xiàn)的輸入及按鍵的狀態(tài)決定,輸出給FPGA

當某時(shí)刻,FPGA控制4根行線(xiàn)分別為ROW1=0、ROW2=1、ROW3=1、ROW4=1時(shí),

  • 對于K1、K2、K3、K4按鍵:按下時(shí)對應4根列線(xiàn)輸出COL1=0、COL2=0、COL3=0、COL4=0,不按時(shí)對應4根列線(xiàn)輸出COL1=1、COL2=1、COL3=1、COL4=1,
  • 對于K5~~~K16之間的按鍵:無(wú)論按下與否,對應4根列線(xiàn)輸出COL1=1、COL2=1、COL3=1、COL4=1,

通過(guò)上面的描述:在這一時(shí)刻只有K1、K2、K3、K4按鍵被按下,才會(huì )導致4根列線(xiàn)輸出COL1=0、COL2=0、COL3=0、COL4=0,否則COL1=1、COL2=1、COL3=1、COL4=1,反之當FPGA檢測到列線(xiàn)(COL1、COL2、COL3、COL4)中有低電平信號時(shí),對應的K1、K2、K3、K4按鍵應該是被按下了。 按照掃描的方式,一共分為4個(gè)時(shí)刻,分別對應4根行線(xiàn)中的一根拉低,4個(gè)時(shí)刻依次循環(huán),這樣就完成了矩陣按鍵的全部掃描檢測,我們在程序中以這4個(gè)時(shí)刻對應狀態(tài)機的4個(gè)狀態(tài)。

矩陣鍵盤(pán)驅動(dòng)設計

通過(guò)上節的描述,大家對于矩陣鍵盤(pán)工作的原理應該都沒(méi)有問(wèn)題了,那么我們怎么編程實(shí)現矩陣鍵盤(pán)驅動(dòng)設計呢?我們將矩陣鍵盤(pán)的掃描周期分為4個(gè)時(shí)刻,對應4個(gè)狀態(tài),使得狀態(tài)機在4個(gè)狀態(tài)上循環(huán)跳轉,最終通過(guò)掃描的方式獲取矩陣鍵盤(pán)的操作狀態(tài)。

狀態(tài)機各狀態(tài)邏輯

狀態(tài)機程序實(shí)現如下:

reg		[1:0]		c_state;
//狀態(tài)機根據clk_200hz信號在4個(gè)狀態(tài)間循環(huán),每個(gè)狀態(tài)對矩陣按鍵的行接口單行有效
always@(posedge clk_200hz or negedge rst_n) begin
	if(!rst_n) begin
		c_state <= STATE0;
		row <= 4'b1110;
	end else begin
		case(c_state)
			//狀態(tài)c_state跳轉及對應狀態(tài)下矩陣按鍵的row輸出
			STATE0: begin c_state <= STATE1; row <= 4'b1101; end
			STATE1: begin c_state <= STATE2; row <= 4'b1011; end
			STATE2: begin c_state <= STATE3; row <= 4'b0111; end
			STATE3: begin c_state <= STATE0; row <= 4'b1110; end
			default:begin c_state <= STATE0; row <= 4'b1110; end
		endcase
	endend

至于狀態(tài)機循環(huán)的周期,根據我們基礎教程里可知,按鍵抖動(dòng)的不穩定時(shí)間在10ms以?xún)?,所以對同一個(gè)按鍵采樣的周期大于10ms,這里同樣取20ms時(shí)間。20ms時(shí)間對應4個(gè)狀態(tài),每5分鐘進(jìn)行一次狀態(tài)轉換。所以我們在狀態(tài)機之前先增加分頻模塊,得到200Hz的分頻時(shí)鐘,然后狀態(tài)機按照200Hz分頻時(shí)鐘的節拍做狀態(tài)跳轉和鍵盤(pán)采樣。

狀態(tài)轉移圖

狀態(tài)機程序實(shí)現如下:

parameter			CNT_200HZ = 60000;//計數器計數分頻實(shí)現5ms周期信號
clk_200hzreg		[15:0]		cnt;
reg					clk_200hz;
always@(posedge clk or negedge rst_n) begin  //復位時(shí)計數器cnt清零,clk_200hz信號起始電平為低電平
	if(!rst_n) begin
		cnt <= 16'd0;
		clk_200hz <= 1'b0;
	end else begin
		if(cnt >= ((CNT_200HZ>>1) - 1)) begin  //數字邏輯中右移1位相當于除2
			cnt <= 16'd0;
			clk_200hz <= ~clk_200hz;  //clk_200hz信號取反
		end else begin
			cnt <= cnt + 1'b1;
			clk_200hz <= clk_200hz;
		end
	endend

通過(guò)以上的程序我們實(shí)現了狀態(tài)機的4個(gè)狀態(tài)循環(huán)跳轉,每個(gè)狀態(tài)都有對應的邏輯輸出,接下來(lái)我們需要將矩陣鍵盤(pán)的輸出采集回來(lái),并以此判斷鍵盤(pán)的操作狀態(tài)。采樣也是需要按照狀態(tài)的,4個(gè)狀態(tài)的采樣數據合并后得到一個(gè)16位數,代表16個(gè)按鍵的操作狀態(tài),是不是非常簡(jiǎn)單呢?比如下面的程序,是不是就搞定了?

鍵盤(pán)采樣功能程序實(shí)現如下:

//因為每個(gè)狀態(tài)中單行有效,通過(guò)對列接口的電平狀態(tài)采樣得到對應4個(gè)按鍵的狀態(tài),依次循環(huán)
always@(negedge clk_200hz or negedge rst_n_in) begin
	if(!rst_n_in) begin
		key_out <= 16'hffff;
	end else begin
		case(c_state)
			STATE0:key_out[3:0] <= col;		//采集當前狀態(tài)的列數據賦值給對應的寄存器位
			STATE1:key_out[7:4] <= col;
			STATE2:key_out[11:8] <= col;
			STATE3:key_out[15:12] <= col;
			default:key_out <= 16'hffff;
		endcase
	endend

結束了嗎? 沒(méi)有,還差一點(diǎn),繼續往下看

對于大多數需要循環(huán)掃描的硬件來(lái)說(shuō),程序寫(xiě)到這里應該就完成了,但是大家想想我們之前基礎數字電路實(shí)驗關(guān)于按鍵消抖部分的內容,因為我們是在對按鍵采樣,按鍵是會(huì )抖動(dòng)的,所以我們還要想辦法對采集回來(lái)的數據做一些判定,怎么判定呢? 這就得回到矩陣鍵盤(pán)工作原理上來(lái)了。

按鍵抖動(dòng)示意

上圖是市面上常見(jiàn)按鍵抖動(dòng)的模型,有三個(gè)參數,按下抖動(dòng)10ms以?xún)?,松開(kāi)抖動(dòng)10ms以?xún)?,按鍵周期數百ms;前面說(shuō)過(guò)鍵盤(pán)的采樣周期為20ms,可以得到以下結論:

  • 按鍵周期內至少有4個(gè)FPGA采樣點(diǎn)同時(shí)落在按鍵穩定區域內
  • 按鍵周期內不會(huì )有相鄰FPGA采樣點(diǎn)同時(shí)落在按鍵抖動(dòng)區域內
  • 如果FPGA連續兩次采樣到低電平即可判定按鍵按下,否則判定為按鍵松開(kāi)

鍵盤(pán)采樣判定功能程序實(shí)現如下:

STATE0: begin 
		key[3:0] <= col;    //矩陣鍵盤(pán)采樣
		key_r[3:0] <= key[3:0];    //鍵盤(pán)數據鎖存
		key_out[3:0] <= key_r[3:0]|key[3:0];   //連續兩次采樣判定
	end

將此程序實(shí)現方法更新到上一部分程序中,最后keyout就是采樣消抖后的直接輸出。當按鍵被按下時(shí)keyout對應位輸出低電平,松開(kāi)按鍵時(shí)keyout對應位恢復高電平輸出。 由以上程序我們完成了矩陣鍵盤(pán)的驅動(dòng),但是keyout這種類(lèi)型的輸出有時(shí)在后級時(shí)序電路設計中不好直接使用,例如對于當前矩陣鍵盤(pán)鍵入系統設計來(lái)講,我們需要按鍵按動(dòng)一次(與按下保持的時(shí)間長(cháng)短無(wú)關(guān))就輸入對應的鍵值,按鍵松開(kāi)后鍵值也不能消失,我們就需要一個(gè)寄存器變量來(lái)儲存按過(guò)的按鍵鍵值,考慮到可能存在多個(gè)按鍵在極短時(shí)間內被先后按下,這樣一來(lái)我們最好將按鍵按動(dòng)這種長(cháng)時(shí)間事件轉化成一個(gè)瞬間的脈沖,方法就是對key_out信號中的每一位進(jìn)行下降沿(或上升沿)檢測,方法如下:

下降沿檢測程序實(shí)現如下:

reg		[15:0]		key_out_r;//Register low_sw_r, lock low_sw to next clk
always @ ( posedge clk  or  negedge rst_n )
	if (!rst_n) key_out_r <= 16'hffff;
	else  key_out_r <= key_out;   //將前一刻的值延遲鎖存 
	//wire	[15:0]		 key_pulse;
	//Detect the negedge of low_sw, generate pulse
	assign key_pulse= key_out_r & ( ~key_out);   //通過(guò)前后兩個(gè)時(shí)刻的值判斷

經(jīng)過(guò)上面程序的處理,我們就得到了16位脈沖信號,平時(shí)為低電平,當按鍵被按下時(shí)刻keypulse產(chǎn)生一個(gè)高脈沖,脈沖的寬度為模塊系統時(shí)鐘clkin的一個(gè)周期。

狀態(tài)機狀態(tài)轉移圖

系統總體實(shí)現

在基礎數字電路實(shí)驗部分我們已經(jīng)掌握了FPGA驅動(dòng)獨立顯示數碼管的原理及方法, 模塊通過(guò)一個(gè)4位的輸入傳遞要顯示的數值,通過(guò)9位的輸出控制數碼管顯示該數值,這里我們不再重復。 矩陣鍵盤(pán)驅動(dòng)模塊輸出的是脈沖信號,后面數碼管驅動(dòng)模塊輸入的是用4位位寬表示的數據,所以中兩個(gè)實(shí)例之間就需要一個(gè)編碼的功能塊,主要功能是根據矩陣鍵盤(pán)的脈沖輸出(keypulse)判定鍵盤(pán)的操作,通過(guò)編碼對應提供按鍵的鍵值數據(segdata),最后通過(guò)連線(xiàn)將鍵值數據連接到數碼管模塊的輸入端口。

鍵值顯示轉碼程序實(shí)現

//key_pulse transfer to seg_data
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		seg_data <= 8'h00;
	end else begin
		case(key_pulse)  //key_pulse脈寬等于clk_in的周期
			16'h0001: seg_data <= 8'h01;  //編碼
			16'h0002: seg_data <= 8'h02;
			16'h0004: seg_data <= 8'h03;
			16'h0008: seg_data <= 8'h04;
			16'h0010: seg_data <= 8'h05;
			16'h0020: seg_data <= 8'h06;
			16'h0040: seg_data <= 8'h07;
			16'h0080: seg_data <= 8'h08;
			16'h0100: seg_data <= 8'h09;
			16'h0200: seg_data <= 8'h10;
			16'h0400: seg_data <= 8'h11;
			16'h0800: seg_data <= 8'h12;
			16'h1000: seg_data <= 8'h13;
			16'h2000: seg_data <= 8'h14;
			16'h4000: seg_data <= 8'h15;
			16'h8000: seg_data <= 8'h16;
			default:  seg_data <= seg_data;   //無(wú)按鍵按下時(shí)保持
		endcase
	end
	end

綜合后的設計框圖如下:

rtl設計框圖

實(shí)驗步驟

  1. 雙擊打開(kāi)Quartus Prime工具軟件;
  2. 新建工程:File → New Project Wizard(工程命名,工程目錄選擇,設備型號選擇,EDA工具選擇);
  3. 新建文件:File → New → Verilog HDL File,鍵入設計代碼并保存;
  4. 設計綜合:雙擊Tasks窗口頁(yè)面下的Analysis & Synthesis對代碼進(jìn)行綜合;
  5. 管腳約束:Assignments → Assignment Editor,根據項目需求分配管腳;
  6. 設計編譯:雙擊Tasks窗口頁(yè)面下的Compile Design對設計進(jìn)行整體編譯并生成配置文件;
  7. 程序燒錄:點(diǎn)擊Tools → Programmer打開(kāi)配置工具,Program進(jìn)行下載;
  8. 觀(guān)察設計運行結果。

實(shí)驗現象

按動(dòng)矩陣鍵盤(pán)上的按鍵,核心板獨立顯示數碼管會(huì )更新顯示對應鍵值。例如上電默認顯示00,按動(dòng)K8按鍵,數碼管顯示08,再按動(dòng)K16按鍵,數碼管顯示16。



評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>