본문 바로가기
TERM Project/2021-1 FPGA Project

[VHDL] 마그네틱 도어센서로 문열림 감지하기

by 겨울 빛 2021. 6. 28.

이번에 진행했던 텀프로젝트..!

원래는 LCD에 ON/OFF 만 표시하면 됐었는데

뭔가 아쉬워서 FPGA에 내장되어 있는 피에조 부저로 소리까지 울릴 수 있게 해보았다.

결선
마그네틱 도어센서 센서선 J1 2번 핀
GND 전원공급 접지
LCD J2 사용, 하단의 결선도 참고

 

 

 

소스코드- VHD

 

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;



---- Uncomment the following library declaration if instantiating

---- any Xilinx primitives in this code.

--library UNISIM;

--use UNISIM.VComponents.all;


entity LCD_test is

   port (

         dir: IN std_LOGIC; -- 도어락 센서 작동을 위한 선언 J1의 P29의 입력을 받아옴.

         FPGA_RSTB : IN std_logic;

         FPGA_CLK : IN std_logic;

          KEY0 : in std_logic;

         LCD_A : OUT std_logic_vector (1 downto 0);

         LCD_EN : OUT std_logic;

         LCD_D : OUT std_logic_vector (7 downto 0);
         
         buzzer: OUT std_logic); -- 부저 작동을 위한 선언       

end LCD_test;

architecture Behavioral of LCD_test is

--시간 설정 부분

signal clk_100k : std_logic; 

signal clk_50 : std_logic;

--LCD 기능 관련 부분

signal lcd_cnt : std_logic_vector (8 downto 0);

signal lcd_state : std_logic_vector (7 downto 0);

signal lcd_db, temp : std_logic_vector (7 downto 0);

signal one, ten: std_logic_vector(3 downto 0):="0000"; 

signal clk_500,db_pushbuttons_previous,db_pushbuttons : std_logic;

begin

   buzzer<= dir;

   process(FPGA_RSTB,FPGA_CLK)      --Clock(100kHz) Generator


   variable cnt_100k : integer range 0 to 250;

   begin

      if FPGA_RSTB = '0' then

         cnt_100k := 0;

         clk_100k <= '0';

      elsif rising_edge (FPGA_CLK) then

         if cnt_100k >= 249 then

            cnt_100k := 0;

            clk_100k <= not clk_100k;

         else 

            cnt_100k := cnt_100k + 1;

         end if;

      end if;

   end process;



   process(FPGA_RSTB,clk_100k)      --Clock(50Hz) Generator

   

   variable cnt_50 : integer range 0 to 1000;

   

   begin

      if FPGA_RSTB = '0' then

         cnt_50 := 0;

         clk_50 <= '0';

      elsif rising_edge (clk_100k) then

         if cnt_50 >= 999 then

            cnt_50 := 0;

            clk_50 <= not clk_50;

         else 

            cnt_50 := cnt_50 + 1;

         end if;

      end if;

   end process;

   process(FPGA_RSTB,clk_100k)      --Clock(50Hz) Generator

   

   variable cnt_500 : integer range 0 to 1000;

   

   begin

      if FPGA_RSTB = '0' then

         cnt_500 := 0;

         clk_500 <= '0';

      elsif rising_edge (clk_100k) then

         if cnt_500 >= 99 then

            cnt_500 := 0;

            clk_500 <= not clk_500;

         else 

            cnt_500 := cnt_500 + 1;

         end if;

      end if;

   end process;   

 process (KEY0, FPGA_RSTB,one,ten,db_pushbuttons)

 begin

     if FPGA_RSTB = '0' then

      one <= "0000"; 

      ten  <= "0000"; 

      db_pushbuttons_previous <= '0';

     elsif rising_edge(clk_500) then 

--      db_pushbuttons <= KEY0 ;

    

 --      if db_pushbuttons = '1' and db_pushbuttons_previous = '0' then --rising edge detect

          if KEY0 = '1' and  db_pushbuttons_previous <= '0' then

            db_pushbuttons_previous <= '1' ;

                if one = "1001" and ten = "1001" then

                  one <= "0000";

                  ten <= "0000";

                  elsif one = "1001" then 

                  one <= "0000";

                  ten <= ten + "0001";

                  else 

                  one <= one + "0001";

