Forum: Mikrocontroller und Digitale Elektronik USART Zahl einlesen, auf uint8_t speichern und in phase- correct-pwm, ATmega8


von Tho W. (tommyprog)


Lesenswert?

Grüß euch alle,

mit einem ATmega8 lese ich über USART R232 eine Zahl aus einen String 
ein, und übergebe diesen Wert an einen lokalen uint8_t- speicher, der 
den Wert dann zu den OCR2 Register übergibt.

Die Übergabe zu den Speicher funktioniert, jedoch liegt am gewünschten 
Ausgang für mein PWM Signal keine Spannung an.
Der Timer kommt auch nie in das Timer interrupt (habs getestet, mit der 
usart_putc- methode)

Vermutlich habe ich die Zuweisung OCR2= aktueller_PWM_Wert; an der 
falschen Stelle gemacht.

hardwaretechnisch ist die Zuweisung im IDLE- Modus.
Bei meiner funktionierenden Dimm-PWM- Schaltung habe ich die Zuweisung 
im interrupt nach den ADC- Wandler gemacht, und es hat da wunderbar 
funktioniert.

Hätte jemand einen Denkanstoß für mich?

EDIT_1: Über ein SPezielles FTDI Kabel bekommt der µC Spannung über USB.
Maximal kann er über das Kabel 450mA ziehen.
Glaubt ihr, dass das Leuchten von 3 LED's zzgl. der Stromverbrauch des 
µC selber über diesen Wert kommt? (Netzspannungsquelle zurzeit nicht 
verfügbar)

mfg,
TommyProg

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> Hätte jemand einen Denkanstoß für mich?

Wie immer.
Poste dein Programm, sonst kann keiner was sagen.

Generell: Bevor du dich aufmachst, dein Programm zu beschreiben und 
darüber zu fachsimpeln, was du deiner Meinung nach alles programmiert 
hast oder nicht programmiert hast, zeig den Code! Das ist für dich 
einfacher und für uns auch.

von Tho W. (tommyprog)


Angehängte Dateien:

Lesenswert?

Grüß Dich, Karl Heinz,

bereits bei anderen Projekten habe ich meinen Code gepostet, jedoch nur 
hier nicht.
Dennoch ist es einfacher, das stimmt. Somit ist der Code im Anhang.

Die Zeile, wo ich einen Wert dem OCR2 zuweise, ist kritisch.

->Die BAUD- Berechnung ist die aus dem Tutorial.

Mfg,
tommyProg

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> ->Die BAUD- Berechnung ist die aus dem Tutorial.

Na. ja.

Wenn die Baudrate nicht korrekt wäre, dann würde gar nichts gehen.

Aber:
Du hast ja eine UART!
Es ist nicht verboten, dass der Mega während der Entwicklungszeit auch 
so Dinge wie Statusmeldungen an den PC schickt, in denen er mitteilt was 
er tut und warum er es tut. Als Programmierer sitzt du dann am PC vor 
deinem Terminalprogramm und analysierst diese Statusmeldungen und ziehst 
daraus deine Schlüsse.

Zb. ist es nicht verboten, dass der Mega gleich mal jedes Zeichen, das 
über die Serielle reinkommt wieder zurückschickt oder dass er in den 
einzelnen States der Statemaschine eine entsprechende (kurze!) Meldung 
per UART rausgibt (ausser vielleicht im Idle State 'TueNichts')


PS:
So was
1
        if((usart_empfangspuffer[2] >47)&&(usart_empfangspuffer[2]<58))          //wenn an der zweiten Stelle eine Zahl vorkommt
ist unklug. Wenn du wissen willst, ob das Zeichen ein Ziffernzeichen 
ist, dann ist das wirklich dümmste was du tun kannst, den ASCII Code als 
Dezimalzahl hinzuschreiben. Als Hex-Zahl würde es gerade noch so lala 
gehen, aber viel einfacher ist
1
        if( usart_empfangspuffer[2] >= '0' &&
2
            usart_empfangspuffer[2] <= '9' )
Da kann jetzt auch ein Blinder greifen, worum es hier geht.
Oder überhaupt gleich
1
        if( isdigit( usart_empfangspuffer[2] ) )

dann brauchst du auch deine Kommentare nicht mehr, weil im Code sichtabr 
ist, was da passieren soll. Wenn irgendwie möglich, willst du deinen 
Code so formulieren, dass der Code sein eigener Kommentar ist. Du WILLST 
nach Möglichkeit alles im Code selber ausdrücken und nicht noch 
zusätzllich einen Kommentar haben, der einem eine Codezeile erklären 
muss.

