<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統 > 設計應用 > 矩陣鍵盤鍵入系統設計

          矩陣鍵盤鍵入系統設計

          作者:時間:2023-12-06來源:電子森林收藏

          實驗任務

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

          實驗目的


          在基礎數字電路實驗部分我們已經掌握了驅動獨立顯示數碼管的原理及方法,掌握了有限狀態機的設計實現思想,本實驗主要學習矩陣鍵盤的原理及驅動設計。

          本文引用地址:http://www.ex-cimer.com/article/202312/453589.htm
          • 熟悉獨立顯示數碼管驅動模塊的應用
          • 熟悉狀態機FSM的編程方法
          • 掌握矩陣鍵盤的工作原理
          • 完成驅動矩陣鍵盤的設計實現

          設計框圖


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

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

          頂層模塊Type_system通過實例化三個子模塊并將對應的信號連接,最終實現矩陣鍵盤鍵入系統的總體設計。

          top-down層次設計

          模塊結構設計


          實驗原理


          鍵盤類型

          嵌入式設計中常見的鍵盤有兩種類型,獨立鍵盤與矩陣鍵盤,

          獨立鍵盤

           

          矩陣鍵盤

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

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

          4x4矩陣鍵盤電路

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

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

          當某時刻,FPGA控制4根行線分別為ROW1=0、ROW2=1、ROW3=1、ROW4=1時,

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

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

          矩陣鍵盤驅動設計

          通過上節的描述,大家對于矩陣鍵盤工作的原理應該都沒有問題了,那么我們怎么編程實現矩陣鍵盤驅動設計呢?我們將矩陣鍵盤的掃描周期分為4個時刻,對應4個狀態,使得狀態機在4個狀態上循環跳轉,最終通過掃描的方式獲取矩陣鍵盤的操作狀態。

          狀態機各狀態邏輯

          狀態機程序實現如下:

          reg		[1:0]		c_state;
          //狀態機根據clk_200hz信號在4個狀態間循環,每個狀態對矩陣按鍵的行接口單行有效
          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)
          			//狀態c_state跳轉及對應狀態下矩陣按鍵的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

          至于狀態機循環的周期,根據我們基礎教程里可知,按鍵抖動的不穩定時間在10ms以內,所以對同一個按鍵采樣的周期大于10ms,這里同樣取20ms時間。20ms時間對應4個狀態,每5分鐘進行一次狀態轉換。所以我們在狀態機之前先增加分頻模塊,得到200Hz的分頻時鐘,然后狀態機按照200Hz分頻時鐘的節拍做狀態跳轉和鍵盤采樣。

          狀態轉移圖

          狀態機程序實現如下:

          parameter			CNT_200HZ = 60000;//計數器計數分頻實現5ms周期信號
          clk_200hzreg		[15:0]		cnt;
          reg					clk_200hz;
          always@(posedge clk or negedge rst_n) begin  //復位時計數器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

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

          鍵盤采樣功能程序實現如下:

          //因為每個狀態中單行有效,通過對列接口的電平狀態采樣得到對應4個按鍵的狀態,依次循環
          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;		//采集當前狀態的列數據賦值給對應的寄存器位
          			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

          結束了嗎? 沒有,還差一點,繼續往下看

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

          按鍵抖動示意

          上圖是市面上常見按鍵抖動的模型,有三個參數,按下抖動10ms以內,松開抖動10ms以內,按鍵周期數百ms;前面說過鍵盤的采樣周期為20ms,可以得到以下結論:

          • 按鍵周期內至少有4個FPGA采樣點同時落在按鍵穩定區域內
          • 按鍵周期內不會有相鄰FPGA采樣點同時落在按鍵抖動區域內
          • 如果FPGA連續兩次采樣到低電平即可判定按鍵按下,否則判定為按鍵松開

          鍵盤采樣判定功能程序實現如下:

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

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

          下降沿檢測程序實現如下:

          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);   //通過前后兩個時刻的值判斷

          經過上面程序的處理,我們就得到了16位脈沖信號,平時為低電平,當按鍵被按下時刻keypulse產生一個高脈沖,脈沖的寬度為模塊系統時鐘clkin的一個周期。

          狀態機狀態轉移圖

          系統總體實現

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

          鍵值顯示轉碼程序實現

          //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;   //無按鍵按下時保持
          		endcase
          	end
          	end

          綜合后的設計框圖如下:

          rtl設計框圖

          實驗步驟

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

          實驗現象

          按動矩陣鍵盤上的按鍵,核心板獨立顯示數碼管會更新顯示對應鍵值。例如上電默認顯示00,按動K8按鍵,數碼管顯示08,再按動K16按鍵,數碼管顯示16。



          評論


          相關推薦

          技術專區

          關閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();