Drehzahlmesser für Plattenspieler

Spielwiese rund um eigene Projekte.
Post Reply
DL1CR
Posts: 13
Joined: Tue 10. Dec 2013, 19:25

Drehzahlmesser für Plattenspieler

Post by DL1CR » Thu 30. Jan 2014, 15:41

Ich habe für meinen Plattenspieler einen Drehzahlmesser mit der Reflexionslichtschranke CNY70 entworfen.
Grundlage war das Programm 12_PingSensor.
Wie es funktioniert, seht ihr hier im kurzem YouTube-Video: http://youtu.be/fEGlwN2663k
Den Code habe ich angehängt, er ist aber noch fertig. Die Formatierung ist leicht chaotisch, da die vom Editor erzeugten Tabs nicht korrekt angezeigt werden.

Ich wünsche allen ein wunderschönes Jahr 2014!

Chris

Code: Select all

/*
 *  Drehzahlmesser für Plattenspieler
 *  Ausgabe in Umdrehungen pro Minute
 *  Date: Dec, 2014
 */
 #include "main.h"
 #include "lcd.h"
 #include "meineFunktionen.h"
 
 #define    Impuls      BIT3
  
 main()
 {
    unsigned long width, timeout =300000; // 3s in 10us 
    volatile unsigned long ump100, umpVorkomma, umpNachkomma,duration_us;
    
    vCPU_init();                          // sets DCO to 1MHz
    vLCD_init(16);                      // init display with 16 columns, Cursor at 0,0
     
    vLCD_puts("UMP V0.1 DL1CR"); // write string to first line
    
     P1DIR &= ~Impuls;                   // P1.3 ist Eingang
     P1OUT |= Impuls;                    // P1.3 ist Eingang, aber pull-up/down auf "up" setzen
     P1REN |= Impuls;                     // Widerstand zuschalten
    
     while( (P1IN & Impuls));            // Warte auf L-Impuls , Marke erscheint  
     while( !(P1IN & Impuls));           // Warte auf H-Impuls  
 
      vLCD_gotoxy(0,0);
      vLCD_puts("               ");
      vLCD_gotoxy(0,1);
      vLCD_puts("               ");
      
 
       while(42)  {

         width=0;               //reset pulse width counter
       
         while( (P1IN & Impuls));             // Warte auf L-Impuls  
    
       while( !(P1IN & Impuls));      // Warte auf H-Impuls  
    
       while( (P1IN & Impuls))      // Warte auf L-Impuls und nimm die Zeit  
          width++;                // it took abt 10 cycles@1MHz per count, Einheit 10us
       
       while( (P1IN & Impuls))      // Warte auf h-Impuls und nimm die Zeit  
          width++;                // it took abt 10 cycles@1MHz per count, Einheit 10us
       
       
       if (width > timeout) width = timeout; //limit to 3s     //
                                        
      // ump = 1/width               Umdrehungen pro 10 Microsekunde   
      // ump = (1E5)/width            Umdrehungen pro Sekunde   
      // ump = (60*1E5)/width         Umdrehungen pro Minute   
      
      ump100 = (6000*1E5)/width;      // 100 * Umdrehungen pro Minute   
      umpVorkomma = ump100/100;       // Vorkommaanteil Umdrehungen pro Minute   
      umpNachkomma = ump100 - 100*umpVorkomma;   // Nachkommaanteil Umdrehungen pro Minute   
      
         
      vLCD_gotoxy(0,0);
        vLCD_puts("                ");
      vLCD_gotoxy(0,0);
        vLCD_putui(width/100);
        vLCD_puts(" ms");
      
      vLCD_gotoxy(0,1);
        vLCD_puts("                ");
      vLCD_gotoxy(0,1);
        vLCD_putui(umpVorkomma);
        vLCD_puts(".");
      vLCD_putui(umpNachkomma);
        vLCD_puts(" U/min");
      
      
      
      vDelay_ms(5000);            //limit update rate
    }
 }
 
 

DL1CR
Posts: 13
Joined: Tue 10. Dec 2013, 19:25

Re: Drehzahlmesser für Plattenspieler

Post by DL1CR » Fri 28. Feb 2014, 19:42

