EPM570扫描4X2键盘,通过IIC发送到LPC2141,然后发送到电脑,EPM570为主机端,LPC2141为从机
以下为CPLD的源代码:
--/*******************************************************************
-- *
-- *
-- * AUTHOR:
-- *
-- * HISTORY:
-- *
-- *******************************************************************/
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
ENTITY KeyIIC IS
PORT (clk,reset : IN std_logic;
KeyIn : IN std_logic_vector(3 downto 0);
led : OUT std_logic_vector(3 downto 0);
KeyOut : OUT std_logic_vector(1 downto 0);
SCL : OUT std_logic;
SDA : OUT std_logic);
END KeyIIC;
ARCHITECTURE behave OF KeyIIC IS
SIGNAL led_reg : std_logic_vector(3 downto 0);
SIGNAL KeyOut_reg : std_logic_vector(1 downto 0);
SIGNAL Key_reg : std_logic_vector(7 downto 0);
SIGNAL KeyIn_reg : std_logic_vector(3 downto 0);
SIGNAL clk_iic : std_logic;
SIGNAL SDA_reg : std_logic;
SIGNAL clk_iic_div : std_logic_vector(2 downto 0);
SIGNAL count : std_logic_vector(3 downto 0);
SIGNAL clk_key : std_logic;
SIGNAL key_down_up : std_logic_vector(1 downto 0);
CONSTANT CLK_DIV_RANGE :integer := 128;
CONSTANT CLK_DIV_C :integer := 10;
CONSTANT CLK_DIV_IIC :integer := 50;
CONSTANT CLK_KEY_RANGE :integer := 31;
CONSTANT CLK_KEY_C :integer := 10;
TYPE state_key is (scan_state,key_state,keydown_state);
TYPE state_iic is (idle,start,addr,data,stop,ack);
SIGNAL keystate,nextstate_key :state_key;
SIGNAL iicstate,nextstate_iic :state_iic;
BEGIN
KeyOut <= KeyOut_reg;
clk_out_gen : PROCESS (clk,reset) --generate the scan clk
VARIABLE clk_div : INTEGER RANGE 0 to CLK_DIV_RANGE;
BEGIN
if(reset ='0') then
clk_div := 0;
elsif(rising_edge(clk))then
if(clk_div = CLK_DIV_IIC)then --10000000/16
clk_div := 0;
clk_iic <= not clk_iic;
else
clk_div := clk_div + 1;
end if;
end if;
END PROCESS;
PROCESS (clk_iic,reset) --generate the scan clk
VARIABLE clk_div : INTEGER RANGE 0 to CLK_DIV_RANGE;
BEGIN
if(reset ='0') then
clk_div := 0;
elsif(rising_edge(clk_iic))then
if(clk_div = CLK_DIV_C)then --10000000/16
clk_div := 0;
clk_key <= not clk_key;
else
clk_div := clk_div + 1;
end if;
end if;
END PROCESS;
process(clk_iic,reset) --rising edge change the iic state
begin
if(reset = '0') then
iicstate <= idle;
elsif(rising_edge(clk_iic)) then
iicstate <= nextstate_iic;
end if;
END PROCESS;
process(clk_iic,reset) --scan the keyboard
begin
if(reset = '0') then
key_down_up <= "00";
elsif(rising_edge(clk_iic))then
if(keystate = key_state and nextstate_key = keydown_state)then
key_down_up <= "01"; --key down
elsif(keystate = keydown_state and nextstate_key = scan_state)then
key_down_up <= "10"; --key up
else
key_down_up <= "00";
end if;
end if;
END PROCESS;
process(clk_iic,reset) --scan the keyboard
begin
if(reset = '0') then
Key_reg(7 downto 6) <= "ZZ";
elsif(rising_edge(clk_iic))then
if(key_down_up /= "00") then --key down
Key_reg(7 downto 6) <= key_down_up;
end if;
end if;
END PROCESS;
process(clk_iic,reset) --rising edge change the iic state
VARIABLE sign :integer range 0 to 1;
begin
if(reset = '0') then
nextstate_iic <= idle;
SDA_reg <= '1';
elsif(rising_edge(clk_iic)) then
case iicstate is --start,data,stop
when idle =>
sign := 0;
clk_iic_div <= "100";
SDA_reg <= '1';
if(key_down_up /= "00") then
nextstate_iic <= start;
end if;
when start =>
clk_iic_div <= clk_iic_div + 1;
if(clk_iic_div = "111")then
nextstate_iic <= addr;
count <= "0000";
elsif(clk_iic_div = "101")then
SDA_reg <= '0';
end if;
when addr =>
clk_iic_div <= clk_iic_div + 1;
if(clk_iic_div = "001")then
count <= count +1;
case count is
when "0000" =>
SDA_reg <= '1';
when "0001" =>
SDA_reg <= '1';
when "0010" =>
SDA_reg <= '0';
when "0011" =>
SDA_reg <= '0';
when "0100" =>
SDA_reg <= '0';
when "0101" =>
SDA_reg <= '0';
when "0110" =>
SDA_reg <= '1';
when "0111" =>
SDA_reg <= '0';
when others =>
SDA_reg <= '1';
end case;
end if;
if(clk_iic_div = "111" and count = "1000")then
nextstate_iic <= ack;
end if;
when ack =>
SDA_reg <= '1';
clk_iic_div <= clk_iic_div + 1;
if(clk_iic_div = "111")then
if(sign = 0) then
nextstate_iic <= data;
else
nextstate_iic <= stop;
end if;
count <= "0000";
end if;
when data =>
sign := 1;
clk_iic_div <= clk_iic_div + 1;
if(clk_iic_div = "001")then
count <= count +1;
case count is
when "0000" =>
SDA_reg <= Key_reg(7);
when "0001" =>
SDA_reg <= Key_reg(6);
when "0010" =>
SDA_reg <= Key_reg(5);
when "0011" =>
SDA_reg <= Key_reg(4);
when "0100" =>
SDA_reg <= Key_reg(3);
when "0101" =>
SDA_reg <= Key_reg(2);
when "0110" =>
SDA_reg <= Key_reg(1);
when "0111" =>
SDA_reg <= Key_reg(0);
when others =>
SDA_reg <= '1';
end case;
end if;
if(clk_iic_div = "111" and count = "1000")then
nextstate_iic <= ack;
end if;
when stop =>
-- SDA_reg <= '1';
clk_iic_div <= clk_iic_div + 1;
if(clk_iic_div = "101")then
SDA_reg <= '1';
nextstate_iic <= idle;
elsif(clk_iic_div = "001")then
SDA_reg <= '0';
end if;
end case;
end if;
END PROCESS;
SDA <= '0' when SDA_reg = '0' else 'Z';
SCL <= '0' when clk_iic_div(2) = '0' else 'Z';
led <= not led_reg;
process(clk_iic,reset) --show the key number pressed
begin --on leds
if(rising_edge(clk_iic)) then
case (Key_reg(5 downto 0)) is
when "100111" =>
led_reg <= "0001";
when "101011" =>
led_reg <= "0010";
when "101101" =>
led_reg <= "0011";
when "101110" =>
led_reg <= "0100";
when "010111" =>
led_reg <= "0101";
when "011011" =>
led_reg <= "0110";
when "011101" =>
led_reg <= "0111";
when "011110" =>
led_reg <= "1000";
when others =>
led_reg <= "0000";
end case;
end if;
END PROCESS;
process(clk_key,reset) --rising edge change the key state
begin
if(reset = '0') then
keystate <= scan_state;
elsif(rising_edge(clk_key)) then
keystate <= nextstate_key;
end if;
END PROCESS;
process(clk_key,reset) --scan the keyboard
VARIABLE times : INTEGER RANGE 0 to 127;
begin
if(reset = '0') then
nextstate_key <= scan_state;
KeyOut_reg <= "01";
elsif(rising_edge(clk_key)) then
case keystate is
when scan_state =>
KeyOut_reg <= not KeyOut_reg;
if(KeyIn /= "1111") then --if any key pressed change the keystate
KeyIn_reg <= KeyIn;
nextstate_key <= key_state;
times := 0;
end if;
when key_state =>
times := times + 1;
if(KeyIn_reg /= KeyIn)then
nextstate_key <= scan_state;
elsif(times = 100) then --if key pressed 10ms show the key
Key_reg(5 downto 0) <= KeyOut_reg & KeyIn_reg;
nextstate_key <= keydown_state;
end if;
when keydown_state =>
if(KeyIn_reg /= KeyIn) then
nextstate_key <= scan_state;
end if;
end case;
end if;
end process;
END behave;