Nichts gegen sprechende Variablen- und Funktionsnamen. Aber deine sind 
schon ein bischen zu lang. Da siehst du vor lauter 'Zeichen-Rauschen' 
das Wesentliche nicht mehr.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> dann brauchst du auch deine Kommentare nicht mehr, weil im Code sichtabr
> ist, was da passieren soll. Wenn irgendwie möglich, willst du deinen
> Code so formulieren, dass der Code sein eigener Kommentar ist. Du WILLST
> nach Möglichkeit alles im Code selber ausdrücken und nicht noch
> zusätzllich einen Kommentar haben, der einem eine Codezeile erklären
> muss.

Das zum Beispiel
1
       case TUE_NICHTS:                            // Im fall tue nichts (IDLE- Modus)
2
          _delay_ms(1);
3
          if(++counter == 250)
4
          {                                //toggle die Gelbe LED fuer 250ms
5
            PORTB ^= GRUENE_LED_AN;
6
            counter = 0;
7
          }

sind völlig sinnlose Kommentare.
Da steht 'Im Fall tue nichts'.
Ah geh. Das hätte ich jetzt nicht gedacht! Und ich hab mich schon 
gewundert, warum der case 'TUE_NICHTS' heisst.
Sinnloser Kommetar. Der erzählt mir nichts, was ich nicht auch im Code 
sehen würde.
Der hier
1
          {                                //toggle die Gelbe LED fuer 250ms
ist sogar falsch. Denn wie im Code sichtbar ist
1
            PORTB ^= GRUENE_LED_AN;
wird eben nicht die gelbe LED getoggelt, sondern die grüne. Und das das 
alle 250ms passiert, kann man auch in 5 Sekunden aus dem Konstrukt
1
          _delay_ms(1);
2
          if(++counter == 250)
3
          {
4
..
5
            counter = 0;
6
          }
ablesen.
Legst du die Zeit dann irgendwann mal in ein #define
1
#define BLINK_TIME_MS   200
2
3
....
4
5
       case TUE_NICHTS:                            // Im fall tue nichts (IDLE- Modus)
6
          _delay_ms(1);
7
          if(++counter == BLINK_TIME_MS)
8
          {                                //toggle die Gelbe LED fuer 250ms
9
            PORTB ^= GRUENE_LED_AN;
10
            counter = 0;
11
          }
dann stimmt noch nicht mal die Zeitnangabe im Kommentar.
Auch das: ein sinnloser Kommentar, der mir nichts erzählt, was ich nicht 
auch im Code sehen würde und in diesem Fall sogar falsch ist. So einen 
Kommentar ignoriert man am besten, wobei sich dann natürlich die Frage 
stellt: Warum steht er dann überhaupt dort?

von Tho W. (tommyprog)


Lesenswert?

> Aber:
> Du hast ja eine UART!
> Es ist nicht verboten, dass der Mega während der Entwicklungszeit auch
> so Dinge wie Statusmeldungen an den PC schickt, in denen er mitteilt was
> er tut und warum er es tut. Als Programmierer sitzt du dann am PC vor
> deinem Terminalprogramm und analysierst diese Statusmeldungen und ziehst
> daraus deine Schlüsse.

Stimmt, deshalb habe ich zu Testzwecken auch immer einen beliebigen 
Buchstaben zurücksenden lassen.


> PS:
> So was
>
1
>         if((usart_empfangspuffer[2] >47)&&(usart_empfangspuffer[2]<58)) 
2
> //wenn an der zweiten Stelle eine Zahl vorkommt
3
>
> ist unklug. Wenn du wissen willst, ob das Zeichen ein Ziffernzeichen
> ist, dann ist das wirklich dümmste was du tun kannst, den ASCII Code als
> Dezimalzahl hinzuschreiben. Als Hex-Zahl würde es gerade noch so lala
> gehen, aber viel einfacher ist
>
1
>         if( usart_empfangspuffer[2] >= '0' &&
2
>             usart_empfangspuffer[2] <= '9' )
3
>
> Da kann jetzt auch ein Blinder greifen, worum es hier geht.
> Oder überhaupt gleich
>
1
>         if( isdigit( usart_empfangspuffer[2] ) )
2
>

Oh, danke dir, wusste nicht, dass es sowas schon fertig gibt.

Wie ist das eigentlich mit dem Register, die PWM (phase-correct) will da 
garnicht hinhauen. Ist die Zuweisung an der richtigen stelle?

von Karl H. (kbuchegg)


Lesenswert?

Äh

Was genau
1
    //die restlichen Zustände auch hier mit einfügen, weil sonst der Compieler meckert! Die Funktionen werden aber generell im Mainprogramm abgearbeitet
2
    case PRUEFE_COMMAND:                        
3
    break;
meckert denn der Compiler?

Mir scheint, du weißt nicht, dass es in einem switch-case auf ein 
'default' gibt, welches alle nicht von einem case angenommenen Fälle 
abdeckt.
1
  switch( a )
2
  {
3
    case 5:
4
      mach was;
5
      break;
6
7
    case 10:
8
      mach was anderes;
9
      break;
10
11
    default:
12
      in allen anderen Fällen, die nicht durch einen case abgedeckt sind
13
      mach dann diese Aktion
14
  }

Womit wir wieder bei einem recht zentralen Punkt sind: Kenne deine 
Programmiersprache und welche Möglichkeiten es gibt!

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> Wie ist das eigentlich mit dem Register, die PWM (phase-correct) will da
> garnicht hinhauen. Ist die Zuweisung an der richtigen stelle?

Der Mega wird sich sicher nicht wehren, wenn du einen Wert ins OCR 
Register schreibst.
Die Frage ist: kommt das Programm überhaupt an diese Stelle?

Das kann ich aber nicht sagen, weil ich nicht sehe bzw. nachvollziehen 
kann, was eigentlich über die Serielle SChnittstelle reinkommt.

Und an dieser Stelle kommt wieder deine Debug-Möglichkeit durch Ausgabe 
von 'STatus-Meldungen' über die UART ins Spiel. Damit könnte man das 
feststellen.

von Tho W. (tommyprog)


Lesenswert?

> meckert denn der Compiler?

Tut er, wenn nicht alle Cases abgedeckt sind.

> Mir scheint, du weißt nicht, dass es in einem switch-case auf ein
> 'default' gibt, welches alle nicht von einem case angenommenen Fälle
> abdeckt.

Echt? Mir nicht, sonst hätte ich es bei der Buchstaben- Überprüfung auch 
nicht eingebaut.

> Womit wir wieder bei einem recht zentralen Punkt sind: Kenne deine
> Programmiersprache und welche Möglichkeiten es gibt!

Klingt vernünftig, wenn du mir noch einige monate bis jahre gibst, bis 
ich mehr Erfahrung gesammelt habe.


--> Statusmeldungen: Auf jeden Fall kann der "aktuelle_pwm_wert" mit 
einen Wert beschrieben, als auch ausgelesen werden. Er Springt aber 
nicht in das Timer- Interrupt rein.


Mfg,
tommyProg

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Und an dieser Stelle kommt wieder deine Debug-Möglichkeit durch Ausgabe
> von 'STatus-Meldungen' über die UART ins Spiel. Damit könnte man das
> feststellen.

Ich würde mir halt mal hier
1
       case UEBERSETZE_BEFEHL:                              //Beim Uebersetzen des Befehls
2
          {                                      //
3
          char sign = usart_empfangspuffer[1];
4
5
          uart_putc( '*' );
6
          uart_putc( sign );
7
8
          switch(sign)
9
...
eine Rückmeldung einbauen um zu sehen, welches Kommando der Mega 
eigentlich 'sieht' (und die sinnlosen Kommentare wieder rauswefen)

Und dann eben genauso in den anderen Zuständen mit einem anderen 
Sonderzeichen, damit ich im Terminal sehe, wie die Statemaschine von 
einem Zustand in den nächsten geht. Kostet ja nichts, da erst mal ein
1
      case ZWISCHENZUSTAND_PWM_1:
2
3
          usart_putc( '#' );
4
          usart_putc( usart_empfangspuffer[2] );
5
6
          if( isdigit( usart_empfangspuffer[2] ) )
7
          {
8
            zwischenzustand_array[0]= usart_empfangspuffer[2];              
9
            PROGRAMM_ZUSTAND = ZWISCHENZUSTAND_PWM_2;
10
          }
11
          else 
12
            PROGRAMM_ZUSTAND= SENDE_AKTUELLEN_PWM_WERT_AN_PC;  
13
          break;
einzubauen.

Eventuell mit einem #ifdef gesichert
1
...
2
#define DEBUG_PWM
3
...
4
5
      case ZWISCHENZUSTAND_PWM_1:
6
7
#ifdef DEBUG_PWM
8
          usart_putc( '#' );
9
          usart_putc( usart_empfangspuffer[2] );
10
#endif
11
          if( isdigit( usart_empfangspuffer[2] ) )
12
          {
13
            zwischenzustand_array[0]= usart_empfangspuffer[2];              
14
            PROGRAMM_ZUSTAND = ZWISCHENZUSTAND_PWM_2;
15
          }
16
          else 
17
            PROGRAMM_ZUSTAND= SENDE_AKTUELLEN_PWM_WERT_AN_PC;  
18
          break;

dann setzt man, wenn alles fertig ist, die Zeile
1
...
2
// #define DEBUG_PWM
3
...
unter Kommentar und die beiden usart_putc werden dann nicht mehr 
mitcompiliert.
Kommt mir was spanisch vor, dann entferne ich den Kommentar wieder, die 
beiden usart_putc werden wieder mitcompiliert und ich kann erneut am 
Terminal mitlesen, was da im µC passiert.

von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:
>> meckert denn der Compiler?
>
> Tut er, wenn nicht alle Cases abgedeckt sind.

Das glaub ich nicht. Denn der Compiler kann prinzipiell überhaupt nicht 
wissen, welche Werte die Variable hier
1
   switch( a )
überhaupt annehmen kann.

> einen Wert beschrieben, als auch ausgelesen werden. Er Springt aber
> nicht in das Timer- Interrupt rein.

dann muss man sich die Konfiguration vom Timer ansehen.
Dazu ist es zb hilfreich, das Komplettprogramm mal zur Seite zu legen, 
mit all seinen unübersichtlichen Verwicklungen, und sich zb ein 
Testprojekt anzulegen, in dem man nur diesen einen Punkt testet.
1
#include  was auch immer gebraucht wird
2
3
ISR( korrekter ISR NAME )
4
{
5
  irgendwas machen, so dass man erkennen kann, das die Funktion
6
  aufgerufen wurde
7
}
8
9
int main()
10
{
11
  Register des Timers initialisieren
12
13
  sei();
14
15
  while( 1 ) {
16
    OCR2 = 50;
17
  }
18
}

vom Prinzip her fertig. Mehr brauchts dazu nicht. Und an diesem 
einfachen überschaubarem Programm findet man dann raus, wie die Register 
des Timers initialisiert werden müssen, damit die ISR aufgerufen wird.
Und da da nichts anderes vorkommt, kann man dann auch sicher sein, dass 
man nur mit dem Timer kämpft und mit nichts anderem.
Hat man das dann soweit alles ausbaldovert, dann überträgt man dieses 
Wissen ins echte Programm - das Testprojekt hat ausgedient.

von Tho W. (tommyprog)


Lesenswert?

> Hat man das dann soweit alles ausbaldovert, dann überträgt man dieses
> Wissen ins echte Programm - das Testprojekt hat ausgedient.

Habe bereits ein fertiges PWM Programm, das einwandfrei funktioniert, 
mit genau diesen Prozessor in genau diesem Prozessortakt.

Dieses habe ich auch größtenteils für das Projekt "mega" übernommen.

Warte mal, ich prüf mal was ab, glaub, da stimmt was nicht..

von Karl H. (kbuchegg)


Lesenswert?

Im übrigen:
Deine Programmlogik scheint da etwas arg verquert zu sein.

Was willst du überhaut erreichen?
Das toggeln der LED in der ISR geht ja noch.
Aber
1
ISR(TIMER2_COMP_vect)
2
{
3
  switch(PROGRAMM_ZUSTAND)
4
  {
5
    case TRIGGERE_ROTE_LED_MIT_WERT:
6
      PORTB^= ROTE_LED_AN;
7
      PROGRAMM_ZUSTAND= TUE_NICHTS;
8
    break;  
9
10
    default:
11
  }
12
}

was soll das werden?
Es ist mehr als zweifelhaft, ob du den PROGRAMM_ZUSTAND im Status 
TRIGGERE_ROTE_LED_MIT_WERT jemals erwischt, wenn du hier in main
1
      case TRIGGERE_ROTE_LED_MIT_WERT:
2
          aktueller_PWM_wert= atoi(zwischenzustand_array);
3
          OCR2 = aktueller_PWM_wert;  
4
          PROGRAMM_ZUSTAND = TUE_NICHTS;

Den Zustand selbst auf TUE_NICHTS änderst, wenn die Statmachine diesen 
Zustand erreicht.

Abgesehen davon: wozu dann die phase correct PWM?


Das ganze sieht alles sehr konfus aus. Sinn macht das nicht wirklich.
Ich denke, du hast dich wieder mal selber mit deiner Programmlogik ins 
Knie geschossen.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

> Was willst du überhaut erreichen?
Das Programm dient (wenn es größer ist) für eine kleine Anlagensteuerung

> Das toggeln der LED in der ISR geht ja noch.
> Aber
>
1
> ISR(TIMER2_COMP_vect)
2
> {
3
>   switch(PROGRAMM_ZUSTAND)
4
>   {
5
>     case TRIGGERE_ROTE_LED_MIT_WERT:
6
>       PORTB^= ROTE_LED_AN;
7
>       PROGRAMM_ZUSTAND= TUE_NICHTS;
8
>     break;
9
> 
10
>     default:
11
>   }
12
> }
13
>
>
> was soll das werden?
hab mir gedacht, dass ich wieder in den Ausgangszustand wechseln muss, 
wenn ich einmal im Zustand bin, dass ich wieder zurück komm.


> Es ist mehr als zweifelhaft, ob du den PROGRAMM_ZUSTAND im Status
> TRIGGERE_ROTE_LED_MIT_WERT jemals erwischt, wenn du hier in main
>
1
>       case TRIGGERE_ROTE_LED_MIT_WERT:
2
>           aktueller_PWM_wert= atoi(zwischenzustand_array);
3
>           OCR2 = aktueller_PWM_wert;
4
>           PROGRAMM_ZUSTAND = TUE_NICHTS;
5
>
>
> Den Zustand selbst auf TUE_NICHTS änderst, wenn die Statmachine diesen
> Zustand erreicht.
Wie meinst du das?


> Abgesehen davon: wozu dann die phase correct PWM?
Das ist nur so eine Übungssache, denke, dass die phase correct pwm 
präziser ist.
>
> Das ganze sieht alles sehr konfus aus. Sinn macht das nicht wirklich.
> Ich denke, du hast dich wieder mal selber mit deiner Programmlogik ins
> Knie geschossen.
möglich. Heute ist es aber schlimmer, habe nämlich bemerkt, dass er 
garnicht in den Zustand Zwischenzustand_PWM_2 kommt.
(Teste noch aus, und veruch weiter)

mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Du Karl,

also habs grad nochmals überprüft, und konnte keinen status 
zurückgeben lassen. Gestern ging es aber interessanterweise noch.
Die Version konnte ich noch auslesen, aber ich bekomme nichts vom 
MIkrocontroller auf meinen PC per HTerm :/.

Versuche jetzt noch rauszufinden, warum das so ist.

Mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

So Karl,

hab Zeichen ausgegeben, und den Zustandsautomaten in meinem Timer- 
Interrupt gelöscht(nachdem ich ihn überprüft habe), nun leuchtet die 
rote LED Wie folgt (teils falsch)

RESET: rote: leuchtet hell_1; grüne: blinkt;
1. Eingabe P; rote leuchtet hell_1; grüne blinkt, wert 0 Ausgabe 
(initialwert)
2. Eingabe P15; rote leuchtet noch heller_1, grüne blinkt;
3. Eingabe P; rote leuchtet noch heller_1, grüne blinkt, wert 15 Ausgabe
4. Eingabe P168; rote leuchtet noch dunkler_1, grüne blinkt,
5. Eingabe P, rote leuchtet noch dunkler_1, grüne blinkt, wert 168 
Ausgabe
6. Eingabe P15, rote leuchtet noch heller_1, grüne blinkt ABER NUN
*wird die LED nach einiger Zeit, nach ca. 2 Sekunden dunkler und 
leuchtet sehr schwach* (untersuche noch die Stelle) Was glaubst du, 
woran das liegt?
//Ab diesem komischen verhalten verhält sich das System, wie es 
eigentlich sein soll//
7. Eingabe P168; rote leuchtet noch heller_1, grüne blinkt
8. Eingabe P15; rote leuchtet extrem schwach, grüne blinkt (wird nach 
der Zeit von alleine nichtmehr heller)
9. Eingabe P; rote leuchtet extrem schwach, grüne blinkt, Ausgabe Wert 
15

Mfg,
tommyProg

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Aus irgendeinen Grund, wenn ich den Wert erst Abfrage, haut es hin.

Mfg,
tommyProg

von Tho W. (tommyprog)


Lesenswert?

Hab beim Timer noch mein COM21 aktiviert, damit beim phase- correct- pwm 
das signal nicht invertiert wird. (hier habe ich natürlich einen anderen 
PIN für meine LED benutzen müssen, aber scheinbar war das der Grund, da 
nun 1) die LED feinfühliger leuchtet, und 2) es gibt keine Probleme mehr 
mit der Anfangsinitialisierung.

Mfg,
tommyProg

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.