Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

So verwenden Sie eine Prozedur in einem Prozess in VHDL

Es ist möglich, externe Signale von einer Prozedur zu treiben. Solange sich das Signal im Geltungsbereich der Prozedur befindet, kann darauf lesend oder schreibend zugegriffen werden, auch wenn es nicht in der Parameterliste aufgeführt ist.

Prozeduren, die im deklarativen Bereich der Architektur deklariert sind, können keine externen Signale ansteuern. Dies liegt einfach daran, dass sich zur Kompilierzeit keine Signale in seinem Gültigkeitsbereich befinden. Eine innerhalb eines Prozesses deklarierte Prozedur hingegen hat Zugriff auf alle Signale, die der Prozess sehen kann.

Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.

Solche Prozeduren können zum Entstören von Algorithmen in Prozessen verwendet werden, in denen die gleichen Operationen mehrmals auftreten. Wir könnten ein normales Verfahren verwenden, bei dem alle Ein- und Ausgänge lokalen Signalen zugewiesen werden, wenn Sie es aufrufen, aber darum geht es nicht. Indem wir die Eingabe- und Ausgabesignale aus dem Prozeduraufruf weglassen, müssen wir weniger tippen und, was noch wichtiger ist, wir machen den Code lesbarer.

Stellen Sie sich einen Prozess vor, der ein komplexes Kommunikationsprotokoll implementiert. Es wäre viel einfacher, den Ausführungsablauf des Hauptalgorithmus zu verstehen, wenn einige Operationen durch Prozeduraufrufe wie RequestToSend() ersetzt würden oder SendAutorizationHeader() . Sie würden wissen, was diese Zeilen taten, indem Sie sich nur die Prozedurnamen ansahen.

Übung

Im vorherigen Tutorial haben wir unseren Finite-State-Machine-Code (FSM) vereinfacht, indem wir eine unreine Funktion verwendet haben. Wir fuhren die Counter Signal von der unreinen Funktion, und wir haben den Rückgabewert verwendet, um zu bestimmen, wann der Zustand geändert werden soll. Was aber, wenn wir die Zuweisung der State verschieben wollen Signal in die Funktion ein und ignoriere den Rückgabewert?

Es ist nicht möglich, eine Funktion aufzurufen, ohne den Rückgabewert irgendetwas in VHDL zuzuweisen. Wenn wir dies versuchen, erzeugt ModelSim den Kompilierungsfehler: Keine zulässigen Einträge für das Unterprogramm „CounterExpired“.

Stattdessen können wir dafür ein Verfahren verwenden. Eine innerhalb eines Prozesses deklarierte Prozedur kann auf jedes Signal innerhalb des Gültigkeitsbereichs dieses Prozesses zugreifen. Dies ähnelt der unreinen Funktion, aber da es sich um eine Prozedur handelt, gibt es keinen Rückgabewert.

In diesem Video-Tutorial vereinfachen wir den FSM-Code, indem wir eine in einem Prozess deklarierte Prozedur verwenden:

Der endgültige Code für die Procedure in Process testbench :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T23_ProcedureInProcessTb is
end entity;

architecture sim of T23_ProcedureInProcessTb is

    -- We are using a low clock frequency to speed up the simulation
    constant ClockFrequencyHz : integer := 100; -- 100 Hz
    constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;
    
    signal Clk         : std_logic := '1';
    signal nRst        : std_logic := '0';
    signal NorthRed    : std_logic;
    signal NorthYellow : std_logic;
    signal NorthGreen  : std_logic;
    signal WestRed     : std_logic;
    signal WestYellow  : std_logic;
    signal WestGreen   : std_logic;

