Pełnomodemowy monitor RS232

Projekty użytkowników forum zarówno sprzętowe, jak i związane z programowaniem w dowolnym języku.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Pełnomodemowy monitor RS232

Postautor: gaweł » środa 10 kwie 2019, 19:42

Jak o się czasami dziwnie składa. Monitor linii RS232 zacząłem
budować dosyć dawno temu. Potem temat trochę odleżał.
Po przerwie zająłem się wykombinowaniem zawartości
dla układu CPLD. Potem prace znowu trochę się wstrzymały.
Ostatnio postanowiłem dokończyć budowę.
Jak urządzenie było w pełni sprawne, następnego
dnia zaistniała konieczność jego użycia (co za przypadek,
przez kilka lat nic i nagle... bum). Jeden gostek zakupił sobie
taki spektrometr atomowy (taki trochę wiekowy, z przełomu
lat 80-tych na 90-te XX wieku, w sumie kawał maszyny,
na moje oko tak gdzieś ze ćwierć tony), który łączył się z kompem
via sieral RS232. By było śmieszniej, to złącze RS232 w spektrometrze
było jako DSUB25. Gostek zakupił odpowiedni kabelek
(z DSUB25 na DSUB9) podłączył i … nie działa (dokładnie to program
w kompie stwierdza błąd komunikacji z maszynerią).
Właśnie monitor RS232 stał się cennym przyrządem diagnostycznym.
Komunikacja pomiędzy PC-tem z spektrometrem oprócz danych
szeregowych używa 5 linii modemowych.
Po rozwiązaniu problemu okazało się, że złącze DSUB25
„nie trzyma standardu”, numery użytych styków w złączu są właściwe,
ale ich znaczenie odbiega od standardu.
Dziwne… jakby „komuś” zależało na tym bym dokończył budowę
urządzenia i co jakiś czas przypominały mi się „zaległości”.


Temat jest kontynuacją tematu Metalowa obudówka, ale z racji, że obecnie jest poświęcony elektronice, pozwoliłem sobie na wyodrębnienie jako oddzielnego wątku.

Urządzenie ma dwa złącza RS232 (jako DSUB9). Jedno (żeńskie) jest przeznaczone do połączenia z komputerem (w ogólności z wyposażeniem komputerowym), drugie (męskie) jest przeznaczone do połączenia z modemem (w ogólności z wyposażeniem modemowym). Samo jest „obserwatorem” zdarzeń zachodzących na liniach RS232.
Poniższa fota pokazuje połączony monitor z kompem, w którym jest odpalony emulator terminala, który jak widać wystawił dwie wyjściowe linie modemowe.
rs232m_01.jpg
Na każdy sygnał występujący w RS232 jest przewidziana dioda |LED do sygnalizacji stanu linii → lampek jest 8. Pierwszych 5 odpowiada sygnałom wejściowym (z punktu widzenia komputera), 3 ostatnie reprezentują sygnały wyjściowe (rzecz jasna z perspektywy komputera).
rs232m_02.jpg
Każdy sygnał (w RS232) jest reprezentowany przez dwie diody LED. Żółta pokazuje stan statyczny → taki jaki jest aktualnie na danej linii oraz czerwona odzwierciedla „dynamikę” sygnału → sygnalizuje błyskiem o określonym czasie każdą zmianę stanu.
Monitor jest zbudowany na bazie układu CPLD (XILINX). Jego schemat pokazują poniższe rysunki.
rs232m_03.png
Serial A (powyższy rysunek) zawiera interfejs RS232 (przetwarza sygnały z napięć typowych w interfejsie) na poziomy logiczne. Serial B zawiera konwersję napięciową z typowych sygnałów logicznych do wartości występujących w RS232. Pomiędzy tymi interfejsami znajduje się blok logiczny, który zajmuje się sterowaniem diodami LED.
rs232m_04.png
Interfejs RS232 w stronę wyposażenia komputerowego pokazuje powyższy rysunek. Zbudowany jest na bazie układu MAX3238 (zawiera 5 nadajników i 3 odbiorniki).
rs232m_05.png
Rozwiązanie lustrzane (interfejs w stronę wyposażenia modemowego) pokazuje powyższy rysunek. Tutaj dla odmiany występuje układ MAX 3243 (zwiera 5 odbiorników i 3 nadajniki).
Całe przetwarzanie sygnałów znajduje się w układzie CPLD, którego schemat pokazuje kolejny rysunek.
rs232m_06.png
Z punktu widzenia „cyfrówki”, układ CPLD (U20, XCR3128) jest automatem synchronicznym, co oznacza, że wymaga sygnału taktującego (typowy generator U202, o częstotliwości 1.8432MHz). Jego częstotliwość nie jest krytyczna (ot taki walał mi się w szufladzie) a z drugiej strony, jest typowy w rozwiązaniach transmisji szeregowej. Każdy automat synchroniczny wymaga reseta na dzień dobry. Do tego jest użyty układ (U205, NE555). Samo sterowanie diodami LED ma w torze układy 74HC541 (U203 i U204). Zastosowany układ nie wnosi „zmiany fazy”. Dioda świeci, jeżeli na jego wejście podany jest stan logicznego zera. Możliwe jest zastosowanie innego rozwiązania, ot choćby popularnego układu ULN2803. Ten jednak wnosi „negację” w tor, przyłączona dioda LED świeci, gdy na wejście ULN 2803 podany jest stan logicznej jedynki. Różnorodność rozwiązań samego „wyświetlania” została ujęta w układzie CPLD w ten sposób, że został wprowadzony sygnał POLS (polaryzacja statyczna) i POLD (polaryzacja dynamiczna). Jeżeli na tym wejściu panuje stan niski, to układ CPLD generuje sygnał do sterowania diodą LED ze aktywnym stanem niskim (zapala diodę LED). Jeżeli wejście polaryzujące będzie w stanie wysokim, to CPLD będzie zapalać diodę stanem wysokim.
Dioda LED, to mała płytka PCB mocowana do frontpanelu.
rs232m_07.png
Całość zamyka zasilacz. Układ U501 (ST1S10) jest stabilizatorem impulsowym, który produkuje +5V (zasila generator, układ NE555 oraz układy 74HC541 sterujące diodami LED). Konieczne dla układu CPLD napięcie zasilania produkuje układ U502 (LF33).
rs232m_08.png
PCB pokazują następujące rysunki.
rs232m_09.png
rs232m_10.png
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Pełnomodemowy monitor RS232

