在被4*4的矩阵键盘搞的有点晕的时候,我决定换成PS2的键盘和LCD1602,在初步认识和简单调试出来1602后,今天准备学习PS2。在FPGA的学习上一直都是这种状态深入不下去,客观上是DE0带的资料确实有点少,一直也没找到一个好的突破口,主要还是付出不够。OK,1602和PS2键盘分别已经基本搞懂了,先总结一下遇到的问题,再来想一下两者中间的连接模块。参考DE2上面的LCD1602的例程。只是它一个LCD1602的控制模块写了两部分,在另一个部分就控制了一个LED_EN,我觉得没有必要就直接写成了一个LCD_Controller模块。
在看PS2协议写PS2代码时,有一个地方说的比较含糊。PS2只有两根线要注意,clk和data,在没有键按下时,时钟和数据线都是高电平,只有有键按下时,时钟线上才会产生时钟信号,原来以为时钟是一直都有的,看来是大错特错了!这样也比较好,按我的错误理解如果没有键按下也有时钟信号的话,那cpu岂不是要一直判断数据线上的信号,看是否为0,来判断起始位。这样CPU势必会比较累。
看黑金的代码觉得还是有点问题的,只是它在控制器的那个模块忽略了8'hf0的情况,如果加上这种情况,那我想演示一定会有问题的,主要的错因还是在于中间模块的数据提取,我们知道一个键按下时会发通码,那我就接受了这个通码,判断不等于8'hf0, 状态机就直接跳到23,当我放开此键时又会发送断码,我还是会接受断码,也就是我oDATA还是8'hf0 ,那么在判断是否等于 8'hf0 , 现在是等于了,结果后面又什么都没做。呵呵,这是值得改进的地方。它之所以没有出错的原因前面已经说了。
今天在写代码时遇到了一个以前没遇到过的问题,觉得比较搞笑,我的PS2_TEST模块的演示时通过LED显示的,大的分就要分两个部分:一个PS2模块,一个译码显示模块,PS2模块就是根据clk和data信号把被按下键的通码取出了组成一个8位的并行数据送给显示模块去译码再显示,我屁颠屁颠的把PS2模块写完,编译出现25个警告,这还没事,最怕的是编译结果报告:
我100多行的代码竟然没有消耗一个逻辑单元,我就很诧异了,找半天原因,因为之前从来没有遇到过这种情况。后来看了一下警告,它说的大概意思也就是说我没有输出,或者我的输入没有驱动输出,恩,后来我把译码显示模块一写完,OK,成功! 下载到板子上测试,恩,对。
工程代码如下:
module LCD_Controller(
iCLK,iRST_N,
iDATA,iDONE,
LCD_RS,LCD_RW,LCD_EN,LCD_BLON,LCD_DATA );
input iCLK,iRST_N;
input iDONE;
input [ 7 : 0 ] iDATA;
output LCD_RS,LCD_RW,LCD_EN,LCD_BLON;
reg LCD_RS,LCD_EN;
output [ 7 : 0 ] LCD_DATA;
reg [ 7 : 0 ] LCD_DATA;
// Internal Wires/Registers
reg [ 2 : 0 ] ST;
reg [ 4 : 0 ] E_DLY;
reg [ 17 : 0 ] mDLY;
reg [ 5 : 0 ] LUT_INDEX;
reg [ 8 : 0 ] LUT_DATA;
reg [ 7 : 0 ] wDATA;
reg Write;
parameter E_DELAY = 16 ;
parameter LCD_INTIAL = 0 ;
parameter LCD_LINE1 = 5 ;
parameter LUT_SIZE = LCD_LINE1;
assign LCD_BLON = 1 ' b1; //Blacklight On
assign LCD_RW = 1 ' b0; //Only Write
always @( posedge iCLK or negedge iRST_N)
begin
if ( ! iRST_N)
begin
LUT_INDEX <= 0 ;
Write <= 0 ;
LCD_EN <= 0 ;
LCD_DATA <= 0 ;
LCD_RS <= 0 ;
E_DLY <= 0 ; // LCD_E Delay > 150ns
mDLY <= 0 ; // Write a byte delay > 400ns
ST <= 0 ;
end
else
begin
if (LUT_INDEX < LUT_SIZE)
begin
case (ST)
0 : begin
LCD_DATA <= LUT_DATA[ 7 : 0 ]; //
LCD_RS <= LUT_DATA[ 8 ]; // Instrction Register
LCD_EN <= 1 ' b1; //LCD Enable
ST <= 1 ; //
end
1 : begin
if (E_DLY < E_DELAY)
E_DLY <= E_DLY + 1 ' b1; //Delay 16*20 = 320ns
else
begin
E_DLY <= 5 ' d0;
ST <= 2 ;
end
end
2 : begin
LCD_EN <= 1 ' b0;
ST <= 3 ;
end
3 : begin
if (mDLY < 18 ' h3FFFE) //Delay a long time
mDLY <= mDLY + 1 ;
else
begin
mDLY <= 0 ;
ST <= 4 ;
end
end
4 : begin
LUT_INDEX <= LUT_INDEX + 1 ;
ST <= 0 ;
end
endcase
end
/* -------------------------------------------------------------------------------- */
else if (iDONE == 1 ' b0) //Why can ' t == 1 ;
Write <= 1 ' b1;
else if (Write == 1 ' b1)
begin
case (ST)
0 : begin
LCD_DATA <= wDATA; //
LCD_RS <= 1 ; // Instrction Register
LCD_EN <= 1 ' b1; //LCD Enable
ST <= 1 ; //
end
1 : begin
if (E_DLY < E_DELAY)
E_DLY <= E_DLY + 1 ' b1; //Delay 16*20 = 320ns
else
begin
E_DLY <= 5 ' d0;
ST <= 2 ;
end
end
2 : begin
LCD_EN <= 1 ' b0;
ST <= 3 ;
end
3 : begin
if (mDLY < 18 ' h3FFFE) //Delay a long time
mDLY <= mDLY + 1 ;
else
begin
mDLY <= 0 ;
ST <= 4 ;
end
end
4 : begin
Write <= 1 ' b0;
ST <= 0 ;
end
endcase
end
end
end
always
begin
case (LUT_INDEX)
// Initial
LCD_INTIAL + 0 : LUT_DATA <= 9 ' h038; //
LCD_INTIAL + 1 : LUT_DATA <= 9 ' h00C; //Function set:8-bit,2-line,5*8 dots
LCD_INTIAL + 2 : LUT_DATA <= 9 ' h001; //clear display
LCD_INTIAL + 3 : LUT_DATA <= 9 ' h006; //Entry Mode Set
LCD_INTIAL + 4 : LUT_DATA <= 9 ' h080; //Set DDRAM Address
endcase
end
always
begin
case (iDATA)
8 ' h1c: wDATA <= 8 ' h41; // A,前面的8'h1c是PS2键值表,后面的ASCII码
8 ' h32: wDATA <= 8 ' h42; // B
8 ' h21: wDATA <= 8 ' h43; // C
8 ' h23: wDATA <= 8 ' h44; // D
8 ' h24: wDATA <= 8 ' h45; // E
8 ' h2b: wDATA <= 8 ' h46; // F
8 ' h34: wDATA <= 8 ' h47; // G
8 ' h33: wDATA <= 8 ' h48; // H
8 ' h43: wDATA <= 8 ' h49; // I
8 ' h3b: wDATA <= 8 ' h4a; // J
8 ' h42: wDATA <= 8 ' h4b; // K
8 ' h4b: wDATA <= 8 ' h4c; // L
8 ' h3a: wDATA <= 8 ' h4d; // M
8 ' h31: wDATA <= 8 ' h4e; // N
8 ' h44: wDATA <= 8 ' h4f; // O
8 ' h4d: wDATA <= 8 ' h50; // P
8 ' h15: wDATA <= 8 ' h51; // Q
8 ' h2d: wDATA <= 8 ' h52; // R
8 ' h1b: wDATA <= 8 ' h53; // S
8 ' h2c: wDATA <= 8 ' h54; // T
8 ' h3c: wDATA <= 8 ' h55; // U
8 ' h2a: wDATA <= 8 ' h56; // V
8 ' h1d: wDATA <= 8 ' h57; // W
8 ' h22: wDATA <= 8 ' h58; // X
8 ' h35: wDATA <= 8 ' h59; // Y
8 ' h1a: wDATA <= 8 ' h5a; // Z
8 ' h45: wDATA <= 8 ' h30; // 0
8 ' h16: wDATA <= 8 ' h31; // 1
8 ' h1e: wDATA <= 8 ' h32; // 2
8 ' h26: wDATA <= 8 ' h33; // 3
8 ' h25: wDATA <= 8 ' h34; // 4
8 ' h2e: wDATA <= 8 ' h35; // 5
8 ' h36: wDATA <= 8 ' h36; // 6
8 ' h3d: wDATA <= 8 ' h37; // 7
8 ' h3e: wDATA <= 8 ' h38; // 8
8 ' h46: wDATA <= 8 ' h39; // 9
endcase
end
endmodule