// ps2scan.v
module ps2scan(clk,rst_n,ps2k_clk,ps2k_data,ps2_byte,ps2_state);
input clk;//20M时钟信号
input rst_n;//复位信号
input ps2k_clk;//PS2接口时钟信号
input ps2k_data;//PS2接口数据信号
output[7:0] ps2_byte;// 1byte键值,只做简单的按键扫描
output ps2_state;//键盘当前状态,ps2_state=1表示有键被按下 //------------------------------------------
reg ps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2;//ps2k_clk状态寄存器//wire pos_ps2k_clk; // ps2k_clk上升沿标志位
wire neg_ps2k_clk;// 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;//下降沿//------------------------------------------
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
elseif(neg_ps2k_clk)
begin //检测到ps2k_clk的下降沿case(num)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
elseif(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[7:0] ps2_asci;//接收数据的相应ASCII码
always @(ps2_byte_r)
begin
case(ps2_byte_r)//键值转换为ASCII码,这里做的比较简单,只处理字母8'h15: ps2_asci <="q";//Q8'h1d: ps2_asci <="w";//W8'h24: ps2_asci <="e";//E8'h2d: ps2_asci <="r";//R8'h2c: ps2_asci <="t";//T8'h35: ps2_asci <="y";//Y8'h3c: ps2_asci <="u";//U8'h43: ps2_asci <="i";//I8'h44: ps2_asci <="o";//O8'h4d: ps2_asci <="p";//P 8'h1c: ps2_asci <="a";//A8'h1b: ps2_asci <="s";//S8'h23: ps2_asci <="d";//D8'h2b: ps2_asci <="f";//F8'h34: ps2_asci <="g";//G8'h33: ps2_asci <="h";//H8'h3b: ps2_asci <="j";//J8'h42: ps2_asci <="k";//K8'h4b: ps2_asci <="l";//L8'h1a: ps2_asci <="z";//Z8'h22: ps2_asci <="x";//X8'h21: ps2_asci <="c";//C8'h2a: ps2_asci <="v";//V8'h32: ps2_asci <="b";//B8'h31: ps2_asci <="n";//N8'h3a: ps2_asci <="m";//M8'h45: ps2_asci <="0";//08'h16: ps2_asci <="1";//18'h1e: ps2_asci <="2";//28'h26: ps2_asci <="3";//38'h25: ps2_asci <="4";//48'h2e: ps2_asci <="5";//58'h36: ps2_asci <="6";//68'h3d: ps2_asci <="7";//78'h3e: ps2_asci <="8";//88'h46: ps2_asci <="9";//9default:;
endcase
end
assign ps2_byte = ps2_asci;
assign ps2_state = ps2_state_r;
endmodule
// lcd1602.v`include "ps2scan.v"
`define LINE_116`define LINE_2 32
module lcd1602(clk20m,CLK,DATA,reset,LCD_DATA,LCD_RW,LCD_EN,LCD_RS);
input clk20m,CLK,DATA,reset;
output [7:0] LCD_DATA;
output LCD_RW,LCD_EN,LCD_RS;
wire[7:0] ps2_byte;
wire ps2_state;
reg[7:0] ps2_data[31:0];
reg[5:0] i;
ps2scan ReadByte(.clk(clk20m),.rst_n(reset),.ps2k_clk(CLK),
.ps2k_data(DATA),.ps2_byte(ps2_byte),.ps2_state(ps2_state));
always @(negedge ps2_state or negedge reset)
begin
if(!reset)
i<=0;
else if(i<=6'd31)
begin
ps2_data[i]<=ps2_byte;
i<=i+1'b1;
end
else
begin
i<=6'd1;;
ps2_data[0]<=ps2_byte;
end
end
reg LCD_RS;
reg [7:0] LCD_DATA;
reg LCD_CLOCK;
reg[21:0] count;
reg [9:0] state;
reg [5:0] char_count=0;
reg [7:0] data_display;
parameter IDLE=10'b00_0000_0000;
parameter CLEAR=10'b00_0000_0001;
parameter RETURN=10'b00_0000_0010;
parameter MODE=10'b00_0000_0100;
parameter DISPLAY=10'b00_0000_1000;
parameter SHIFT=10'b00_0001_0000;
parameter FUNCTION=10'b00_0010_0000;
parameter CGRAM=10'b00_0100_0000;
parameter DDRAM=10'b00_1000_0000;
parameter WRITE=10'b01_0000_0000;
parameter STOP=10'b10_0000_0000;
assign LCD_RW=1'b0;
assign LCD_EN=LCD_CLOCK;
always @(posedge clk20m or negedge reset)
begin
if(!reset)
begin
count <= 22'b0;
LCD_CLOCK <= 1'b0;
end
else if(count==39999)//4ms zhouqi
begin
count <= 22'b0;
LCD_CLOCK <= ~LCD_CLOCK;
end
else
count <= count + 1'b1;
end
always @(posedge LCD_CLOCK or negedge reset)
begin
if(!reset)
LCD_RS <= 1'b0;
else if(state==WRITE)
LCD_RS <= 1'b1;
else
LCD_RS <= 1'b0;
end
always @(posedge LCD_CLOCK or negedge reset)
begin
if(!reset)
begin
state <= IDLE;
LCD_DATA <= 8'bzzzz_zzzz;
char_count<=6'd0;
end
else
begin
case(state)
IDLE:begin
state <= CLEAR;
LCD_DATA <= 8'bzzzz_zzzz;
end
CLEAR:begin
state <= RETURN;
LCD_DATA <= 8'b0000_0001;
end
RETURN:begin
state <= MODE;
LCD_DATA <= 8'b0000_0010;
end
MODE:begin
state <= DISPLAY;
LCD_DATA <= 8'b0000_0110;
end
DISPLAY:begin
state <= SHIFT;
LCD_DATA <= 8'b0000_1100;
end
SHIFT:begin
state <= FUNCTION;
LCD_DATA <= 8'b0001_0100;
end
FUNCTION:begin
state <= DDRAM;
LCD_DATA <= 8'b0011_1000;
end
DDRAM:begin
if(i==0)
begin
state <= DDRAM;
LCD_DATA <= 8'b1000_0000;
end
else if((char_count==`LINE_1)&&(char_count!=i))
begin
state <=WRITE;LCD_DATA<=8'b1100_0000;
end
else
begin
state <=WRITE;LCD_DATA<=8'b1000_0000;
char_count <=0;
end
end
WRITE:begin
if((char_count+1'b1==`LINE_1)||(char_count+1'b1==`LINE_2)||(char_count+1'b1==i))
state <=DDRAM;else
state <=WRITE;
char_count <= char_count +1'b1;LCD_DATA<= ps2_data[char_count];
end
//STOP: state <=STOP;default:state <=IDLE;
endcase
end
end
endmodule