library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity main is Port ( CLK : in std_logic; sio_rxd : in std_logic; -- serieller Eingang sio_txd : out std_logic; -- serieller Ausgang MI : out std_logic := '0'; -- Sendeleitung DD : in std_logic; -- Empfangsleitung CD : in std_logic; -- Träger-Erkennung sw : in std_logic_vector(8 downto 1); RS : out std_logic := '0'; -- Switch um Sendeleitung zu aktivieren led: out std_logic_vector(15 downto 0) ); end main; architecture Behavioral of main is constant Baud : POSITIVE := 434; -- Taktteilerwert für 115200 Bps constant praeambel : std_logic_vector(16 downto 1) := "1011001111000010"; constant Counts : NATURAL := 50; -- bewirkt 1 MHz "Takt" signal Q : NATURAL := 0; -- Zähler für Taktteiler signal Takt_100kHz : std_logic := '0'; -- 100 kHz Signal signal encode : std_logic_vector(16 downto 1); -- SW in halber Manchaster-Codierung signal sendeposition : POSITIVE := 16; -- mit diesem Zeiger wird der sendecode abgearbeitet constant lead_in_timer_default : NATURAL := 300; signal lead_in_timer : NATURAL := 300; -- ergibt 3ms im 100 kbit Strom signal Input_Stream: std_logic_vector(47 downto 1); -- Empfangscode ohne aktuellstes (Input-)Bit signal von_aurel: std_logic_vector(8 downto 1) := "00000000"; -- Empfangs PayLoad vorm Speicher signal to_pc: std_logic_vector(8 downto 1) := "00000000"; -- Empfangs PayLoad nach dem Speicher signal rcv_ram_in_flag : std_logic := '0'; signal rcv_ram_empty : std_logic := '0'; signal rcv_ram_next : std_logic := '0'; signal von_pc : std_logic_vector(8 downto 1) := "00000000"; -- Sende PayLoad vorm Speicher signal to_aurel : std_logic_vector(8 downto 1) := "00000000"; -- Sende PayLoad nach dem Speicher signal send_ram_in_flag : std_logic := '0'; signal send_ram_empty : std_logic := '0'; signal send_ram_next : std_logic := '0'; signal DigitalData: std_logic; signal einMHzTakt: std_logic; signal Input: std_logic; signal Input_Error: std_logic; signal Takt: std_logic; signal is_prae1: std_logic; signal is_prae2: std_logic; signal Input_Byte: std_logic_vector(8 downto 1); signal Dec_Error: std_logic; --###################################### -- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< --###################################### component TP is -- Counts Takte werden Einsen und Nullen gesammelt. -- Wer am Ende überwiegt, bestimmt dann die Ausgabe von Output. Port ( CLK: in std_logic; Counts: in NATURAL; Input: in std_logic; Takt: out std_logic; Output: out std_logic ); end component; component Takterkennung is Port ( CLK: in std_logic; In_Takt: in std_logic; Input: in std_logic; CD: in std_logic; Out_Takt: out std_logic; Output: out std_logic; Error: out std_logic ); end component; component is_praeambel is Port ( Input: in std_logic_vector(16 downto 1); Praeambel: in std_logic_vector(16 downto 1); Output: out std_logic ); end component; component encod is Port ( input: in std_logic_vector(8 downto 1); output: out std_logic_vector(16 downto 1) ); end component; component decod is Port ( Input1: in std_logic_vector(15 downto 1); Input2: in std_logic; Output: out std_logic_vector(8 downto 1); Error: out std_logic ); end component; component speicher_klein is Port ( CLK: in std_logic; input: in std_logic_vector(8 downto 1); -- Daten in den Ringspeicher input_flag: in std_logic; -- Wenn hier eine Flanke auftritt, wird der input Wert im Speicher abgelegt output: out std_logic_vector(8 downto 1); -- Daten vom Ringspeicher empty_flag: out std_logic := '1'; -- Wenn der Speicher leer ist steht dieses Flag auf 1 next_flag: in std_logic -- Wenn hier eine Flanke auftritt, wird ein neuer Wert auf output gelegt ); end component; component speicher_gross is Port ( CLK: in std_logic; input: in std_logic_vector(8 downto 1); -- Daten in den Ringspeicher input_flag: in std_logic; -- Wenn hier eine Flanke auftritt, wird der input Wert im Speicher abgelegt output: out std_logic_vector(8 downto 1); -- Daten vom Ringspeicher empty_flag: out std_logic := '1'; -- Wenn der Speicher leer ist steht dieses Flag auf 1 next_flag: in std_logic -- Wenn hier eine Flanke auftritt, wird ein neuer Wert auf output gelegt ); end component; component rs232_in is Port ( CLK: in std_logic; output: out std_logic_vector(8 downto 1); out_flag: out std_logic; Baud : in POSITIVE; sio_rxd: in std_logic ); end component; component rs232_out is Port ( CLK: in std_logic; input: in std_logic_vector(8 downto 1); empty_flag: in std_logic := '0'; next_flag: out std_logic := '0'; Baud : in POSITIVE; -- Taktteilerwert für Bps sio_txd: out std_logic ); end component; --###################################### -- <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< --###################################### begin einMHzTP : TP port map ( CLK => CLK, Counts => Counts, Input => DD, Takt => einMHzTakt, Output => DigitalData ); Takt_1 : Takterkennung port map ( CLK => CLK, In_Takt => einMHzTakt, Input => DigitalData, CD => CD, Out_Takt => Takt, Output => Input, Error => Input_Error ); Prae_check_part1 : is_praeambel port map ( Input => Input_Stream(31 downto 16), Praeambel => praeambel, Output => is_prae1 ); Prae_check_part2 : is_praeambel port map ( Input => Input_Stream(47 downto 32), Praeambel => praeambel, Output => is_prae2 ); Encoder : encod port map ( Input => to_aurel, Output => encode ); Decoder : decod port map ( Input1 => Input_Stream(15 downto 1), Input2 => Input, Output => Input_Byte, Error => Dec_Error ); Sende_Speicher : speicher_gross port map ( CLK => CLK, input => von_pc, input_flag => send_ram_in_flag, output => to_aurel, empty_flag => send_ram_empty, next_flag => send_ram_next ); Empfangs_Speicher : speicher_klein port map ( CLK => CLK, input => von_aurel, input_flag => rcv_ram_in_flag, output => to_pc, empty_flag => rcv_ram_empty, next_flag => rcv_ram_next ); serial_in : rs232_in port map ( CLK => CLK, output => von_pc, out_flag => send_ram_in_flag, Baud => Baud, sio_rxd => sio_rxd ); serial_out : rs232_out port map ( CLK => CLK, input => to_pc, empty_flag => rcv_ram_empty, next_flag => rcv_ram_next, Baud => Baud, sio_txd => sio_txd ); --###################################### -- Taktteiler für 100kHz --###################################### process(CLK) begin if (CLK'event and (CLK='1')) then if (Q > 250) then Q <= 0; Takt_100kHz <= not Takt_100kHz; else Q <= Q + 1; end if; end if; end process; --###################################### -- Empfangs-Stream-Erkennung --###################################### process(CLK) variable Takt_helper : std_logic; -- Um eine Flanke der Bit-Erkennung als Trigger-Kriterium hier zu nutzen variable LEVEL1 : NATURAL := 17; variable LEVEL2 : NATURAL := 17; variable watch_takt : NATURAL := 0; variable counter : std_logic_vector(7 downto 0) := "00000000"; begin if (CLK'event and (CLK='1')) then -- sollte im Normalfall nicht gebraucht werden... if (watch_takt = 0) then watch_takt := 500; if (LEVEL2 > 0) then LEVEL2 := LEVEL2 - 1; end if; if (LEVEL1 > 0) then LEVEL1 := LEVEL1 - 1; end if; else watch_takt := watch_takt - 1; end if; if (Takt_helper /= Takt) AND (Input_Error = '0') then -- neues Bit ohne Fehler, da muß man was tun :-) watch_takt := 750; -- 1,5 Mal so lange, wie ein Bit if (LEVEL2 > 0) then LEVEL2 := LEVEL2 - 1; end if; if (LEVEL1 > 0) then LEVEL1 := LEVEL1 - 1; end if; -- Paeambel OK und Byte if (is_prae1 = '1') AND (is_prae2 = '1') AND (Dec_Error = '0') then von_aurel <= Input_Byte; rcv_ram_in_flag <= not rcv_ram_in_flag; LEVEL1 := 17; LEVEL2 := 0; -- counter := counter + 1; led(7 downto 0) <= counter; -- elsif (Dec_Error = '0') AND (LEVEL1 = 1) then von_aurel <= Input_Byte; rcv_ram_in_flag <= not rcv_ram_in_flag; LEVEL2 := 17; LEVEL1 := 0; elsif (Dec_Error = '0') AND (LEVEL2 = 1) then von_aurel <= Input_Byte; rcv_ram_in_flag <= not rcv_ram_in_flag; LEVEL2 := 17; end if; -- Schieberegister munter weiter füttern. Input_Stream <= Input_Stream(46 downto 1) & Input; end if; Takt_helper := Takt; end if; end process; --###################################### -- Byte per Funk senden --###################################### process(Takt_100kHz) variable busy : std_logic := '0'; variable prae : NATURAL := 32; variable prae_watch_dog : NATURAL := 0; variable praecode : std_logic_vector(32 downto 1); -- 2 Praeambeln variable sendecode : std_logic_vector(16 downto 1); -- 1 Byte variable lead_out : NATURAL := 200; variable counter : std_logic_vector(7 downto 0) := "00000000"; begin if (Takt_100kHz'event) and (Takt_100kHz='1') then -- Also 100.000 Mal pro Sekunde praecode := praeambel & praeambel; if (prae = 0) then -- Also eine Praeambel wurde vollständig versand if (prae_watch_dog > 0) then -- Es dürfen noch mehr als Null Bits ohne extra Praeambel versand werden prae_watch_dog := prae_watch_dog - 1; -- Das folgende Bit schonmal abziehen else prae := 32; -- Es ist eine neue Praeambel nötig. end if; end if; if (send_ram_empty = '0') or (busy = '1') then -- Wenn was im Speicher liegt, oder wir schon in medias res sind :-) RS <= '1'; -- Sender einschalten -- lead_out := 3; -- 2 volle Bits das Signal am Ende halten, Bit 3 sorgt dafür, daß Bit 2 auch wirklich sein Ziel erreicht lead_out := 3 + CONV_INTEGER(sw); -- Mehr ist besser ;-) -- Einschwingzeit if (lead_in_timer > 0) then -- if (lead_in_timer <= (lead_in_timer_default / 2) ) then -- Nur die Hälfte wird zur Glättung gefordert... MI <= CONV_STD_LOGIC_VECTOR(lead_in_timer,8)(0); -- end if; lead_in_timer <= lead_in_timer - 1; -- Praeambel senden elsif (prae > 0) then prae_watch_dog := 1; -- Damit uns der Hund nicht beim Praeambelsenden festhält... if (prae = 1) then send_ram_next <= not send_ram_next; -- Frisches Byte aus dem Speicher anfordern sendeposition <= 16; -- Lesezeiger auf Start busy := '1'; -- counter := counter + 1; led(15 downto 8) <= counter; -- end if; MI <= praecode(prae); prae := prae - 1; -- Erstes Bit des Sendecodes elsif (sendeposition = 16) then -- beim ersten Bit den Code zusammenbauen sendecode := encode; -- Sendecode zusammensetzen if (prae_watch_dog = 0) then prae_watch_dog := 15 + ( 16 * CONV_INTEGER(to_aurel) ); -- prae_watch_dog := 11; -- also bei jedem Zeichen eine Praeambel. -- prae_watch_dog := 11 + CONV_INTEGER(sw); end if; MI <= sendecode(sendeposition); -- Erstes Bit senden sendeposition <= sendeposition - 1; -- Lesezeiger einen weiter schieben -- Letztes Bit des Sendecodes elsif (sendeposition = 1) then MI <= sendecode(sendeposition); -- letztes Bit senden if (send_ram_empty = '0') and (prae_watch_dog > 0) then -- wenn weitere Daten im Speicher vorliegen send_ram_next <= not send_ram_next; -- Frisches Byte aus dem Speicher anfordern sendeposition <= 16; -- Lesezeiger auf Start busy := '1'; else busy := '0'; -- In Bereitschaftsmodus wechseln end if; -- Übertragung, also mitten im Sendecode else MI <= sendecode(sendeposition); -- Bit senden sendeposition <= sendeposition - 1; -- Lesezeiger einen weiter schieben end if; else -- Also gerade nichts zu übertragen... if (lead_out > 0) then lead_out := lead_out - 1; else RS <= '0'; -- Auf Empfangsmodus gehen (Sender aus) lead_in_timer <= lead_in_timer_default; end if; prae := 32; end if; end if; end process; end Behavioral;