Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

Dekodowanie alfabetu Morse 'a

mazur_vhdl
-
-
Posty:2
Rejestracja:10 sty 2008, o 18:32
Lokalizacja:Poznań
Dekodowanie alfabetu Morse 'a

Postautor: mazur_vhdl » 10 sty 2008, o 18:49

Mam problem z projektem zaliczeniowym. Program ma dekodowac litery w kodzie
morse'a i podawac na wyswietlacze ich numery alfabetu. Zczytane litery sa
przechowywane w 4-bitowym wektorze logicznym. Rozpoznawanie kropki badz
kreski odbywa sie poprzez porownanie czasu przytrzymania KEY3. Gdy uplynie
odpowiednia ilosc wolnych taktow, wektor logiczny jest zamieniany na liczbe
calkowita i wyswietlany powinien zostac odpowiedni numer litery.

Oryginalan treśc mojego zadania:
Dekodowanie alfabetu Morsa. Należy napisać program który zdekoduje litery podawane za pomocą sygnału morsa (podawanie sygnałów będzie polegało na wciskaniu przycisków odpowiednio długo z odpowiednimi przerwami) i wyświetli na wyświetlaczu co za litera została nadana. Ze względu na fakt że na wyświetlaczu 7-segmentowym trudno reprezentować w sposób rozróżnialny wszystkie litery alfabetu wystarczy że zostanie podany numer litery lub inna reprezentacja pozwalająca odróżnić poszczególne znaki.

Mój kod wygląda następująco:

