原创 CPLD/FPGA PS/2键盘接口代码第一天(经验总结,更新到了第二天)

2009-7-16 21:44 4335 8 8 分类: FPGA/CPLD

今天做CPLD/FPGA 的PS/2 键盘,用状态机做;


对状态机理解不透 ,导致程序可以综合,但是生成的状态机图错误,各状态间没有关系,后进过群里 做逻辑的朋友指点:


    我的状态机是在状态里判断时钟边沿,


    改成在时钟边沿条件下选择状态;


   改好了后程序通过,但是读出的PS/2键盘通码错误(键盘有自己的通吗和段码,按下某个间比如A ,通码就是1C,放开这个A键断码就是F01C,就是说A键已经弹起了);


   我想到是不是PS/2键盘的输出时钟问题,我测了下PS/2 CLK的时钟 大约在13K,我想应该是边沿毛刺 对数据造成了误读,所以我对PS/2 键盘的时钟寄存了1次,建议大家寄存2次(用系统时钟22.1184M做触发器的时钟,在时钟上升沿把PS/2键盘的时钟输入到寄存器然后输出), 做些滤波处理好


  做了上面 再读数据,键盘通码显示正确;


  相信很多朋友也看到了一些FPGA的板子 有源时钟是先过芯片一次再出来进CPLD/FPGA 这样的波形就很好了,


  切记切记!!! 缓存2次,这在多时钟设计上可以避免亚稳态的发生...


  PS/2 数据格式 11位数据 1个起始位总为1,8位数据位(低位在前),1位奇校验,1位停止位总为1;和串口通信格式一样,


点击看大图


还一个要说明的是,直接接PS/2键盘上去,键盘上的3个灯永远也不会亮,需要主机到键盘通信 复位 ,工作方式什么的把!!!网上的程序多没有这样的语句,买来的书也没有这个东西;PS/2 协议上介绍,这个东西我没有做,先把基本的做起来;


    PS/2 设备(键盘,鼠标)是自己产生时钟的,不需要主机(HOST)产生时钟,主机可以是PC,CPLD/FPGA,MCU等。同时主机可以抑制PS/2设备通信通过下拉时钟线;


   PS/2设备的时钟线和数据线多是集电极开路输出的,所以一定要上拉电阻,平时 时钟线 数据线多是1,当有动作时候,PS/2设备自动输出时钟和相应的数据,我们只学要在时钟的下降沿读入数据就可以了:


下面是PS/2技术参考,中英文对照,有点错误,比如在主机到设备的通行中


有个是应该 释放 时钟线的,他写成了释放数据线;


http://www.mcu-fpga.com/download/PS2_Technology_Reference.pdf


我博客里也有几篇其他的PS/2的资料,大家找找可以看下


下面是程序:


用状态机读出PS/2键盘发来的11位数据,取出8个数据位,在发光二极管上显示


没有判断 起始位 校验 停止位; 明天还要继续做新功能,这个先练练手 给大家


参考了,我也很菜,大家多提点意见啊!!!


按下A 通码是1C 一直按着不放 输出的永远是1C 断开A,输出的是F01C


先送F0,在送1C,所以在LED上显示的还是1C;


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
use IEEE.STD_LOGIC_arith.ALL;


entity PS2_Keyboard is
Port (clk: in std_logic;                                   --22.1184M system clock
   --reset: in std_logic;                               --Reset Keyboard
   PS2_CLK: in std_logic;                               --PS/2 Keyboard clock
   PS2_Data: in std_logic;                              --PS/2 Keyboard data
   data_out : out std_logic_vector(7 downto 0);         --to 8 bits led
   data3 : out std_logic_vector(2 downto 0)             --to IO
 );
end PS2_Keyboard;


architecture behav of PS2_Keyboard is
type  state_type IS (start_state,data_state,parity_state,stop_state);
signal present_state,next_state : state_type;
--signal timer0 : std_logic_vector(15 downto 0) := x"0000";
--signal en_timer0 : std_logic := '1';
signal start_bit : std_logic;
signal parity_bit : std_logic;
signal stop_bit : std_logic;
signal recive_data : std_logic_vector(7 downto 0);
signal i: integer range 0 to 15 := 0;
signal PS2_CLKP : std_logic;
begin    
data3(0)<=start_bit;
data3(1)<=parity_bit;
data3(2)<=stop_bit;
--state register process
state_reg:process
    begin
   wait until clk'event AND clk = '1';
         PS2_CLKP <= PS2_CLK;
         present_state <= next_state;
   
    end process;
  
state_switch:process(PS2_CLKP)  
       begin
      if PS2_CLKP'event and PS2_CLKP='0' then
   
    case present_state is
     
     when start_state =>
       start_bit <= PS2_Data;
       next_state <= data_state; 
            
           when data_state =>
       if (i = 7) then
       i <= 0;
       data_out(7 downto 0) <= NOT recive_data(7 downto 0);
        next_state <= parity_state;
       else
       recive_data(i) <= PS2_Data;
       i <= i+1;
          next_state <= data_state;
      end if;
           
                    when parity_state =>
       parity_bit <= PS2_Data;
          next_state <= stop_state;
      
     when stop_state =>
       stop_bit <= PS2_Data;
       next_state <= start_state;
        when others =>
                next_state <= start_state;
     end case;
   end if;
   end process;
end behav; 


 


 


第二天:


我想我是不是一定要用状态机呢?


先认为有必要吧!


再看我的状态


我认为的这11个PS/2数据是完整的,即一有PS/2时钟信号就是连续的11个下降沿和对应的11位数据,如果中间突然断开了,程序锁死在某个状态下出不来;等下次数据来临读出的数据位也是错位或错误的;


比如在进入接受8个数据位的时候突然没有了PS/2时钟那要怎么办,状态机一直处在接受8位数据位状态,下个时钟到来起始位的数据就成了数据位,错乱啊!


我没有判断 1。起始位  2.奇偶校验位 3.停止位 的正确与否


你一直按住PS/2键盘不放 键盘会一直发出时钟和数据,他们是有段间隔时间的;


 


 


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
8
关闭 站长推荐上一条 /3 下一条