--                  end if;

                  end if;

           elsif KEY0 = '0' then

             db_pushbuttons_previous <= '0' ;

           end if;

           end if;

--       end if;

 end process;



   process(FPGA_RSTB,clk_50,lcd_cnt)

   begin

      if FPGA_RSTB = '0' then

         lcd_cnt <= (others => '0');

         temp <= (others => '0');

      elsif rising_edge (clk_50) then

         if (lcd_cnt >= "001000100") then -- 상태는 총 68(x"22" x 2)개       

-- if some trouble, press reset button

             lcd_cnt <= "000101000";  -- 두번재 줄만 새로 표시 (x"21" x 2 - 1) (원하는 명령의 순서x2 - 1) 혹은 (x"21" x 2 ) (리셋 버튼 누를 것)

            temp <= temp + '1';

         else

            lcd_cnt <= lcd_cnt + 1;

         end if;

      end if;

   end process;



lcd_state <= lcd_cnt (8 downto 1);



   process(lcd_state)

   begin

   if dir = '1' then -- 도어락 센서 자석이 안 닿아 있을 때

      case lcd_state is

         when  X"00" =>   lcd_db <= X"28";      -- Function set (4 bit mode)

         when  X"01" => lcd_db <= X"00";      -- Display OFF  (MSB 4 bit part)

         when  X"02" => lcd_db <= X"80";      --              (LSB 4 bit part)

         when  X"03" => lcd_db <= X"00";      -- Display clear (MSB 4 bit part)

         when  X"04" => lcd_db <= X"10";      --               (LSB 4 bit part)         

         when  X"05" => lcd_db <= X"00";      -- Entry mode set (MSB 4 bit part)

         when  X"06" => lcd_db <= X"60";      --                (LSB 4 bit part)

         when  X"07" => lcd_db <= X"00";      -- Display ON    (MSB 4 bit part)

         when  X"08" => lcd_db <= X"c0";      --               (LSB 4 bit part)

         when  X"09" => lcd_db <= X"00";      -- Return Home   (MSB 4 bit part)

         when  X"0a" => lcd_db <= X"30";      --               (LSB 4 bit part)



         when  X"0b" =>   lcd_db <= X"40";      -- D

         when  X"0c" =>   lcd_db <= X"40";      -- 

         when  X"0d" =>   lcd_db <= X"40";      -- O

         when  X"0e" =>   lcd_db <= X"f0";      -- 

         when  X"0f" =>   lcd_db <= X"40";      -- O

         when  X"10" =>   lcd_db <= X"f0";      -- 

         when  X"11" =>   lcd_db <= X"50";      -- R

         when  X"12" =>   lcd_db <= X"20";      -- 

         when  X"13" =>   lcd_db <= X"20";      -- 공백

         when  X"14" =>   lcd_db <= X"00";      -- 

         

         when  X"15" => lcd_db <= X"C0";

         when  X"16" => lcd_db <= X"00";

         



         when  X"17" =>   lcd_db <= X"40";      -- O
         
         when  X"18" =>   lcd_db <= X"f0";      -- 
         
         when  X"19" =>   lcd_db <= X"50";      -- P
         
         when  X"1a" =>   lcd_db <= X"00";      -- 
         
         when  X"1b" =>   lcd_db <= X"40";      -- E
         
         when  X"1c" =>   lcd_db <= X"50";      -- 
         
         when  X"1d" =>   lcd_db <= X"40";      -- N
         
         when  X"1e" =>   lcd_db <= X"e0";      --

         when  X"1f" =>   lcd_db <= X"20";      -- 공백

         when  X"20" =>   lcd_db <= X"00";      -- 
         
         when  X"21" =>   lcd_db <= X"20";      -- 공백

         when  X"22" =>   lcd_db <= X"00";      -- 



         when others =>   lcd_db <= (others => '0');

      end case;

      

      else -- 도어락 센서 자석이 닿아 있는 경우

        case lcd_state is

         when  X"00" =>   lcd_db <= X"28";      -- Function set (4 bit mode)

         when  X"01" => lcd_db <= X"00";      -- Display OFF  (MSB 4 bit part)

         when  X"02" => lcd_db <= X"80";      --              (LSB 4 bit part)

         when  X"03" => lcd_db <= X"00";      -- Display clear (MSB 4 bit part)

         when  X"04" => lcd_db <= X"10";      --               (LSB 4 bit part)         

         when  X"05" => lcd_db <= X"00";      -- Entry mode set (MSB 4 bit part)

         when  X"06" => lcd_db <= X"60";      --                (LSB 4 bit part)

         when  X"07" => lcd_db <= X"00";      -- Display ON    (MSB 4 bit part)

         when  X"08" => lcd_db <= X"c0";      --               (LSB 4 bit part)

         when  X"09" => lcd_db <= X"00";      -- Return Home   (MSB 4 bit part)

         when  X"0a" => lcd_db <= X"30";      --               (LSB 4 bit part)



         when  X"0b" =>   lcd_db <= X"40";      -- D

         when  X"0c" =>   lcd_db <= X"40";      -- 

         when  X"0d" =>   lcd_db <= X"40";      -- O

         when  X"0e" =>   lcd_db <= X"f0";      -- 

         when  X"0f" =>   lcd_db <= X"40";      -- O

         when  X"10" =>   lcd_db <= X"f0";      -- 

         when  X"11" =>   lcd_db <= X"50";      -- R

         when  X"12" =>   lcd_db <= X"20";      -- 

         when  X"13" =>   lcd_db <= X"20";      -- 공백

         when  X"14" =>   lcd_db <= X"00";      -- 



         when  X"15" => lcd_db <= X"C0";

         when  X"16" => lcd_db <= X"00";

         
         when  X"17" =>   lcd_db <= X"40";      -- C
         
         when  X"18" =>   lcd_db <= X"30";      -- 
         
         when  X"19" =>   lcd_db <= X"40";      -- L
         
         when  X"1a" =>   lcd_db <= X"c0";      -- 
         
         when  X"1b" =>   lcd_db <= X"40";      -- O
         
         when  X"1c" =>   lcd_db <= X"f0";      -- 
         
         when  X"1d" =>   lcd_db <= X"50";      -- S
         
         when  X"1e" =>   lcd_db <= X"30";      -- 
         
         when  X"1f" =>   lcd_db <= X"40";      -- E
         
         when  X"20" =>   lcd_db <= X"50";
         
         when  X"21" =>   lcd_db <= X"20";      -- 공백

         when  X"22" =>   lcd_db <= X"00";      -- 

         

         when others =>   lcd_db <= (others => '0');

         end case;

         

         end if;

   end process;