Postautor: gaweł » środa 10 kwie 2019, 20:15

Zawartość układu CPLD (wysmarowana w VHDL'u) to w gruncie rzeczy jest osiem razy powielony ten sam układ. Każdy monitorowany sygnał ma swoje wejście (czy to od strony wyposażenia komputerowego czy od strony wyposażenia modemowego) i wyjście. Stan statyczny jest również prosty do zobrazowania. Pamiętając, że stanem aktywnym w transmisji szeregowej (zarówno danych szeregowych jak stanu linii modemowych) jest logiczne zero, to do sygnalizacji stanu statycznego wystarczy wprost danym sygnałem wysterować diodę LED. Trochę bardziej skomplikowaną sytuacją jest obróbka sygnału w sensie dynamicznym (sygnalizującym zmiany stanu). Tu w torze przetwarzania znajduje się blok specjalizowanego komparatora, którego zadaniem jest wykrywanie zmian stanu linii (zarówno danych szeregowych jak i linii modemowych). Wykrycie zmiany stanu (sygnalizowane krótkim impulsem) pobudza do działania odpowiedni timer, którego zadaniem jest wygenerowanie impulsu o „optycznie akceptowalnym” czasie trwania (nie za krótki, bo musi być widoczny gołym okiem oraz nie musi lampić się zbyt długo).

Kod: Zaznacz cały

library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.std_logic_ARITH.ALL;
use IEEE.std_logic_UNSIGNED.ALL;

entity serialtrace is port ( Clk : in std_logic ;
                             Reset : in std_logic ;
                             PolStat : in std_logic ;
                             PolDyn : in std_logic ;
                             InRX : in  std_logic ;
                             InTX : in  std_logic ;
                             InRTS : in  std_logic ;
                             InCTS : in  std_logic ;
                             InDTR : in  std_logic ;
                             InDSR : in  std_logic ;
                             InDCD : in  std_logic ;
                             InRI : in  std_logic ;
                             OutRX : out  std_logic ;
                             OutTX : out  std_logic ;
                             OutRTS : out  std_logic ;
                             OutCTS : out  std_logic ;
                             OutDTR : out  std_logic ;
                             OutDSR : out  std_logic ;
                             OutDCD : out  std_logic ;
                             OutRI : out std_logic ;
                             StatRX : out std_logic ;
                             StatTX : out  std_logic ;
                             StatRTS : out  std_logic ;
                             StatCTS : out  std_logic ;
                             StatDTR : out  std_logic ;
                             StatDSR : out  std_logic ;
                             StatDCD : out  std_logic ;
                             StatRI : out  std_logic ;
                             DynRX : out  std_logic ;
                             DynTX : out  std_logic ;
                             DynRTS : out  std_logic ;
                             DynCTS : out  std_logic ;
                             DynDTR : out  std_logic ;
                             DynDSR : out  std_logic ;
                             DynDCD : out  std_logic ;
                             DynRI : out  std_logic ) ;
end serialtrace ;

architecture Behavioral of serialtrace is

  component Timer port ( Clk : in  std_logic ;
                         TClk : in std_logic ;
                         Reset : in  std_logic ;
                         Start : in  std_logic ;
                         TimeUp : out  std_logic ) ;
   end component ;

  component ClockGen port ( Clk : in  std_logic ;
                            Reset : in std_logic ;
                            SClk : out std_logic ;
                            TClk : out  std_logic ) ;
  end component ;

  component Comparator port ( Clk : in  std_logic ;
                              Reset : in  std_logic ;
                              InpSignal : in std_logic ;
                              Change : out std_logic ) ;
  end component ;

  signal TClk : std_logic ;
  signal SClk : std_logic ;

  signal ChangeRX : std_logic ;
  signal ChangeTX : std_logic ;
  signal ChangeRTS : std_logic ;
  signal ChangeCTS : std_logic ;
  signal ChangeDTR : std_logic ;
  signal ChangeDSR : std_logic ;
  signal ChangeDCD : std_logic ;
  signal ChangeRI : std_logic ;

  signal LocDynRX : std_logic ;
  signal LocDynTX : std_logic ;
  signal LocDynRTS : std_logic ;
  signal LocDynCTS : std_logic ;
  signal LocDynDTR : std_logic ;
  signal LocDynDSR : std_logic ;
  signal LocDynDCD : std_logic ;
  signal LocDynRI : std_logic ;

begin

  TClockGen : ClockGen port map ( Clk => Clk ,
                                  Reset => Reset ,
                                  SClk => SClk ,
                                  TClk => TClk ) ;

  RXComparator : Comparator port map ( Clk => SClk ,
                                       Reset => Reset ,
                                       InpSignal => InRX ,
                                       Change => ChangeRX ) ;

  TXComparator : Comparator port map ( Clk => SClk ,
                                       Reset => Reset ,
                                       InpSignal => InTX ,
                                       Change => ChangeTX ) ;

  RTSComparator : Comparator port map ( Clk => SClk ,
                                        Reset => Reset ,
                                        InpSignal => InRTS ,
                                        Change => ChangeRTS ) ;

  CTSComparator : Comparator port map ( Clk => SClk ,
                                        Reset => Reset ,
                                        InpSignal => InCTS ,
                                        Change => ChangeCTS ) ;

  DTRComparator : Comparator port map ( Clk => SClk ,
                                        Reset => Reset ,
                                        InpSignal => InDTR ,
                                        Change => ChangeDTR ) ;

  DSRComparator : Comparator port map ( Clk => SClk ,
                                        Reset => Reset ,
                                        InpSignal => InDSR ,
                                        Change => ChangeDSR ) ;

  DCDComparator : Comparator port map ( Clk => SClk ,
                                        Reset => Reset ,
                                        InpSignal => InDCD ,
                                        Change => ChangeDCD ) ;

  RIComparator : Comparator port map ( Clk => SClk ,
                                       Reset => Reset ,
                                       InpSignal => InRI ,
                                       Change => ChangeRI ) ;

  RXTimer : Timer port map ( Clk => Clk ,
                             TClk => TClk ,
                             Reset => Reset ,
                             Start => ChangeRX ,
                             TimeUp => LocDynRX ) ;

  TXTimer : Timer port map ( Clk => Clk ,
                             TClk => TClk ,
                             Reset => Reset ,
                             Start => ChangeTX ,
                             TimeUp => LocDynTX ) ;

  RTSTimer : Timer port map ( Clk => Clk ,
                              TClk => TClk ,
                              Reset => Reset ,
                              Start => ChangeRTS ,
                              TimeUp => LocDynRTS ) ;

  CTSTimer : Timer port map ( Clk => Clk ,
                              TClk => TClk ,
                              Reset => Reset ,
                              Start => ChangeCTS ,
                              TimeUp => LocDynCTS ) ;

  DTRTimer : Timer port map ( Clk => Clk ,
                              TClk => TClk ,
                              Reset => Reset ,
                              Start => ChangeDTR ,
                              TimeUp => LocDynDTR ) ;

  DSRTimer : Timer port map ( Clk => Clk ,
                              TClk => TClk ,
                              Reset => Reset ,
                              Start => ChangeDSR ,
                              TimeUp => LocDynDSR ) ;

  DCDTimer : Timer port map ( Clk => Clk ,
                              TClk => TClk ,
                              Reset => Reset ,
                              Start => ChangeDCD ,
                              TimeUp => LocDynDCD ) ;

  RITimer : Timer port map ( Clk => Clk ,
                             TClk => TClk ,
                             Reset => Reset ,
                             Start => ChangeRI ,
                             TimeUp => LocDynRI ) ;

  StatRX <= InRX xor PolStat ;
  StatTX <= InTX xor PolStat ;
  StatRTS <= InRTS xor PolStat ;
  StatCTS <= InCTS xor PolStat ;
  StatDTR <= InDTR xor PolStat ;
  StatDSR <= InDSR xor PolStat ;
  StatDCD <= InDCD xor PolStat ;
  StatRI <= InRI xor PolStat ;

  DynRX <= LocDynRX xor PolDyn ;
  DynTX <= LocDynTX xor PolDyn ;
  DynRTS <= LocDynRTS xor PolDyn ;
  DynCTS <= LocDynCTS xor PolDyn ;
  DynDTR <= LocDynDTR xor PolDyn ;
  DynDSR <= LocDynDSR xor PolDyn ;
  DynDCD <= LocDynDCD xor PolDyn ;
  DynRI <= LocDynRI xor PolDyn ;

  OutRX <= InRX ;
  OutTX <= InTX ;
  OutRTS <= InRTS ;
  OutCTS <= InCTS ;
  OutDTR <= InDTR ;
  OutDSR <= InDSR ;
  OutDCD <= InDCD ;
  OutRI <= InRI ;

end Behavioral ;
Zapisy (na przykładzie linii RX):

Kod: Zaznacz cały

StatRX <= InRX xor PolStat ;
OutRX <= InRX ;
oznaczają, że sygnał wejściowy jest przekazany na wyjście (oraz każdy występujący w RS232 sygnał) oraz steruje diodą LED w sensie sygnału statycznego.
Do każdej monitorowanej linii jest przyłączony komparator stanów jako zapis (na przykładzie linii RXD):

Kod: Zaznacz cały

  RXComparator : Comparator port map ( Clk => SClk ,
                                       Reset => Reset ,
                                       InpSignal => InRX ,
                                       Change => ChangeRX ) ;

który jako wyjście generuje sygnał ChangeRX. Ten z kolei jest wyzwalaczem generacji impulsu sterującego diodą LED.

Kod: Zaznacz cały

  RXTimer : Timer port map ( Clk => Clk ,
                             TClk => TClk ,
                             Reset => Reset ,
                             Start => ChangeRX ,
                             TimeUp => LocDynRX ) ;
Sygnał aktywujący diodę LED (LocDynRX) przechodzi przez logikę dopasowania polaryzacji DynRX <= LocDynRX xor PolDyn ; i wychodzi na zewnątrz układu CPLD.
Do obsługi automatu komparatora oraz odmierzania czasu aktywacji diody LED (wskaźnik dynamiczny) potrzebny jest generator taktu zegarowego. Częstotliwość zewnętrznego generatora 1.8432MHz jest podzielona przez 4 (do taktowania komparatora) oraz podzielona przez 32768 do odmierzania czasu. Biorąc pod uwagę typowy układ UART (przykładowo 16C550, gdzie typowa częstotliwość taktująca transmisją 1.8432MHz jest dzielona wewnętrznie przez przez 16 oraz dodatkowo przez programowalny podzielnik), taktowanie komparatora powinno „zauważyć” pojedynczy bit aktywny (o stanie logicznego zera) o czasie trwania przynajmniej połowy najszybszej transmisji szeregowej (tj. 115200bps).
Komponent generatora sygnałów taktujących jest następujący:

Kod: Zaznacz cały

library IEEE ;
use IEEE.STD_LOGIC_1164.ALL ;
use IEEE.STD_LOGIC_ARITH.ALL ;
use IEEE.STD_LOGIC_UNSIGNED.ALL ;

entity ClockGen is port ( Clk : in  std_logic ;
                          Reset : in std_logic ;
                          SClk : out std_logic ;
                          TClk : out  std_logic ) ;
end ClockGen ;

architecture Behavioral of ClockGen is

  signal Cnt : STD_LOGIC_VECTOR ( 14 downto 0 ) ;

begin
  process ( Clk , Reset )
  begin
    if ( Reset = '0' ) then
      Cnt <= ( others => '0' ) ;
    else
      if ( Clk'event and Clk = '1' ) then
         Cnt <= Cnt + 1 ;
      end if ;
    end if ;
  end process ;

  TClk <= Cnt ( 14 ) ;
  SClk <= Cnt ( 1 ) ;

end Behavioral ;
W skład oprogramowania narzędziowego do obróbki układów CPLD wchodzi również symulator (często wielce przydatny). Symulacja działania komponentu generatora taktującego jest następująca (dla „powiększenia” właściwego dla sygnału taktującego komparatorem):
rs232m_21.png
oraz dla sygnału taktującego odmierzaniem czasu:
rs232m_22.png
Komponent komparatora jest następujący:

Kod: Zaznacz cały

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Comparator is port ( Clk : in  std_logic ;
                            Reset : in  std_logic ;
                            InpSignal : in std_logic ;
                            Change : out std_logic ) ;
end Comparator ;

architecture Behavioral of Comparator is

  type CompStateType is ( IdleState   , -- stan jalowy (oczekiwania na zmiane sygnalu wejsciowego)
                          Start1State , -- badanie stabilnosci sygnalu wejsciowego (krok 1)
                          Start2State , -- badanie stabilnosci sygnalu wejsciowego (krok 2)
                          NewState    , -- wykrycie stabilnej zmiany stanu sygnalu wejsciowego
                          EndState1   , -- przedluzenie wygenerowanego sygnalu (Change) [krok 1]
                          EndState2 ) ; -- przedluzenie wygenerowanego sygnalu (Change) [krok 2]

  signal LastState : std_logic ;
  signal CompState : CompStateType ;

begin
  TState : process ( Clk , Reset , InpSignal )
  begin
    if Reset = '0' then
      CompState <= IdleState ;
      LastState <= InpSignal ;
      Change <= '1' ;
    else
      if Clk'event and Clk = '1' then
        case CompState is
          when IdleState =>
            if LastState = InpSignal then
              CompState <= IdleState ;
            else
              CompState <= Start1State ;
            end if ;
            Change <= '1' ;
          when Start1State =>
            if LastState = InpSignal then
              CompState <= IdleState ;
            else
              CompState <= Start2State ;
            end if ;
            Change <= '1' ;
          when Start2State =>
            if LastState = InpSignal then
              CompState <= IdleState ;
            else
              CompState <= NewState ;
            end if ;
            Change <= '1' ;
          when NewState =>
            LastState <= InpSignal ;
            CompState <= EndState1 ;
            Change <= '0' ;
          when EndState1 =>
            CompState <= EndState2 ;
            Change <= '0' ;
          when EndState2 =>
            CompState <= IdleState ;
            Change <= '0' ;
          when others =>
            CompState <= IdleState ;
            Change <= '0' ;
        end case ;
      end if ;
    end if ;
  end process ;

end Behavioral ;

Ponieważ symulacja działania pozwala na „zbadanie układu w kompie”, to poprawność jego działania została potwierdzona przez symulator. Komponent testowy jest następujący:

Kod: Zaznacz cały

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;

ENTITY comparator_tb_vhd IS
END comparator_tb_vhd;

ARCHITECTURE behavior OF comparator_tb_vhd IS

-- Component Declaration for the Unit Under Test (UUT)
  COMPONENT Comparator PORT ( Clk : IN std_logic;
                              Reset : IN std_logic;
                              InpSignal : IN std_logic;         
                              Change : OUT std_logic);
  END COMPONENT;

--Inputs
  SIGNAL Clk :  std_logic := '0';
  SIGNAL Reset :  std_logic := '0';
  SIGNAL InpSignal :  std_logic := '0';

--Outputs
  SIGNAL Change :  std_logic;

BEGIN

-- Instantiate the Unit Under Test (UUT)
  uut: Comparator PORT MAP ( Clk => Clk ,
                             Reset => Reset ,
                             InpSignal => InpSignal ,
                             Change => Change ) ;

  tb : PROCESS
  BEGIN
-- Wait 100 ns for global reset to finish
    Clk <= '0' ;
    Reset <= '1' ;
    wait for 100 ns;
    Reset <= '0' ;
    InpSignal <= '1' ;
    wait for 100 ns;
    Reset <= '1' ;
    wait for 100 ns;
    for Inx in 0 to 3 loop
      Clk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    InpSignal <= '0' ;
    for Inx in 0 to 31 loop
      Clk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    InpSignal <= '1' ;
    for Inx in 0 to 31 loop
      Clk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    wait; -- will wait forever
  END PROCESS;

END;

Zawiera on zmianę sygnału monitorowanego w dwóch wariantach: przejście z zera na jeden oraz odwrotnie. Symulator twierdzi, że działa.
rs232m_23.png
Wygenerowany przez komparator stanów sygnał inicjuje odmierzanie czasu, jest ono taktowane znacząco zmniejszoną częstotliwością sygnału zegarowego. Można by oczywiście użyć tego samego sygnału zegarowego co w detektorze zmian stanu, ale wymagałoby to kilkunastobitowego licznika. Biorąc pod uwagę, że układ jest powielony osiem razy, to sumaryczne zapotrzebowanie przekracza zasoby układu CPLD. Rozwiązaniem jest znacząco zwolniona częstotliwość taktująca i kilkubitowy licznik. Komponent do odmierzania czasu jest następujący:

Kod: Zaznacz cały

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Timer is port ( Clk : in std_logic ;
                       TClk : in std_logic ;
                       Reset : in  std_logic ;       -- aktywne zerem
                       Start : in std_logic ;        -- aktywne zerem
                       TimeUp : out  std_logic ) ;   -- aktywne zerem
end Timer ;

architecture Behavioral of Timer is

  type TimerStateType is ( TimerIdleState ,
                           TimerStartState ,
                           TimerWaitState ,
                           TimerStopState ) ;

  signal TimerState : TimerStateType ;
  signal TimerEnable : std_logic ;
  signal TCounter : std_logic_vector ( 3 downto 0 ) ;
  signal TFlipFlop : std_logic ;
  signal TimerReset : std_logic ;

begin
  TState : process ( Clk , Reset )
  begin
    if Reset = '0' then
      TimerState <= TimerIdleState ;
      TimerEnable <= '0' ;
      TFlipFlop <= '1' ;
    else
      if Clk'event and Clk = '1' then
        case TimerState is
          when TimerIdleState =>
            if Start = '1' then
              TimerState <= TimerIdleState ;
            else
              TimerState <= TimerStartState ;
            end if ;
          when TimerStartState =>
            TimerState <= TimerWaitState ;
            TFlipFlop <= '0' ;
            TimerEnable <= '1' ;
          when TimerWaitState =>
            if TCounter = "1111" then
              TimerState <= TimerStopState ;
            else
              TimerState <= TimerWaitState ;
            end if ;
          when TimerStopState =>
            TimerState <= TimerIdleState ;
            TFlipFlop <= '1' ;
            TimerEnable <= '0' ;
          when others =>
            TimerState <= TimerIdleState ;
        end case ;
      end if ; 
    end if ;
  end process ;

  TimerReset <= Reset and Start ;

  TDelay : process ( TClk , TimerReset , TimerEnable )
  begin
    if TimerReset = '0' then
      TCounter <= ( others => '0' ) ;
    else
      if TClk'event and TClk = '0' then
        if TimerEnable = '1' then
          TCounter <= TCounter + 1 ;
        end if ;
      end if ;
    end if ;
  end process ;

  TimeUp <= TFlipFlop ;

end Behavioral ;
Pomiar czasu polega na odliczeniu określonej liczby impulsów zegarowych (tych zwolnionych). Uruchomienie zegara jest sterowane odpowiednim automatem synchronicznym (taktowanych identycznie jak wykrywacz zmian stanu na monitorowanych liniach). Podobnie jak w przypadku poprzednich komponentów, ten również został przesymulowany. Moduł jest następujący:

Kod: Zaznacz cały

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;

ENTITY timer_tb_vhd IS
END timer_tb_vhd;

ARCHITECTURE behavior OF timer_tb_vhd IS

-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Timer PORT ( Clk : IN std_logic ;
                       TClk : IN std_logic ;
                       Reset : IN std_logic ;
                       Start : IN std_logic ;
                       TimeUp : OUT std_logic ) ;
END COMPONENT;

--Inputs
  SIGNAL Clk :  std_logic := '0';
  SIGNAL TClk :  std_logic := '0';
  SIGNAL Reset :  std_logic := '0';
  SIGNAL Start :  std_logic := '0';

--Outputs
  SIGNAL TimeUp :  std_logic;

BEGIN

-- Instantiate the Unit Under Test (UUT)
  uut: Timer PORT MAP ( Clk => Clk ,
                        TClk => TClk ,
                        Reset => Reset ,
                        Start => Start ,
                        TimeUp => TimeUp ) ;
  tb : PROCESS
  BEGIN
-- Wait 100 ns for global reset to finish
    Clk <= '0' ;
    TClk <= '0' ;
    Reset <= '0' ;
    Start <= '1' ;
    wait for 100 ns;
    Reset <= '1' ;
    for Inx in 0 to 7 loop
      Clk <= '1' ;
      TClk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
      Clk <= '1' ;
      TClk <= '0' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    Start <= '0' ;
    Clk <= '1' ;
    TClk <= '1' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Clk <= '1' ;
    TClk <= '0' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Start <= '1' ;
    for Inx in 0 to 31 loop
      Clk <= '1' ;
      TClk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
      Clk <= '1' ;
      TClk <= '0' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    Start <= '0' ;
    Clk <= '1' ;
    TClk <= '1' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Clk <= '1' ;
    TClk <= '0' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Start <= '1' ;
    for Inx in 0 to 3 loop
      Clk <= '1' ;
      TClk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
      Clk <= '1' ;
      TClk <= '0' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    Start <= '0' ;
    Clk <= '1' ;
    TClk <= '1' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Clk <= '1' ;
    TClk <= '0' ;
    wait for 100 ns;
    Clk <= '0' ;
    wait for 100 ns;
    Start <= '1' ;
    for Inx in 0 to 31 loop
      Clk <= '1' ;
      TClk <= '1' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
      Clk <= '1' ;
      TClk <= '0' ;
      wait for 100 ns;
      Clk <= '0' ;
      wait for 100 ns;
    end loop ;
    wait; -- will wait forever
  END PROCESS ;

END ;
Wynik symulacji pokazują poniższe rysunki. Wariant prosty, gdzie zachodzi pojedyncza zmiana,
rs232m_24.png
oraz bardziej złożony, gdzie następuje kolejne wyzwolenie zanim upłynął czas (układ ma odmierzyć ustalony czas od ostatniego wyzwolenia).
rs232m_25.png
Symulacja... symulacją. Prawdę okazuje dopiero rzeczywistość. Po zaprogramowaniu układu działa on zgodnie z oczekiwaniami. Nawet sprawdziłem zachowanie monitora na danych szeregowych. Wybrałem najbardziej niekorzystny wariant nadawanych danych: wysłałem znak o kodzie FF hex z prędkością transmisji 115200 bps. Jak wiadomo, ten znak zawiera same jedynki, więc sam UART dokłada jedynie bit startu oraz bit stopu. Powstaje sygnał szeregowy z najkrótszym impulsie zerowym. Monitor ten stan wykrył i zasygnalizował. Oczywiście mrugnięcie lampki żółtej (sygnał statyczny) było praktycznie niezauważalne, ale lampka czerwona (sygnalizująca zmiany stanu) stanęła na wysokości zadania.

Załączniki: projekt dla CPLD (w XILINX ISE)
serialtrace.zip
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: Pełnomodemowy monitor RS232

Postautor: tasza » piątek 12 kwie 2019, 10:53

A ja tylko z takim wnioskiem racjonalizatorskim niewielkim w postaci zapamiętywania "zdarzeń" występujących na liniach portu RS232, może nie tyle RxD, TxD co tych kontrolnych. Chodzi mi o trwałą indykację, że "coś" się wydarzyło na obserwowanej linii. Taki gadżet mają moje sondy HP545A, potrafi lampką na górze wskazać, że był choćby króciutki, jednorazowy impuls, trudny(niemożliwy) do zauważenia na świecącej końcówce sondy. Do kasowania wskaźnika jest specjalny guzik, tu pisałam: https://microgeek.eu/viewtopic.php?t=1622

Myślę, że w amatorskiej dłubaninie dużo częściej zdarza się wykorzystywać linie modemowe do innych niż planowano celów, jako swego rodzaju uniwersalne IO (ja na przykład linię DTR ulubiłam sobie do zdalnych resetów ewentualnie przełączania kierunku w RS485, jakoś tak padło) stąd i konieczność zmierzenia się z niestandardowym zachowaniem tych sygnałów.

W tej konstrukcji możliwe, że dałoby się to zgrabnie upchnąć, bo core rozwiązania jest gotowy - to opisywany komparator stanów i w sumie potrzeba tylko jednego guzika reset do globalnego skasowania wszystkich dostępnych wskaźników zdarzeń no i przełącznika trybów pracy - wskaźnik dynamicznego stanu / wskaźnik wystąpienia zdarzenia, dwa piny wejściowe chyba się znajdą.

Ja taki wskaźnik-pułapkę w sondzie HP doceniłam majstrując przy PWM dla CA80. Przerzutnik wyjściowy mi się resetował przypadkowymi, krzywymi impulsami, nijak zwykła sonda nie chciała tego "mignięcia" pokazać a jak już pokazywała, to ja akurat ślepiłam się na co inne.
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1259
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Pełnomodemowy monitor RS232

Postautor: gaweł » piątek 12 kwie 2019, 16:34

Co robi windoza na starcie?
rs232m.mov

Grzebie po wyjściowych liniach modemowych, tak jakby czegoś tam szukała. Jednak dane szeregowe nie zostały tknięte.

tasza pisze:A ja tylko z takim wnioskiem racjonalizatorskim...

Każda idea jest warta rozważenia.

tasza pisze:Myślę, że w amatorskiej dłubaninie dużo częściej zdarza się wykorzystywać linie modemowe do innych niż planowano celów, jako swego rodzaju uniwersalne IO (ja na przykład linię DTR ulubiłam sobie do zdalnych resetów ewentualnie przełączania kierunku w RS485, jakoś tak padło) stąd i konieczność zmierzenia się z niestandardowym zachowaniem tych sygnałów.

W rzeczy samej, nikt nie powiedział, że linie modemowe służą jedynie do komunikacji z modemem. Ot choćby w serwerze www, jedna linia modemowa służy do reseta, druga determinuje wejście proca w stan ładowania kodu programu do wewnętrznego FLASH. W sumie pomysłów może być tyle ile myślących. A, że powszechnie wiadomo, że lubisz "wykorzystywać ... do innych niż planowano celów", jest to godne pochwały i naśladowania (byle było sensowne).
tasza pisze:W tej konstrukcji możliwe, że dałoby się to zgrabnie upchnąć, bo core rozwiązania jest gotowy - to opisywany komparator stanów i w sumie potrzeba tylko jednego guzika reset do globalnego skasowania wszystkich dostępnych wskaźników zdarzeń no i przełącznika trybów pracy - wskaźnik dynamicznego stanu / wskaźnik wystąpienia zdarzenia, dwa piny wejściowe chyba się znajdą.
Ja taki wskaźnik-pułapkę w sondzie HP doceniłam majstrując przy PWM dla CA80. Przerzutnik wyjściowy mi się resetował przypadkowymi, krzywymi impulsami, nijak zwykła sonda nie chciała tego "mignięcia" pokazać a jak już pokazywała, to ja akurat ślepiłam się na co inne.

No przyznam, że zaintrygowałaś mnie. Co prawda obecnego egzemplarza nie będę "psuł i dziurawił", ale... coś da się zrobić. Tak całkiem "przypadkiem" uchował mi się troszkę starszy wariant (w sumie konstrukcyjnie bardzo podobny).
rs232m_31.jpg
rs232m_32.jpg

Nawet te PCB jest wykonane chałupniczo. Pinów w CPLD to spokojnie wystarczy, można podlutować się delikatnie do pinów. Tak naszła mnie teraz taka myśl na przyszłość: może warto każdy wolny pin w układzie wyprowadzić na punkt lutowniczy, tak na wszelki wypadek na przyszłość. Pozostaje kwestia określenie funkcjonalności. Czy reagować na zmianę każdej linii, czy może zignorować dane szeregowe, bo tam to wiadomo, ciągle coś się macha. A może dodać przycisk i tą cechę konfigurować (potrzebny będzie może jakiś LED dodatkowy). W wyniku detekcji zmiany stanu zatrzasnąć stan wszystkich sygnałów? A może niech by się kasowało po jakimś czasie? A może przycisk determinujący czy ma kasować się samo, czy na dodatkowy przycisk? Można wymyślać, bo cóż może nas ograniczać?
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „DIY”

Kto jest online

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