-- pour compiler sur Altera MAX3000A (EPM3064A-LC44), -- utiliser Quartus-II (fit plus efficace que MaxPlusII) -- optimisation: balanced (mieux que speed, bien mieux que area) LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; ENTITY coupatan IS PORT( reset,clock : in std_logic; clocktimer : in std_logic; -- clock=pour cadencer clavier et afficheur (128-256 Hz) -- clocktimer=pour cadencer le comptage et le séparateur (0.5 Hz) clavierx : out STD_LOGIC_vector(0 to 2); claviery : in std_logic_vector(0 to 3); -- relier clavierx aux fils X du clavier (type téléphone 123/456/789/#0*) -- relier claviery aux fils Y du clavier et mettre des pull-downs -- mettre des capas sur claviery pour faire anti-rebond! septseg: out std_logic_vector(1 to 7); separateur: out std_logic; marche: out std_logic; buzzerOD: inout std_logic ); END coupatan; ARCHITECTURE a OF coupatan IS signal clocktimer_sync, clocktimer_lent,clocktimer_pulse:std_logic; signal clocktimer_1Hz,clocktimer_1Hz_pulse:std_logic; -- pour clavier SIGNAL scan:std_logic_vector(1 downto 0); -- compteur pour adressage signal clavsync:std_logic_vector(0 to 3); -- synchro signal touche_ce_scan: std_logic; signal touche:std_logic_vector(4 downto 0); -- touche reconnue + numéro chiffre signal toucheok:std_logic; signal enfonce:std_logic; -- pour timer signal bcd:std_logic_vector(11 downto 0); -- signal suspend_timer:std_logic_vector(2 downto 0); -- arrêter timer si clavier signal suspend_timer:std_logic_vector(1 downto 0); -- arrêter timer si clavier (2 secondes, ça suffit) signal touche2:std_logic; signal zeros:std_logic_vector(2 downto 0); signal zero:std_logic; -- pour 7 segments signal bcd1:std_logic_vector(3 downto 0); BEGIN -- horloges horloges: process(reset,clock) begin if reset='0' then clocktimer_1Hz<='0'; elsif rising_edge(clock) then clocktimer_sync<=clocktimer; clocktimer_lent<=clocktimer_sync; if clocktimer_pulse='1' then clocktimer_1Hz<=not clocktimer_1Hz; end if; end if; end process; clocktimer_pulse<='1' when clocktimer_sync='1' and clocktimer_lent='0' else '0'; clocktimer_1Hz_pulse<='1' when clocktimer_pulse='1' and clocktimer_1Hz='0' else '0'; -- clavier clavier:process (reset,clock) begin if reset='0' then scan<="00"; clavsync<=(others=>'0'); elsif rising_edge(clock) then scan<=scan+1; clavsync<=claviery; if scan="00" then touche_ce_scan<='0';enfonce<=touche_ce_scan; elsif clavsync/="0000" then touche_ce_scan<='1'; end if; if clavsync(0)='1' then case scan is when "10" => touche<="10010"; --2 when "11" => touche<="10011"; --3 when others => touche<="10001"; --1 end case; elsif clavsync(1)='1' then case scan is when "10" => touche<="10101"; --5 when "11" => touche<="10110"; --6 when others => touche<="10100"; --4 end case; elsif clavsync(2)='1' then case scan is when "10" => touche<="11000"; --8 when "11" => touche<="11001"; --9 when others => touche<="10111"; --7 end case; elsif clavsync(3)='1' then case scan is when "10" => touche<="10000"; --0 when others => touche<="00000"; -- * ou # end case; end if; end if; end process; clavierx(0)<='1' when scan="00" else '0'; clavierx(1)<='1' when scan="01" else '0'; clavierx(2)<='1' when scan="10" else '0'; toucheok<=touche(4) and enfonce; -- clavsync<=claviery; -- timer timer:process(reset,clock) begin -- suspendre le comptage si on appuie sur des touches du clavier! if reset='0' then suspend_timer<=(others=>'1'); -- pour allumage au reset elsif rising_edge(clock) then if toucheok='1' then suspend_timer<=(others=>'1'); elsif clocktimer_1Hz_pulse='1' and suspend_timer(suspend_timer'high)='1' then suspend_timer<=suspend_timer-1; end if; end if; -- entrer clavier et décompter if reset='0' then bcd<=(others=>'0'); elsif rising_edge(clock) then touche2<=toucheok; if touche2='0' and toucheok='1' then -- nouvelle touche bcd<=bcd(bcd'high-4 downto 0) & touche(3 downto 0); -- décalage elsif clocktimer_1Hz_pulse='1' and suspend_timer(suspend_timer'high)='0' and zero='0' then -- décomptage if zeros(0)='0' then bcd(3 downto 0) <= bcd(3 downto 0)-1; else bcd(3 downto 0)<="1001"; --9 if zeros(1)='0' then bcd(7 downto 4)<=bcd(7 downto 4)-1; else bcd(7 downto 4)<="0101"; --5 bcd(11 downto 8)<=bcd(11 downto 8)-1; end if; end if; end if; end if; end process; zeros(2)<='1' when bcd(11 downto 8)="0000" else '0'; zeros(1)<='1' when bcd(7 downto 4)="0000" else '0'; zeros(0)<='1' when bcd(3 downto 0)="0000" else '0'; zero<='1' when zeros="111" else '0'; -- 7 segments: afficheur sélectionné avec "clavierx" -- numérotation des segments: -- +---1---+ -- | | -- 6 2 -- | | -- +---7---+ -- | | -- 5 3 -- | | -- +---4---+ with scan select bcd1<=bcd(11 downto 8) when "00", bcd(7 downto 4) when "01", bcd(3 downto 0) when others; WITH bcd1 SELECT septseg <= "1111110" when "0000", "0110000" when "0001", "1101101" when "0010", "1111001" when "0011", "0110011" when "0100", "1011011" when "0101", "1011111" when "0110", "1110000" when "0111", "1111111" when "1000", "1111011" when "1001", "1001001" when others; --inconnu --septseg<=bcd1 & "000"; -- sans décodeur: utiliser un 74LS47 pour 3 afficheurs -- separateur entre minutes et secondes (clignote normalement, mais s'allume fixe si comptage suspendu ou fini) separateur<='1' when suspend_timer(suspend_timer'high)='1' or zero='1' else clocktimer_1Hz; -- marche/arrêt marche <='1' when zero/='1' or suspend_timer(suspend_timer'high)='1' else '0'; -- buzzer: open-drain, mis à zéro à "001" buzzerOD <='0' when zeros(2)='1' and zeros(1)='1' and bcd(3 downto 0)="0001" and suspend_timer(suspend_timer'high)='0' else 'Z'; END a;