mikrocontroller.net

Forum: Compiler & IDEs Sinusfunktion und glcd


Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
#include <math.h>

....


void plot_sinus()
{
  int x;
  int y;

  for( x = 0; x < 128; ++x ) {
    y = sin( x / 0.5 ) * 31 + 32;

    set_pixel( x, y );
  }
}

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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  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?  :-/

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein paar Experimente und daraus folgende Schlussfolgerungen solltest du 
schon selbst machen.

Zb. Welcher Punkt wird bei setpixel( 0, 0 ) eingeschaltet?

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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ß

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ...

Autor: Olaf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Mitte/Mitte

Hat sowas schonmal irgendwo einer gesehen? Und werden dann Pixel
ueber Radius und Gon adressiert? :-D

Olaf

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Adam (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Richard H. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
void plot_sinus(void)
{
  int x;
  int y;

  for(x=0; x<128; ++x) 
  {
    y = sin(x*2*3.14/128) * 31 + 32;
    LCDD_DrawPixel(hor_left_aligned, x, y, WHITE);
  }
}

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

Autor: Paul W. (dantor)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne Gewähr, liegt das vielleicht an Rundungsfehlern, hervorgerufen 
durch die ints?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
#define M_PI 3.141592653589793238462643

Johann

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.