------------------------------------------------------------------------------- -- Title : Premier projet -- Project : ------------------------------------------------------------------------------- -- File : premier.vhd -- Author : Patrice -- Company : -- Created : 2008-03-19 -- Last update: 2008/06/16 -- Platform : -- Standard : VHDL'93 ------------------------------------------------------------------------------- -- Description: Une horloge avec alarme ------------------------------------------------------------------------------- -- Copyright (c) 2008 http://vhdl33.free.fr ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2008-03-19 1.0 patrice Created ------------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; USE work.primitives_pack.ALL; -- au niveau de l'entite , les seuls types recommandes sont des types -- std_logic afin de garder une interface portable ENTITY premier IS GENERIC ( simulation : boolean := false); -- permet de changer l'echelle du temps PORT ( clock : IN std_ulogic; -- horloge externe 50 Mhz par defaut boutons : IN std_logic_vector(3 DOWNTO 0); -- "reset, mode, plus, moins" afficheurs : OUT std_logic_vector(31 DOWNTO 0); -- 4 X 7 segments avec point leds : OUT std_logic_vector(2 DOWNTO 0)); -- seconde, alarme, alarme END premier; ARCHITECTURE mixte OF premier IS COMPONENT bouton_poussoir GENERIC ( simulation : boolean := false); PORT ( clock : IN std_ulogic; -- horloge systeme poussoir : IN std_ulogic; -- bouton poussoir appui : OUT std_ulogic); -- impulsion de largeur une periode END COMPONENT; SIGNAL reset, mode, plus, moins : std_ulogic; -- appuis SIGNAL clignotement : std_ulogic; -- 1 Hz SIGNAL tempo_1s : std_ulogic; -- premier diviseur SIGNAL tempo_1minute : std_ulogic; -- deuxieme diviseur CONSTANT div_500ms : natural := 25000000; -- pour 50 Mhz CONSTANT div_500ms_simu : natural := 3; -- arbitraire mais faible TYPE type_etat IS (etat0, etat1, etat2, etat3, etat4); SIGNAL etat : type_etat; SIGNAL normal, prog_heure, prog_min, prog_alarmH, prog_alarmM : boolean; SIGNAL inc_minute, inc_heure, dec_minute, dec_heure : boolean; SIGNAL inc_alarm_m, inc_alarm_h, dec_alarm_m, dec_alarm_h : boolean; SIGNAL egalite : boolean; -- pour alarme SIGNAL heure_suivante : boolean; -- toutes les 59 minutes -- chiffres des heures, minutes pour heure et alarme SIGNAL hd, hu, md, mu, amd, amu, ahd, ahu : std_logic_vector(3 DOWNTO 0); SIGNAL chiffres : std_logic_vector(31 DOWNTO 0); SIGNAL activ_alarm : std_ulogic; -- autorisation/interdiction SIGNAL a_afficher : std_logic_vector(15 DOWNTO 0); -- heure ou alarme ? BEGIN -- mixte -- les quatres boutons avec filtrage B1 : bouton_poussoir GENERIC MAP ( simulation => simulation) PORT MAP ( clock => clock, poussoir => boutons(3), appui => reset); B2 : bouton_poussoir GENERIC MAP ( simulation => simulation) PORT MAP ( clock => clock, poussoir => boutons(2), appui => mode); B3 : bouton_poussoir GENERIC MAP ( simulation => simulation) PORT MAP ( clock => clock, poussoir => boutons(1), appui => plus); B4 : bouton_poussoir GENERIC MAP ( simulation => simulation) PORT MAP ( clock => clock, poussoir => boutons(0), appui => moins); -- sequenceur (qui pourrait etre un compteur) -- machine d'etat type Moore fsm : PROCESS BEGIN -- PROCESS WAIT UNTIL rising_edge(clock); IF reset = '1' THEN etat <= etat0; ELSE CASE etat IS WHEN etat0 => IF mode = '1' THEN etat <= etat1; END IF; WHEN etat1 => IF mode = '1' THEN etat <= etat2; END IF; WHEN etat2 => IF mode = '1' THEN etat <= etat3; END IF; WHEN etat3 => IF mode = '1' THEN etat <= etat4; END IF; WHEN etat4 => IF mode = '1' THEN etat <= etat0; END IF; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS; -- les sorties representatives des etats normal <= etat = etat0; prog_heure <= etat = etat1; prog_min <= etat = etat2; prog_alarmH <= etat = etat3; prog_alarmM <= etat = etat4; -- les commandes compteurs / decompteurs inc_minute <= (normal AND (tempo_1minute = '1')) OR (prog_min AND (plus = '1')); dec_minute <= prog_min AND (moins = '1'); inc_heure <= (normal AND heure_suivante ) OR (prog_heure AND (plus = '1')); dec_heure <= prog_heure AND (moins = '1'); inc_alarm_h <= prog_alarmH AND (plus = '1'); dec_alarm_h <= prog_alarmH AND (moins = '1'); inc_alarm_m <= prog_alarmM AND (plus = '1'); dec_alarm_m <= prog_alarmM AND (moins = '1'); -- Diverses temporisations ------------------------------------------------ -- Signal 1 Hz prediv : PROCESS CONSTANT div_500ms : natural := 25000000; -- pour 50 Mhz CONSTANT div_500ms_simu : natural := 2; -- arbitraire mais faible VARIABLE compt : natural RANGE 0 TO 2 * div_500ms ; VARIABLE valeur_tempo : natural RANGE 0 TO div_500ms; -- reel ou simu ? BEGIN -- PROCESS prediv IF simulation THEN valeur_tempo := div_500ms_simu; ELSE valeur_tempo := div_500ms; END IF; WAIT UNTIL rising_edge(clock); tempo_1s <= '0'; IF compt /= 0 THEN compt := compt -1; ELSE compt := 2 * valeur_tempo -1; tempo_1s <= '1'; END IF; IF compt < valeur_tempo THEN -- signal carré clignotement <= '0'; ELSE clignotement <= '1'; END IF; END PROCESS prediv; -- le battement de la seconde leds(2) <= clignotement; -- division par 60 pour minute div60 : PROCESS VARIABLE compt : natural RANGE 0 TO 60; VARIABLE valeur_tempo : natural RANGE 0 TO 60; -- reel ou simu ? BEGIN -- PROCESS div60 IF simulation THEN valeur_tempo := 3; -- pourquoi pas ? ELSE valeur_tempo := 60; -- 60 secondes END IF; WAIT UNTIL rising_edge(clock); tempo_1minute <= '0'; IF tempo_1s = '1' THEN IF compt /= valeur_tempo - 1 THEN compt := compt +1; ELSE compt := 0; tempo_1minute <= '1'; END IF; END IF; END PROCESS div60; -- compteur des minutes --compteur de type bcd min : PROCESS VARIABLE u : natural RANGE 0 TO 9; -- unites VARIABLE d : natural RANGE 0 TO 5; -- dizaines BEGIN -- PROCESS min WAIT UNTIL rising_edge(clock); heure_suivante <= false; IF inc_minute THEN IF u /= 9 THEN u := u + 1; ELSE u := 0; IF d /= 5 THEN d := d + 1; ELSE d := 0; heure_suivante <= true; END IF; END IF; ELSIF dec_minute THEN IF u /= 0 THEN u := u - 1; ELSE u := 9; IF d /= 0 THEN d := d - 1; ELSE d := 5; END IF; END IF; END IF; md <= std_logic_vector(to_unsigned(d, 4)); mu <= std_logic_vector(to_unsigned(u, 4)); END PROCESS min; -- compteur des heures --compteur de type bcd de 00 à 23 heu : PROCESS VARIABLE u : natural RANGE 0 TO 9; -- unites VARIABLE d : natural RANGE 0 TO 5; -- dizaines BEGIN -- PROCESS heu WAIT UNTIL rising_edge(clock); IF inc_heure THEN IF d < 2 THEN IF u /= 9 THEN u := u + 1; ELSE u := 0; d := d + 1; END IF; ELSE IF u /= 3 THEN u := u + 1; ELSE u := 0; d := 0; END IF; END IF; ELSIF dec_heure THEN IF u /= 0 THEN u := u - 1; ELSE u := 9; IF d /= 0 THEN d := d - 1; ELSE d := 2; u := 3; -- 24h = 00h END IF; END IF; END IF; hd <= std_logic_vector(to_unsigned(d, 4)); hu <= std_logic_vector(to_unsigned(u, 4)); END PROCESS heu; -- alarme minute -- va servir en comparaison avec le chiffre des minutes -- compteur de type bcd al_min : PROCESS VARIABLE u : natural RANGE 0 TO 9; -- unites VARIABLE d : natural RANGE 0 TO 5; -- dizaines BEGIN -- PROCESS min WAIT UNTIL rising_edge(clock); IF inc_alarm_m THEN IF u /= 9 THEN u := u + 1; ELSE u := 0; IF d /= 5 THEN d := d + 1; ELSE d := 0; END IF; END IF; ELSIF dec_alarm_m THEN IF u /= 0 THEN u := u - 1; ELSE u := 9; IF d /= 0 THEN d := d - 1; ELSE d := 5; END IF; END IF; END IF; amd <= std_logic_vector(to_unsigned(d, 4)); amu <= std_logic_vector(to_unsigned(u, 4)); END PROCESS al_min; -- compteur de l'alarme heure --compteur de type bcd de 00 à 23 al_heu : PROCESS VARIABLE u : natural RANGE 0 TO 9; -- unites VARIABLE d : natural RANGE 0 TO 5; -- dizaines BEGIN -- PROCESS heu WAIT UNTIL rising_edge(clock); IF inc_alarm_h THEN IF d < 2 THEN IF u /= 9 THEN u := u + 1; ELSE u := 0; d := d + 1; END IF; ELSE IF u /= 3 THEN u := u + 1; ELSE u := 0; d := 0; END IF; END IF; ELSIF dec_alarm_h THEN IF u /= 0 THEN u := u - 1; ELSE u := 9; IF d /= 0 THEN d := d - 1; ELSE d := 2; u := 3; -- 24h = 00h END IF; END IF; END IF; ahd <= std_logic_vector(to_unsigned(d, 4)); ahu <= std_logic_vector(to_unsigned(u, 4)); END PROCESS al_heu; ------------------------------------------------------------------------------- -- multiplexage heure /alarme a_afficher <= (ahd & ahu & amd & amu) WHEN prog_alarmH OR prog_alarmM ELSE (hd & hu & md & mu); -- decodage bcd 7 segments, toutes les fonctions sont identiques -- le point decimal dp est eteind chiffres(7 DOWNTO 0) <= hexato7seg(a_afficher(3 DOWNTO 0)) & '1'; chiffres(15 DOWNTO 8) <= hexato7seg(a_afficher(7 DOWNTO 4)) & '1'; chiffres(23 DOWNTO 16) <= hexato7seg(a_afficher(11 DOWNTO 8)) & '1'; chiffres(31 DOWNTO 24) <= hexato7seg(a_afficher(15 DOWNTO 12)) & '1'; -- clignotement eventuel de l'affichage afficheurs(31 DOWNTO 16) <= (OTHERS => '1') WHEN (prog_heure OR prog_alarmH) AND (clignotement = '1') ELSE chiffres(31 DOWNTO 16); afficheurs(15 DOWNTO 0) <= (OTHERS => '1') WHEN (prog_min OR prog_alarmM) AND (clignotement = '1') ELSE chiffres(15 DOWNTO 0); -- comparaison entre heure courante et alarme (activee ou non egalite <= (hd = ahd)AND (hu = ahu) AND ( md = amd) AND (mu = amu); -- activation de l'alarme act_al : PROCESS BEGIN -- PROCESS act_al WAIT UNTIL rising_edge(clock); IF reset = '1' THEN activ_alarm <= '0'; ELSE IF normal AND (plus = '1') THEN activ_alarm <= '1'; ELSIF normal AND (moins = '1') THEN activ_alarm <= '0'; END IF; IF (activ_alarm = '1') AND egalite THEN leds(0) <= '1'; -- alarme sonne END IF; IF (activ_alarm = '1') AND (moins = '1') THEN leds(0) <= '0'; -- arret sonnerie END IF; END IF; END PROCESS act_al; -- voyant temoin de la programmation leds(1) <= activ_alarm; END mixte;