Forum: Compiler & IDEs RGB LED Steuerung (AVR)


von tymm (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte eine RGB Led mit einem Atmega8 von meinem PC aus steuern.
Die Led hängt an den 3 PWM Pins des Atmega8.

Die Ansteuerung übernimmt ein Python Programm.
Das Python Programm zeigt eine Farbpalette und übermittelt via serielle 
Schnittstelle die RGB Daten an den Controller.

Die RGB Daten werden in Form von Hexadezimalzahlen (z.B. "FFE0F3") 
verschickt.
Die RGB Daten werden in R, G und B aufgesplittet und dann in einen 
Zahlenwert umgerechnet und den PWM Pins zugewiesen.
Bei "FFFFFF" würde dann Rot, Grün und Blau mit voller Leistung leuchten, 
da FF umgerechnet 255 darstellen.

Leider weiss ich gerade nicht mehr weiter.
Vielleicht seht ihr ja den Fehler oder kann mir eine andere Lösung 
vorschlagen.

Der Code befindet sich im Anhang.

Die Led blinkt sogar für einen sehr kurzen Moment auf (aber nur eine 
Farbe), aber geht dann sofort wieder aus.

Gruss,   Tymm

von Stefan E. (sternst)


Lesenswert?

1
  char r[2]; 
2
  char g[2];
3
  char b[2];
4
...
5
    r[0]=Line[0];
6
    r[1]=Line[1];
7
    g[0]=Line[2];
8
    g[1]=Line[3];
9
    b[0]=Line[4];
10
    b[1]=Line[5];
11
    
12
    // Die Hexadezimal Werte welche als char vorhanden sind umwandeln und zuweisen
13
    OCR1A = strtol(g,NULL,16);  
14
    OCR1B = strtol(b,NULL,16);
15
    OCR2 = strtol(r,NULL,16);

Bei den Strings in r, g und b fehlt die Null-Terminierung.

von tymm (Gast)


Lesenswert?

Vielen Dank.
Habe den Code so erweitert:
1
        char r[3];
2
        char g[3];
3
        char b[3];
4
        r[2]='\0';
5
        b[2]='\0';
6
        g[2]='\0';

Bringt aber leider nichts. Die Led blitzt weiterhin nur kurz auf :(

Gruss,   Tymm

von Michael Wilhelm (Gast)


Lesenswert?

Stackoverflow?

MW

von Stefan E. (sternst)


Lesenswert?

Überprüfe mal deine Timer-Konfiguration.
1
TCCR1A = (1<<WGM10)|(1<<COM1A1)|(1<<CS10)|(1<<COM1B1);
2
TCCR1B = (1<<CS10);
Ich glaube nämlich nicht, dass das Bit CS10 in beiden Registern ist.

von tymm (Gast)


Lesenswert?

@Michael Wilhelm wo?

Du meinst in den Registern OCR1A, OCR1B und OCR2?
strtol liefert long int zurück.
Ich weiss jetzt nicht ob das ein Problem ist und wenn ja wie man es 
löst.

Gruss,   Tymm

von Jörg X. (Gast)


Lesenswert?

@OP:
Werd' mal das '#include "uart.c"' los, das macht man nicht! (die 
.c-Dateien werden im Makefile/im AVR-Studio-Projekt eingetragen).

Bist du sicher, dass dein string vom PC mit "\n"-endet (Unter Windows 
wäre das eher "\r\n") ? (Als ersten Ansatz, mach mal "char Line[7]" zu 
"char Line[10]").

hth. Jörg
ps. Deine Timereinstellungen hab ich mir noch garnicht angeschaut

von tymm (Gast)


Lesenswert?

@Jörg X. :
Ich benutze ausschließlich Linux. Von daher kein AVR Studio und Strings 
die ganz sicher mit \n enden (echo "FFFFFF" > /dev/ttyUSB0).
Danke für den Tipp mit den Makefiles.

Aber wieso Line[10]? Ich habe doch nur 7 Zeichen: "FFFFFF" (6 Zeichen) 
und ein "\0" (1 Zeichen).

Gruss,   Tymm

von Jörg X. (Gast)


Lesenswert?

>Ich benutze ausschließlich Linux.
hättest du evtl. andeuten können ...

Aber wie schon _Stefan Ernst (sternst)_ schrieb:
>> Überprüfe mal deine Timer-Konfiguration.
Die muss nämlich so (bzw. so ähnlich) aussehen:
1
  // Timer1 init 
2
  TCCR1A = (1<<WGM10)|(1<<COM1A1)|(1<<COM1B1);
3
  TCCR1B = (1<<CS10);
4
5
  // Timer2 init for PWM on Pin PB3 
6
7
  TCCR2 = (1<<WGM20) |(1<< CS20)|(1<<COM21);

Du brauchst zwar für eine LED nicht unbedingt drei Hardware 
PWM-Einheiten, aber das kannst du ja später noch ändern ;)

