- LiTime Speicher und Akkus         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 17

Thema: mega168 - ICP vs. Port als Ausgang?!

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30

    mega168 - ICP vs. Port als Ausgang?!

    Anzeige

    Praxistest und DIY Projekte
    Hi.

    - ATmega168
    - AVR-Studio 4.12 SP1
    - AVR-GCC 3.4.5
    - AVR-DUDE 1.72 mit GUI 0.2.0

    Ich Suche nach einer Möglichkeit, wie ich die oberen 4 Bit (7-4) eines Ports beschreiben kann, OHNE auf den unteren 4 Bit (3-0)/Pins Interrupts auszulösen..
    Wozu?:.. Ich will das Input-Capture-Register auf einer LED-Zeile ausgeben (8 Stück).

    Zuordnung der LED's zu den Pins/Ports: |PB7|PB6|PB5|PB4|PC3|PC2|PC1|PC0|

    Weshalb diese Zerstückelung? Weil:...
    - PB0 wird für den Input Capture Pin benötigt.
    - Port C hat nur 7 Bit.
    - Port D wird auch schon durch Interrupt belegt..

    Die Auszugebende Variable ist folgendermassen definiert und wird durch Zuweisung aus dem ICR1 (Input-Capture-Register) gewonnen, bei einem solchen Interrupt:

    volatile unsigned short int icp;
    icp = ICR1;


    Ports sind folgendermassen initiiert:
    DDRB |= (1<<DDB7)|(1<<DDB6)|(1<<DDB5)|(1<<DDB4); /* PinB7-4 als AUSGANG */
    DDRB |= (0<<DDB0); /* Eingang für ICP1 */
    DDRC |= (1<<DDC3)|(1<<DDC2)|(1<<DDC1)|(1<<DDC0); /* PinC3-0 als AUSGANG */
    DDRD |= (0<<DDD3)|(0<<DDD2); /* Eingänge für INT0 und INT1 */


    Nun will ich die binäre Information der Variablen 'icp' auf den Pins 7-4 des Port B ausgeben und hab dies bisher folgendermassen getan:

    PORTB = ~(icp);

    Gibt es eine Möglichkeit, wie ich das Beschreiben der unteren 4 Bits von Port B bei dieser Zuweisung "schützen" kann, so dass dort garantiert keine Interrupts ausgelöst werden?
    Ist dies schon mit Hilfe der Richtungsangabe im Data-Direction-Register erledigt?

    Danke und Grüße
    Nico

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.02.2005
    Ort
    Erfurt
    Alter
    58
    Beiträge
    134
    >Gibt es eine Möglichkeit, wie ich das Beschreiben der unteren 4 Bits >von Port B bei dieser Zuweisung "schützen" kann, so dass dort >garantiert keine Interrupts ausgelöst werden?

    ja, ganz einfach,

    1. den jeweiligen PORTx erstmal einlesen durch "in temp, PINx"
    2. dann mit and bzw or die jeweiligen PINS herausfiltern und schützen
    jeweils vom PORTx und von Deinem Wert
    3. das ganze wieder zurückschreiben "out PORTx, temp"


    PS: der zweite Schritt kann etwas knifflig sein, aber Dir fällt sicherlich was dazu ein ?

    Bernhard

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    57
    Beiträge
    1.195
    Ja das geht:
    Code:
    uint8_t icp; // icp ist ein 8bit wert
    uint8_t pb;
    
    pb    = PINB & 0x0f; // nur die unteren vier bit
    icp  &= 0xf0;        // nur die oberen vier bit
    PORTB = icp | pb;

  4. #4
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30
    Ok, Danke ihr Zwei. Nun weiß ich wenigstens, dass diese Sache nicht das Problem ist.

    Ich werd mal nen neuen Thread aufmachen..

    Grüße
    Nico

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Du musst erst das icp auseinanderfriemeln:
    Code:
    #include <avr/interrupt.h>
    ...
    uint8_t sreg = SREG;
    cli();
    uint16_t icp1 = ICP1;
    uint8_t portc = PORTC & 0xf0;
    uint8_t portb = PORTB & 0x0f;
    PORTB = portb | (icp1 & 0xf0); // bits 4..7
    PORTC = portc | (icp1 & 0xf); // bits 0..3
    SREG = sreg;
    Offenbar verwendest du Interrupts. Das SREG mit cli() brauchst du, falls du PORTC oder PORTB in einer ISR änderst, damit die Änderungen nicht durch die Sequenz überschrieben werden.
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    21.10.2005
    Ort
    Erde
    Alter
    57
    Beiträge
    1.195
    Es muss IMHO aber auf der rechte Seite PINC heissen.

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30
    Ist ok.. die Tipps waren ok und es funktioniert auch damit..

    Das Problem lag aber woanders. Ich will einen Impuls messen (2µs, 4µs, 8µs...). INT0 nimmt die steigende Flanke und resettet Timer1 (16Bit) mit einem nackten Assembler Interrupt (11cycles lang). Die fallende Flanke wird dann vom ICP über das ICR1 Register des Timer1 aufgenommen.
    Laut Datenblat des ATmega168 kein Thema und im Bereich des Möglichen.

    Mein Problem war nun, das dieser Impuls im Bereich von 2µs noch erfassbar sein sollte.. deswegen wollte ich mir (was jetzt funktioniert - auch ohne die oben angegebene Interrupt-sichere Beschreibung der Ausgabepins) den Wert von ICR1 binär ausgeben lassen..
    Zu erwarten sind ungefähr Werte von 16, 32, 64.. (16cyclesx0,125µs/cycle sind grade 2µs) usw.. für die Impulsbreite, aber die kamen nicht..
    Auf der LED Zeile war irgendwie nichts stimmig.. weswegen ich hier Probleme mit zufällig ausgelösten Interrupts vermutete, ansonsten sah ja alles gut aush.. naja..

    ..4h später - eher zufällig...

    Gelegen hats an folgendem:
    Der Clock des Prozessors muss für diese Messung natürlich auf 8MHz laufen - Standard ist 1MHz - Prescaler=8.. also muss man auch den Clock_IO Prescaler verstellen..
    Ich dachte das hätte ich!..
    (hätte eigentlich schon vorher stutzig werden müssen, da die kleinste mögliche Messung 32µs betrug!)

    Nun ja:
    CLKPR |= (1<<CLKPCE);
    CLKPR = 0;

    funktionierte offensichtlich nicht, wie ich feststellen musste.
    Der CLK_IO blieb bei 1MHz. /den Schnipsel hatte ich glaube aus dem Forum...

    Verwendet hab ich nun:
    CLKPR = (1<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)(0< <CLKPS0);
    CLKPR = (0<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)(0< <CLKPS0);


    Damit funktioniert alles wie ich es wollte...
    2µs Impulse sind damit erfassbar.. INTO resettet Timer1 und ICP1 liest den Wert vom Timer1 bei fallender Flanke.

    Ich denke mal, ich bräuchte nur bei der oberen Variante die erste Zeile durch 'CLKPR = 0x80;' ersetzen und es würde laufen.. vielleicht teste ich das morgen
    Die Vorschrift zum setzen des CLK_IO Prescalers sagt ja, zuerst CLKPCE auf 1 und alle anderen auf Null und dann danach gleich CLKPCE auf Null und die anderen entsprechend dem Prescale... der '|' wird wohl der Übeltäter sein, da durch seinen Einsatz die CLKPS-Bits nicht gesetzt werden (IMHO)

    Grüße und vielen Dank
    Nico

    PS: wenn der Code noch gewünscht wird, bitte bescheid sagen, dann poste ich den noch..

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Zitat Zitat von ogni42
    Es muss IMHO aber auf der rechte Seite PINC heissen.
    Wirklich?

    Mit PORTX liest man die Werte aus PORTX zurück, wie man sie geschrieben hat. Wenn man PINx liest und es ist ein Eingang, würde man mit Lesen von PINX und Schreiben nach PORTX die Pullups verstellen, wenn sich das Signal ändert!
    Disclaimer: none. Sue me.

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    17.02.2005
    Ort
    Erfurt
    Alter
    58
    Beiträge
    134
    >...das dieser Impuls im Bereich von 2µs noch erfassbar sein sollte..

    Ich kenn das Problem mit den kurzen Impulsen, deshalb schalte ich gern

    ein einfaches FLIP-FLOP-GATTER vor den Eingang, somit ist die

    Impulslänge total egal

  10. #10
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Und wie unterscheidest du dann z.B. zwischen 2µs und 4µs-Pulsen?
    Disclaimer: none. Sue me.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

LiTime Speicher und Akkus