Nach einer langen (un)freiwilligen Pause konnte ich heute wieder an meine MPS-Projekte gehen. Der Drehzahlmesser für meinen Plattenspieler soll endlich fertig werden, damit ich mich auf den Antennentuner konzentrieren kann. Das Messkonzept läuft bereits, jetzt muss ein vernünftiges Power-Management her.

Mein Ziel ist ist der Betrieb mit einer Knopfzelle CR2032 mit ca. 200mAh. Das DOG-Display soll hinterleuchtet werden, die IR-LED von der Reflexionslichtschranke zieht auch einige mA. Vergisst man das Ausschalten, ist am nächsten Morgen die Batterie erschöpft. Also sollte sich das Gerät nach 1min selbst ausschalten und bei Bedarf auch sofort.

Hier mein Konzept.
Der MSP fällt nach dem Einlegen der Batterie in den LPM4 Sleep-Modus.
Durch Tastendruck wird ein Interrupt ausgelöst, der über einen Port einen Schalttransistor aktiviert.
Display und LED werden eingeschaltet, die Messroutine läuft.
Nach 1min oder nach erneutem Tastendruck fällt der MSP wieder in den Sleep-Modus und schaltet die Verbraucher wieder ab.

In dem folgenden Video sieht man - mit etwas Phantasie - das Einschalten, manuelle Ausschalten und das zeitgesteuerte Ausschalten. Ich schalte den Taster auf dem Launchpad, die blinkende LED zeigt den Zustand:
http://www.youtube.com/watch?v=2CpFWMDf3p8&

Es fällt unangenehm auf, dass die Stromaufnahme im Sleep-Modus nicht - wie erwartet - unter 1uA fällt, sondern mit über 20uA viel zu hoch ist. Ich habe dann durch Zufall bemerkt, dass der Strom - uppps?!? - von der Lichtstärke meiner Arbeitslampe abhängt.Nach ein paar Versuchen stellte sich heraus, dass die LED2 als Fotozelle arbeitet und dem MSP Strom entnimmt. Ich habe das nicht weiter untersucht, nach Ziehen des Jumpers war der Spuk vorbei.
Hier dazu das Video, die LED decke ich mit einem schwarzen Stift ab.
http://www.youtube.com/watch?v=6cOwT0HjrQ0

73 Chris

Code: Select all

/*
 *  Drehzahlmesser für Plattenspieler
 *  Ausgabe in Umdrehungen pro Minute
 *  Date: Feb, 2014
 */
 #include "main.h"
 #include "LCDdogm.h"
 #include "meineFunktionen.h"
 
 #define 	Impuls		0x04	
 #define	Taste		0x08
 #define	Led			0x01
 #define 	Sleep		0x01
   
 void display();
   
 unsigned  mode, i, j, k;  
   
 main()
 {
	vCPU_init();					//sets DCO to 1MHz
 	
 	// Taste
  	P1DIR &= ~Taste;				// Eingang
  	P1OUT |= Taste;				// pull-up/down zu "up"
	P1REN |= Taste;				// Widerstand zuschalten
	P1IE  |= Taste;					// Interrupt Trigger aktivieren 
	P1IES |= Taste;					// Hi->Lo Flanke löst Interrupt aus 
	P1IFG &= ~Taste;			        // IFG Flag löschen 
	
	// Led
	P1DIR |= Led;					// Ausgang
	P1OUT |= Led;					// Led ein
  	
  	// Lichtschranke
  	P1DIR &= ~Impuls;				// Eingang
  	P1OUT |= Impuls;				// pull-up/down zu "up"
	P1REN |= Impuls;				// Widerstand zuschalten

	// MC einschlafen lassen
	_bis_SR_register(LPM4_bits + GIE); // Modus LPM4 auslösen
	
 } // main  	
  

#pragma vector=PORT1_VECTOR	
 	interrupt void Port_1 (void) {
 	P1IE  &= ~Taste;					// Interrupt Trigger deaktivieren 
 	while (!(P1IN & Taste));			       // warten, bis Taste losgelassen wird 
 	
 	P1OUT &= ~Led;					// Led aus 		
 		
 	 		
 	// Test -----------------------------------------
 	for (j=0; j<40; j++) { 
 		if (!(P1IN & Taste)) goto stopp;
 		
 		vDelay_ms (30);
 		P1OUT ^= Led;	
 	 		
 		if (!(P1IN & Taste)) goto stopp;
 		vDelay_ms (30);
 		P1OUT ^= Led;	// LED Blinkt
 	}	
 	P1OUT &= ~Led;	// LED Blinkt
 	// 	
 	
	stopp:
 	P1OUT &= ~Led;					       // Led aus
 	P1IFG &= ~Taste;					       //IFG Flag löschen
 	P1IE  |= Taste;						      // Interrupt Trigger aktivieren  
 	_bis_SR_register(LPM4_bits + GIE); 	               // Modus LPM4 auslösen
 		
 	} // interrupt
 }
 
 

