library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity rilevatore is generic( periodo_clock : real := 20.0e-9; --considerando un clock di 50MHz, dichiaro un segnale con il suo periodo ppr : integer := 8 -- pulse per round ); port( ch_a : in std_logic; --canale A ch_b : in std_logic; --canale B clock : in std_logic; direzione : out std_logic; feedback_out : out signed (7 downto 0) -- segnale che entrerà nel controllore PI e verrà confrontato con il riferimento ); end entity; architecture struct of rilevatore is signal segnalino : unsigned (1 downto 0) := "00"; signal spp: unsigned (9 downto 0); -- spp indica il tempo tra 2 pulse (second per pulse) signal giro : unsigned (9 downto 0); --secondi per giro (spr) signal RPM : integer; signal RPM_scalato : signed (7 downto 0) :="00000000"; --(mi divido i 1000RPM possibili in 127 possibili valori (CA2)) signal stato : std_logic_vector (1 downto 0);-- segnale di ausilio signal statopre : std_logic_vector (1 downto 0); -- segna lo stato precedente signal dir : std_logic; signal flag_b : std_logic; -- mi indica se sono passato da B dopo essere passato da A signal contatore : integer; -- mi conta il numero di fronti di salita del clock begin process (ch_a, ch_b, clock) is begin -- calcolo della velocità if clock'event and clock='1' then if ch_a'event and ch_a='1' and ch_b='0' then if segnalino="00" then -- il segnalino mi dice quante volte passo da A, è da considerare come un flag_a (è inizializzato a 00) contatore<=contatore + 1; end if; segnalino<=segnalino+1; end if; if ch_b'event and ch_b='1' then if segnalino = "01" then flag_b<='1'; --sta andando tutto bene end if; end if; if ch_a'event and ch_a='1' and ch_b='0' then if segnalino = "10" then -- se segnalino è 10 significa che posso calcolarmi il tempo trascorso tra 2 pulse spp<=real(contatore)*periodo_clock; -- calcolo seconds per pulse giro<=spp*real(ppr); -- tempo impiegato per fare un giro completo ( praticamente SPR, quindi il periodo della frequenza, ossia RPS) RPM<=(60.0/giro); RPM_scalato<=to_signed(integer(127.0*real(RPM)/1000.0), rpm_scalato'length); segnalino<="00";-- azzero segnalino flag_b<='0';-- azzero al flag contatore<=0;-- azzero il contatore end if; end if; -- ############### rilevamento senso di rotazione ################# -- -- generalmente la regola di rilevamento del senso di rotazione di un encoder in quadratura è -- partendo da uno 0 comune, se A diventa alto prima di B, ruota in senso orario e vice versa -- gli stati possono essere 00 10 11 01 00 in CW -- 00 01 11 10 00 in CCW -- N.B. se dir=1 significa CW, se dir=0 significa CCW -- qui non faccio altro che salvarmi lo stato precedente e lo stato presente in modo da poter intuire il senso inequivocabile di rotazione if ch_a='1' and ch_b='0' then stato<="10"; if statopre="00" then dir<='1'; elsif statopre="11" then dir<='0'; else null; end if; end if; if ch_a='0' and ch_b='1' then stato<="01"; if statopre="11" then dir<='1'; elsif statopre="00" then dir<='0'; else null; end if; end if; if ch_a='0' and ch_b='0' then stato<="00"; if statopre="01" then dir<='1'; elsif statopre="10" then dir<='0'; else null; end if; end if; if ch_a='1' and ch_b='1' then stato<="11"; if statopre="10" then dir<='1'; elsif statopre="01" then dir<='0'; else null; end if; end if; statopre<=stato; end if; direzione<=dir; if dir='1' then -- cioè se ruota in senso orario feedback_out<=RPM_scalato; elsif dir='0' then -- senso antiorario feedback_out<=not(RPM_scalato)+1; --faccio il complemento a 2 end if; end process; end architecture;