rtfm, Jörg

von tymm (Gast)


Lesenswert?

>> Überprüfe mal deine Timer-Konfiguration.
Danke, das eine |(1<<CS10) war zuviel.
Allerdings funktioniert PWM auch mit dem |(1<<CS10) zuviel.

Am PWM liegt es leider nicht...

von Stefan E. (sternst)


Lesenswert?

Funktioniert die serielle Kommunikation denn überhaupt?
Mach doch mal ein "echo" in das Programm, und schaue, was auf dem PC so 
zurückkommt. Also z.B. ein "uart_puts(Line);" nach dem uart_gets.

von tymm (Gast)


Lesenswert?

Die serielle Kommunikation funktioniert, allerdings nicht wirklich gut 
wie ich gerade festgestellt habe.

Komischerweise kommen bei einem 'echo -n "Hallo" > /dev/ttyUSB0' die 
"Hallo"s häufiger vollständig zurück als bei einem 'echo "Hallo" > 
/dev/ttyUSB0'.
(echo -n gibt kein \n am Ende aus, echo ohne option schon)
In einem Terminal gibt es auch häufiger Aussetzer.

Am Atmega8 hängt ein 8Mhz Quarz und die Fuse Bits habe ich bei Low auf 
0xEE und bei High auf 0xD9.

Trotzdem glaube ich dass es nicht am UART liegt, weil irgendwann ja 
immer mal was ganz durchkommt.
In einem anderen Programm steuere ich die Led mit einzelnen Buchstaben 
('R' = Rot wird heller, 'r' = Rot wird dunkler usw.) und das 
funktioniert tadellos.

Langsam verzweifel ich...

von tymm (Gast)


Angehängte Dateien:

Lesenswert?

Es geht!

Es gab zwei Probleme:
1. Das Problem mit dem kurzen Aufleuchten habe ich gelöst indem ich 
bevor ich die empfangenen Daten verarbeite, abfrage ob es sich um 
hexadezimal Ziffern handelt (UART_NO_DATA funktionierte bei mir nicht).

2. Nachdem ich hinter das uart_gets per Zufall ein paar Befehle 
geschrieben hatte, wurde das UART aufeinmal stabiler.
Ich habe jetzt ein paar delays hinter dem uart_gets und vor der 
Verarbeitung der ankommenden Daten und es geht.

Ein Problem bleibt aber:
Wenn ich sehr schnell viele Farbcodes an den Atmega schicke, wird das 
UART anscheinend wieder instabiler und falsche Farben werden erzeugt.

Im Anhang befindet sich der funktionierende Code + Python Programm zur 
Ansteuerung.

Gruss,   Tymm

von Falk B. (falk)


Lesenswert?

@ tymm (Gast)

>2. Nachdem ich hinter das uart_gets per Zufall ein paar Befehle
>geschrieben hatte, wurde das UART aufeinmal stabiler.
>Ich habe jetzt ein paar delays hinter dem uart_gets und vor der
>Verarbeitung der ankommenden Daten und es geht.

AUA!

>Ein Problem bleibt aber:
>Wenn ich sehr schnell viele Farbcodes an den Atmega schicke, wird das
>UART anscheinend wieder instabiler und falsche Farben werden erzeugt.

Und das wundert dich?
Du bremmst deinen AVR TIERISCH aus, der muss nach jedem empfangenen 
String 5s! warten, ehe er wieder was machen darf. Da läuft garantiert 
ein Empfangsbuffer über. Solche delays sind totaler Mist.

