verilog語言RS232串列埠傳送模組設計——採集ps2鍵盤資料在串列埠除錯工具顯示
阿新 • • 發佈:2019-01-08
頂層模組程式碼:module ps2_driever( clk,rst_n,ps2k_clk,ps2k_data,sm_bit,sm_seg,ps2_state,ps2_byte); input clk; //50M時鐘訊號 input rst_n; //復位訊號 input ps2k_clk; //PS2介面時鐘訊號 input ps2k_data; //PS2介面資料訊號 //wire [7:0] ps2_byte; // 1byte鍵值,只做簡單的按鍵掃描 output ps2_state; //鍵盤當前狀態,ps2_state=1表示有鍵被按下 output reg [1:0] sm_bit='b01; output reg [7:0]sm_seg; output [7:0]ps2_byte; //------------------------------------------ reg ps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2; //ps2k_clk狀態暫存器 //wire pos_ps2k_clk; // ps2k_clk上升沿標誌位 wire neg_ps2k_clk; // ps2k_clk下降沿標誌位 //裝置傳送向主機的資料在下降沿有效,首先檢測PS2k_clk的下降沿 //利用上面邏輯賦值語句可以提取得下降沿,neg_ps2k_clk為高電平時表示資料可以被採集 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin ps2k_clk_r0 <= 1'b0; ps2k_clk_r1 <= 1'b0; ps2k_clk_r2 <= 1'b0; end else begin //鎖存狀態,進行濾波 ps2k_clk_r0 <= ps2k_clk; ps2k_clk_r1 <= ps2k_clk_r0; ps2k_clk_r2 <= ps2k_clk_r1; end end assign neg_ps2k_clk = ~ps2k_clk_r1 & ps2k_clk_r2; //下降沿 //-----------------資料採集------------------------- /* 幀結構:裝置發往主機資料幀為11位元,(主機發送資料包為12bit) 1bit start bit ,This is always 0, 8bit data bits, 1 parity bit,(odd parity)校驗位,奇校驗, data bits 為偶數個1時該位為1, data bits 為奇數個1時該位為0. 1bit stop bit ,this is always 1. num 範圍為 'h00,'h0A; */ reg[7:0] ps2_byte_r; //PC接收來自PS2的一個位元組資料儲存器 reg[7:0] temp_data; //當前接收資料暫存器 reg[3:0] num; //計數暫存器 always @ (posedge clk or negedge rst_n) begin if(!rst_n) begin num <= 4'd0; temp_data <= 8'd0; end else if(neg_ps2k_clk) begin //檢測到ps2k_clk的下降沿 case (num) /* 幀結構中資料位為一個位元組,且低位在前,高位在後, 這裡要定義一個buf,size is one Byte. */ 4'd0: num <= num+1'b1; 4'd1: begin num <= num+1'b1; temp_data[0] <= ps2k_data; //bit0 end 4'd2: begin num <= num+1'b1; temp_data[1] <= ps2k_data; //bit1 end 4'd3: begin num <= num+1'b1; temp_data[2] <= ps2k_data; //bit2 end 4'd4: begin num <= num+1'b1; temp_data[3] <= ps2k_data; //bit3 end 4'd5: begin num <= num+1'b1; temp_data[4] <= ps2k_data; //bit4 end 4'd6: begin num <= num+1'b1; temp_data[5] <= ps2k_data; //bit5 end 4'd7: begin num <= num+1'b1; temp_data[6] <= ps2k_data; //bit6 end 4'd8: begin num <= num+1'b1; temp_data[7] <= ps2k_data; //bit7 end 4'd9: begin num <= num+1'b1; //奇偶校驗位,不做處理 end 4'd10: begin num <= 4'd0; // num清零 end default: ; endcase end end reg key_f0; //鬆鍵標誌位,置1表示接收到資料8'hf0,再接收到下一個資料後清零 reg ps2_state_r; //鍵盤當前狀態,ps2_state_r=1表示有鍵被按下 //+++++++++++++++資料處理開始++++++++++++++++============= always @ (posedge clk or negedge rst_n) begin //接收資料的相應處理,這裡只對1byte的鍵值進行處理 if(!rst_n) begin key_f0 <= 1'b0; ps2_state_r <= 1'b0; end else if(num==4'd10) ///一幀資料是否採集完。 begin //剛傳送完一個位元組資料 if(temp_data == 8'hf0) key_f0 <= 1'b1;//判斷該接收資料是否為斷碼 else begin //========================理解困難================================== if(!key_f0) begin //說明有鍵按下 ps2_state_r <= 1'b1; ps2_byte_r <= temp_data; //鎖存當前鍵值 end else begin ps2_state_r <= 1'b0; key_f0 <= 1'b0; end //===================================================== end end end /*+++++++++++++等效寫法+++++++++++++++++++++++++++++ reg key_released;//收到碼段後是否鬆開 reg [7:0] ps2_byte; always @(posedge clk or negedge rst) begin if(!rst) key_released<='b0; else if(cnt=='h0A)//一幀資料是否採集完。 begin if(ps2_byte_buf==8'hF0)//資料為段碼f0 key_released<='b1;//鬆開標誌位置位 else key_released<='b0; end end always @ (posedge clk or negedge rst) begin if(!rst) key_pressed<= 0; else if (cnt == 4'hA) // 採集完一個位元組? begin if (!key_released) // 有鍵按過? begin ps2_byte<= ps2_byte_buf; // 鎖存當前鍵值 key_pressed <= 'b1; // 按下標誌置一 end else key_pressed <= 'b0; // 按下標誌清零 end end */ reg[7:0] ps2_asci; //接收資料的相應ASCII碼 always @ (ps2_byte_r) begin case (ps2_byte_r) //鍵值轉換為ASCII碼,這裡做的比較簡單,只處理字母 8'h15: ps2_asci <= 8'h51; //Q 8'h1d: ps2_asci <= 8'h57; //W 8'h24: ps2_asci <= 8'h45; //E 8'h2d: ps2_asci <= 8'h52; //R 8'h2c: ps2_asci <= 8'h54; //T 8'h35: ps2_asci <= 8'h59; //Y 8'h3c: ps2_asci <= 8'h55; //U 8'h43: ps2_asci <= 8'h49; //I 8'h44: ps2_asci <= 8'h4f; //O 8'h4d: ps2_asci <= 8'h50; //P 8'h1c: ps2_asci <= 8'h41; //A 8'h1b: ps2_asci <= 8'h53; //S 8'h23: ps2_asci <= 8'h44; //D 8'h2b: ps2_asci <= 8'h46; //F 8'h34: ps2_asci <= 8'h47; //G 8'h33: ps2_asci <= 8'h48; //H 8'h3b: ps2_asci <= 8'h4a; //J 8'h42: ps2_asci <= 8'h4b; //K 8'h4b: ps2_asci <= 8'h4c; //L 8'h1a: ps2_asci <= 8'h5a; //Z 8'h22: ps2_asci <= 8'h58; //X 8'h21: ps2_asci <= 8'h43; //C 8'h2a: ps2_asci <= 8'h56; //V 8'h32: ps2_asci <= 8'h42; //B 8'h31: ps2_asci <= 8'h4e; //N 8'h3a: ps2_asci <= 8'h4d; //M default: ; endcase end assign ps2_byte = ps2_asci; assign ps2_state = ps2_state_r; //==================keyboard driver part over====================== //=======================1KHz div====display part start=================== parameter N2=50000; reg clk3=1'b0; reg [16:0]count3=17'd0; //assign clk_out=clk3; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin count3<=17'd0; clk3<=1'b0; end else if(count3<N2-1) begin count3<=count3+1'b1; if(count3<(N2/2-1)) clk3<=1'b0; else clk3<=1'b1; end else begin count3<=17'd0; clk3<=1'b0; end end //==================state select================ reg[3:0] Num; always @(posedge clk3) begin case (sm_bit) 'b01: begin Num<=ps2_byte[7:4]; sm_bit<='b10; end 'b10: begin Num<=ps2_byte[3:0]; sm_bit<='b01; end default: Num<='b0; endcase /*if(sm_bit=='b01) begin Num<=ps2_byte[3:0]; sm_bit<='b10; end else if(sm_bit=='b10) begin Num<=ps2_byte[7:4]; sm_bit<='b01; end */ end //========================================================= always @ (Num)// begin case (Num) 4'h0 : sm_seg = 8'h3f; // "0" 4'h1 : sm_seg = 8'h06; // "1" 4'h2 : sm_seg = 8'h5b; // "2" 4'h3 : sm_seg = 8'h4f; // "3" 4'h4 : sm_seg = 8'h66; // "4" 4'h5 : sm_seg = 8'h6d; // "5"//共陰極數碼管表 4'h6 : sm_seg = 8'h7d; // "6" 4'h7 : sm_seg = 8'h07; // "7" 4'h8 : sm_seg = 8'h7f; // "8" 4'h9 : sm_seg = 8'h6f; // "9" 4'ha : sm_seg = 8'h77; // "a" 4'hb : sm_seg = 8'h7c; // "b" 4'hc : sm_seg = 8'h39; // "c" 4'hd : sm_seg = 8'h5e; // "d" 4'he : sm_seg = 8'h79; // "e" 4'hf : sm_seg = 8'h71; // "f" endcase end //============================================== endmodule