Tomasz DUMAŁA IV rok Koło Naukowe Techniki Cyfrowej Dr inŝ. Wojciech Mysiński opiekun naukowy ELECTRIC IMPULSE DURATION MEASUREMENT USING VHDL LANGUAGE ZASTOSOWANIE JĘZYKA VHDL DO POMIARU CZASU TRWANIA IMPULSU ELEKTRYCZNEGO. Keywords: VHDL, measurement, electric impulse, programmable device, duration Słowa kluczowe: VHDL, pomiar, impuls elektryczny, układ programowalny, czas trwania 1. KONCEPCJA UKŁADU POMIAROWEGO. Pomiar czasu trwania impulsu prostokątnego moŝna przeprowadzić między innymi wykorzystując liczniki, układy mikroprocesorowe, mikrokontrolery lub stosując układy programowalne. W mojej pracy postaram się przedstawić, w jaki sposób korzystając z układów programowalnych(fpga) skonstruować układ spełniający załoŝenia tematu. Na początek postaram się przedstawić algorytm, którym będę się kierował projektując układ. W tym celu sporządziłem schemat blokowy przedstawiony na poniŝszym rysunku. Rys. 1.1 Schemat blokowy układu pomiarowego.
1.1. ZASADA DZIAŁANIA 1. Podanie mierzonego impulsu: a. na blok sterujący b. na bramkę elektroniczną 2. Podanie sygnału z generatora wzorcowego na bramkę elektroniczną. 3. Bramka elektroniczna porównuje sygnały na nią podane. a. gdy impuls mierzony jest w stanie wysokim to bramka przepuszcza sygnały z generatora wzorcowego b. gdy impuls mierzony jest w stanie niskim to bramka na wyjściu przyjmuje stan niski (czyli nie przepuszcza sygnału z generatora) 4. Gdy bramka przepuszcza sygnał z generatora to zaczyna swą prace układ zaliczający. 5. Blok sterowania(umoŝliwia pomiar wielu impulsów występujących po sobie): a. kontrola zerowania licznika b. kontrola zatrzasku 6. Wyświetlenie wyniku pomiaru na wyświetlaczu. 1.2. ALGORYTM UKŁADU ZLICZAJĄCEGO IMPULSY. Rys. 1.2. Algorytm układu.
Wynikiem działania kolejnych bloków powyŝszego schematu jest układ wykresów przedstawiający role i funkcje podanych segmentów. Rys. 1.3. Wykresy zaleŝności między blokami układu pomiarowego. Działanie układu polega na zliczaniu impulsów podawanych z generatora wzorcowego. Znając okres generatora moŝemy obliczyć czas trwania impulsu według następującej zaleŝności. gdzie: T I T W T I = n T - czas trwania impulsu mierzonego - okres impulsu z generatora wzorcowego W
1.3. OGRANICZENIA ZWIĄZANE Z BŁĘDAMI POMIAROWYMI. W danym czasie układ zlicza n ± 1 impulsów, zatem błąd z tym związany będzie wynosił 1. Wynika stąd, iŝ im krótszy pomiar czasu tym jest on obarczony większym błędem. n Całkowity błąd jakim jest obarczony układ będzie sumą poszczególnych błędów w nim występujących. W rzeczywistości na kaŝdym elemencie występuje opóźnienie związane z czasem propagacji. Dlatego teŝ stosuje się generatory wzorcowe, których błąd waha się w granicach 10-5 10-8. Przyjmując za błąd techniczny wartość 1% moŝna oszacować jaki minimalny czas, który moŝemy zmierzyć uŝywając generatora o określonej częstotliwości. f częstotliwość generatora T- okres impulsu generatora t- minimalny czas, który moŝemy zmierzyć, przy danej częstotliwości nie przekraczając błędu technicznego Długość okresu obliczamy ze wzoru: T = 1 f Jak wspomniałem wyŝej błąd pomiaru obliczamy ze wzoru: gdzie n- liczba zliczonych impulsów. 1 δ = n Zatem δ 0,01 = 1% dla n 100 Czyli t = nt Układ, który dla przykładu skonstruowałem jest taktowany częstotliwością f=1mhz, więc T= 0,1µs z czego wynika, Ŝe moŝemy nim wykonać pomiar impulsu nie krótszego niŝ t=1ms, aby błąd nie przekroczył 1%.
2. PODSTAWY JĘZYKA VHDL I IMPLEMENTACJA PROJEKTU. 2.1. PODSTAWY PROGRAMOWANIA W VHDL u. 2.1.1. WPROWADZENIE. Nazwa pochodzi od Very High Speed Integrated Circuit i Hardware Description Language. Sięga on 1983 roku. Początkowo był językiem stworzonym dla amerykańskiego Departamentu Obrony, do opisu sprzętu elektronicznego. W 1987 roku doczekał się standaryzacji. Następne poprawki były w 1993 roku. Dziś jest to powszechnie stosowany język do opisu, syntezy i symulacji sprzętu elektronicznego. Dzięki niemu moŝemy łatwo tworzyć i symulować roŝnego rodzaju urządzenia cyfrowe bez większych nakładów finansowych. Przy prostych projektach uŝytkownik nie musi się martwić o optymalizację wykonywanych funkcji gdyŝ robi to za niego system projektowy. Dzięki stałej pracy programistów powyŝsze systemy są ciągle ulepszane i staja się mniej zawodne, mogą równieŝ zastępować inŝyniera na niektórych etapach projektowania. Jak widać takie podejście znacznie skraca czas od zaprojektowania do wykonania danego elementu, co przy dzisiejszej konkurencji jest istotną sprawą. Technika ta w ostatnich latach znacznie poszła do przodu dzięki czemu w dzisiejszych czasach produkowane są juŝ układy zbudowane z setek tysięcy, a nawet milionów bramek, co daje nam niezmiernie duŝe moŝliwości. Dla przykładu podam kilka układów FPGA firmy Xilinx z rodziny Spartan-3. Układ XC3S50, gdzie ostatnia liczba 50 oznacza liczbę bramek systemowych, które zawiera układ. Inne układy z tej rodziny to XC3S200, XC3S400, XC3S1000, XC3S1500, XC3S2000, XC3S4000 oraz XC3S5000. Jak widać pierwszy z nich zawiera 50000 bramek, natomiast ostatni, aŝ 5000000 bramek. Przygotowując przykłady do powyŝszego referatu korzystam z oprogramowania WebPACK w wersji 6.3.03i firmy Xilinx. Obecnie jest juŝ na rynku wersja 8.1 jednak Ŝe wersja 6.3 jest juŝ sprawdzoną i niezawodną wersją, w przeciwieństwie do nowo wychodzących wersji. Do symulacji polecam ModelSim XE III 6.0a. Programy te, po uprzednim zarejestrowaniu się moŝna ściągnąć ze strony producenta www.xilinx.com.
2.1.2. PODSTAWOWE ZAGADNIENIA JĘZYKA. KaŜdy projekt w języku VHDL składa się z jednostki projektowej (opis tzw. czarnej skrzynki, z wyszczególnionymi tylko wejściami i wyjściami) i architektury, która opisuje zaleŝności pomiędzy wejściami i wyjściami danej czarnej skrzynki. Opis jednostki entity bramka_and is Port ( nazwy i typu portów wejść i wyjść ); end bramka_and; Podstawowe części programu w języku VHDL. Opis architektury architecture arch_and of bramka_and is begin opis zaleŝności między wejściami i wyjściami end arch_and; A oto przykładowy prosty program w VHDL u opisujący dwu wejściową bramkę AND: (znak -- oznacza przejście do opisu) library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; Przykładowy projekt. deklaracja wykorzystywanych bibliotek -- Uncomment the following lines to use the declarations that are -- provided for instantiating Xilinx primitive components. --library UNISIM; --use UNISIM.VComponents.all; entity bramka_and is Port ( a : in std_logic; b : in std_logic; y : out std_logic); end bramka_and; architecture arch_and of bramka_and is begin y <= a and b; end arch_and; deklaracja jednostki projektowej, wraz z opisem wejść-wyjść in-wejście, out-wyjście koniec deklaracji jednostki deklaracja architektury zawierającej opis zaleŝności pomiędzy wejściami i wyjściami (y <= a and b;) koniec deklaracji architektury
2.1.3. OBIEKTY W VHDL u Podstawowym obiektem jest sygnał. MoŜe on być zewnętrzny (pobierany z portów układu) lub wewnętrzny (deklarowany w ciele architektury, przed słowem kluczowym begin ). Deklaracja sygnału wewnętrznego wygląda następująco: signal nazwa_sygnału : typ_sygnału Na końcu moŝemy dodać ograniczenie lub wartość domyślną sygnału, jak to jest pokazane poniŝej. signal calkowita : intiger range 0 to 10; -- ograniczenie od 0 do 10 signal a : bit := 1 ; -- wartość domyślna W procedurach i podprogramach moŝemy równieŝ korzystać ze zmiennych, które są pomocnicze do zapamiętywania wyników naszych obliczeń. Deklaracja wygląda tak: variable nazwa_zmiennej : typ_zmiennej Wartość domyślną oraz ograniczenie tworzymy tak samo jak w przypadku sygnałów. MoŜemy równieŝ stosować wartości stałe, a ich deklaracja wygląda następująco: constant nazwa_stałej : typ_stałej :=wyraŝenie Do przechowywania danych mogą słuŝyć pliki, ich deklaracja to: file nazwa_pliku : typ_danych [open tryb] is nazwa_pliku ; 2.1.4. TYPY W VHDL u Spis typów języka VHDL. TYP OPIS bit Wartość logiczna 0 lub 1 boolean Logiczna prawda lub fałsz integer Liczby całkowite natural Liczby naturalne positive Liczby naturalne z wyjątkiem zera real Liczby rzeczywiste std_ulogic i std_logic Typy wielowartościowe dzięki którym moŝemy np. opisać stan wysokiej impedancji, stan niezainicjowany czy tez dowolny character Znaki ze zbioru ASCII time Czas, zakres od 0 do 2147483647 i jednostki: fs, ps, ns, us, ms, sec, min, hr string Deklaruje ciągi znaków UŜytkownik moŝe deklarować własne typy: Wyliczeniowe (wypisanie kolejno elementów) np. type wyliczeniowy is (1,3,5,7,9); ZłoŜone (odpowiednik tablicy w innych językach) np. type złoŝony is array(0 to 7) of bit; signal a : bit_vector(0 to 3);
Podtypy (ograniczenie zakresu typów) np. subtype liczby is integer range 0 to 12; 2.1.5. OPERATORY W VHDL u Lista operatorów stosowanych w języku. OPERATOR OPIS Operatory logiczne not Negacja wartości logicznej and Iloczyn logiczny nand Zanegowany iloczyn logiczny or Suma logiczna nor Zanegowana suma logiczna xor Prawda gdy sygnały róŝnych wartości Xnor Negacja xor Operatory arytmetyczne + Arytmetyczne dodawanie - Arytmetyczne odejmowanie * MnoŜenie / Dzielenie & Sklejanie mod Obliczanie modułu rem Reszta z dzielenia Operatory relacji = Rowność /= Nierówność < Mniejszy > Większy <= Mniejszy bądź równy >= Większy bądź równy Operatory przesunięcia sll Przesuwa słowo logiczne w lewo, puste miejsca wypełniają się zerami srl Przesuwa słowo logiczne w prawo, puste miejsca wypełniają się zerami sla Przesuwa słowo logiczne w lewo, puste miejsca wypełniają się jedynkami sra Przesuwa słowo logiczne w prawo, puste miejsca wypełniają się jedynkami rol Przesuwa słowo logiczne w lewo do okoła, ostatni bit staje się pierwszym ror Przesuwa słowo logiczne w prawo do okoła, pierwszy bit staje się ostatnim RoŜne abs Liczy wartość bezwzględną ** Potęgowanie + Określenie znaku wartości - Określenie znaku wartości
2.2. IMPLEMENTACJA PROJEKTU. Schemat projektu moŝemy przedstawić następująco: Rys. 2.1 Schemat blokowy układu do pomiaru czasu trwania impulsu elektrycznego. Układ umoŝliwia da sposoby pomiaru: 1) pomiar tylko jednego impulsu 2) pomiar czasu impulsów następujących po sobie Jak widać układ składa się pojedynczych bloków, które najpierw oddzielnie opisze w języku VHDL, a następnie połączę wykorzystując moŝliwości tego języka. Jest to tzw. programowanie strukturalne. Pierwszym blokiem, który opisze będzie układ wejściowy odpowiadający za kierowanie zliczaniem impulsów zegarowych. Dzięki niemu moŝemy wybrać rodzaj pracy dla naszego urządzenia. W programie jest to zrobione w ten sposób, Ŝe jeŝeli sygnał zewnętrzny: sposób jest równy 1 to mierzymy czas wszystkich następujących po sobie impulsów i wyświetlamy zmierzone czasy na na wyświetlaczu(po kaŝdym zboczu opadającym). A jeŝeli sposob
równa się 0 to układ zlicza czas tylko jednego impulsu a jego zbocze opadające powoduje jego wyświetlenie na wyświetlaczu i zablokowanie dalszego zliczania. PoniŜej przedstawiam kod opisywanego bloku. entity poczatek is Port ( C : in std_logic; sygnal : in std_logic; sposob : in std_logic; wyjs : out std_logic); end poczatek; architecture Behavioral of poczatek is signal a : std_logic := '1'; begin process(sposob,sygnal) begin if sposob = '1' then a <= '1'; elsif sposob = '0' then if falling_edge(sygnal) then a <= '0'; end if; end if; end process; wyjs <= C when (a and sygnal) = '1' else '0'; end Behavioral; W kolejnym kroku omówię serce całego projektu to znaczy licznik. Składa się on z 6 liczników liczących w kodzie BCD. Dzięki tej jednostce pokaŝe sposób łączenia małych programów (komponentów) w większe bardziej złoŝone projekty. W tym celu zaimplementowałem pojedynczy licznik: entity licznikbcd is Port ( zegar : in std_logic; reset : in std_logic; przen : out std_logic; wyjscie : out std_logic_vector(3 downto 0) ); end licznikbcd; architecture Behavioral of licznikbcd is
begin process(zegar,reset) variable zmien_pom : unsigned(3 downto 0); begin if reset = '1' then zmien_pom := "0000"; elsif rising_edge(zegar) then if zmien_pom < 9 then zmien_pom := zmien_pom + 1; przen <= '0'; else zmien_pom := "0000"; przen <= '1'; end if; end if; wyjscie <= std_logic_vector(zmien_pom); end process; end Behavioral; Liczni ten posiada 2 wejścia : zegar i reset oraz 2 wyjścia : przen i wyjscie, które jest wektorem 4-ro bitowym. W procesie wykorzystujemy zmienną pomocniczą : zmien_pom. Układ reaguje na zbocze rosnące zegara(funkcja rising_edge(zegar)), gdy je wykryje to zwiększa nasza zmienną pomocniczą o 1 i tak do 9. Jeśli licznik zliczy 9 impulsów to następne pojawia się na nim 0 i równocześnie jest podawany sygnał przeniesienia. Sygnał przeniesienia generowany w danym liczniku jest podawany na następny jako sygnał zegarowy i tak oto uzyskujemy kolejną liczbę do wyświetlenia na naszym wyświetlaczu. Aby to jednak połączyć musimy napisać poniŝszy program: entity licz_zlozony is Port ( zeg : in std_logic; res : in std_logic; wyj1 : out std_logic_vector(3 downto 0); wyj2 : out std_logic_vector(3 downto 0); wyj3 : out std_logic_vector(3 downto 0); wyj4 : out std_logic_vector(3 downto 0); wyj5 : out std_logic_vector(3 downto 0); wyj6 : out std_logic_vector(3 downto 0)); end licz_zlozony; architecture gotowe of licz_zlozony is COMPONENT licznikbcd PORT( zegar : IN std_logic; reset : IN std_logic; przen : OUT std_logic;
wyjscie : OUT std_logic_vector(3 downto 0) ); END COMPONENT; signal a,b,c,d,e,f : std_logic; begin g1: licznikbcd port map (zeg,res,a,wyj1); g2: licznikbcd port map (a,res,b,wyj2); g3: licznikbcd port map (b,res,c,wyj3); g4: licznikbcd port map (c,res,d,wyj4); g5: licznikbcd port map (d,res,e,wyj5); g6: licznikbcd port map (e,res,f,wyj6); end gotowe; Program ten przy pomocy komponentów odwołuje się do programu licznikbcd i łączy ze sobą 6 takich pojedynczych liczników, w sposób pokazany na poniŝszym rysunku. zegar reset przen zegar przen wyj1 wyj2 zegar przen wyj3 zegar przen wyj4 zegar przen wyj5 zegar wyj6 Rys. 2.2 Sposób połączenia licznika. KaŜdy komponent to jakby jeden wewnętrzny bloczek. Do ich połączenia uŝywamy pomocniczych sygnałów wewnętrznych: a, b, c, d, e, f, oraz specjalnej procedury : G1: licznikbcd port map (zeg,res,a,wyj1); Dzięki temu poleceniu moŝemy łatwo przypisać sygnały wejściowe i wyjściowe do odpowiednich komponentów, co daje nam połączenie ich w jeden większy program
Mógłbym opisać tu wszystkie bloki, jakie znajdują się w głównym rysunku, takie jak: zatrzask, dekoder, dzielnik czy wyświetlanie, jednakŝe zajęłoby wiele czasu, a nie oto tu chodzi. Myślę, Ŝe w przedstawionym przeze mnie materiale ukazałem podstawową architekturę i sposób projektowania. Na zakończenie podam tylko kod do głównego programu, który scala wszystkie bloki z Rys.2.1 w jedną całość. Korzystałem tu równieŝ z komponentów. entity pomiar_czasu is Port ( zegar : in std_logic; sygnal : in std_logic; sposob : in std_logic; reset : in std_logic; led : out std_logic_vector(6 downto 0); wyswietlacz : out std_logic_vector(5 downto 0)); end pomiar_czasu; architecture gotowa of pomiar_czasu is COMPONENT poczatek PORT( C : IN std_logic; sygnal : IN std_logic; sposob : IN std_logic; wyjs : OUT std_logic ); END COMPONENT; COMPONENT licz_zlozony PORT( zeg : IN std_logic; res : IN std_logic; wyj1 : OUT std_logic_vector(3 downto 0); wyj2 : OUT std_logic_vector(3 downto 0); wyj3 : OUT std_logic_vector(3 downto 0); wyj4 : OUT std_logic_vector(3 downto 0); wyj5 : OUT std_logic_vector(3 downto 0); wyj6 : OUT std_logic_vector(3 downto 0) ); END COMPONENT; COMPONENT zatrzask PORT( syg : IN std_logic; we1 : IN std_logic_vector(3 downto 0); we2 : IN std_logic_vector(3 downto 0); we3 : IN std_logic_vector(3 downto 0); we4 : IN std_logic_vector(3 downto 0); we5 : IN std_logic_vector(3 downto 0); we6 : IN std_logic_vector(3 downto 0); wy1 : OUT std_logic_vector(3 downto 0);
wy2 : OUT std_logic_vector(3 downto 0); wy3 : OUT std_logic_vector(3 downto 0); wy4 : OUT std_logic_vector(3 downto 0); wy5 : OUT std_logic_vector(3 downto 0); wy6 : OUT std_logic_vector(3 downto 0) ); END COMPONENT; COMPONENT dekoder_zlozony PORT( we1 : IN std_logic_vector(3 downto 0); we2 : IN std_logic_vector(3 downto 0); we3 : IN std_logic_vector(3 downto 0); we4 : IN std_logic_vector(3 downto 0); we5 : IN std_logic_vector(3 downto 0); we6 : IN std_logic_vector(3 downto 0); seg1 : OUT std_logic_vector(6 downto 0); seg2 : OUT std_logic_vector(6 downto 0); seg3 : OUT std_logic_vector(6 downto 0); seg4 : OUT std_logic_vector(6 downto 0); seg5 : OUT std_logic_vector(6 downto 0); seg6 : OUT std_logic_vector(6 downto 0) ); END COMPONENT; COMPONENT wyswietlanie PORT( zegar : IN std_logic; we1 : IN std_logic_vector(6 downto 0); we2 : IN std_logic_vector(6 downto 0); we3 : IN std_logic_vector(6 downto 0); we4 : IN std_logic_vector(6 downto 0); we5 : IN std_logic_vector(6 downto 0); we6 : IN std_logic_vector(6 downto 0); wyjs : OUT std_logic_vector(6 downto 0); wy : OUT std_logic_vector(5 downto 0) ); END COMPONENT; COMPONENT dzielnik PORT( zegar : IN std_logic; podzielony : OUT std_logic ); END COMPONENT; signal a,multip : std_logic; signal b1,b2,b3,b4,b5,b6 : std_logic_vector(3 downto 0); signal c1,c2,c3,c4,c5,c6 : std_logic_vector(3 downto 0); signal d1,d2,d3,d4,d5,d6 : std_logic_vector(6 downto 0);
begin g1: poczatek port map (zegar,sygnal,sposob,a); g2: licz_zlozony port map (a,reset,b1,b2,b3,b4,b5,b6); g3: zatrzask port map (sygnal,b1,b2,b3,b4,b5,b6,c1,c2,c3,c4,c5,c6); g4: dekoder_zlozony port map (c1,c2,c3,c4,c5,c6,d1,d2,d3,d4,d5,d6); g5: dzielnik port map (zegar,multip); g6: wyswietlanie port map (multip,d1,d2,d3,d4,d5,d6,led,wyswietlacz); end gotowa; Dla zainteresowanych polecam ksiąŝkę umieszczoną pod pozycją numer [3] w literaturze, gdyŝ zawiera ona wiele ciekawych przykładów. LITERATURA [1] Karkowski Zdzisław, Miernictwo elektroniczne, WSiP, Warszawa 1982. [2] Pieńkoś Jan, Turczyński Janusz, Układy scalone TTL w systemach cyfrowych, WKŁ, Warszawa 1986. [3] Mark Zwoliński, z jęz. ang. przeł. Marian Adamski, Marek Węgrzyn, Zbigniew Skowroński Projektowanie układów cyfrowych z wykorzystaniem języka VHDL.WKŁ, Warszawa 2002.