MfG
Falk

von tymm (Gast)


Lesenswert?

>Du bremmst deinen AVR TIERISCH aus, der muss nach jedem empfangenen
>String 5s! warten, ehe er wieder was machen darf. Da läuft garantiert
>ein Empfangsbuffer über. Solche delays sind totaler Mist.

Ein _delay_ms(1000) sind bei mir lange keine Sekunde, was wohl an 
falschen Einstellungen meinerseits liegt.
Kann auch sein das delays totaler Mist sind.
Ich bin Anfänger, ich habe keine Ahnung.
Ich weiss nur, dass ohne delays oder irgendetwas anderes was Zeit in 
Anspruch nimmt garnichts geht.

>Und das wundert dich?
Trotz der Gefahr noch ein "AUA!" zu kassieren und der Tatsache dass mein 
AVR keine 5s wartet: Mich wundert es schon ein bisschen.
Ich dachte Peter Fleury's UART Lib arbeitet mit Interrupts.
Und wenn ich das richtig verstanden habe, unterbrechen Interrupts das 
Hauptprogramm?

Gruss,   Tymm

von lkmiller (Gast)


Lesenswert?

>Ein _delay_ms(1000) sind bei mir lange keine Sekunde
Ja, dann ist was mit der Taktfrequenz-Angabe faul.


Aus dem Programm:
1
/* define CPU frequency in Mhz here if not defined in Makefile */
2
#ifndef F_CPU
3
#define F_CPU 8000000L
4
#endif
trifft die erste Zeile zu?
1
if( (Line[0] == '0') | (Line[0] == '1') | (Line[0] == '2') | (Line[0] == '3') | (Line[0] == '4') | (Line[0] == '5') | (Line[0] == '6') | (Line[0] == '7') | (Line[0] == '8') | (Line[0] == '9') | (Line[0] == 'A') | (Line[0] == 'B') | (Line[0] == 'C') | (Line[0] == 'D') | (Line[0] == 'E') | (Line[0] == 'F'))
2
    {...
könnte auch so beschrieben werden:
1
if( (Line[0] >= '0' && Line[0] <= '9') || (Line[0] >= 'A' && (Line[0] <= 'F') )
2
    {...

von lkmiller (Gast)


Lesenswert?

Dir ist schon klar, dass du mit
1
uart_gets(Line, sizeof(Line));
auch nur mal halbe Zeilen abholen könntest?

Die Funktion holt ab, was gerade im Puffer ist. Da wird nicht bis zum 
CR/LF gewartet. Und du machst keinerlei Plausibilitätsprüfungen, ob 
überhaupt ein ganzer String für deine Line[] gekommen ist.

Kein Wunder, dass längeres Warten dir da etwas hilft.

von Stefan E. (sternst)


Lesenswert?

In der Tat. Ich war davon ausgegangen, dass uart_getc so lange wartet, 
bis auch tatsächlich ein Zeichen empfangen wurde. Ich habe mal einen 
Blick in die Dokumentation der Peter-Fleury-Uart-Lib geworfen, und dem 
ist nicht so.

@ tymm:
Du musst also deine uart_gets ändern. Z.B. uart_getc immer in einer 
Schleife so lange aufrufen, bis kein UART_NO_DATA mehr zurückkommt.

von lkmiller (Gast)


Lesenswert?

Ja, da scheint mir die Implementierung von uart_gets() die möglichen 
Rückgabewerte von uart_getc() noch nicht richtig abzufangen:

Returns:
    lower byte: received byte from ringbuffer
    higher byte: last receive status
    * 0 successfully received data from UART
    * UART_NO_DATA
      no receive data available
    * UART_BUFFER_OVERFLOW
      Receive ringbuffer overflow. We are not reading the receive buffer
      fast enough, one or more received character have been dropped
    * UART_OVERRUN_ERROR
      Overrun condition by UART. A character already present in the
      UART UDR register was not read by the interrupt handler before
      the next character arrived, one or more received characters have
      been dropped.
    * UART_FRAME_ERROR
      Framing Error by UART

Aus:
http://homepage.hispeed.ch/peterfleury/group__pfleury__uart.html

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.