Kod: Zaznacz cały

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.NUMERIC_STD.ALL; entity morse_code is port ( CLOCK_50 : IN STD_LOGIC; KEY3: IN STD_LOGIC; -- klawisz glowny KEY2: IN STD_LOGIC; -- klawisz do kasowania HEX5: OUT STD_LOGIC_VECTOR(0 TO 6); -- wyswietlacz dziesiatek HEX4: OUT STD_LOGIC_VECTOR(0 TO 6) -- wyswietlacz jednosci ); end morse_code; architecture Behavioral of morse_code is signal licznik_wolnych_taktow: integer; -- licznik taktow gdy button jest zwolniony, w celu rozpoznania konca litery signal licznik_taktow: integer; -- licznik biezacych taktow pomiedzy akcjami na buttonie (przycisnieciem a zwolnieniem) signal zmierzone_wolne_takty: integer; -- licznik do porownan signal zmierzone_takty: integer; -- licznik do porownan signal litera : STD_LOGIC_VECTOR(0 TO 3); -- wcisnieta litera signal litera_int: integer; -- litera po konwersji signal litera_alf: integer; -- numer litery po konwersji w alfabecie signal indeks: integer; -- indeks aktualnej pozycji w wektorze bitowym dla litery signal liczba_gotowa: integer; -- OGOLNE ZALOZENIA: -- Kropka (sygnal trwajacy 0 sek - 1 sek) jest interpretowana jako 1 -- Kreska (sygnal trwajacy 1 sek - 2 sek) jest interpretowana jako 0 -- Sygnal dluzszy od 2 sek oznacza przerwe miedzy literami -- Gdy wciskamy przycisk zostaje mierzony czas do jego zwolnienia. -- Nastepnie na odpowiednim miejscu (indeks) wektora bitowego zostaje dopisane 0 lub 1 -- Jesli przez odpowiednio dlugi okres czasu (licznik_wolnych_taktow przekroczy wartosc 100 000) button nie zostanie wcisniety, liczba zostaje uznana za skonczona -- moze wystarczy rozbic proces glowny na 2 procesy??? --process (clock_50) is --begin --end process; --process (KEY3) is --begin --end process; begin -- PROCES LICZACY TAKTY process (clock_50) is begin -- ZLICZANIE TAKTOW ZEGARA if clock_50'event and clock_50 = '1' then licznik_taktow <= licznik_taktow + 1; licznik_wolnych_taktow <= licznik_wolnych_taktow + 1; end if; end process; -- ############################################################################### -- PROCES DLA PRZYCISKU process (KEY3) is begin --licznik_wolnych_taktow <= 0; -- SPRAWDZANIE STANU PRZYCISKU - wciskanie if KEY3'event and KEY3 = '1' then licznik_taktow <= 0; -- SPRAWDZANIE STANU PRZYCISKU - zwalnianie elsif KEY3'event and KEY3 = '0' then zmierzone_takty <= licznik_taktow; -- SYNTEZA LICZBY - dopisywanie kropek - 1 if zmierzone_takty>1 and zmierzone_takty<50000 then if indeks = 0 then litera <= litera or "1000"; end if; if indeks = 1 then litera <= litera or "0100"; end if; if indeks = 2 then litera <= litera or "0010"; end if; if indeks = 3 then litera <= litera or "0001"; end if; end if; -- SYNTEZA LICZBY - dopisywanie kresek - 0 -- elsif zmierzone_takty>50000 and zmierzone_takty<100000 then -- nic sie nie dzieje, po prostu zwiekszony bedzie indeks a na miejscu kreski zostanie 0 indeks <= indeks + 1; -- INTERPRETOWANIE LITERY (jej nr) I WYSWIETLANIE JEJ - gdy uplyna minimum 2 sekundy if licznik_wolnych_taktow>100000 OR indeks = 4 then liczba_gotowa <= 1; else liczba_gotowa <= 0; end if; end if; end process; -- ############################################################################### -- PROCES WYSWIETLAJACY LICZBE process (liczba_gotowa) is begin if liczba_gotowa = 1 then -- tylko dla pojawienia sie nowej gotowej liczby -- konwersja wektora bitowego opisujacego liczbe na wartosc calkowita do porownan litera_int <= CONV_INTEGER(litera); -- konwersja z powyzszej wartosci na wartosc odpowiadajaca numerze litery w alfabecie -- w zasadzie ten etap moglby zostac wyeliminowany poprzez modyfikacje nastepnego case'a, ale w ten sposob zachowujemy wieksza czytelnosc if litera_int = 8 and indeks = 2 then litera_alf <= 1; end if; if litera_int = 15 and indeks = 4 then litera_alf <= 2; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 3; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 4; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 5; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 6; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 7; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 8; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 9; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 10; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 11; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 12; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 13; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 14; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 15; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 16; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 17; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 18; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 19; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 20; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 21; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 22; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 23; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 24; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 25; end if; if litera_int = 1 and indeks = 1 then litera_alf <= 26; end if; -- wypisywanie na wyswietlacze case litera_alf is when 1 => HEX4 <= "1001111"; -- A when 2 => HEX4 <= "0010010"; -- B when 3 => HEX4 <= "0000110"; -- C when 4 => HEX4 <= "1001100"; -- D when 5 => HEX4 <= "0100100"; -- E when 6 => HEX4 <= "0100000"; -- F when 7 => HEX4 <= "0001111"; -- G when 8 => HEX4 <= "0000000"; -- H when 9 => HEX4 <= "0000100"; -- I when 10 =>HEX4 <= "0000001"; -- J -- 1: "1001111" when 11 => HEX4 <= "1001111"; -- K when 12 => HEX4 <= "0010010"; -- L when 13 => HEX4 <= "0000110"; -- M when 14 => HEX4 <= "1001100"; -- N when 15 => HEX4 <= "0100100"; -- O when 16 => HEX4 <= "0100000"; -- P when 17 => HEX4 <= "0001111"; -- Q when 18 => HEX4 <= "0000000"; -- R when 19 => HEX4 <= "0000100"; -- S when 20 => HEX4 <= "0000001"; -- T -- 2: "0010010" when 21 => HEX4 <= "1001111"; -- U when 22 => HEX4 <= "0010010"; -- V when 23 => HEX4 <= "0000110"; -- W when 24 => HEX4 <= "1001100"; -- X when 25 => HEX4 <= "0100100"; -- Y when 26 => HEX4 <= "0100000"; -- Z when others => HEX4 <= "0000001"; -- '0' gdy nie rozpoznano litery end case; --zerowanie aby mozna bylo dekodowac nastepna litere indeks <= 0; zmierzone_takty <= 0; liczba_gotowa <= 0; end if; end process; -- ############################################################################### -- PROCES KASUJACY WSZYSTKO process (KEY2) is begin if KEY2'event and KEY2 = '1' then HEX4 <= "0000001"; HEX5 <= "0000001"; indeks <= 0; litera <= "0000"; liczba_gotowa <= 0; end if; end process; -- ############################################################################### end Behavioral;
Niestety nie umiem tego doprowadzic do dzialania... Wciaz dostaje bledy
roznego typu (kompiluje w Quartus II). Bardzo prosze o pomoc :)