begin

    -- The Device Under Test (DUT)
    i_TrafficLights : entity work.T23_TrafficLights(rtl)
    generic map(ClockFrequencyHz => ClockFrequencyHz)
    port map (
        Clk         => Clk,
        nRst        => nRst,
        NorthRed    => NorthRed,
        NorthYellow => NorthYellow,
        NorthGreen  => NorthGreen,
        WestRed     => WestRed,
        WestYellow  => WestYellow,
        WestGreen   => WestGreen);


    -- Process for generating clock
    Clk <= not Clk after ClockPeriod / 2;

    -- Testbench sequence
    process is
    begin
        wait until rising_edge(Clk);
        wait until rising_edge(Clk);
    
        -- Take the DUT out of reset
        nRst <= '1';
    
        wait;
    end process;
    
end architecture;

Der endgültige Code für das Ampel-Modul :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T23_TrafficLights is
generic(ClockFrequencyHz : integer);
port(
    Clk         : in std_logic;
    nRst        : in std_logic; -- Negative reset
    NorthRed    : out std_logic;
    NorthYellow : out std_logic;
    NorthGreen  : out std_logic;
    WestRed     : out std_logic;
    WestYellow  : out std_logic;
    WestGreen   : out std_logic);
end entity;

architecture rtl of T23_TrafficLights is

    -- Enumerated type declaration and state signal declaration
    type t_State is (NorthNext, StartNorth, North, StopNorth,
                        WestNext, StartWest, West, StopWest);
    signal State : t_State;

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is

        -- Procedure for changing state after a given time
        procedure ChangeState(ToState : t_State;
                              Minutes : integer := 0;
                              Seconds : integer := 0) is
            variable TotalSeconds : integer;
            variable ClockCycles  : integer;
        begin
            TotalSeconds := Seconds + Minutes * 60;
            ClockCycles  := TotalSeconds * ClockFrequencyHz -1;
            if Counter = ClockCycles then
                Counter <= 0;
                State   <= ToState;
            end if;
        end procedure;

    begin
        if rising_edge(Clk) then
            if nRst = '0' then
                -- Reset values
                State   <= NorthNext;
                Counter <= 0;
                NorthRed    <= '1';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '1';
                WestYellow  <= '0';
                WestGreen   <= '0';

            else
                -- Default values
                NorthRed    <= '0';
                NorthYellow <= '0';
                NorthGreen  <= '0';
                WestRed     <= '0';
                WestYellow  <= '0';
                WestGreen   <= '0';

                Counter <= Counter + 1;

                case State is

                    -- Red in all directions
                    when NorthNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartNorth, Seconds => 5);

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(North, Seconds => 5);

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        ChangeState(StopNorth, Minutes => 1);

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(WestNext, Seconds => 5);

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartWest, Seconds => 5);

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        ChangeState(West, Seconds => 5);

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        ChangeState(StopWest, Minutes => 1);

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        ChangeState(NorthNext, Seconds => 5);

                end case;

            end if;
        end if;
    end process;

end architecture;

Die Wellenform, nachdem wir run 5 min eingegeben haben Befehl in der ModelSim-Konsole:

Analyse

Wir haben das Verhalten des Moduls nicht geändert und können sehen, dass die Wellenform unverändert ist.

Im Vergleich zum Code aus dem Tutorial, in dem wir ursprünglich das Ampelmodul erstellt haben, ist der FSM-Code jetzt viel besser lesbar. Sie können dem implementierten Algorithmus leicht folgen, indem Sie den Code lesen. Die Zeitgeber- und Zustandsänderungslogik in einer einzigen Prozedur zu haben, ist vorteilhaft, weil sie sicherstellt, dass sie überall gleich implementiert wird, wo sie verwendet wird.

Imbiss


VHDL

  1. Lernprogramm - Einführung in VHDL
  2. Prozeduranweisung – VHDL-Beispiel
  3. Wie verwenden wir Molybdän?
  4. So erstellen Sie eine Liste von Zeichenfolgen in VHDL
  5. So verwenden Sie eine unreine Funktion in VHDL
  6. So verwenden Sie eine Funktion in VHDL
  7. So verwenden Sie eine Prozedur in VHDL
  8. So erstellen Sie einen Timer in VHDL
  9. So erstellen Sie einen getakteten Prozess in VHDL
  10. So verwenden Sie einen Cutter Grinder