-
        

Ergebnis 1 bis 5 von 5

Thema: Freuqenz erzeugen

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    06.01.2009
    Alter
    26
    Beiträge
    104

    Freuqenz erzeugen

    Anzeige

    Hallo,

    möchte mit einem PIC (16F628A bzw 12F675) eine Frequenz an einem PIN erzeugen. Sie soll von ca. 20 Hz bis 1,6 kHz in 10 Hz Schritten mittels zweier Taster einstellbar sein. Eine Frequenz zu erzeugen war auch nicht das Problem, nur ist es so das es keine Lineare Funktion ist. Es lassen sich die niedrigen Werte sehr genau, die hohen Werte sehr ungenau einstellen.

    Um das zu verdeutlichen hab ich eine Wertetabelle im Anhang. Die Werte passen zwar nicht mehr zu dem Programm, verdeutlichen das Problem aber.

    Hier noch das Programm:

    Code:
    #pragma config |= 0b.0011.0101.0000.0010    //Prozessor Konfiguration
    void pause1(uns16 ms)
    {
        while(ms)
        {
            OPTION = 2;
            TMR0 = 131;
            while (TMR0);
            ms--;
        }
    }
    void pause(void)
    {
        OPTION = 2;
        TMR0 = 131;
        while (TMR0);
    }
    void main(void)                             // Hier beginnt das Hauptprogramm
    {
        TRISA = 0b.0000.0000;
        TRISB = 0b.1111.1111;
        bit Plus @ PORTB.1 ;                    // Pin RB1 erhält Name "Plus"
        bit Minus @ PORTB.2 ;                   // Pin RB2 erhält Name "Minus"
        char w;                                 // W für Tasterentprellung
        unsigned int Zahler;                    // Zähler für Taster
        Zahler=100;                             // Zähler-Startwert = 100
        Sprungmarke:
        if (Plus)                               // Wenn "Plus"-Taster gedrückt ist, dann
        {
            Zahler = Zahler + 10;               // Zähler + 10
    
        }
        for (w=0;w<50;w++)
        {
            pause();                            // Hier wird zum Entprellen gewartet
        }
        if (Minus)                              // Wenn "Minus"-Taster gedrückt ist, dann
        {
            Zahler = Zahler - 10;               // Zähler - 10
    
        }
        for (w=0;w<50;w++)
        {
            pause();                            // Hier wird zum Entprellen gewartet
        }
        PORTA.0 = 1;                            // PIN wird high
        pause1(Zahler);                         // Warte durch Zähler definierte Zeit
        PORTA.0 = 0;                            // PIN wird low
        pause1(Zahler);                         // Warte durch Zähler definierte Zeit
        goto Sprungmarke;
    }
    Ich hatte auch schon versucht das ganze mittels Switch und case umzusetzen, also jedem Wert eine Frequenz zuzuordnen. Das hat auch funktioniert allerdings wird das Programm dadurch natürlich viel zu groß. Deshalb hab es es dann nach 10 Werten gelassen, abgesehen davon wird es bei den hohen Frequenzen auch wieder unmöglich die 10er Schritte beizubehalten. Wenn jemand noch eine andere Idee hat, wie man es hinbekomm eine Frequenz zu erzeugen die man in 10er Schritten hoch bzw. runter stellen kann wäre ihm sehr dankbar.

    Gruß
    Kevin
    Miniaturansichten angehängter Grafiken Miniaturansichten angehängter Grafiken wertetabelle.jpg  

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    521
    Das Hauptproblem liegt darin, daß Du die Zeiten nicht berücksichtigst, welche für die eigentlichen Programmzeilen benötigt werden.
    Der Timer selbst läuft schon absolut exakt.
    Das ist bei tiefen Freuqenzen nicht ganz so tragisch, je höher aber deine Frequenz wird, desto mehr
    geht diese zusätzliche Zeit mit ein, bzw. macht sich negativ bemerkbar.
    Zwischen deiner "Sprungmarke" und dem Setzen des Ports auf Low, liegt ja deine Tastenabfrage, während dieser
    Zeit ist der Portpin weiterhin auf LOW. Während deiner Entprellzeiten ebenfalls.


    Um eine exakte Frequenz zu erzeugen gäbe es folgende Möglichkeit.
    Ich hoffe, daß ich es nicht zu schwierig erkläre, weil das ist nicht ganz so einfach zu verstehen.
    mit dem PIC16F628:

    Der RB3/CCP1 Pin ist dein Ausgang für die Frequenz.
    Timer 1 wird ganz normale als aufwärtszähler benutzt. Also von 0..65535 mit internem Takt
    Das Capture Compare Register CCP1L sowie CCP1H wird als Vergleichsregister benutzt,
    also der "Compare Mode" hier muss ein Wert rein, welcher irgendwie deiner Frequenz entspricht.
    Wenn der Timer 1 und das Vergleichsregister übereinstimmen, wird etwas ausgelöst.
    Hier gibt es einen sogenannten "Special Event Trigger"
    Der kann dann den PIN RB3 automatisch entweder auf High oder auf Low setzen.
    Das Timer Register wird dann automatisch wieder gelöscht und der Timer fängt wieder an von 0 zu zählen.
    So bekommst Du ein einwandfreies Timing. Wenn dann deine Tasten betätigt werden, muss der Wert in den
    Registern CCP1L und CCP1H verändert werden.

    Prinzipeller Ablauf:
    Timer 1 wird auf Asynchron Counter Mode gesetzt.
    Du setzt im CCP1M Register den Wert so, daß bei einer Übereinstimmung der Ausgangspin RB3/CCP1 auf High gesetzt wird.
    also CCPM BITS = 1000
    Wenn ein Interrupt ausgelöst wird, stellt sich der Timer automatisch wieder auf 0 zurück, darum brauchst Du Dich nicht kümmern.
    nun stellst Du in aller Ruhe das CCP1M Register so ein, daß bei der nächsten Übereinstimmung der Ausgangspin RB3/CCP1
    auf Low geschaltet wird. Also CCPM Bits = 1001
    Wenn der nächste Interrupt kommt, stellst Du die CCPM Bits wieder auf 1000 wie am Anfang.
    So bekommst Du ein "einwandfreies Timing" für deinen Pin.

    Info: Das geht nur mit Timer 1.
    Der Inhalt des Zählerregisters vom Timer 1 ist in diesem Falle völlig unwichtig.
    In den Registern CCP1L und CCP1H muss der Vergleichswert stehen, wann der PIN umschalten soll.
    Also im Prinzip die halbe Frequenz, da der Pin mit jedem Ablauf des Timers umgeschaltet wird.

    nicht einfach, gebe ich zu.
    ich hoffe, ich konnte Dir damit etwas helfen.

    mfg Siro

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    06.01.2009
    Alter
    26
    Beiträge
    104
    Danke erstmal für die Antwort.
    Das Prinzip habe ich verstanden, allerdings hackts an der Umsetzung. Habe von Assembler Null Ahnung und mit C kann man nicht in Register schreiben, oder? (außer Inline Assembler).

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    05.11.2007
    Ort
    Berlin
    Beiträge
    521
    Hallo Kevin,

    natürlich kannst Du in "C" auch in die Register schreiben, das hast Du doch schon getan:

    TMR0 = 131;
    TRISA = 0b.0000.0000
    PORTA.0 = 0;

    das sind alles direkte Registerzugriffe.

    Das Problem bei mir liegt darin, daß ich noch nie die PICs in "C" programmiert habe. Gibts denn da überhaupt einen "Free C Compiler ?"

    mfg. Siro

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    06.01.2009
    Alter
    26
    Beiträge
    104
    Zitat Zitat von Siro
    natürlich kannst Du in "C" auch in die Register schreiben, das hast Du doch schon getan:
    , Alles klar, Danke!

    Zitat Zitat von Siro
    Das Problem bei mir liegt darin, daß ich noch nie die PICs in "C" programmiert habe. Gibts denn da überhaupt einen "Free C Compiler ?"
    Jo, es gibt cc5x, die kostenlose Version erlaubt zwar nur bis 1k Code, dass kann man aber legal umgehen. http://cc5x.de/

    Gruß Kevin

Berechtigungen

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