DL1CR
Posts: 13
Joined: Tue 10. Dec 2013, 19:25

Re: Drehzahlmesser für Plattenspieler

Post by DL1CR » Tue 4. Mar 2014, 11:24

So, jetzt ist läuft der Drehzahlmesser. Nachdem ich im Sleep-Modus alle Ports auf LOW gelegt habe, fließt auch kein Reststrom mehr zum DOG-Controller und der Batteriestrom geht auf Werte deutlich unter 1uA zurück. Einige Stunden habe ich aber gebraucht, um nachzuvollziehen, dass im Trace-Modus weiterhin ein Reststrom von ca. 20uA fließt. Erst wenn ich den MSP nach Unterbrechung von Ub wieder neu starte, klappt es wie erwartet.

Nur mein schlichtes ON-OFF-Power-Management lässt mir keine Ruhe. Da diese Herausforderung in vielen Anwendungen vorkommt, lohnt es sich - wie ich finde - darüber nachzudenken.
Ich wünsche mir folgendes Verhalten:
Das komplette Gerät lässt sich jederzeit per Taste ein- und ausschalten.
Nach einiger Zeit schaltet sich das Gerät von selbst ab.

Einiges davon habe ich bereits umgesetzt:
1 Nach dem Einlegen der Batterie geht in den LPM4 Sleep-Modus. -> OK

2 Durch Tastendruck wird ein Interrupt ausgelöst und ein Zähler gestartet (siehe 5). -> Teilweise OK

3 In der Interrupt-Routine wird über einen Port mit angeschlossenen Schalttransistor die Peripherie aktiviert und die eigentliche Routine gestartet. -> OK

4 Drückt man jetzt den Schalter erneut, kommt man wieder in den Zustand 1, der Gerät wird wieder abgeschaltet -> Unklar. Wird "innerhalb der Interrupt-Funktion" die Funktion erneut aufgerufen? Wenn ja, müsste man die rekursive Funktionskette erst abarbeiten. Ich löse das bisher folgendermaßen: In der Routine wird der Schalter gepollt. Wenn er gedrückt wird, springe ich per goto-Befehl an das Ende der Interrupt-Routine und dann in den Zustand 1.

5 Ist der Zähler abgelaufen, wir ein zweiter Interrupt ausgelöst, der wieder zum Schritt 1 führt. -> Unklar. Ich löse das bisher folgendermaßen: In der Interrupt-Routine läuft die Software innerhalb einer Zählschleife. Wenn die abgelaufen ist, gehts wieder in den Zustand 1

73 Chris

DL9GFA
Posts: 66
Joined: Thu 12. Apr 2012, 22:30

Re: Drehzahlmesser für Plattenspieler

Post by DL9GFA » Wed 5. Mar 2014, 22:10

Hallo Chris,

genau darin, nämlich eine geeignete Struktur (oder vornehm Architektur :D ) für die Software zu finden, besteht die Kunst.
Du benutzt schon das Wort Zustand, also was liegt näher, als einen Zustandsautomaten für den Ablauf zu entwerfen?

Was dazu nötig ist, steht in meinen MSP430-Kursunterlagen ab Seite 99 :geek: .
1.) Erstellen einer Zustandsvariablen zum Speichern des aktuellen Zustandes
2.) Definition aller möglichen auftretenden Zustände
3.) Zuordnen der verschiedenen Aktionen zu den Zuständen
4.) Definition der Reihenfolge der Zustände und Bedingungen zum Übergang
5.) Dekodieren der Zustandsvariablen, um in die verschiedenen Zustände zu kommen (z.B. switch/case-Konstrukt)

Wenn man die Zustandswechsel grundsätzlich über Interrupts (Timer oder ext.) vornimmt, kann die CPU den Rest der Zeit schlummern.

Wir können das ja Donnerstag vertiefen.

vy 73 de Gerrit, DL9GFA

Post Reply