Hallo Profis. Ich habe erstmal folgende Frage an Euch. Ich möchte an meinem 128x64 glcd eine Sinus-Kurve darstellen. Bis jetzt habe ich eine Funktion mit der ich nur einen Punkt darstellen kann. set_pixel(x,y); //schreibt einen Pixel auf dem LCD Hat jemand vielleicht eine Funktion/Lib mit der ich eine gesamte Sinus Kurve darstellen kann ??? Wäre es möglich meine set_pixel Funktion in die Sinus Funktion zu implementieren? Für Antworten sowie Anregungen bin ich sehr Dankbar. Liebe Grüße Adam
Hi, ich denke die einfachste Möglichkeit wäre, eine Tabelle anzulegen, in der die Sinuswerte für 90° eingetragen sind. Durch Spiegelung etc. erreichst du dann die anderen Werte. Die Anzahl der Einträge bestimmt die Genauigkeit, also z.B. 0.5°- oder 1°-Schritte. Über die Gradangabe ermittelst du den Sinuswert. Ralf
Danke Ralf. Hast Du vielleicht ein Link bzw ein Beispiel dafür ? Wie Du merkst ist das Darstellen von Kurven nicht meine Stärke. Vieln Dank nochmal für die Antwort. Liebe grüße
> Ich möchte an meinem 128x64 glcd eine Sinus-Kurve darstellen.
Soso, mit welchem Prozessor denn? Mit welcher Sprache denn?
Es gibt in allen handelsüblichen Programmiersprachen eine Funktion zur
Berechnung eines Sinus-Wertes ( sowas wie sin() ). Die liefert dann
einen Wert zwischen -1 und +1 zurück, den mußt du nur noch entsprechend
skalieren und einen Offset dazuaddieren. Und dann dein set_pixel()
aufrufen.
Hallo Lothar. Danke erstmal für die rasche Antwort. Controller : Atmega32 Sprache : C GLCD : 128x64 ich kann also einen Punkt am glcd "zeichnen". Soweit bin ich :o) In wieweit kann ich denn math.h miteinbeziehen ??? Habe außerdem noch folgendes gefunden : for(fx=0;fx<=129;fx=fx+1) { fy=((sin(fx/10)*20)+ 64); LCD_pixel_write8((int8)(fx), (int8)(fy),BLACK); fy=((sin(fx/10+128)*20)+ 64); LCD_pixel_write8((int8)(fx), (int8)(fy),BLACK); } Dies gibt mir jedoch nur "Quatsch" aus... Ich komme da einfach nicht weiter Liebe Grüße
Adam wrote: > Danke Ralf. > > Hast Du vielleicht ein Link bzw ein Beispiel dafür ? > > Wie Du merkst ist das Darstellen von Kurven nicht meine Stärke. Du musst dir eine Funktion ausdenken, die deine Kurve realisiert, indem du ein x vorgibst. Dann lässt du das x in einer for-Schleife von 0 bis 127 laufen, rufst deine Funktion dafür auf (und erhältst so den y-Wert) und rufst deine set_pixel mit den so bekannten Werten auf. Deine Funktion muss jetzt nur noch dafür sorgen, dass die errechneten y-Werte in einem sinnvollen Bereich (bei dir 0 bis 63) liegen. Das kannst du aber durch Mutliplikationen bzw. Addition von Werten leicht erreichen. zb. liefert ein Sinus ja Werte zwischen -1 und +1 Damit die in den Bereich 0 bis 63 zu liegen kommen, kannst du zb. mit 31 multiplizieren (dadurch wird der Wertebereich zu -31 bis +31) und dann noch 32 addieren (was den Wertebereich auf 0 bis 63 verschiebt) y = sin( x ) * 31 + 32; indem du das Argument for x noch mit einem Faktor multiplizierst oder dividierst, kannst du jetzt den Sinus in die Länge ziehen
1 | #include <math.h> |
2 | |
3 | ....
|
4 | |
5 | |
6 | void plot_sinus() |
7 | {
|
8 | int x; |
9 | int y; |
10 | |
11 | for( x = 0; x < 128; ++x ) { |
12 | y = sin( x / 0.5 ) * 31 + 32; |
13 | |
14 | set_pixel( x, y ); |
15 | }
|
16 | }
|
Du wirst wahrscheinlich auch schnell sehen, wo die Grenzen dieses einfachen Verfahrens liegen: WEnn sich deine Kurve nur schnell genug zwischen 2 benachbarten X-Werten verändert, entsteht eine Lücke, weil ja die zugehörigen Y-Werte mehr als 1 Pixel auseinander liegen. In dem Fall müsste mann dann einfach Linien zwischen jeweils 2 benachbarten (x,y) Wertepaaren zeichnen.
> y = sin( x ) * 31 + 32; wobei anzumerken ist, das sin() einen Wert zwischen 0 und 2*PI für einen vollständigen Umlauf erwartet. Also wäre für > x in einer for-Schleife von 0 bis 127... die Funktion besser mit einen skalierten Wert aufzurufen: y = sin( x*2*PI/128 ) * 31 + 32; EDIT: > y = sin( x / 0.5 ) * 31 + 32; Liege ich so falsch? :-/
Vielen Dank Euch Beiden ! @Karl heinz Buchegger @Lothar Miller Beide Beiträge waren sehr hilfreich und haben zum Ergebnis geführt.. Lösung : void plot_sinus() { int x; int y; for( x = 0; x < 128; ++x ) { y = sin( x*2*3.14/128 ) * 31 + 32; set_pixel( x, y ); } } Anstatt PI musste ich jedoch mit 3.14 angeben. (PI wird nicht akzeptiert ) Nun habe ich eine Sinuskurve :o) Vielen Dank für die Hilfe Liebe Grüße
Lothar Miller wrote: > > EDIT: >> y = sin( x / 0.5 ) * 31 + 32; > Liege ich so falsch? :-/ Nein, überhaupt nicht. Hängt davon ab, wieviele Sinus-Schwingungen er sehen will. Und ein bischen was zum Nachdenken soll für den TO ja schliesslich auch noch bleiben. Der Hinweis mit dem Winkelargument in Radianten war schon wichtig.
Hallo nochmal! Die Sinuskurve wird von der Mitte des LCD´s gezeichnet sprich in der rechten Hälfte des LCD´s bis zum rechten Rand. Dann wird sie weiter in der linken Hälfte der LCD´s bis zu Mitte gzeichnet. Warum (wahrscheinlich gibt es dafür eine einfache Erklärung )???? Am Chipselect liegt es 100%-ig nicht. Das kann ich außschliessen. Liebe Grüße Adam
Ein paar Experimente und daraus folgende Schlussfolgerungen solltest du schon selbst machen. Zb. Welcher Punkt wird bei setpixel( 0, 0 ) eingeschaltet?
Hallo Karl heinz. Bitte überbewerte meine AVR-kenntnisse nicht. Bin ein blutiger Anfänger :o) sorry laut : for( x = 0; x < 128; ++x ) { y = sin( x*2*3.14/128 ) * 31 + 32; set_pixel( x, y ); wird der erste Punkt bei x=0 und y=32 gesetzt. Das wäre die absolute linke Hälfte des LCD´s nicht die Mitte. irgendwie tappe ich noch im Dunkeln. Gruß
Adam wrote: > Hallo Karl heinz. > Bitte überbewerte meine AVR-kenntnisse nicht. Bin ein blutiger > Anfänger :o) sorry Das hat nichts mit AVR zu tun. > laut : > > for( x = 0; x < 128; ++x ) { > y = sin( x*2*3.14/128 ) * 31 + 32; > > set_pixel( x, y ); > > wird der erste Punkt bei x=0 und y=32 gesetzt. > Das wäre die absolute linke Hälfte des LCD´s nicht die Mitte. Sagt wer? Was macht denn die set_pixel Funktion? Die kann ihren 0-Punkt überall haben, wo sie will. Links/oben Links/unten Mitte/Mitte Mitte/oben Mitte/unten .... und ja nachdem, wo die set_pixel ihren 0-Punkt hat, verschieben sich dann natürlich alle andern Funktionen, die auf set_pixel aufbauen. Also gilt es erst mal rauszufinden, welches Pixel von set_pixel eingeschaltet wird, wenn set_pixel(0,0) aufgerufen wird. Und genau das meine ich mit: Die siehst einen seltsamen Effekt, überlegst dir was es sein könnte, klärst ihn ab und hast etwas ganz auf eigene Fasut gelernt. Ganz zu schweigen vom Erkentnissgewinn, dass höhere Funktionen (wie das Zeichnen einer Kurve) genau dann von den genauen Eigenschaften einer niedrigern Funktion (wie set_pixel) abhängen und man daher oft auch deren Details kennen sollte. Vielleicht ist aber auch einfach nur dein GLCD verdreht und das was du als X-Achse ansiehst, ist in Wirklichkeit die Y-Achse. Oder ...
> Mitte/Mitte
Hat sowas schonmal irgendwo einer gesehen? Und werden dann Pixel
ueber Radius und Gon adressiert? :-D
Olaf
Olaf wrote: >> Mitte/Mitte > > Hat sowas schonmal irgendwo einer gesehen? Macht man sogar relativ oft, dass bei einer Window/Viewport Transformation das default Window [-1..+1, -1..+1] lautet, der 0-Punkt also in der Mitte liegt. > Und werden dann Pixel > ueber Radius und Gon adressiert? :-D LOL Wenns dir Spass macht kannst du das auch so kriegen.
Hallo. @Karl heinz Buchegger Also. Ich habe den "Fehler" gefunden. Es hatte doch (peinlich) was mit den Display-Controllern zu tun. Die CS1 und CS2 Anschlüsse waren zwar korrekt verdrahtet aber in der set_pixel Funktion habe ich einen Dreher gehabt und habe nun CS1 und CS2 vertauscht. <i>Am Chipselect liegt es 100%-ig nicht. Das kann ich außschliessen.</i> Die Aussage bezog sich nur auf die Verdrahtung und nicht auf die softwaremäßige Auswahl der Chipselect. Aus Fehlern lernt man. Jetzt versuche ich mal eine Variablenabhängige Sinus Funktion darzustellen. Ich komme wieder :o) Danke mal wieder für die Hilfe. Grüße
Hi, habe folgendes Problem mit der hier diskutierten Routine. Compiler ist AVR Studio 4.16 und Chip ein ATmega644 mit 16MHz. Display ist ein 320x240 Grafik-LCD mit SSD2119 LCD-Controller.
1 | void plot_sinus(void) |
2 | {
|
3 | int x; |
4 | int y; |
5 | |
6 | for(x=0; x<128; ++x) |
7 | {
|
8 | y = sin(x*2*3.14/128) * 31 + 32; |
9 | LCDD_DrawPixel(hor_left_aligned, x, y, WHITE); |
10 | }
|
11 | }
|
Diese Funktion generiert im Bereich von x=14 bis x=48 fehlerhafte Werte. y nimmt in diesem Bereich nur Werte von 2, 32 oder 36 an. Außerhalb des Bereichs stimmen die Werte von y. Setze ich jetzt z.B. x=19 ohne for-Schleife, dann passt das Ergebnis mit y=56. In der for-Schleife ist aber bei x=19 das Ergebnis für y=2 ?!? Kann mir da jemand weiterhelfen? Gruß Richard
Ohne Gewähr, liegt das vielleicht an Rundungsfehlern, hervorgerufen durch die ints?
Paul W. schrieb: > Ohne Gewähr, liegt das vielleicht an Rundungsfehlern, hervorgerufen > durch die ints? Nicht in der Größenordnung. Irgendetwas läuft da mächtig schief, aber ich kann nicht sagen was. Der Codeausschnitt ist auf jeden Fall in Ordnung.
Adam schrieb: > > Anstatt PI musste ich jedoch mit 3.14 angeben. (PI wird nicht akzeptiert) > In der math.h gibt es einen Define M_PI geben, der Pi auf einige Dezimalstellen genau angibt:
1 | #define M_PI 3.141592653589793238462643
|
Johann
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.