- LiTime Speicher und Akkus         
Ergebnis 1 bis 9 von 9

Thema: PollSwitch() fehlerhaft (??) + SIG_INTERRUPT1 Problem

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    24.11.2006
    Beiträge
    40

    PollSwitch() fehlerhaft (??) + SIG_INTERRUPT1 Problem

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hi,
    ich habe ein Problem. PollSwitch() liefert mir bei jeder abfrage einen wert >0 zurück. Bsp:
    Code:
    int main(void){
    	int x;
    	Init();
    	for(x=0;x<20;x++){
    		PollSwitch();
    	}
    	PollSwitch();
    	while(PollSwitch()==0){
    		PollSwitch();
    		MotorSpeed(150,150);
    		MotorDir(FWD,FWD);
    	}
    	MotorDir(BREAK,BREAK);
    	MotorSpeed(0,0);
    	StatusLED(RED);
    	
    while(1);	
    }
    sobald ich asuro anschalte, wird die Status LED rot und es bewegt sich nix.

    programmiere ich die taster mit dem interrupt SIG_INTERRUPT1 funktioniert alles bestens.

    noch eine frage: kann es sein dass die funktionen Sleep() und Msleep() im interrupt nicht funktionieren? jedesmal wenn ich im interrupt Msleep aufrufe hängt er sich auf.

    vielen dank im vorraus...

  2. #2
    Moderator Robotik Einstein Avatar von damaltor
    Registriert seit
    28.09.2006
    Ort
    Milda
    Alter
    37
    Beiträge
    4.062
    nein, die funktionen funktionieren im interrupt nicht, da sie selbst einen interrupt benötigen (den timer-interrupt). da der taster interrupt eine höhere priorität hat, wird der timer int nicht ausgeführt.

    direkt nach dem einschalten ist pollswitch meist größer als null. mach mal Msleep(10) vor der ersten abfrage. die 10 millisekunden fallen nicht auf, und dann wird der wert wahrscheinlich besser sein.
    Read... or die.
    ff.mud.de:7600
    Bild hier  

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    01.02.2007
    Ort
    Ashausen
    Alter
    65
    Beiträge
    64
    Hi upaucc,

    PollSwitch() muss keinesfalls Null zurückgeben, wenn Du keine Taste drückst! Wenn Du genauer sehen willst, wo Dein Problem liegt, dann kopiere Dir die PollSwitch() Funktion in Dein Programm, bennene sie um (ich setze dann gern einen Unterstrich vor die Funktion) und laß dir über SerPrint() und PrintInt() sowohl die Rohdaten des AD-Wandlers als auch den errechneten Wert für die Schalter ausgeben. In myasuro.h kannst Du dann eine Einstellung vornehmen, die dann hoffentlich dazu führt, dass die immer die richtigen Bits gesetzt sind, wenn Du Schalter betätigst.

    Was die Interrupts betrifft - mit SIGNAL eingeleitete Interruptroutinen können nicht von einem anderen Interrupt unterbrochen werden - darum funktionieren die Sleep()-Funktionen nicht. Benutze statt dessen eine for-Schleife, die nichts tut, als eine Variable hochzuzählen.

    Viel Erfolg...

    _HP_

  4. #4
    Moderator Robotik Einstein Avatar von damaltor
    Registriert seit
    28.09.2006
    Ort
    Milda
    Alter
    37
    Beiträge
    4.062
    Allerdings sollten interruptroutinen möglichst kurz gehalten werden (zeitlich kurz), da der asuro in dieser zeit "blind" ist. der normale programmablauf wird nicht fortgeführt!
    Read... or die.
    ff.mud.de:7600
    Bild hier  

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    24.11.2006
    Beiträge
    40
    danke für die schnellen antworten!

    @_HP_: kannst du bitte genauer erklären was du mit deinem hinweis meinst. ich habe das nicht richtig verstanden. meinst du die syntax der funktion PollSwitch() in das hauptprogramm kopieren? und wie ist das mit myasuro.h gemeint? wird in der asuro.h nicht nur die funktion erwähnt, in asuro.c aber dann erst richtig implementiert?

    //edit: Kann es möglicherweise sein, dass meine asuro.c zu lang ist?

    ich erläuter am besten mal mein Problem, vielleicht kann man das auch komplett mit dem interrupt lösen:

    ASURO soll, wenn eine Kollision Auftritt, eine bestimmte Zeit, fürs beispiel 3 sekunden, warten. wenn nach diesen 3 sekunden die kollision immer noch da ist soll eine funktion zum umfahren aufgerufen werden, wenn die kollision nach den 3 sekunden weg ist, soll das programm weiter abgearbeitet werden.
    seht ihr eine möglichkeit, das ohne pollswitch zu realisieren?

  6. #6
    Benutzer Stammmitglied
    Registriert seit
    01.02.2007
    Ort
    Ashausen
    Alter
    65
    Beiträge
    64
    Hallo upaucc,

    sorry – ich habe erst jetzt ein wenig Zeit gefunden, Dir zu antworten.

    Lass uns mal kleine Schritte machen – sonst liest das keiner

    In der ersten Folge wollen wir uns mal mit der PollSwitch()-Funktion beschäftigen.
    Dazu ist ein Blick in die Schaltung noch mal recht hilfreich. Die Schalter werden nämlich nicht direkt gelesen - dann würde man 6 digitale Eingänge benötigen. Da man Prozessorpins sparen wollte (Geiz ist also auch bei Robotern geil) misst man die Spannung über dem Spannungsteiler R23 und R25-30. Ist kein Schalter gedrückt, dann liegt an diesem Punkt die Betriebsspannung V+ an (jedenfalls nach einer gewissen Zeit, was mit dem Kondensator C7 zu tun hat – aber zu dem kommen wir später).
    Wird ein Schalter betätigt, so fließt durch den zugehörigen Widerstand Strom und die Spannung am PIN 27 (ADC4) sinkt. Da nun jeder Schalter mit einem anderen Widerstand verbunden ist, ist die Spannung jedes Mal verschieden. Damit könnte man eine Tabelle anlegen, die für jeden Schalter die entsprechende Spannung enthält und wüsste somit, welcher Schalter gedrückt wurde. Wie groß müsste diese Tabelle sein? Nein, es reicht nicht aus dort 6 Werte einzutragen sondern es müssen auch alle möglichen Kombinationen der Schalter berücksichtigt werden. Man braucht also 2^6=64 Tabelleneinträge! Und durch die Toleranzen der Widerstände bedingt, müsste diese Tabelle für jeden ASURO speziell erstellt werden! Darum haben die Entwickler zu einem genialen Trick gegriffen – sie haben die Widerstände so gewählt, dass man errechnen kann, welche Tasten gedrückt wurden!!! Und genau das macht PollSwitch():

    1024.0/(float)i - 1.0)) * 63.0 + 0.5)

    Die Herleitung dieser Formel überlasse ich Dir – Du kannst Sie aber im Buch „Mehr Spaß mit Asuro – Band 1“ finden.

    Das Ergebnis der Berechnung soll so sein, dass für jeden Schalter das entsprechende Bit gesetzt ist, wenn er gedrückt wurde – auch in Kombinationen mit anderen Schaltern.

    Soweit die Theorie – und jetzt noch ein Wort zur wirklichen Welt:

    Auf Grund der Bauelementetoleranzen kann es sein, dass der Faktor 63 nicht passt – dann muss man damit einwenig experimentieren. Außerdem treten in der Schaltung Störimpulse auf, die von den Motoren verursacht werden. Der Kondensator C7 soll diese glätten. Leider erkauft man sich diesen Vorteil mit dem Nachteil, dass der Kondensator eine gewisse Zeit braucht, bis er auf die Spannung des Spannungsteilers aufge- oder entladen hat. Aus diesem Grunde muss man etwas warten, bis der Wert am AD-Wandler stabil ist.

    So, und jetzt zum Programm:

    Ich habe als Vorlage mal den Auslieferungszustand genommen – also asuro.c und asuro.h so, wie sie auf der CD - sind. Am Anfang gibt es ein paar Hilfsfunktionen für die Ausgabe, die ich aus der Lib2.7 entliehen habe. Die Funktion Pause() dient nur dazu, den Output in Terminal-Fenster zu bremsen.

    Dann habe ich die Funktion PollSwitch() aus asuro.c kopiert und umbenannt (ich hätte sonst die Funktion in der asuro.c auskommentieren müssen, was auch möglich gewesen wäre).
    Und jetzt kann ich mit der Funktion machen, was ich will – ist ja meine

    Ich habe ein paar Kommentare rein geschrieben und die Werte für die Rohdaten des AD-Wandlers und die berechneten Daten der Schalter ausgegeben.

    Schau doch mal, was das Terminalprogramm ausgibt, wen Du keine Tasten drückst und was es ausgibt, wenn du eine beliebige Tastenkombination drückst. Schreibe Deine Ergebnisse hier rein und wir schauen dann weiter…

    Code:
    #include "asuro.h"
    
    void UartPutc (unsigned char zeichen)
    {
      UCSRB  = 0x08;                        // enable transmitter
      UCSRA |= 0x40;                        // clear transmitter flag
      while (!(UCSRA & 0x20))               // wait for empty transmit buffer
        ;
      UDR = zeichen;
      while (!(UCSRA & 0x40))               // Wait for transmit complete flag (TXC)
        ;
    }
    
    void SerPrint(char *data)
    {
      unsigned char i = 0;
    
      while (data[i] != 0x00)
        UartPutc(data [i++]);
    }
    
    void PrintInt(int wert)
    {
      char text [7];                        // "-12345"
    
      itoa(wert, text, 10);
      SerPrint(text);
    }
    
    void Pause(void)
    {
    	int i;
    	for (i=1; i<250; i++) Sleep(255);
    }
    
    /* function to read out switches */
    unsigned char _PollSwitch (void)
    {
    	unsigned int i, Schalter;
    	
    	DDRD |= SWITCHES;				// Switches as Output
    	SWITCH_ON;						// Output HIGH for measurement
    	ADMUX = (1 << REFS0) | SWITCH;	// AVCC reference with external capacitor
    	Sleep(10);
    	
    	ADCSRA |= (1 << ADSC);			// Start conversion
    	while (!(ADCSRA & (1 << ADIF)));// wait for conversion complete
    	ADCSRA |= (1 << ADIF);			// clear ADCIF
    	i = ADCL + (ADCH << 8);
    	
    	SWITCH_OFF;
    	
    	/* Hier wurde der Wert für die Schalter ausgelesen. Also schauen
    	 * wir uns den mal an:
    	 */
    	SerPrint("\r\n\r\nAD-Wandlerwert der Schalter: ");
      PrintInt(i);
    
    	/* Und erst jetzt wird versucht, den Spannungswert in ein Bitmuster
    	 * für die Schalter umzurechnen. Also schauen wir uns den Wert auch
    	 * an:
    	 */
    	
    	Schalter = ((unsigned char) ((( 1024.0/(float)i - 1.0)) * 63.0 + 0.5));
    	SerPrint("\r\nGedrückte Schalter: ");
      PrintInt(Schalter);
      
      /* Sollte jetzt der Wert nicht dem erwarteten entsprechen, musst Du 
       * den Wert 63.0 solange ändern bis es für alle Schalter passt!
       */
       
      return Schalter;
      
      
    }
    
    int main(void){  
    	while(1)
    	{
    		_PollSwitch();
    		Pause(); // nur damit die Daten nicht wie wild über den Bildschirm sausen
    	}    
    }
    Viel Spaß,

    _HP_

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    01.02.2007
    Ort
    Ashausen
    Alter
    65
    Beiträge
    64
    An alle,

    in dem obigen Geschreibsel von mir ist mindestens ein inhaltlicher Fehler versteckt! Wer findet den (oder die) Fehler?

    Gruß,

    _HP_

  8. #8
    Benutzer Stammmitglied
    Registriert seit
    24.11.2006
    Beiträge
    40
    Ok, vielen Dank für die ausführliche Hilfe, werde mich heut aben damit auseinandersetzen und dann die Ergebnisse hier posten!

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    01.02.2007
    Ort
    Ashausen
    Alter
    65
    Beiträge
    64
    Hi all,

    da ich mich ab morgen für drei Wochen (roboterfrei) nach Florida verkrümele, will ich vorher noch das Rätsel um den Fehler im Text auflösen:

    Der Fehler liegt hier
    …misst man die Spannung über dem Spannungsteiler R23 und R25-30…
    Natürlich besteht der Spannungsteiler, an dem die Spannung für die Schalter gemessen wird, aus R24 und R25-30 (je nachdem, welche Schalter gedrückt sind)! Das ist ein gewaltiger Unterschied, da R24 nur 1KOhm groß ist, R23 aber 1MOhm. Genau genommen besteht der Spannungsteiler eigentlich sogar aus einer Parallelschaltung von R23 und R24 zu R25-30. Aber da der Unterschied in den Werten so groß ist, fällt R23 kaum ins Gewicht. Wer das nicht glaubt, sollte es nachrechnen der Wert, der herauskommen muss ist 999,000999000999000999000999001 Ohm.

    Damit R24 nun ins Geschehen eingreifen kann, muss PIN5 (PD3) als Output geschaltet werden – also Betriebsspannung führen. Diese wir in der Funktion PollSwitch() erledigt:
    Code:
    …
    DDRD |= SWITCHES;               // Switches as Output
    SWITCH_ON;                           // Output HIGH for measurement
    …
    Und die Definition von SWITCHES und SWITCH_ON findet man in der asuro.h:
    Code:
    …
    #define SWITCHES   (1 << PD3)
    #define SWITCH_ON  PORTD |= SWITCHES
    …
    Und nun muss dem AD-Wandler nur noch gesagt werden, womit er die gemessene Spannung vergleichen soll. In diesem Fall soll er sie mit der Betriebsspannung vergleichen und das geschieht hier:
    Code:
    …
    ADMUX = (1 << REFS0) | SWITCH;   // AVCC reference with external capacitor
    …
    Mit dem Setzen von REFS0 wird die (über den Kondensator C6 geglättete) Betriebsspannung als Referenz eingestellt und mit SWITCH Pin27 (PC4) als Eingang für den AD-Wandler gewählt.

    Jetzt wird die Spannung gemessen und umgerechnet.

    Und wozu ist R23 dann überhaupt da? Das ist die Frage für den nächsten Teil in dieser Reihe, die aber erst in 3 Wochen folgen wird.

    Bis dahin viel Erfolg beim Testen…

    _HP_
    Ist es nicht schrecklich, dass der menschlichen Klugheit so enge Grenzen gesetzt sind und der menschlichen Dummheit überhaupt keine?
    - Konrad Adenauer

Berechtigungen

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

LiFePO4 Speicher Test