Forum: Mikrocontroller und Digitale Elektronik MSP430F16xx-- CAP-Modus im Timer B einstellen


von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Leider komme ich mit meinem Problem, welches schon im 
Beitrag "MSP430F1610 und TIMER-B" beschrieben wurde, 
nicht weiter. Ich will die Impulslänge, welche ein 
Ultraschallabstandsmesser als Echo sendet, messen.
Mit dem Eingang TB0 (1.Gerät) funktioniert die Messung einwandfrei, 
während die Messung mit z.B. TB3 (2.Gerät) nicht läuft.
Offensichtlich reicht es nicht, nur die Register von TBCCTL0 auf z.B. 
TBCCTL3 umzustellen und  TBCCR3 auszulesen.
In dem Datenblatt zum MSP430F16xx  steht unter
„interrupt vector addresses“
Timer_B7 (see Note 5) TBCCR0 CCIFG (see Note 2) Maskable 0FFFAh 13
Timer_B7 (see Note 5) TBCCR1 to TBCCR6 CCIFGs, TBIFG (see Notes 1 & 2)
Maskable 0FFF8h 12

was ich leider nicht deuten kann. Ich entnehme nur, dass es einen 
Unterschied zwischen TBCCR0 und TBCCR1 bis TBCCR6 gibt.
Kennt sich jemand genauer damit aus und könnte mir helfen?

von Clemens L. (c_l)


Lesenswert?

Das User's Guide sagt in Abschnitt 12.2.6:
> Two interrupt vectors are associated with the 16-bit Timer_B module:
> ☐ TBCCR0 interrupt vector for TBCCR0 CCIFG
> ☐ TBIV interrupt vector for all other CCIFG flags and TBIFG

oder <msp430f1610.h>:
> #define TIMERB1_VECTOR  (13)    /* 0xFFF8 Timer B CC1-6, TB */
> #define TIMERB0_VECTOR  (14)    /* 0xFFFA Timer B CC0 */

Für CCR3 darfst du also nicht TIMERB0_VECTOR nehmen.

Und außer für CCR0 werden die CCIFG-Bits nicht automatisch gelöscht. Das 
muss dein Code tun; siehe das User's Guide.

von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Clemens L. schrieb:
> Für CCR3 darfst du also nicht TIMERB0_VECTOR nehmen.
>
> Und außer für CCR0 werden die CCIFG-Bits nicht automatisch gelöscht. Das
> muss dein Code tun; siehe das User's Guide.

Danke für die Hinweise.
Die Umstellung auf TIMERB1 sollte ja nicht das Problem sein.
Aber wie die CCIFG-Bits zu löschen sind, da hab ich wieder so meine 
Probleme.

Im Anhang mein "überarbeiteter" Programmschipsel mit der Fehlermeldung 
für die letzte Zeile:
>Error[Pe137]: expression must be a modifiable lvalue

Wie wäre es richtig?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Was soll TBIV_TBCCR3 sein?

Im "Family User's Guide" (slau049f) gibt es das nicht.

von Wolle G. (wolleg)


Lesenswert?

Rufus Τ. F. schrieb:
> Was soll TBIV_TBCCR3 sein?

steht bei mir in msp430x16x.h

>/* TB7IV Definitions */
>#define TBIV_NONE           (0x0000)    /* No Interrupt pending */
>#define TBIV_TBCCR1         (0x0002)    /* TBCCR1_CCIFG */
>#define TBIV_TBCCR2         (0x0004)    /* TBCCR2_CCIFG */
>#define TBIV_TBCCR3         (0x0006)    /* TBCCR3_CCIFG */

wahrscheinlich bin ich da auf dem Holzweg

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ah. Das ist ein Bitwert, kein Register.

Du willst im Register TBIV etwas löschen:
1
TBIV &= ~TBIV_CCR3;

Sieh Dir im Family User's Guide die Seite 12-25 an, da wird das Register 
TBIV beschrieben.

von Wolle G. (wolleg)


Lesenswert?

Rufus Τ. F. schrieb:
> TBIV &= ~TBIV_CCR3;

Leider erzeugt diese Zeile bei mir die gleiche Fehlermeldung.
>Error[Pe137]: expression must be a modifiable lvalue

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das würde bedeuten, daß es das Register TBIV nicht gibt. Da stimmt was 
nicht.

Sieh Dir dir Tabelle der Register in slau049f auf Seite 12-20 (244) an.

Wie ist das Register mit der Adresse 0x11E in Deiner Headerdatei 
definiert?

von Clemens L. (c_l)


Lesenswert?

Rufus Τ. F. schrieb:
> Das ist ein Bitwert

