2012年11月21日 星期三

LAB08 移動蛇電路顯示電路

LAB08 移動蛇電路7-seg LED顯示電路 適用於DE2-70

結果影片 http://youtu.be/VjA-otc9ViE

使用FSM有限狀態機方式設計 

x g f e d c b a
0 HEX0 1 1 1 1 1 1 1 1 255
HEX1 1 1 1 1 1 1 1 1 255
HEX2 1 1 1 1 1 1 1 1 255
HEX3 1 1 1 1 1 1 1 0 254
HEX4 1 1 1 1 1 1 1 0 254
HEX5 1 1 1 1 1 1 1 0 254
  x g f e d c b a
1 HEX0 1 1 1 1 1 1 1 1 255
HEX1 1 1 1 1 1 1 1 1 255
HEX2 1 1 0 1 1 1 1 1 223
HEX3 1 1 1 1 1 1 1 0 254
HEX4 1 1 1 1 1 1 1 0 254
HEX5 1 1 1 1 1 1 1 1 255
x g f e d c b a
2 HEX0 1 1 1 1 1 1 1 1 255
HEX1 1 1 1 1 1 1 1 1 255
HEX2 1 1 0 0 1 1 1 1 207
HEX3 1 1 1 1 1 1 1 0 254
HEX4 1 1 1 1 1 1 1 1 255
HEX5 1 1 1 1 1 1 1 1 255




module _7_seg(SW, LEDG , CLOCK_27 ,KEY 
             ,HEX0 ,HEX1 ,HEX2,HEX3,
             ,HEX4 ,HEX5 ,HEX6,HEX7
              );

input  [17:0] SW; // toggle switches
input  [7:0] KEY;     // Push bottom
input  CLOCK_27; //Clock 27MHz , 50Mhz

