Willkommen in unserer Community

Werde Teil unserer Community und registriere dich jetzt kostenlos ...

Berechnung eines RC-Gliedes für's Einstellen der Frequenz

Dieses Thema im Forum "Schaltungen und Layout" wurde erstellt von Hemi, 2. März 2018.

  1. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    Servus zusammen,

    irgendwie stehe ich auf dem Schlauch und brauche Eure Schwarmintelligenz. :)

    Also, es existiert ein Rechtecksignal, das so aufgebaut ist:

    signal.png

    Dieses Signal wird von einem Multiplexer erzeugt. Der Multiplexer hat acht Eingänge (Switch 1, Switch 2, ....), die gelesen werden und dann die Flanken im Signal gesetzt werden (die Flächen mit einem X).

    Dieser Multiplexer läuft mit einer Frequenz, die über ein RC-Glied eingestellt wird, nach der Formel:

    formel.png
    Also: fosc = 1/(Cosc * (0,79*Rosc + 2260))

    Soweit so gut und auch verständlich.

    Dann, gibt es im Datenblatt eine "Referenztabelle", die so aussieht:
    werte.png

    Und davon abgeleitete Timings:
    timings.png

    Auch, soweit so gut. One bit von 0,156ms entspricht 6,4kHz Frequenz, bzw. 6,41kHz.

    Wenn ich aber die Werte für Cosc und Rosc in die Formel oben einfüge, bekomme ich ein ganz anderes Ergebnis:

    fosc = 1/(0,000000001 * (0,79*200000 + 2260))
    fosc = 1/(0,000000001 * 160260)
    fosc = 1/0,00016026
    fosc = 6239,86Hz

    Es sollten aber 6410Hz rauskommen, das entspricht einer Abweichung von rund 170Hz, das ist schon heftig, wie ich finde.

    Habe ich einen Denkfehler?

    Hier ist das Datenblatt zum Multiplexer und Demultiplexer: klick mich

    Die Formel ist direkt auf der Seite 1, die Timings und Referenzwerte finden sich auf der Seite 5.

    Vielen Dank Euch!
     
  2. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Na ja, so ganz heftig finde ich 'ne Abweichung von 2,6 % jetzt nicht grade. Bei Bauteiltoleranzen von 10-20 % kann man das vernachlässigen.
    Auf Seite 15 steht, daß die Oszillatorfrequenz für den Transmitter minimal 1kHz und maximal 20kHz betragen darf.
    Und da der Receiver mit vierfacher Frequenz sampled, sollte so eine kleine Abweichung locker ausgeglichen werden können.
     
  3. Pirx

    Pirx Mitglied

    Registriert seit:
    15. August 2009
    Beiträge:
    252
    Zustimmungen:
    6
    Ort:
    Möckern
    Sprachen:
    Assembler
    Map
    Hallo Hemi,

    ich komme auf dasselbe Ergebniss und einen Denkfehler kann ich nicht erkennen.

    Im Abschnitt 1.2 ist zwar auch von Toleranzen des internen Widerstands die Rede aber mit dem 100fach größeren externen Widerstand macht der gerade mal knapp 1% aus und die Abweichung liegt bei 2,7%.

    Vielleicht ein Fehler im Datenblatt ? Vielleicht nochmal beim Hersteller danach suchen ... ?

    Gruß
    Pirx
     
    #3 Pirx, 2. März 2018
    Zuletzt bearbeitet: 3. März 2018
  4. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    Hallo Ihr Beide, danke schön erstmal :)

    Hersteller kontaktieren ist so eine Sache, den Chip gibt seit 15 Jahren nicht mehr und Temic ist jetzt nicht der Hersteller, der gern weiterhilft...

    So wie ich es rauslese, beträgt der MUX und DEMUX Verhältnis 1:4, sprich der Demultiplexer läuft mit 4x Multiplexerfrequenz.

    Ich habe ein Signal, was eine Bitzeit von 0,17ms hat (statt 0,156ms von oben). Meint es wird trotzdem noch gehen? Oder soll ich RC doch etwas anpassen?
     
  5. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Im Datenblatt habe ich auf die Schnelle keine Angaben zu geforderten Bauteiletoleranzen gefunden, daher würde ich davon ausgehen, daß Bauteile mit üblichen Toleranzen ausreichen, d.h. 10 % für Widerstände und 20 % für Kondensatoren. Das kann einen Gesamtfehler von +-30 % ergeben. Da liegst Du mit 8 % doch recht gut.

    Ich würde es so probieren. Wenn es nicht funktioniert, kannst Du die Frequenz ja immer noch anpassen.
     
  6. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    Ich habe das Datenblatt durchgelesen und habe da auch nichts bezüglich der Toleranzen finden können.

    Übrigens auch bei Berechnung der Frequenz für den Receiver mit den gegebenen RC Werten liegt man daneben... Es sollten 25,6kHz sein, sind aber mit den gegebenen Werten 28,363kHz...

    EDIT: Wenn beim für Rocs 220k einsetzt, kommt man auf 25,817kHz, also liegt nicht mal so sehr daneben...

    Dann latsche ich am Montag mal beim Conrad und hole die einpaar Kondensatoren und Widerstände.
     
    #6 Hemi, 2. März 2018
    Zuletzt bearbeitet: 2. März 2018
  7. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    War bei Conrad und Zeug geholt, leider hatten sie ein Widerstand nicht, muss erst noch einbisschen waren.

    Hab ich in der Zwischenzeit etwas programmiert, man könnte es ja schön über ICP abtasten, hier der Code (angehängt ist das ganze Projekt, hier nur ISR):



    CodeBox C und C++
    ISR(TIMER1_CAPT_vect) {  
        uint16_t clicks = ICR1;
    
        // interrupt gefeuert bei der fallenden Flanke
        if ( !(TCCR1B & (1 << ICES1)) ) {
            invert_icp();
          
            // start des frames, der Timerwert ist sehr groß
            if (is_between(clicks, DATA_INTERVAL_LOW, DATA_INTERVAL_HIGH)) {
                state = start_of_frame;  
                actual_bit = 0;
                total_edge_counter = 0;
                value = 0;
            }
          
            // kurzer bit = 1
            if (is_between(clicks, DATA_SHORT_LOW, DATA_SHORT_HIGH)) {
                value |= (1 << actual_bit);
                actual_bit += 1;
            }
          
            // langer bit = 0
            if (is_between(clicks, DATA_LONG_LOW, DATA_LONG_HIGH)) {
                value |= (0 << actual_bit);  
                actual_bit += 1;
            }
        }
      
        // interrupt gefeuert auf der steigenden flanke
        if ( TCCR1B & (1 << ICES1) ) {
            reset_icp();
            invert_icp();
        }
      
        total_edge_counter += 1;
      
        if ((total_edge_counter == 17) && (actual_bit == 7)) {
            value ^= (0xff);
            state = end_of_frame;
        }
    }
    


    Die Variable state ist nur eine StateMachine, diese wird in der main() abgefragt und ist ein Merker dafür, dass der Frame vollständig empfangen wurde.

    Was meint Ihr?
     

    Anhänge:

    • MFL.zip
      Dateigröße:
      33,1 KB
      Aufrufe:
      1
  8. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Habe nicht alles genau angesehen, aber diese Zeile:


    CodeBox C und C++
    value |= (0 << actual_bit);

    tut garnichts.

    Ich hätte das eher so gemacht:


    CodeBox C und C++
    // interrupt gefeuert bei der fallenden Flanke
        if ( !(TCCR1B & (1 << ICES1)) ) {
            invert_icp();
          
            // start des frames, der Timerwert ist sehr groß
            if (is_between(clicks, DATA_INTERVAL_LOW, DATA_INTERVAL_HIGH)) {
                state = start_of_frame;
                actual_bit = 0x01; // bit 0 setzen
                total_edge_counter = 0;
                value = 0;
            }
          
            // kurzer bit = 1
            if (is_between(clicks, DATA_SHORT_LOW, DATA_SHORT_HIGH)) {
                value |= actual_bit; // aktuelles bit speichern
                actual_bit <<= 1; // bit um eine Position nach links verschieben
            }
          
            // langer bit = 0
            if (is_between(clicks, DATA_LONG_LOW, DATA_LONG_HIGH)) {
                                 // hier braucht nichts gespeichert zu werden
                actual_bit <<= 1; // aber das bit muß auch hier geschoben werden
            }
        }

    und hier muß es dann natürlich


    CodeBox C und C++
    if ((total_edge_counter == 17) && (actual_bit == 0x80))

    heißen.
    Da die AVRs keinen Barrelshifter haben, muß in Deiner Version die 1 bzw. 0 insgesamt 28 mal geschoben werden, um ein Byte zu empfangen. (Der Compiler würde das Schieben der 0 wahrscheinlich wegoptimieren)
    In meiner Version braucht nur 7 mal geschoben zu werden.
     
  9. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    Hallo Mikro,

    danke Dir erstmal.

    Die Variable "actual_bit" ist lediglich ein Zähler, der die Bits im Frame fählt (oben im Bild heißt es Switch 1 bis Switch 8).

    Das Schiften einer 0 kann man auch weglassen, da hast Du natürlich Recht, war nur eine Gedankenstütze für mich.

    Auch in meiner Version wird nur acht Mal geschoben, weil es nur 8 fallenden Flanken gibt und die vor den Startbits ist für's Schieben uninteressant (das wäre dann die 9te fallende Flanken, die Initialisiert das Ganze).
     
  10. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Nein, da actual_bit keine Konstante ist, muß die Anzahl der Schiebeoperationen zur Laufzeit berechnet werden, wie man im Disassemblerlisting sehen kann.


    CodeBox Assembler
             value |= (1 << actual_bit);
    0000009D  LDS R18,0x0061     Load direct from data space
    0000009F  LDI R24,0x01       Load immediate
    000000A0  LDI R25,0x00       Load immediate
    000000A1  MOV R0,R18         Copy register
    000000A2  RJMP PC+0x0003     Relative jump
    000000A3  LSL R24            Logical Shift Left
    000000A4  ROL R25            Rotate Left Through Carry
    000000A5  DEC R0             Decrement
    000000A6  BRPL PC-0x03       Branch if plus
    000000A7  LDS R25,0x0060     Load direct from data space
    000000A9  OR R24,R25         Logical OR
    000000AA  STS 0x0060,R24     Store direct to data space
             actual_bit += 1;
    000000AC  SUBI R18,0xFF      Subtract immediate
    000000AD  STS 0x0061,R18     Store direct to data space
    000000AF  RJMP PC-0x0035     Relative jump
    

    Warum sogar eine 16bit-Variable geschoben wird ist mir jetzt auch noch nicht ganz klar.
    Auf jeden Fall wird, wenn actual_bit = 1 ist einmal geschoben, bei 2 zweimal... und bei 7 siebenmal.

    Edit:
    Da die 1 in

    CodeBox C und C++
    value |= (1 << actual_bit);
    nicht weiter spezifiziert ist, nimmt der Compiler wahrscheinlich an, daß es sich um eine Integer-Konstante handelt und Integer hat auf AVRs 16 Bit.
     
    #10 Mikro23, 8. März 2018
    Zuletzt bearbeitet: 8. März 2018
  11. LotadaC

    LotadaC Sehr aktives Mitglied

    Registriert seit:
    22. Januar 2009
    Beiträge:
    2.877
    Zustimmungen:
    42
    Ort:
    Hennigsdorf
    Sprachen:
    BascomAVR, Assembler
    Map
    Nicht auf AVRs, sondern Euer C-Compiler nimmt für Integer 16-Bit an.
    Die AVRs selbst kennen eigentlich(*) nur ganzzahlige (->Integer) 8-Bit-Zahlen. Selbst vorzeichenbehaftet/-los ist für den AVR kein Unterschied. Der ergibt sich nur durch die, ... genau ... vom Compiler(!) verwendeten Instruktionen.

    (*) Als Ausnahmen gibt es:
    • zwei Instruktionen, die eine 5-Bit-Konstante (also 0..63) auf ein Doppelregister addieren, oder von diesem subtrahieren können.
    • eine Instruktion, die ein Register-Paar in ein anderes Register-Paar kopieren kann.
     
  12. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Ja, klar. Die Controller selbst kennen überhaupt keine Datentypen wie Integer o.ä.
    Ich meinte natürlich, daß der GCC für AVRs die Wortbreite für Integer standardmäßig auf 16 Bit setzt, wenn nichts anderes angegeben ist. Wenn der GCC Programme für neuere PCs übersetzt, ist Integer ohne genauere Angabe 64 Bit breit.
     
  13. Hemi

    Hemi Premium Benutzer

    Registriert seit:
    30. November 2008
    Beiträge:
    963
    Zustimmungen:
    4
    Ort:
    Korntal-Münchingen, Germany
    Sprachen:
    C, C++, PHP, Java
    Map
    @Mikro23 : Danke Dir für die Erklärung. :) Ist jetzt nicht wirklich sinnvoll, was der GCC da macht.
     
  14. Mikro23

    Mikro23 Mitglied

    Registriert seit:
    2. Januar 2017
    Beiträge:
    211
    Zustimmungen:
    15
    Ort:
    Großraum Hannover
    Sprachen:
    C, Assembler
    Map
    Der Compiler macht genau das, was Du ihm sagst. Wenn Du ihm sagst: nimm eine 16bit-Konstante (die 1) und schiebe sie um eine zur Compilezeit unbekannte Anzahl von Stellen (actual_bit) nach links, dann hat er das hier genau richtig gemacht. ;)
    Da die aktuelle Bitposition nirgendwo explizit gebraucht wird, habe ich statt des Bitzählers die 8bit-Variable mit einer 1 an Bitposition 0 geladen, verodere sie bei Bedarf mit der Zielvariablen und schiebe sie anschließend um eine Bitposition nach links.
    Man könnte das sicher auch so hinkriegen, das er nur eine 8bit-Konstante nimmt, da ich aber so gut wie nie Bitpositionen brauche, sondern immer nur Bitmasken, habe ich mir darüber noch keine Gedanken gemacht. (Die Anzahl der Schiebeoperationen (28 wenn alle Bits gesetzt sind) würde das aber auch nicht ändern.)

    Bei solchen Ausdrücken dagegen:

    CodeBox C und C++
    TIMSK |= (1 << TICIE1);
    ist TICIE1 eine Konstante und der Ausdruck (1 << TICIE1) kann gleich vom Präprozessor berechnet und in eine Bitmaske verwandelt werden. Zur Laufzeit kein Schieben mehr nötig.

    Ich habe mit Assembler (6800, 6502, 6805, 6809, 68000) angefangen zu programmieren und schaue deshalb gerne mal nach, was der Compiler so aus meinem Programm macht. Daher ist der C-Compiler für mich immer noch sowas wie ein besserer Makroassembler. ;)

    Im Allgemeinen werden C-Programme mit dem GCC schneller und kleiner, als ich es selbst in Assembler schreiben könnte, allerdings es gibt immer mal wieder so kleine Haken, die man aber meistens durch eine andere Programmstruktur umgehen kann, wie man an meiner Version sehen kann.

    CodeBox Assembler
            value |= actual_bit;
    0000009E LDS R24,0x0061   Load direct from data space
    000000A0 LDS R25,0x0060   Load direct from data space
    000000A2 OR R25,R24       Logical OR
    000000A3 STS 0x0060,R25   Store direct to data space
            actual_bit <<= 1;
    000000A5 LSL R24          Logical Shift Left
    000000A6 STS 0x0061,R24   Store direct to data space
    000000A8 RJMP PC-0x002E   Relative jump
     
  • Über uns

    Unsere immer weiter wachsende Community beschäftigt sich mit Themenbereichen rund um Mikrocontroller- und Kleinstrechnersysteme. Neben den Themen Design von Schaltungen, Layout und Software, beschäftigen wir uns auch mit der herkömmlichen Elektrotechnik.

    Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  • Coffee Time

    Unser makerconnect-Team arbeitet hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und unser eigener makerconnekt-Server regelmäßig gewartet wird. Wir nehmen das Thema Datensicherung und Datenschutz sehr ernst und sind hier sehr aktiv, auch sorgen wir uns darum, dass alles Drumherum stimmt!

    Dir gefällt das Forum und die Arbeit unseres Teams und du möchtest es unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft, unser Team freut sich auch über eine Spende für die Kaffeekasse :-)
    Vielen Dank!
    Dein makerconnect-Team

    Spende uns! (Paypal)