Nein, das ist die Nummer des Interrupts (mal zwei, damit man das direkt 
als Offset verwenden kann).

Das IFG-Bit kann man auf die übliche Art löschen:
1
TBCCTL3 &= ~CCIFG;

Aber wenn man mehrere Interrupts behandeln muss, nimmt man lieber das 
IV-Register:
1
switch (TBIV) {
2
case TBIV_TBCCR1:
3
    ...
4
    break;
5
case TBIV_TBCCR2:
6
    ...
7
    break;
8
case TBIV_TBCCR3:
9
    ...
10
    break;
11
...
12
}
Beim Lesen des TBIV-Registers wird das entsprechende IFG-Bit autmatisch 
gelöscht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du hast natürlich recht. Habe wohl nicht aufmerksam genug in die 
Dokumentation gesehen; das Register TBIV ist obendrein nur les-, aber 
nicht beschreibbar.

von Wolle G. (wolleg)


Lesenswert?

Rufus Τ. F. schrieb:
> Wie ist das Register mit der Adresse 0x11E in Deiner Headerdatei
> definiert?

meinst Du damit diese Definitionen?
>* Timer B7
>************************************************************/
>#define _MSP430_HAS_TB7_ /* Definition to show that Module is available */

>#define TBIV_               (0x011E)  /* Timer B Interrupt Vector Word */
>READ_ONLY DEFW( TBIV           , TBIV_)
>#define TBCTL_              (0x0180)  /* Timer B Control */
>DEFW(   TBCTL             , TBCTL_)
>#define TBCCTL0_            (0x0182)  /* Timer B Capture/Compare Control 0 */
>DEFW(   TBCCTL0           , TBCCTL0_)

Ich habe es zusätzlich mal mit mspgcc probiert. Hier kommt zwar keine 
Fehlermeldung, aber das Programm hängt sich auf.

Da war ich zu langsam. Die weiteren Tips werde ich mal testen.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ich bin mit meinen Kenntnissen des 'F1611 wohl etwas arg rostig; ich 
kann Dir nur raten, Dir mal die verschiedenen Sourcecodebeispiele von TI 
höchstselbst zu Gemüte zu führen - und ansonsten den Beitrag von Clemens 
zu lesen.

http://www.ti.com/lit/zip/slac015

von Wolle G. (wolleg)


Lesenswert?

So richtig verstanden habe ich zwar noch nicht alles, aber mein Programm 
läuft jetzt erst einmal wunschgemäß.
Verwendet habe ich:
>Das IFG-Bit kann man auf die übliche Art löschen:
>TBCCTL3 &= ~CCIFG;
Der 2. Teil wurde für einen evtl. späteren Gebrauch abgespeichert.
Für die Hilfe recht vielen Dank.

von jump table (Gast)


Lesenswert?

Clemens L. schrieb:
> switch (TBIV) {

natürlich mit evem_in_range ()

;-)))

von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

wolle g. schrieb:
> aber mein Programm läuft jetzt erst einmal wunschgemäß.
Mit dieser Einschätzung war ich wohl etwas zu voreilig.

Das Programm läuft bei mir nur, wenn man jeweils nur einen HC SR04 
betreibe.
Ziel ist es aber, 2x HC SR04 an einem µC zu betreiben.
Wenn ich, wie im Anhang unter TimerA0, beide HC SR04 betreibe, dann ist 
das Messergenis des HC SR01-1 nur Müll.
HC SR04-2 behält aber seine brauchbaren Werte.
Wird nur HC SR01-1 getaktet, dann liefert auch dieser brauchbare Werte.
Kann mir noch einmal jemand helfen?

: Bearbeitet durch User
von Clemens L. (c_l)


Lesenswert?

Das kommt davon, wenn du TBCLR verwendest – das setzt den gesamten Timer 
auf Null, beeinflusst also auch alle CCRs.

Um eine Zeitdauer zu messen, solltest du den Timer-Zähler vorher und 
nachher speichern (1. per Hand, 2. mit Capture-Event), und dann 
subtrahieren.

von Wolle G. (wolleg)


Lesenswert?

Clemens L. schrieb:
> Das kommt davon, wenn du TBCLR verwendest – das setzt den gesamten Timer
> auf Null, beeinflusst also auch alle CCRs.

Das war eigentlich auch so gedacht. Zuerst die Impulslänge von HC SR04-1 
erfassen (TB0) --> TBCCR0 lesen --> Timer auf Null setzen --> Pause und 
dann das Gleiche mit HC SR04-2 an TB3 wiederholen.
Da bin ich offensichtlich auf dem Holzweg.