rafszym
-
-
Posty:44
Rejestracja:4 gru 2007, o 12:39
Lokalizacja:Warszawa

Postautor: rafszym » 11 sty 2008, o 15:00

heja,

na pierwszy rzut oka mam kilka uwag do kodu VHDL:

1. w jednym procesie może byc tylko jedna detekcja zbocza (narastającego lub opadającego), a w procesie "process(KEY3) is..." są dwa zapisy "KEY3'event and KEY3 = '1'.." oraz "KEY3'event and KEY3 = '0'..."

2. proces "-- PROCES KASUJACY WSZYSTKO..." - nie można w kilku różnych procesach podstawiać dane do tych samych zmiennych lub sygnałów, ponadto w tym procesie detektujesz zbocze narastajace KEY2 - to powoduje tworzenie przerzutnika a nie kasowanie zawartych zmiennych, kasowanie/ustawianie robimy TYLKO poziomem czyli bez 'event

3. w konwersji z litera_int na litera_alf używasz if..then..endif, brakuje else, w Twoim zapisie generowane są przez kompilator przerzutniki typu latch (zatrzask), proponuje użyć instrukcji case oczywiście z ostatnim wierszem "when others=>..." aby nie było zatrzasków

pozrd,

rafszym

Awatar użytkownika
pajaczek
Moderator
Moderator
Posty:2653
Rejestracja:24 sty 2005, o 00:39
Lokalizacja:Winny gród

Postautor: pajaczek » 11 sty 2008, o 19:30

1. w jednym procesie może byc tylko jedna detekcja zbocza (narastającego lub opadającego), a w procesie "process(KEY3) is..." są dwa zapisy "KEY3'event and KEY3 = '1'.." oraz "KEY3'event and KEY3 = '0'..."
Dodajmy , ze jest to wymog nie tyle jezyka VHDL co jego syntezowalnego podzbioru. Nie myle sie ??
2. proces "-- PROCES KASUJACY WSZYSTKO..." - nie można w kilku różnych procesach podstawiać dane do tych samych zmiennych lub sygnałów
I tu w podobnej formie ("o ile sie nie myle")... mozna bylo by podstawiac, o ile sygnal mialby funkcje rezolucji...

mazur_vhdl
-
-
Posty:2
Rejestracja:10 sty 2008, o 18:32
Lokalizacja:Poznań

Postautor: mazur_vhdl » 11 sty 2008, o 20:25

Bardzo dziekuje za dotychczasowe odpowiedzi :611:

Uwzglednilem Wasze sugestie i doprowadzilem kod do nastepujacej postaci:

Kod: Zaznacz cały

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.NUMERIC_STD.ALL; entity morse_code is port ( CLOCK_50 : IN STD_LOGIC; KEY3: IN STD_LOGIC; -- klawisz glowny KEY2: IN STD_LOGIC; -- klawisz do kasowania HEX5: OUT STD_LOGIC_VECTOR(0 TO 6); -- wyswietlacz dziesiatek HEX4: OUT STD_LOGIC_VECTOR(0 TO 6) -- wyswietlacz jednosci ); end morse_code; architecture Behavioral of morse_code is signal licznik_wolnych_taktow: integer; -- licznik taktow gdy button jest zwolniony, w celu rozpoznania konca litery signal licznik_taktow: integer; -- licznik biezacych taktow pomiedzy akcjami na buttonie (przycisnieciem a zwolnieniem) signal zmierzone_wolne_takty: integer; -- licznik do porownan signal zmierzone_takty: integer; -- licznik do porownan signal litera : STD_LOGIC_VECTOR(0 TO 3); -- wcisnieta litera signal litera_int: integer; -- litera po konwersji signal litera_alf: integer; -- numer litery po konwersji w alfabecie signal indeks: integer; -- indeks aktualnej pozycji w wektorze bitowym dla litery signal indeks_gotowy: integer; signal liczba_gotowa: integer; -- OGOLNE ZALOZENIA: -- Kropka (sygnal trwajacy 0 sek - 1 sek) jest interpretowana jako 1 -- Kreska (sygnal trwajacy 1 sek - 2 sek) jest interpretowana jako 0 -- Sygnal dluzszy od 2 sek oznacza przerwe miedzy literami -- Gdy wciskamy przycisk zostaje mierzony czas do jego zwolnienia. -- Nastepnie na odpowiednim miejscu (indeks) wektora bitowego zostaje dopisane 0 lub 1 -- Jesli przez odpowiednio dlugi okres czasu (licznik_wolnych_taktow przekroczy wartosc 100 000) button nie zostanie wcisniety, liczba zostaje uznana za skonczona begin -- PROCES GLOWNY - liczenie taktow, obsluga przyciskow process (clock_50) is variable staryK: std_logic := '0'; begin -- ZLICZANIE TAKTOW ZEGARA if clock_50'event and clock_50 = '1' then -- SPRAWDZANIE STANU PRZYCISKU - wciskanie if KEY3 = '1' and staryK = '0' then licznik_wolnych_taktow <= 0; -- SPRAWDZANIE STANU PRZYCISKU - zwalnianie elsif KEY3 = '0' and staryK='1' then zmierzone_takty <= licznik_taktow; -- SYNTEZA LICZBY - dopisywanie kropek - 1 if zmierzone_takty>1 and zmierzone_takty<50000 then if indeks = 0 then litera <= litera or "1000"; end if; if indeks = 1 then litera <= litera or "0100"; end if; if indeks = 2 then litera <= litera or "0010"; end if; if indeks = 3 then litera <= litera or "0001"; end if; end if; -- SYNTEZA LICZBY - dopisywanie kresek - 0 -- po prostu zwiekszamy indeks indeks <= indeks + 1; -- INTERPRETOWANIE LITERY (jej nr) I WYSWIETLANIE JEJ - gdy uplyna minimum 2 sekundy if licznik_wolnych_taktow>100000 OR indeks = 4 then indeks_gotowy <= indeks; -- konwersja wektora bitowego opisujacego liczbe na wartosc calkowita do porownan litera_int <= CONV_INTEGER(litera); -- zerowanie zmiennych aby mozna bylo dekodowac nastepna litere indeks <= 0; litera <= "0000"; zmierzone_takty <= 0; liczba_gotowa <= 1; else liczba_gotowa <= 0; end if; -- ZWYKLY TAKT ZEGARA - BEZ AKCJI NA PRZYCISKU else licznik_taktow <= licznik_taktow + 1; licznik_wolnych_taktow <= licznik_wolnych_taktow + 1; end if; staryK := KEY3; end if; end process; -- ############################################################################### -- PROCES WYSWIETLAJACY LICZBE process (liczba_gotowa, indeks_gotowy) is begin if liczba_gotowa = 1 then -- tylko dla pojawienia sie nowej gotowej liczby -- wartosc odpowiadajaca # litery w alfabecie if litera_int = 8 and indeks = 2 then litera_alf <= 1; end if; if litera_int = 7 and indeks = 4 then litera_alf <= 2; end if; if litera_int = 5 and indeks = 4 then litera_alf <= 3; end if; if litera_int = 6 and indeks = 3 then litera_alf <= 4; end if; if litera_int = 8 and indeks = 1 then litera_alf <= 5; end if; if litera_int = 13 and indeks = 4 then litera_alf <= 6; end if; if litera_int = 2 and indeks = 3 then litera_alf <= 7; end if; if litera_int = 15 and indeks = 4 then litera_alf <= 8; end if; if litera_int = 12 and indeks = 2 then litera_alf <= 9; end if; if litera_int = 8 and indeks = 4 then litera_alf <= 10; end if; if litera_int = 4 and indeks = 3 then litera_alf <= 11; end if; if litera_int = 11 and indeks = 4 then litera_alf <= 12; end if; if litera_int = 0 and indeks = 2 then litera_alf <= 13; end if; if litera_int = 4 and indeks = 2 then litera_alf <= 14; end if; if litera_int = 0 and indeks = 3 then litera_alf <= 15; end if; if litera_int = 9 and indeks = 4 then litera_alf <= 16; end if; if litera_int = 2 and indeks = 4 then litera_alf <= 17; end if; if litera_int = 10 and indeks = 3 then litera_alf <= 18; end if; if litera_int = 14 and indeks = 3 then litera_alf <= 19; end if; if litera_int = 0 and indeks = 1 then litera_alf <= 20; end if; if litera_int = 12 and indeks = 3 then litera_alf <= 21; end if; if litera_int = 14 and indeks = 4 then litera_alf <= 22; end if; if litera_int = 8 and indeks = 3 then litera_alf <= 23; end if; if litera_int = 6 and indeks = 4 then litera_alf <= 24; end if; if litera_int = 4 and indeks = 4 then litera_alf <= 25; end if; if litera_int = 3 and indeks = 4 then litera_alf <= 26; end if; -- wypisywanie na wyswietlacze case litera_alf is when 1 => HEX4 <= "1001111"; -- A when 2 => HEX4 <= "0010010"; -- B when 3 => HEX4 <= "0000110"; -- C when 4 => HEX4 <= "1001100"; -- D when 5 => HEX4 <= "0100100"; -- E when 6 => HEX4 <= "0100000"; -- F when 7 => HEX4 <= "0001111"; -- G when 8 => HEX4 <= "0000000"; -- H when 9 => HEX4 <= "0000100"; -- I when 10 =>HEX4 <= "0000001"; -- J -- 1: "1001111" when 11 => HEX4 <= "1001111"; -- K when 12 => HEX4 <= "0010010"; -- L when 13 => HEX4 <= "0000110"; -- M when 14 => HEX4 <= "1001100"; -- N when 15 => HEX4 <= "0100100"; -- O when 16 => HEX4 <= "0100000"; -- P when 17 => HEX4 <= "0001111"; -- Q when 18 => HEX4 <= "0000000"; -- R when 19 => HEX4 <= "0000100"; -- S when 20 => HEX4 <= "0000001"; -- T -- 2: "0010010" when 21 => HEX4 <= "1001111"; -- U when 22 => HEX4 <= "0010010"; -- V when 23 => HEX4 <= "0000110"; -- W when 24 => HEX4 <= "1001100"; -- X when 25 => HEX4 <= "0100100"; -- Y when 26 => HEX4 <= "0100000"; -- Z when others => HEX4 <= "0000001"; -- '0' gdy nie rozpoznano litery end case; end if; end process; -- ############################################################################### end Behavioral;
Zrezygnowalem z klawisza kasujacego wszystko, gdyz nie umiem tak naprawde obsluzyc jego akcji... Zakaz dostepu do tej samej zmiennej z kilku roznych miejsc jest dla mnie trudny do pojecia - podejscie calkowicie inne od programowania imperatywnego :629:


Nie wiem jak zamienic konstrukcje "if litera_int = x and indeks = y then litera_alf <= z; end if;" na case'a (tutaj wystepuja 2 warunki, a w case musi byc chyba 1?).

Mam tez problem z blokiem case w kodzie. Przykladowo we fragmencie:
when 11 => HEX4 <= "1001111"; chcialbym takze dolaczyc HEX5 <= "1001111"; ale nie wiem jak to "obudowac" :625:
Probowalem czegos takiego, niestety nie dziala:

Kod: Zaznacz cały

when 11 => begin HEX4 <= "1001111"; HEX5 <= "1001111"; end;
Bede wdzieczny za wszelkie rady :611:

rafszym
-
-
Posty:44
Rejestracja:4 gru 2007, o 12:39
Lokalizacja:Warszawa

Postautor: rafszym » 12 sty 2008, o 15:08

heja chłopy,

jeśli można to swoje uwagi będę umieszczał w miarę wolnego czasu...
oraz sorry za ewntualne błędy w opisach...


pajączek:
# funkcja rezolucji istnieje ale jak to zrobić z kilku wyjść cyfrowych :), ktoś powie dlaczego nie dać wyjść OC (otwarty kolektor) - jak na razie nie spotkałem fpga/cpld aby we wnętrzu dało się zrobić OC
# pewnie, że nie ma przerzutnika z dwoma osobnymi wejściami zegarowymi :)
ale... spróbuj zaprojektować dwukierunkowy licznik posiadający osobne wejścia zegarowe dla zliczania w góre UP i w dół DOWN, zakładamy że impulsy na wejściach UP i DOWN nie wystąpią w jednej chwili, :)
układ przyda się do ustawiania dowolnych danych wejściowych układu cyfrowego np. DDS, PWM :)

