- LiFePO4 Speicher Test         
Ergebnis 1 bis 8 von 8

Thema: Abfallen von Ausgängen verzögern

  1. #1
    Benutzer Stammmitglied Avatar von modtronic
    Registriert seit
    14.05.2011
    Ort
    Hagen
    Alter
    46
    Beiträge
    68

    Abfallen von Ausgängen verzögern

    Anzeige

    Powerstation Test
    Guten Morgen

    Folgende Situation.
    Ich möchte an einem AT-Mega 8 einen kompletten Port als Eingang auf einen I2C IC übertragen.
    In diesem Fall habe ich den MCP23017 gewählt.

    Im Programm ist das eine einfache Routine, da ich den Port z.b D einfach auf den I2C schreiben kann.
    Ich nutze das so , um mit 2 Adern (gepufferter I2c) vielen Daten zu übertragen.

    das funktioniert auch soweit.
    Zeile aus dem Programm: i2c_write (PIND); (Beispiel)

    jetzt habe ich aber das Problem, das das sofort geschieht. ich würde gerne das die Eingänge eines Ports zwar sofort übertragen werden, zb PIND.0 wird direkt zum GBA0 übertragen (HIGH Zustand), der GBA0 aber verzögert wieder 0 wird.(ca. 200ms, bzw auch einstellbar wenn länger oder kürzer)
    Die Lösung das ganze über Kondensatoren zu machen finde ich nicht wirklich toll und zu unflexibel.

    Vom Gedanke her, müsste ich daher jeden einzelnen AT Mega PIN aufbröseln, verzögern und wieder als Gesamtes Byte zusammenfügen und dann an den I2C übertragen.
    Ich habe dazu schonmal was von Bitmanipulation gelesen. oder ist das falsche Ansatz ?
    hat da jemand schonmal in der Richtung was gemacht und kann mir da weiterhelfen ??

    Gruss
    Patrick

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.702
    Blog-Einträge
    133
    Hallo modtronic,

    So richtig verstehe ich nicht, was Du möchtest.

    Du hast einen Atmega8 und einen MCP23017.
    Beide sind über einen I2C Bus verbunden.
    Mit "i2c_write (PIND);" schickst Du den Inhalt von dem PIND Register zum MCP23017

    Meinem Verständnis nach sind dann die PD0 bis PD7 des Mega8 als Eingänge konfiguriert.
    Die GPA0 bis GPA7 des MCP23017 nehmen nach dem i2c_write (PIND) dann als Ausgänge den Zustand der Mega8 PortD Eingänge an.

    An welcher Stelle soll denn was genau verzögert werden?

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  3. #3
    Benutzer Stammmitglied Avatar von modtronic
    Registriert seit
    14.05.2011
    Ort
    Hagen
    Alter
    46
    Beiträge
    68
    Zitat Zitat von Searcher Beitrag anzeigen
    Hallo modtronic,

    So richtig verstehe ich nicht, was Du möchtest.

    Du hast einen Atmega8 und einen MCP23017.
    Beide sind über einen I2C Bus verbunden.
    Mit "i2c_write (PIND);" schickst Du den Inhalt von dem PIND Register zum MCP23017

    Meinem Verständnis nach sind dann die PD0 bis PD7 des Mega8 als Eingänge konfiguriert.
    Die GPA0 bis GPA7 des MCP23017 nehmen nach dem i2c_write (PIND) dann als Ausgänge den Zustand der Mega8 PortD Eingänge an.

    An welcher Stelle soll denn was genau verzögert werden?

    Gruß
    Searcher
    ja genau, der PORDT fungiert als Eingang der PORT GPA des MCP als Ausgang.
    Wenn ich jetzt einen beliegigen PIN des Mega 8 oder mehrere auf 1 lege, wird das ja direkt zum MCP übertragen.
    sobald der entsprechende PIN wieder 0 wird wird auch der PIN am MCP wieder 0.
    vom Verständnis ist das das PIND.0 gleich GPA0 ist, PIND.1 gleich GPA1 ist usw.

    ich möchte nun, sobald ein PIN des Portes D "1" wird das dieser auch sofort "1" am MCP wird, sobald nun der ensprechende PIN wieder 0 wird, dieser verzögert am MCP 0 wird.
    das heisst wenn PIN 0, 1 und 2 HIGH sind, sind auch die PINS am MCP HIGH.
    Wenn PIN 0, nun 0 wird, 1 und 2 High bleiben soll der PIN GPA0 am MCP verzögert "0" werden, der Rest nicht betroffen sein. bzw das soll für jeden Pin getrennt möglich sein.

    Hoffe ich habe das verständlich erklären können ?

    Gruss
    Patrick

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    27.08.2013
    Ort
    Region Basel
    Alter
    66
    Beiträge
    2.435
    Hallo Patrick,

    Etwas Software brauchst du dazu schon.

    Du brauchst für jedes Bit einen Timer. Das kannst du mit einem Timer-Interrupt machen, welcher z.B. alle 1ms aufgerufen wird.
    Wenn die Timer >0 wird der Wert jedes Mal um 1 verringert.

    Wenn du PORTD einliest, wird jedes Mal für eine gelesene 1 der entsprechende Timer mit 200 beschrieben.

    Für die Ausgabe musst für jeden Timer welcher >0 eine 1 ins entsprechende Bit setzen.

    So in der Art (nicht getestet):
    Code:
    unsigned char timer[8];
    
    void interrupt(void)
      {
         char i;
    
         for (i = 0; i < 8; i++)
           {
              if (timer[i]) timer[i]--;
           }
      }
    
    void out(void)
      {
        char i;
        unsigned char x = 0;
    
         for (i = 0; i < 8; i++)
           {
              if (timer[i]) (x |= (1 << i));
           }
          i2c_write (x); 
      }
    
    unsigned char in(void)
    {
        unsigned char x;
        char i;
    
         x = PORTD;
         for (i = 0; i < 8; i++)
           {
              if (x & (1 << i)) timer[i] = 200;
           }
    }
    Kann Reste von Tippfehlern enthalten.

    MfG Peter(TOO)
    Manchmal frage ich mich, wieso meine Generation Geräte ohne Simulation entwickeln konnte?

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.702
    Blog-Einträge
    133
    Zitat Zitat von modtronic Beitrag anzeigen
    Hoffe ich habe das verständlich erklären können ?
    Ja, ich glaube wenigstens, daß ich das jetzt verstanden habe. Ich habe auch mal ein Programm in Bascom mit den wichtigsten Bestandteilen und hoffentlich verständlich kommentiert eingefügt. Leider kann ich C nicht wirklich und kann nicht beurteilen, ob ich das gleiche mache wie Peter. Auf jeden Fall habe ich auch den Millisekundentimer, der "Timer" für die Portpins runterzählt. Programm ist auch nicht getestet.


    Code:
    '
    ' ab Hochkomma (') beginnt in Bascom ein Kommentar
    '
    ' mit PIND.Bit_no, also Variable bzw Register Punkt Ziffer kann man einzelne Bits Adressieren.
    '
    '####################################################################
    '1. Programm liest PIND Register ein und speichert für spätere Vergleiche.
    '2. Stellt Änderungen von Portpins zum vorherigen Einlesen fest
    '3.a Wird ein Wechsel von "1" auf "0" festgestellt, wird ein Timerregister für den entsprechenden Eingang auf 200ms gesetzt
    '3.b Wird ein Wechsel von "0" auf "1" festgestellt, wird das entsprechende Timerregister auf 0 gesetzt.
    '0 Ein Interrupt decrementiert jede Millisekunde alle Timerregister größer 0 um eins.
    '4.a Bei einem gesetzten Timerregister fand ein Eingangswechsel von 1 nach 0 statt und der Eingang muß noch auf 1 bleiben
    '4.b Bei einem Timerregister = 0 gab es einen Wechsel von 0 nach 1 oder die Zeit lief ab ->
    '    Die eingelesene "0" kann durchgreifen und zur Ausgabe übernommen bzw. eine eingelesene "1" wird übernommen.
    '5. Ausgabe über I2C
    '####################################################################
    
    Config Timer0 = Timer , Prescale = ...                      'für 1ms Interrupts
    
    'time_counter ist ein array für Zeitmessung für einzelne Bits im PIND
    Dim Time_counter(8) As Byte
    
    'Initialisierung von Pind_save und output_save
    Output_byte = Pind                                      'erstes Einlesen von PIND
    Pind_save = Output_byte
    
    'Erste Ausgabe über I2C
    I2c_write(output_byte)
    
    Do                                                          'Hauptschleife
    
      Pind_get = Pind                                      'Einlesen PIND Register
    
     'Feststellen, welche Eingänge sich geändert haben (entsprechende Pind_change Bits werden zu "1")
      Pind_change = Pind_get Xor Pind_save
    
      'Scannen nach geänderten Eingängen
      For Bit_no = 0 To 7
        'Nur veränderte PIND Eingänge bearbeiten
        If Pind_change.bit_no = 1 Then
          'Falls Eingang = "0" gab es Wechsel nach 0 -> Timer zum runterzählen setzen, sonst Wechsel nach "1" und Timer auf "0" setzen
          If Pind_get.bit_no = 0 Then Time_counter(bit_no) = 200 Else Time_counter(bit_no) = 0
          'Wenn Timer läuft, output noch auf "1" lassen sonst gegenwärtigen Zustand "0" oder "1" nach output übernehmen.
          If Time_counter(bit_no) > 0 Then Output_byte.bit_no = 1 Else Output_byte.bit_no = Pind_get.bit_no
        End If
      Next I
      Pind_save = Pind_get
      I2c_write(output_byte)                             'Ausgabe
    
    Loop                                                        'Ende Hauptschleife
    
    
    Isr_timer:                                                  'soll jede ms aufgerufen werden
      For I = 0 To 7
         If Time_counter(i) > 0 Then Time_counter(i) = Time_counter(i) - 1       'zählt Zeit für den "1" auf "0" Wechsel runter
      Next I
    Return
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.651
    .. Problem .. Eingänge eines Ports .. sofort übertragen werden .. aber verzögert wieder 0 wird ..
    Wenn ich Dich nu richtig verstanden habe - so etwas läuft bei mir öfters.
    Hintergrund: seit "Urzeiten" läuft auf fast allen meinen Controllern ein Heartbeat, den ich schon anfangs auf 50 µs festgelegt hatte. Diese Routine erledigt nur ein paar Timer, sonst nix. Beispiel Heartbeat. Die Routine zählt 20000 (zwanzigtausend) Interrupts, dann ist genau eine Sekunde rum - und eine LED wird getoggelt <=> solange diese LED blinkt ist der Controller "am Leben". Anfangs musste ich nämlich eigentlich bestimmte Laufzeiten messen, dabei erschienen mir die 50 µs als sinnvoller Kompromiss zwischen Auflösung und Interruptzeit-besetzte-CPU-time. Mittlerweile benutze ich diesen Takt zu mancherlei Zeitmessungen. Bei Dir fiele mir ne Lösung ein wie sie schon oben skizziert wurde:

    Du setzt einen Ausgang auf 1 - und der soll nach 200 ms wieder auf 0 gehen.
    Nun könnte ich auf meinen Platinen gleichzeitig mit dem "Ausgang-auf-1-setzen" einen separaten Timer>>WERT<< , sagen wir "modtron" auf 4001 setzen - dies entspräche bei meinem 50µs-Timer 200 ms + 50 µs *gg*. Der Wert modtron wird in der Timerroutine runtergezählt und ausgewertet, etwa so:
    Code:
      set(ausgang, 1);
      modtron  =  4001;
    ..
    // In der Timer-ISR
      if ( modtron ) modtron --;    // zählt nur bis 0 runter, 1Byte => max 255, 2 Byte max 65535
      if ( modtron == 1 ) set(ausgang, 0);
    ..
    Nun wird also der Ausgang 200 ms halten. Durch Setzen von modtron auf verschiedene Werte lässt sich die Abfallverzögerung variieren.

    Ist das verständlich ?
    Ciao sagt der JoeamBerg

  7. #7
    Benutzer Stammmitglied Avatar von modtronic
    Registriert seit
    14.05.2011
    Ort
    Hagen
    Alter
    46
    Beiträge
    68
    Zitat Zitat von Peter(TOO) Beitrag anzeigen
    Hallo Patrick,

    Etwas Software brauchst du dazu schon.

    Du brauchst für jedes Bit einen Timer. Das kannst du mit einem Timer-Interrupt machen, welcher z.B. alle 1ms aufgerufen wird.
    Wenn die Timer >0 wird der Wert jedes Mal um 1 verringert.

    Wenn du PORTD einliest, wird jedes Mal für eine gelesene 1 der entsprechende Timer mit 200 beschrieben.

    Für die Ausgabe musst für jeden Timer welcher >0 eine 1 ins entsprechende Bit setzen.

    So in der Art (nicht getestet):
    Code:
    unsigned char timer[8];
    
    void interrupt(void)
      {
         char i;
    
         for (i = 0; i < 8; i++)
           {
              if (timer[i]) timer[i]--;
           }
      }
    
    void out(void)
      {
        char i;
        unsigned char x = 0;
    
         for (i = 0; i < 8; i++)
           {
              if (timer[i]) (x |= (1 << i));
           }
          i2c_write (x); 
      }
    
    unsigned char in(void)
    {
        unsigned char x;
        char i;
    
         x = PORTD;
         for (i = 0; i < 8; i++)
           {
              if (x & (1 << i)) timer[i] = 200;
           }
    }
    Kann Reste von Tippfehlern enthalten.

    MfG Peter(TOO)
    Guten Morgen

    Vielen Dank. mit dieser Lösung könnte ich etwas anfängen
    könntest du mir dazu noch mehr erklären..
    zb was hinkommt wo das x ist ??

    Danke und Gruss
    Patrick

    - - - Aktualisiert - - -

    Moin

    Ich nochmal..manchmal sieht man ja den Wald vor lauter Bäumen nicht.
    ich habe eine Lösung gefunden, die zwar nicht so elegant ist wie hier oben beschrieben, aber jetzt auch läuft.

    Folgender Weg wurde eingeschlagen.
    Der I2C Datenwert besteht ja aus den Werten 0 - 255. Mein Gedanke war wie ich nun jeden einzelnen Pin steuern kann.
    Ich habe daher nun die Grundwerte 1, 2,4,8,16,32,64 und 128 auf eine Variable aufgeteilt, die immer nur diese Wertigkeit oder 0 hat.

    Ich habe dann diese einzelnen Variablen auf eine Gesamtvariable addiert, und diese dann an den Bus gesendet.
    Gleichzeitig werden diese Einzelvariablen immer von je einem PIN des AT-Mega gesteuert. Das erlaubt mir wiederum, jeden Beliebigen Pin zu verwenden und nicht zwingend ein komplettes Byte.
    Durch diese Addition wird z.b bei der Variable 1 und 2 eine 3 gesendet, was zwei Ausgänge GPA0 und GPA1 des MCP steuern.
    wenn nun die Variable 1 Low wird, und die 2 aber High bleibt, wird die 1 von dem Gesamtwert 3 abgezogen und es wird GPA1 HIGH bleiben und GPA0 wird Low werden.

    so kann ich nun jeden einzelnen Pin des MCP gezielt ansprechen.
    Wenn ich nun diese Einzelvariable noch im Abfall verzögere (Timer, Zähler) kann ich gezielt eine Abfallzeit für jeden Pin steuern.

    Wunderbar.

    Gruss
    Patte

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    27.08.2013
    Ort
    Region Basel
    Alter
    66
    Beiträge
    2.435
    Hallo Platte,
    Ich habe daher nun die Grundwerte 1, 2,4,8,16,32,64 und 128 auf eine Variable aufgeteilt, die immer nur diese Wertigkeit oder 0 hat.
    In manchen Programmiersprachen, wie z.B. ursprünglich in BASIC, gab es keinen anderen Weg um einzelne Bits manipulieren zu können.

    C/C++ hat aber von Anfang an extra Mechanismen um einzelne Bits manipulieren zu können.

    (1 << i) macht auch nichts anderes
    1 << 0 = 1
    1 << 1 = 2
    1 << 2 = 4

    C wurde ursprünglich entwickelt um ein Betriebssystem (Unix) schreiben zu können. Zu einem Betriebssystem gehören auch eine Menge Hardware-Treiber und folglich auch eine Menge Bits, welche bearbeitet werden müssen.

    BASIC steht für "Beginner’s All-purpose Symbolic Instruction Code", was so viel bedeutet wie „symbolische Allzweck-Programmiersprache für Anfänger. War also nur für Anwender-Programme gedacht. Auf vielen kleineren Computern wurde BASIC auch als "Betriebssystem" eingesetzt.

    Bis Auf Unix waren praktisch alle Betriebssysteme komplett in Assembler programmiert. Für eine neue CPU musste immer alles neu geschrieben werden. Unix bestand dann nur noch aus ein paar Prozent aus Assembler, der ganze Rest war in C geschrieben.

    Einen anderen Weg ging, ein paar Jahre später, U.C.S.D.-Pascal. Dabei bastelte man sich eine theoretische CPU zusammen, welche dann auf einer konkreten CPU simuliert wurde. Den Assembler-Code für diese simulierte CPU nannte man P-Code (Pseudo-Code). Man musste dann immer nur den P-Code für den einfachen Interpreter für eine neue CPU neu in Assembler schreiben.
    Java verwendet diese Technik heute noch, dort nennt man den P-Code Byte-Code.

    MfG Peter(TOO)
    Manchmal frage ich mich, wieso meine Generation Geräte ohne Simulation entwickeln konnte?

Ähnliche Themen

  1. Gabellichtschranke signal verzögern
    Von T4Sven im Forum Elektronik
    Antworten: 6
    Letzter Beitrag: 23.02.2013, 22:32
  2. Waasermelder Signal verzögern
    Von nero24 im Forum Elektronik
    Antworten: 11
    Letzter Beitrag: 15.01.2011, 09:59
  3. Signal um 250ns verzögern
    Von Robbo im Forum Elektronik
    Antworten: 16
    Letzter Beitrag: 15.03.2007, 11:19
  4. Relais nach x Sekunden abfallen lassen
    Von BlaueLed im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 7
    Letzter Beitrag: 17.11.2006, 17:34
  5. Antworten: 6
    Letzter Beitrag: 06.03.2006, 09:51

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiTime Speicher und Akkus