>Um eine Zeitdauer zu messen, solltest du den Timer-Zähler vorher und
>nachher speichern (1. per Hand, 2. mit Capture-Event), und dann
>subtrahieren.
Das erscheint für mich zu hoch zu sein. z.B. Was soll per Hand gemacht 
werden?
Könntest Du vielleicht mein Programm versuchsweise  korrigieren?

von Clemens L. (c_l)


Lesenswert?

Innerhalb eines Interrupthandlers sind alle Interrupts erst einmal 
gesperrt. Der Code in Timer_A() sollte in die Hauptschleife verschoben 
werden.

Um die Schleife in regelmäßigen Abständen auszuführen, kann sich der 
Code dort schlafen legen und durch den TimerA-Interrupt-Handler 
aufwecken lassen.

von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Nach einer „kleinen“ Pause melde ich jetzt wieder.
Clemens L. schrieb:
> Innerhalb eines Interrupthandlers sind alle Interrupts erst einmal
> gesperrt. Der Code in Timer_A() sollte in die Hauptschleife verschoben
> werden.
Ich habe mal mein Programm (leider immer noch erfolglos) umgebaut. Den 
Start und die Antwort habe ich in die while-Schleife  der Hauptschleife 
verlegt.
War es so gemeint?
Wird jeweils  nur 1 Ultraschallmesser gestartet, dann erscheint die 
Antwort plausibel. Sind beide, wie im umgebauten Programm, in Betrieb, 
dann gibt es unbrauchbare Messergebnisse.
MfG

von Wolle G. (wolleg)


Lesenswert?

Ich muss meine Anfrage mal wieder hochschieben.

von Clemens L. (c_l)


Lesenswert?

Die beiden CCRs kommen sich immer noch in die Quere; TBCLR und das 
Start-Signal für den Sensor sind nicht synchonisiert.

Also konkret: beim Start und beim Ende wird der Zeitstempel gelesen:
1
  start1 = TBR;
2
  P4OUT &= ~BIT1;
3
  ...
Im Interrupt:
1
  ende1 = TBCCR0;
2
  ech1 = ende1 - start1;
Der Timer wird dabei nie auf 0 zurückgesetzt! (Und dann könnte man 
auch beide Messungen gleichzeitig machen.)

Und "volatile" fehlt bei den gemeinsam vom Hauptprogramm und 
Interrupt-Handlern benutzen Variablen.
Und Warteschleifen macht man besser mit __delay_cycles().

von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Clemens L. schrieb:
> Der Timer wird dabei nie auf 0 zurückgesetzt! (Und dann könnte man
> auch beide Messungen gleichzeitig machen.)
>
> Und "volatile" fehlt bei den gemeinsam vom Hauptprogramm und
> Interrupt-Handlern benutzen Variablen.
> Und Warteschleifen macht man besser mit __delay_cycles().

Das sehe ich zum Teil etwas anders.

Im Prinzip habe ich nur meine Warteschleifen (pause) durch 
__delay_cycles() ersetzt und das überarbeitete Programm  funzt. Könnte 
man diesen Effekt erklären?
Noch zwei Fragen:
Warum sollte man "volatile" verwenden?
Wie hängen  __delay_cycles() und die Quarzfrequenz zusammen?

Im Anhang jetzt das in meinen Augen funktionstüchtige Programm. (Falls 
es jemanden interessiert)

von Clemens L. (c_l)


Lesenswert?

wolle g. schrieb:
> Im Prinzip habe ich nur meine Warteschleifen (pause) durch
> __delay_cycles() ersetzt und das überarbeitete Programm funzt. Könnte
> man diesen Effekt erklären?

Offensichtlich waren die Warteschleifen zu kurz, oder wurden vom 
Compiler wegoptimiert.

> Warum sollte man "volatile" verwenden?

http://stackoverflow.com/q/246127/11654

> Wie hängen __delay_cycles() und die Quarzfrequenz zusammen?

Du hast MCLK auf 8 MHz konfiguriert, also 1 Takt = 125 ns.

von Wolle G. (wolleg)


Lesenswert?

Clemens L. schrieb:
>> Warum sollte man "volatile" verwenden?
> http://stackoverflow.com/q/246127/11654
>> Wie hängen __delay_cycles() und die Quarzfrequenz zusammen?
> Du hast MCLK auf 8 MHz konfiguriert, also 1 Takt = 125 ns.

Danke.
Gibt es auch etwas ohne Frage- Antwortspiel und in deutsch?
und wann wird der Compiler ohne "volatile" etwas wegoptimieren?
Kann man das auch in wenigen Sätzen beschreiben?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.