mazur_vhdl:
# można zapisać co się podoba w case:

Kod: Zaznacz cały

when 11 => HEX4 <= "1001111"; HEX5 <= "1001111";
albo dwa osobne case dla każdego sygnału, ale dużo pisaniny:

Kod: Zaznacz cały

case ... is when 11 => HEX4 <= "1001111"; ... when others =>...; end case

Kod: Zaznacz cały

case ... is when 11 => HEX5 <= "1001111"; ... when others =>...; end case
# konstrukcje "if litera_int = x and indeks = y then litera_alf <= z; end if;"
masz rację przeoczyłem istnienie dwoch warunków :), ja bym to zrobił tak:
wersja 1 - zagnieździć case

Kod: Zaznacz cały

case indeks is when 1 => case litera_int is when ... end case, when 2 => case litera_int is when ... end case, when 3 => case litera_int is when ... end case, when others => case litera_int is when ... end case, end case;
wersja 2 - zagnieździć if, ale dużo zasobów scalaka zabierze, ale najprościej przerobisz swój kod

Kod: Zaznacz cały

if litera_int = 8 and indeks = 2 then litera_alf <= 1; elsif litera_int = 7 and indeks = 4 then litera_alf <= 2; elsif litera_int = 5 and indeks = 4 then litera_alf <= 3; ... else litera_alf <= ...; -- cos wpisz aby nie było pamięci czyli latch'ów end if;
wersja 3 - zagnieździć case i if

Kod: Zaznacz cały

case indeks is when 1 => if litera_int=... then litera_alf<=...; elsif litera_int=... then litera_alf<=...; ... end if; when 2 => ... when 3 => ... when others => ... end case;
pzdr.

Wróć do „PLD/FPGA i inne zagadnienia techniki cyfrowej”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 86 gości