output [7:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3,HEX4,HEX5,HEX6,HEX7; //7-segment display
    

// output [4:0] Cs; // 5位元輸出

wire   Clr;
assign Clr=KEY[0];
assign HEX6=8'hff; //OFF HEX6 , HEX7
assign HEX7=8'hff;
reg [6:0] HEX0,HEX1,HEX2,HEX3,HEX4,HEX5;


reg    Clk,Clk_en; // 宣告為暫存器資料
reg    [24:0] Cnt; // 宣告為暫存器資料
reg    [4:0] Cs, Ns; // 宣告為暫存器資料

parameter [4:0] // 宣告狀態參數, 二進制編碼
S0=5'b00000,  S1=5'b00001,  S2=5'b00010,  S3=5'b00011,
S4=5'b00100,  S5=5'b00101,  S6=5'b00110,  S7=5'b00111,
S8=5'b01000,  S9=5'b01001, S10=5'b01010, S11=5'b01011,
S12=5'b01100, S13=5'b01101, S14=5'b01110, S15=5'b01111,
S16=5'b10000, S17=5'b10001, S18=5'b10010, S19=5'b10011;


// 除頻
always@ (posedge CLOCK_27 or negedge Clr)
begin
if(!Clr)
      Cnt = 0;
    else
 Cnt = Cnt + 1;
 //Clk = Cnt[0]; // 模擬用
 Clk = Cnt[24]; // 實際電路用
end


// 取得 Clk_state, Clk_en
always@ (posedge Clk or negedge Clr)
begin
if (!Clr)
Cs = 5'b00000;
else 
Cs = Ns;
end


// 決定次一狀態 Ns 與輸出 Q, 組合邏輯電路
always@ (Cs)
case (Cs)
    S0 : begin
           Ns = S1;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hfe;
           HEX4=8'hfe;
           HEX5=8'hfe;
         end
    S1 : begin
           Ns = S2;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hdf;
           HEX3=8'hfe;
           HEX4=8'hfe;
           HEX5=8'hff;
         end
    S2 : begin
           Ns = S3;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hcf;
           HEX3=8'hfe;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S3 : begin
           Ns = S4;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hc7;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S4 : begin
           Ns = S5;
           HEX0=8'hff;
           HEX1=8'hf7;
           HEX2=8'he7;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S5 : begin
           Ns = S6;
           HEX0=8'hf7;
           HEX1=8'hf7;
           HEX2=8'hf7;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S6 : begin
           Ns = S7;
           HEX0=8'hf3;
           HEX1=8'hf7;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
         
    S7 : begin
           Ns = S8;
           HEX0=8'hf1;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S8 : begin
           Ns = S9;
           HEX0=8'hf8;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
         
    S9 : begin
           Ns = S10;
           HEX0=8'hfc;
           HEX1=8'hfe;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S10 : begin
           Ns = S11;
           HEX0=8'hfe;
           HEX1=8'hfe;
           HEX2=8'hfe;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S11 : begin
           Ns = S12;
           HEX0=8'hff;
           HEX1=8'hfe;
           HEX2=8'hfe;
           HEX3=8'hfd;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S12 : begin
           Ns = S13;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hfe;
           HEX3=8'hf9;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S13 : begin
           Ns = S14;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hf1;
           HEX4=8'hff;
           HEX5=8'hff;
         end
    S14 : begin
           Ns = S15;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hf3;
           HEX4=8'hf7;
           HEX5=8'hff;
         end     

S15 : begin
           Ns = S16;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hf7;
           HEX4=8'hf7;
           HEX5=8'hf7;
         end
    S16 : begin
           Ns = S17;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hf7;
           HEX5=8'he7;
         end
    S17 : begin
           Ns = S18;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hc7;
         end
    S18 : begin
           Ns = S19;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hff;
           HEX5=8'hce;
         end
         
     S19 : begin
           Ns = S0;
           HEX0=8'hff;
           HEX1=8'hff;
           HEX2=8'hff;
           HEX3=8'hff;
           HEX4=8'hfe;
           HEX5=8'hde;
         end     
         
    default :
            Ns=S0;
            
         
endcase

assign LEDG[4:0]=Cs; //show to LEDG


endmodule

LAB07 LCD Display FSM有限狀態機方式

LAB07 LCD Display FSM有限狀態機方式 
適用於DE2-70

S0-S7 狀態顯示於LEDG[2:0]
LEDG[7] 顯示Reset_Delay 完成
最後ADDR , 及InData 設定LCD1602 顯示的位置及字形


//*************************************

// LCM 液晶顯示模組

module LCM (CLOCK_50,KEY,LCD_DATA,LEDG,
            LCD_EN,LCD_RS,LCD_RW,LCD_ON,LCD_BLON
      );
      
input  CLOCK_50;
input  [3:0]KEY;
inout  [7:0] LCD_DATA;
output [7:0] LEDG;
output LCD_EN;
output LCD_RS;
output LCD_RW;
output LCD_ON;
output LCD_BLON;

wire [7:0]ADDR;
wire [7:0]InData; 
wire RTSN;
assign RSTN=KEY[0];
wire [7:0] LCD_DATA;
wire LCD_RS;
wire LCD_RW;
wire LCD_EN;
wire DLY_RST;

assign LCD_ON=1'b1;
assign LCD_BLON=1'b0;
assign ADDR=8'h81; //setting Address
assign InData=8'h41; //Setting Data
Reset_Delay r0(.iCLK(CLOCK_50),.iRST(RSTN),.oRESET(DLY_RST));
assign LEDG[7]=DLY_RST;
    //module LCD_1602(Clk10M,Clr,EN,RS,RW,D,Cs);
LCD_1602(
.Clk10M(CLOCK_50),
.Clr(DLY_RST),
.ADDR(ADDR),
.InData(InData),
.EN(LCD_EN),
.RS(LCD_RS),
.RW(LCD_RW),
.D(LCD_DATA),
.Cs(LEDG[2:0])
);

endmodule



//*************************************




module Reset_Delay(iCLK,iRST,oRESET);
input iCLK;
input iRST;
output reg oRESET;
reg[19:0] Cont;


always@(posedge iCLK or negedge iRST)
begin
   if (!iRST)
      Cont<=20'h0;
   else if(Cont!=20'hfffff)
begin
Cont<=Cont+1'b1;
oRESET<=1'b0;
end
else
oRESET<=1'b1;
end

endmodule

//*************************************

module LCD_1602(Clk10M,Clr,ADDR,InData,EN,RS,RW,D,Cs);

input  Clk10M,Clr; // 一位元輸入
input  [7:0] ADDR;
input  [7:0] InData;
output EN,RS,RW; // 一位元輸出 
output [7:0] D; // 八位元輸出
output [2:0] Cs; // 二位元輸出

reg    Clk,Clk_en; // 宣告為暫存器資料
reg    [7:0] D; // 宣告為暫存器資料
wire   [7:0] ADDR,InData;
reg    [23:0] Cnt; // 宣告為暫存器資料
reg    [1:0] Cn; // 宣告為暫存器資料
reg    [2:0] Cs, Ns; // 宣告為暫存器資料
parameter [2:0] // 宣告狀態參數, 二進制編碼
S0=3'b000, S1=3'b001, S2=3'b010, S3=3'b011,
S4=3'b100, S5=3'b101, S6=3'b110, S7=3'b111;

// 除頻
always@ (posedge Clk10M or negedge Clr)
begin
if(!Clr)
      Cnt = 0;
    else
 Cnt = Cnt + 1;
 //Clk = Cnt[0]; // 模擬用
 Clk = Cnt[23]; // 實際電路用
end


// 取得 Clk_state, Clk_en
always@ (posedge Clk or negedge Clr)
begin
    if (!Clr)
begin
Cn = 0;
Cs = 3'b000;
end
    else if (Cn == 2'b10)
begin 
Cn = 0; 
Cs = Ns;
end 
    else
Cn = Cn + 1;
Clk_en = Cn[0];
end

// 決定次一狀態 Ns 與輸出 Q, 組合邏輯電路
always@ (Cs)
case (Cs)
    S0 : begin
           Ns = S1;
           D = 8'b00111000; // 8'h38
         end
    S1 : begin
           Ns = S2;
           D = 8'b00111000; // 8'h38 
         end
    S2 : begin
           Ns = S3;
           D = 8'b00001110; // 8'h0E 
         end
    S3 : begin
           Ns = S4;
           D = 8'b00000110; // 8'h06 
         end
    S4 : begin
           Ns = S5;
           D = 8'b00000001; // 8'h01 
         end
    S5 : begin
           Ns = S6;
           D = ADDR;   //8'b11000100; // 8'hC4 
// DD RAM ADDRESS 8'h44                       
         end
    S6 : begin
           Ns = S7;
           D = InData; //8'b01000001;  DD RAM DATA 8'h41='A'
         end
    S7 : begin
           Ns = S7;
           D = 8'b00000000;                       
         end
endcase

assign EN = (Cs == S7)  ? 0 : Clk_en;
assign RS = (Cs == S6)  ? 1 : 0;
assign RW = 0;

endmodule

//*************************************

LAB06 LCD Display "Hello Word I like FPGA"

LAB06 LCD Display "Hello Word I like FPGA" 適用於DE2-70

源自於 http://www.haogongju.net/art/1532697


//程序實現的功能:在LCD1602液晶上顯示字符; 
module lcd_1602(CLOCK_50,KEY,LCD_DATA,LCD_EN,LCD_RS,LCD_RW,LCD_ON,LCD_BLON);

input  CLOCK_50;
input  [3:0]KEY;
output  [7:0] LCD_DATA;
output LCD_EN;
output LCD_RS;
output LCD_RW;
output LCD_ON;
output LCD_BLON;


// (sysclk, rst_n, lcd_en, lcd_rs, lcd_rw, lcd_data ); 
//input sysclk; //系統時鐘 50MHZ 
//input rst_n; //復位信號,低電平有效;  
//output lcd_en; //讀寫使能信號,高電平有效; 
//output lcd_rs; //數據命令選擇端(H/L); 
//output lcd_rw; //讀寫選擇端(H/L); 
//output[7:0] lcd_data; //8位數據口;  

wire sysclk; 
assign sysclk=CLOCK_50;
wire rst_n; 
assign rst_n=KEY[0];
assign LCD_ON=1'b1;

wire LCD_EN;
wire LCD_RW;
reg  LCD_RS; 
reg[7:0] LCD_DATA; 


parameter [127:0]row1="    hello world!"; 
//因為lcd1602每一行可顯示16個字符,一個字符占8位; 
parameter [127:0]row2="    I like FPGA!"; 
//所以每一行一共有16*8=128位;  

reg [15:0] time_cnt; 

always @(posedge sysclk or negedge rst_n) 
begin 
if(!rst_n) 
   time_cnt<=16'h0; 
else 
   time_cnt<=time_cnt+16'b1;  
end 
 
assign LCD_RW=1'b0; 
assign LCD_EN=time_cnt[15]; 
wire state_flag ; 
//狀態標誌位 ,因為FPGA的運算速度比LCD1602要快的多, 
//所以必須要等到LCD1602穩定後才往裏面寫數據; 
 
assign state_flag=(time_cnt==16'h7fff)?1'b1:1'b0 ; 
//lcd_en最小值500ns ,所以lcd_en的頻率應維持在2MHZ以內;   
parameter IDLE=8'h00; //lcd1602 initial; 
parameter INI_SET=8'h01; //顯示工作模式設置;  
parameter INI_CLR=8'h02; //清屏顯示;  
parameter CURSOR_SET1=8'h03; // 光標設置1;  
parameter CURSOR_SET2=8'h04; //光標設置2;  
 
//display line 1; 
parameter LINE1_ADDER=8'h05;  
parameter LINE1_0=8'h06;  
parameter LINE1_1=8'h07;  
parameter LINE1_2=8'h08;  
parameter LINE1_3=8'h09;  
parameter LINE1_4=8'h0A;  
parameter LINE1_5=8'h0B;  
parameter LINE1_6=8'h0C;  
parameter LINE1_7=8'h0D;  
parameter LINE1_8=8'h0E;  
parameter LINE1_9=8'h0F;  
parameter LINE1_A=8'h10;  
parameter LINE1_B=8'h11;  
parameter LINE1_C=8'h12;  
parameter LINE1_D=8'h13;  
parameter LINE1_E=8'h14;  
parameter LINE1_F=8'h15; 
 
// display line 2; 
parameter LINE2_ADDER=8'h16;  
parameter LINE2_0=8'h17;  
parameter LINE2_1=8'h18;  
parameter LINE2_2=8'h19;  
parameter LINE2_3=8'h1A;  
parameter LINE2_4=8'h1B;  
parameter LINE2_5=8'h1C;  
parameter LINE2_6=8'h1D;  
parameter LINE2_7=8'h1E;  
parameter LINE2_8=8'h1F;  
parameter LINE2_9=8'h20;  
parameter LINE2_A=8'h21;  
parameter LINE2_B=8'h22;  
parameter LINE2_C=8'h23;  
parameter LINE2_D=8'h24;  
parameter LINE2_E=8'h25;  
parameter LINE2_F=8'h26; 
 
//------------------------------------------------// 
reg[7:0] state; 
reg[7:0] next_state; 
      
always @ (posedge sysclk or negedge rst_n) 
      begin 
     if(!rst_n) 
state<=IDLE; 
          else if(state_flag) 
state<=next_state; 
 end 

always @ (*) 
begin case(state) //display line1; 
IDLE : next_state=INI_SET; 
INI_SET : next_state=INI_CLR; 
INI_CLR : next_state=CURSOR_SET1; 
CURSOR_SET1 : next_state=CURSOR_SET2; 
CURSOR_SET2 : next_state=LINE1_ADDER; 
LINE1_ADDER : next_state=LINE1_0; 
LINE1_0 : next_state=LINE1_1; 
LINE1_1 : next_state=LINE1_2; 
LINE1_2 : next_state=LINE1_3; 
LINE1_3 : next_state=LINE1_4; 
LINE1_4 : next_state=LINE1_5; 
LINE1_5 : next_state=LINE1_6; 
LINE1_6 : next_state=LINE1_7; 
LINE1_7 : next_state=LINE1_8; 
LINE1_8 : next_state=LINE1_9; 
LINE1_9 : next_state=LINE1_A; 
LINE1_A : next_state=LINE1_B; 
LINE1_B : next_state=LINE1_C; 
LINE1_C : next_state=LINE1_D; 
LINE1_D : next_state=LINE1_E; 
LINE1_E : next_state=LINE1_F; 
LINE1_F : next_state=LINE2_ADDER; 

//display line2; 
LINE2_ADDER : next_state=LINE2_0; 
                LINE2_0 : next_state=LINE2_1; 
                LINE2_1 : next_state=LINE2_2; 
                LINE2_2 : next_state=LINE2_3; 
                LINE2_3 : next_state=LINE2_4; 
   LINE2_4 : next_state=LINE2_5; 
       LINE2_5 : next_state=LINE2_6; 
LINE2_6 : next_state=LINE2_7; 
LINE2_7 : next_state=LINE2_8; 
LINE2_8 : next_state=LINE2_9; 
LINE2_9 : next_state=LINE2_A; 
LINE2_A : next_state=LINE2_B; 
LINE2_B : next_state=LINE2_C; 
LINE2_C : next_state=LINE2_D; 
LINE2_D : next_state=LINE2_E; 
LINE2_E : next_state=LINE2_F; 
LINE2_F : next_state=LINE1_ADDER; 
default : next_state=IDLE; 
endcase 
      end 

always @ (posedge sysclk or negedge rst_n) 
 begin 
if(!rst_n) 
begin 
LCD_RS <= 1'h0; 
LCD_DATA <= 8'hxx; 
end 
else if(state_flag)
begin 
case (next_state) 
IDLE: LCD_RS <= 1'h0;  
INI_SET: LCD_RS <= 1'h0;  
INI_CLR: LCD_RS <= 1'h0;  
CURSOR_SET1 : LCD_RS <= 1'h0;  
CURSOR_SET2 : LCD_RS <= 1'h0; 
// line1 
LINE1_ADDER : LCD_RS <= 1'h0;   
LINE1_0 : LCD_RS <= 1'h1;  
LINE1_1 : LCD_RS <= 1'h1;  
LINE1_2 : LCD_RS <= 1'h1;   
LINE1_3 : LCD_RS <= 1'h1;  
LINE1_4 : LCD_RS <= 1'h1;  
LINE1_5 : LCD_RS <= 1'h1;  
LINE1_6 : LCD_RS <= 1'h1;   
LINE1_7 : LCD_RS <= 1'h1;  
LINE1_8 : LCD_RS <= 1'h1;  
LINE1_9 : LCD_RS <= 1'h1;  
LINE1_A : LCD_RS <= 1'h1;   
LINE1_B : LCD_RS <= 1'h1;  
LINE1_C : LCD_RS <= 1'h1;  
LINE1_D : LCD_RS <= 1'h1;  
LINE1_E : LCD_RS <= 1'h1;   
LINE1_F : LCD_RS <= 1'h1; 

// line2  
LINE2_ADDER : LCD_RS <=1'h0;   
LINE2_0 : LCD_RS <=1'h1;  
LINE2_1 : LCD_RS <=1'h1;  
LINE2_2 : LCD_RS <=1'h1;   
LINE2_3 : LCD_RS <=1'h1;  
LINE2_4 : LCD_RS <=1'h1;  
LINE2_5 : LCD_RS <=1'h1;  
LINE2_6 : LCD_RS <=1'h1;   
LINE2_7 : LCD_RS <=1'h1;  
LINE2_8 : LCD_RS <=1'h1;  
LINE2_9 : LCD_RS <=1'h1;  
LINE2_A : LCD_RS <=1'h1;   
LINE2_B : LCD_RS <=1'h1;  
LINE2_C : LCD_RS <=1'h1;  
LINE2_D : LCD_RS <=1'h1;  
LINE2_E : LCD_RS <=1'h1;   
LINE2_F : LCD_RS <=1'h1;  
endcase 

case(next_state) 
IDLE : LCD_DATA <=8'hxx;  
INI_SET : LCD_DATA <=8'h38; 
//設置16*2顯示,5*7點陣,8位數據接口;  
INI_CLR : LCD_DATA <=8'h01; //清屏顯示;  
CURSOR_SET1 : LCD_DATA <=8'h06; 
//寫一個字符後地址指針加一;   
CURSOR_SET2 : LCD_DATA <=8'h0c; 
//設置開顯示,不顯示光標; 
//line1  
LINE1_ADDER : LCD_DATA <=8'h80; 
//LCD1602第一行 首地址;   
LINE1_0 : LCD_DATA <=row1[127:120]; 
LINE1_1 : LCD_DATA <=row1[119:112]; 
LINE1_2 : LCD_DATA <=row1[111:104]; 
LINE1_3 : LCD_DATA <=row1[103:96]; 
LINE1_4 : LCD_DATA <=row1[95:88]; 
LINE1_5 : LCD_DATA <=row1[87:80]; 
LINE1_6 : LCD_DATA <=row1[79:72]; 
LINE1_7 : LCD_DATA <=row1[71:64]; 
LINE1_8 : LCD_DATA <=row1[63:56]; 
LINE1_9 : LCD_DATA <=row1[55:48]; 
LINE1_A : LCD_DATA <=row1[47:40]; 
LINE1_B : LCD_DATA <=row1[39:32]; 
LINE1_C : LCD_DATA <=row1[31:24]; 
LINE1_D : LCD_DATA <=row1[23:16]; 
LINE1_E : LCD_DATA <=row1[15:8]; 
LINE1_F : LCD_DATA <=row1[7:0]; 

//line2 
LINE2_ADDER : LCD_DATA <=8'hC0; 
//LCD1602第二行首地址(8'h80+8'h40=8'hC0) 
LINE2_0 : LCD_DATA <=row2[127:120]; 
LINE2_1 : LCD_DATA <=row2[119:112]; 
LINE2_2 : LCD_DATA <=row2[111:104]; 
LINE2_3 : LCD_DATA <=row2[103:96]; 
LINE2_4 : LCD_DATA <=row2[95:88]; 
LINE2_5 : LCD_DATA <=row2[87:80]; 
LINE2_6 : LCD_DATA <=row2[79:72]; 
LINE2_7 : LCD_DATA <=row2[71:64]; 
LINE2_8 : LCD_DATA <=row2[63:56]; 
LINE2_9 : LCD_DATA <=row2[55:48]; 
LINE2_A : LCD_DATA <=row2[47:40]; 
LINE2_B : LCD_DATA <=row2[39:32]; 
LINE2_C : LCD_DATA <=row2[31:24]; 
LINE2_D : LCD_DATA <=row2[23:16]; 
LINE2_E : LCD_DATA <=row2[15:8]; 
LINE2_F : LCD_DATA <=row2[7:0]; 
endcase 
end 
end 

endmodule

LAB05 PS2 Keyboard & LED 7-SEGMENT DISPLAY

LAB05  PS2 Keyboard & LED 7-SEGMENT DISPLAY 
適用於DE2-70







源自於 http://www.computer-engineering.org/ps2keyboard/scancodes2.html

Keyboard Scan Codes: Set 2
*All values are in hexadecimal
101-, 102-, and 104-key keyboards:
 

KEY
MAKE
BREAK
-----
KEY
MAKE
BREAK
-----
KEY
MAKE
BREAK
A
1C
F0,1C
 
9
46
F0,46
 
[
54
FO,54
B
32
F0,32
 
`
0E
F0,0E
 
INSERT
E0,70
E0,F0,70
C
21
F0,21
 
-
4E
F0,4E
 
HOME
E0,6C
E0,F0,6C
D
23
F0,23
 
=
55
FO,55
 
PG UP
E0,7D
E0,F0,7D
E
24
F0,24
 
\
5D
F0,5D
 
DELETE
E0,71
E0,F0,71
F
2B
F0,2B
 
BKSP
66
F0,66
 
END
E0,69
E0,F0,69
G
34
F0,34
 
SPACE
29
F0,29
 
PG DN
E0,7A
E0,F0,7A
H
33
F0,33
 
TAB
0D
F0,0D
 
U ARROW
E0,75
E0,F0,75
I
43
F0,43
 
CAPS
58
F0,58
 
L ARROW
E0,6B
E0,F0,6B
J
3B
F0,3B
 
L SHFT
12
FO,12
 
D ARROW
E0,72
E0,F0,72
K
42
F0,42
 
L CTRL
14
FO,14
 
R ARROW
E0,74
E0,F0,74
L
4B
F0,4B
 
L GUI
E0,1F
E0,F0,1F
 
NUM
77
F0,77
M
3A
F0,3A
 
L ALT
11
F0,11
 
KP /
E0,4A
E0,F0,4A
N
31
F0,31
 
R SHFT
59
F0,59
 
KP *
7C
F0,7C
O
44
F0,44
 
R CTRL
E0,14
E0,F0,14
 
KP -
7B
F0,7B
P
4D
F0,4D
 
R GUI
E0,27
E0,F0,27
 
KP +
79
F0,79
Q
15
F0,15
 
R ALT
E0,11
E0,F0,11
 
KP EN
E0,5A
E0,F0,5A
R
2D
F0,2D
 
APPS
E0,2F
E0,F0,2F
 
KP .
71
F0,71
S
1B
F0,1B
 
ENTER
5A
F0,5A
 
KP 0
70
F0,70
T
2C
F0,2C
 
ESC
76
F0,76
 
KP 1
69
F0,69
U
3C
F0,3C
 
F1
05
F0,05
 
KP 2
72
F0,72
V
2A
F0,2A
 
F2
06
F0,06
 
KP 3
7A
F0,7A
W
1D
F0,1D
 
F3
04
F0,04
 
KP 4
6B
F0,6B
X
22
F0,22
 
F4
0C
F0,0C
 
KP 5
73
F0,73
Y
35
F0,35
 
F5
03
F0,03
 
KP 6
74
F0,74
Z
1A
F0,1A
 
F6
0B
F0,0B
 
KP 7
6C
F0,6C
0
45
F0,45
 
F7
83
F0,83
 
KP 8
75
F0,75
1
16
F0,16
 
F8
0A
F0,0A
 
KP 9
7D
F0,7D
2
1E
F0,1E
 
F9
01
F0,01
 
]
5B
F0,5B
3
26
F0,26
 
F10
09
F0,09
 
;
4C
F0,4C
4
25
F0,25
 
F11
78
F0,78
 
'
52
F0,52
5
2E
F0,2E
 
F12
07
F0,07
 
,
41
F0,41
6
36
F0,36
 
PRNT
SCRN
E0,12,
E0,7C 
E0,F0,
7C,E0,
F0,12 
 
.
49
F0,49
7
3D
F0,3D
 
SCROLL
7E
F0,7E
 
/
4A
F0,4A
8
3E
F0,3E
 
PAUSE
E1,14,77,
E1,F0,14,
F0,77
-NONE-

 
 
ACPI Scan Codes:

KeyMake CodeBreak Code
PowerE0, 37E0, F0, 37
SleepE0, 3FE0, F0, 3F
WakeE0, 5EE0, F0, 5E
Windows Multimedia Scan Codes:

KeyMake CodeBreak Code
Next TrackE0, 4DE0, F0, 4D 
Previous TrackE0, 15E0, F0, 15
StopE0, 3BE0, F0, 3B
Play/PauseE0, 34E0, F0, 34
MuteE0, 23E0, F0, 23
Volume UpE0, 32E0, F0, 32
Volume DownE0, 21E0, F0, 21
Media SelectE0, 50E0, F0, 50
E-MailE0, 48E0, F0, 48
CalculatorE0, 2BE0, F0, 2B
My ComputerE0, 40E0, F0, 40
WWW SearchE0, 10E0, F0, 10
WWW HomeE0, 3AE0, F0, 3A
WWW BackE0, 38E0, F0, 38
WWW ForwardE0, 30E0, F0, 30
WWW StopE0, 28E0, F0, 28
WWW RefreshE0, 20E0, F0, 20
WWW FavoritesE0, 18E0, F0, 18








    module ps2lab1(
      // Clock Input (50 MHz)
      input  CLOCK_50,
      //  Push Buttons
      input  [3:0]  KEY,
      //  DPDT Switches 
      input  [17:0]  SW,
      //  7-SEG Displays
      output  [6:0]  HEX0, HEX1, HEX2, HEX3, HEX4, HEX5, HEX6, HEX7,
      //  LEDs
      output  [8:0]  LEDG,  //  LED Green[8:0]
      output  [17:0]  LEDR,  //  LED Red[17:0]
      //  PS2 data and clock lines
      input PS2_DAT,
      input PS2_CLK,
      //  GPIO Connections
      inout  [35:0]  GPIO_0, GPIO_1
    );

    //  set all inout ports to tri-state
    assign  GPIO_0    =  36'hzzzzzzzzz;
    assign  GPIO_1    =  36'hzzzzzzzzz;

    wire RST;
    assign RST = KEY[0];


    // Connect dip switches to red LEDs
    assign LEDR[17:0] = SW[17:0];

    // turn off green LEDs
    assign LEDG = 0;

    wire reset = 1'b0;
    wire [7:0] scan_code;

    reg [7:0] history[1:4];
    wire read, scan_ready;

    oneshot pulser(
       .pulse_out(read),
       .trigger_in(scan_ready),
       .clk(CLOCK_50)
    );

    keyboard kbd(
      .keyboard_clk(PS2_CLK),
      .keyboard_data(PS2_DAT),
      .clock50(CLOCK_50),
      .reset(reset),
      .read(read),
      .scan_ready(scan_ready),
      .scan_code(scan_code)
    );

    hex_7seg dsp0(history[1][3:0],HEX0);
    hex_7seg dsp1(history[1][7:4],HEX1);

    hex_7seg dsp2(history[2][3:0],HEX2);
    hex_7seg dsp3(history[2][7:4],HEX3);

    hex_7seg dsp4(history[3][3:0],HEX4);
    hex_7seg dsp5(history[3][7:4],HEX5);

    hex_7seg dsp6(history[4][3:0],HEX6);
    hex_7seg dsp7(history[4][7:4],HEX7);



    always @(posedge scan_ready)
    begin
    history[4] <= history[3];
    history[3] <= history[2];
    history[2] <= history[1];
    history[1] <= scan_code;
    end

    // blank remaining digits
    /*
    wire [6:0] blank = 7'h7f;
    assign HEX2 = blank;
    assign HEX3 = blank;
    assign HEX4 = blank;
    assign HEX5 = blank;
    assign HEX6 = blank;
    assign HEX7 = blank;
    */

    endmodule




    module hex_7seg(hex_digit,seg);
    input [3:0] hex_digit;
    output [6:0] seg;
    reg [6:0] seg;
    // seg = {g,f,e,d,c,b,a};
    // 0 is on and 1 is off

    always @ (hex_digit)
    case (hex_digit)
    4'h0: seg = 7'b1000000;
    4'h1: seg = 7'b1111001; // ---a----
    4'h2: seg = 7'b0100100; // |  |
    4'h3: seg = 7'b0110000; // f  b
    4'h4: seg = 7'b0011001; // |  |
    4'h5: seg = 7'b0010010; // ---g----
    4'h6: seg = 7'b0000010; // |  |
    4'h7: seg = 7'b1111000; // e  c
    4'h8: seg = 7'b0000000; // |  |
    4'h9: seg = 7'b0011000; // ---d----
    4'ha: seg = 7'b0001000;
    4'hb: seg = 7'b0000011;
    4'hc: seg = 7'b1000110;
    4'hd: seg = 7'b0100001;
    4'he: seg = 7'b0000110;
    4'hf: seg = 7'b0001110;
    endcase

    endmodule




    module keyboard(keyboard_clk, keyboard_data, clock50, reset, read, scan_ready, scan_code);
    input keyboard_clk;
    input keyboard_data;
    input clock50; // 50 Mhz system clock
    input reset;
    input read;
    output scan_ready;
    output [7:0] scan_code;
    reg ready_set;
    reg [7:0] scan_code;
    reg scan_ready;
    reg read_char;
    reg clock; // 25 Mhz internal clock

    reg [3:0] incnt;
    reg [8:0] shiftin;

    reg [7:0] filter;
    reg keyboard_clk_filtered;

    // scan_ready is set to 1 when scan_code is available.
    // user should set read to 1 and then to 0 to clear scan_ready

    always @ (posedge ready_set or posedge read)
    if (read == 1) scan_ready <= 0;
    else scan_ready <= 1;

    // divide-by-two 50MHz to 25MHz
    always @(posedge clock50)
    clock <= ~clock;



    // This process filters the raw clock signal coming from the keyboard 
    // using an eight-bit shift register and two AND gates

    always @(posedge clock)
    begin
       filter <= {keyboard_clk, filter[7:1]};
       if (filter==8'b1111_1111) keyboard_clk_filtered <= 1;
       else if (filter==8'b0000_0000) keyboard_clk_filtered <= 0;
    end


    // This process reads in serial data coming from the terminal

    always @(posedge keyboard_clk_filtered)
    begin
       if (reset==1)
       begin
          incnt <= 4'b0000;
          read_char <= 0;
       end
       else if (keyboard_data==0 && read_char==0)
       begin
    read_char <= 1;
    ready_set <= 0;
       end
       else
       begin
      // shift in next 8 data bits to assemble a scan code
      if (read_char == 1)
        begin
          if (incnt < 9) 
          begin
    incnt <= incnt + 1'b1;
    shiftin = { keyboard_data, shiftin[8:1]};
    ready_set <= 0;
    end
    else
    begin
    incnt <= 0;
    scan_code <= shiftin[7:0];
    read_char <= 0;
    ready_set <= 1;
    end
    end
    end
    end

    endmodule



    module oneshot(output reg pulse_out, input trigger_in, input clk);
    reg delay;

    always @ (posedge clk)
    begin
    if (trigger_in && !delay) pulse_out <= 1'b1;
    else pulse_out <= 1'b0;
    delay <= trigger_in;
    end 
    endmodule

      清除項目編譯快取 執行 flutter clean 重新取得套件依賴 執行 flutter pub get 完整重新編譯並執行 flutter run 1. 新增專案套件 (pubspec.yaml) 在 Flutter 專案根目錄下的 pubspec.yaml 中,新增 ...