이번에 진행했던 텀프로젝트..!
원래는 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. 냉장고) 등에 응용해볼 수 있겠다
댓글