LCD_A(1) <= '0';

LCD_A(0) <= '0' when (lcd_state >= X"00" and lcd_state < X"0b") or (lcd_state >= X"15" and lcd_state < X"17") else '1'; --명령어 범위 수정

LCD_EN <= not lcd_cnt(0); -- 입력 허가상태와 입력 금지 상태를 반복한다. 이렇게 하면 자동으로 한 칸씩 캐리어가 옮겨지게 되어있다.

LCD_D <= lcd_db;



end Behavioral;

 

사실 DOOR은 앞으로 빼도 되는데 그냥 보기쉬우라고 두번 넣었다.

 

LCD에 넣을 문자 4bit로 코드 작성하기 위해 위 표를 참고하였다. 

 

UCF 
NET "FPGA_CLK" LOC = P55;

NET "FPGA_RSTB" LOC = P1;

# J1의 2번 핀과 연결하여 문열림 센서가 닿아 있는 경우 0 / 안 닿아 있는 경우 1로 출력이 나온다.

NET "dir" LOC = P29;  

NET "LCD_A[0]" LOC = P47;    

NET "LCD_A[1]" LOC = P30; 

NET "LCD_EN"   LOC = P48;

NET "LCD_D[0]" LOC = P32;

NET "LCD_D[1]" LOC = P33;

NET "LCD_D[2]" LOC = P34;

NET "LCD_D[3]" LOC = P35;

NET "LCD_D[4]" LOC = P50;

NET "LCD_D[5]" LOC = P51;

NET "LCD_D[6]" LOC = P56;

NET "LCD_D[7]" LOC = P57;

NET "KEY0" LOC = P74;

# 부저 활용을 위한 핀번호 P2 사용

NET "buzzer" LOC = P2;

 

작동영상

간단한 결선과 코드만으로 구현한 작품이지만 

기능을 추가한다면 항상 문이 닫혀있어야 하는 곳 (ex. 냉장고) 등에 응용해볼 수 있겠다


 

댓글