Forum: Mikrocontroller und Digitale Elektronik c / atmega328: 16bit-arraywerte werden komisch gespeichert


von blinksdinks (Gast)


Angehängte Dateien:

Lesenswert?

hallo,

ich stehe bei einem Programmierproblem total auf dem Schlauch.
In einem C Programm (Atmega 328P über ISP mit AtmelStudio 6) speichert 
mir mein Programm einfache Arraywerte falsch und ich find den Fehler 
nicht!

eigentlich lasse ich nur über diese Billo-Funktion:

void fill_pwm_values()
{
  for (uint8_t j = 0; j < 16; j++)
  {
    pwm_values[j] = 100;
  }

}

ein array beschreiben, welches global so

uint16_t pwm_values[16];

definiert ist.

Genutzt wird das Array dann so:

void create_pwm_values_for_spi()
{
uint8_t counter = 0;

  fill_pwm_values();

  for (uint8_t i = 0; i < 16; i += 2)
  {
  pwm_values_for_spi[counter] = ((pwm_values[i]  & 0x0ff) >> 4);

pwm_values_for_spi[counter+1] = ((pwm_values[i] & 0x0f) << 4) | 
(pwm_values[i+1] >> 8);
  pwm_values_for_spi[counter+2] = (pwm_values[i+1]) << 8;
  counter += 3;
  }

}



Lasse ich mir jetzt über die watch die Werte anzeigen, zeigt er mir 
irgendwelche 16bit Werte an (pwm_value[0] = 50197, pwm_value[1] = 287, 
pwm_value[2] = 8224, pwm_value[3] = 0, pwm_value[4] = 7876 ...)

Wenn ich meine Funktion einzeln in ATMEL-Studio teste, zeigt mir die 
watch die richtigen Werte an. Was ist denn da los? Die Werte ändern sich 
auch dauernd. Im Anhang mein Test-Code, es muss irgendwie an dem liegen, 
aber ich find den Fehler nicht.
Ist bisher nur Testcode, es speichert eigentlich nur ein 16-bit-Array, 
zerlegt die 16bit-Werte SPI-kompatibel in 8bit und sendet diese an den 
TLC.
Über den Timer wird ein Takt erzeugt und mitgezählt, brauch ich für die 
Ansteuerung des TLC5940.  Ob das alles schon so funktioniert weiß ich 
nicht, weil ich ja schon vorher stecken bleibe...

Danke für etwaige Hilfe,

c.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

blinksdinks schrieb:
> pwm_values_for_spi[counter] = ((pwm_values[i]  & 0x0ff) >> 4);
>   pwm_values_for_spi[counter+1] = ((pwm_values[i] & 0x0f) << 4) |
> (pwm_values[i+1] >> 8);
>   pwm_values_for_spi[counter+2] = (pwm_values[i+1]) << 8;

Was machst Du da? Was soll das bewirken?

von Olly T. (twinpeaks)


Lesenswert?

blinksdinks schrieb:
> pwm_values_for_spi[counter+2] = (pwm_values[i+1]) << 8;

Mit pwm_values[i+1] greift Du bei i == 15 hinter Dein Array, was schon 
mal nicht stimmen kann.

Edit: OK, sehe gerade, dass Du in der Schleife immer um 2 hochzählst und 
die Schleife somit nur bis 14 zählt.

: Bearbeitet durch User
von blinksdinks (Gast)


Lesenswert?

sorry fürdie blöde formatierung oben, hier besser:

void create_pwm_values_for_spi()  {
  uint8_t counter = 0;

  fill_pwm_values();

  for (uint8_t i = 0; i < 16; i += 2)
  {
    pwm_values_for_spi[counter] = ((pwm_values[i]  & 0x0ff) >> 4);
    pwm_values_for_spi[counter+1] = ((pwm_values[i] & 0x0f) << 4) | 
(pwm_values[i+1] >> 8);
    pwm_values_for_spi[counter+2] = (pwm_values[i+1]) << 8;
    counter += 3;
  }

}

Der TLC5940 ist ein 16Kanal-PWM-IC, er hat 16 12-bit-PWM-Kanäle. Ich 
zerlege mit dieser Funktion meine 12bit-Werte (gespeichert als 16bit) in 
8-bit-Werte und sende diese Über SPI. Diese Zerlegefunktion funktioniert 
auch im Test.


Olly T. schrieb:
> Mit pwm_values[i+1] greift Du bei i == 15 hinter Dein Array, was schon
> mal nicht stimmen kann.

deswegen läuft i aber nur bis 14...

von Jim M. (turboj)


Lesenswert?

1
pwm_values_for_spi[counter+2] = (pwm_values[i+1]) << 8;

Was glaubst Du das diese Zeile macht? Die ist falsch, Du wolltest hier 
vermutlich
1
pwm_values_for_spi[counter+2] = (pwm_values[i+1]) & 0xFF;

schreiben.

Ich würde zu Testzwecken das 16-bittige Array auch mit verschiedenen 
Werten füllen, z.B. 100+i, sonst sieht man einige Fehler nicht.

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Vermutlich "schwurbelst" Du da hin:

https://de.wikipedia.org/wiki/Byte-Reihenfolge

von blinksdinks (Gast)


Angehängte Dateien:

Lesenswert?

Problem gelöst!


Jim M. schrieb:
> Was glaubst Du das diese Zeile macht? Die ist falsch, Du wolltest hier
> vermutlich
> pwm_values_for_spi[counter+2] = (pwm_values[i+1]) & 0xFF;
>
> schreiben.

Danke für den Hinweis, vielleicht wollte ich das wirklich so schreiben 
;-)
War aber nicht die Ursache.


Dieter F. schrieb:
> "schwurbelst" Du da hin:
>
> https://de.wikipedia.org/wiki/Byte-Reihenfolge

An sowas dachte ich auch, aber es ist eine ISR, die mir dazwischenfunkt. 
Oder der Timer. Würde mich freuen, wenn mir jemand erklären könnte, 
warum dem so ist:
Ich erzeuge mir einen Takt über Timer0 für den TLC5940. Der braucht nen 
Takt für die Erzeugung seiner PWM; Nach 4096 Takten muß man den IC 
einmal toggeln. Eigentlich wollte ich den Takt über Compare Match Mode 
machen, habs dann aber über Fast-PWM gemacht. Ich lege TOP und Compare 
Match fest und krieg so meinen 50%Duty-Cycle. In einer ISR zähle ich den 
Takt mit.
Ich wollte den Tak so schnell wie möglich machen und hab deswegen als 
TOP einfach mal 15 und Compare Match auf 7 gesetzt. Und das zerhaut mir 
die Speicherung meiner Variablen. Lege ich den Top-Wert auf 63 und 
Compare Match auf 31, läuft alles wie gewünscht, also in meinem Array 
sind meine Werte und nicht irgendein Quatsch.
Oder hab ich da nen Programmierschnitzer? Bin noch recht neu auf dem 
Gebiet, teste gerade mit den Timern rum und es bereitet mir schon auch 
Probleme, dass alles zu verstehen - und umzusetzen! Also falls es eher 
mit meinen Code als mit einer Überforderung des Atmegas zu tun hat, 
würde ich mich freuen, wenn sich jemand nochmal den Code anschaut, ob 
der Timer oder die ISR irgendwie blöd sind. Habe ihn deswegen nochmal 
überarbeitet angehängt. Ob die Ansteuerung des TLC5940 jetzt 
funktioniert kann ich grad nicht testen, weil Aufbau nicht hier, aber 
ist für die Frage mit dem wirren Speichern der Variablen ja auch egal.
Danke für die ganzen Hinweise bisher! Schöne Nacht euch allen!

von Jim M. (turboj)


Lesenswert?

blinksdinks schrieb:
> Ich wollte den Tak so schnell wie möglich machen und hab deswegen als
> TOP einfach mal 15 und Compare Match auf 7 gesetzt. Und das zerhaut mir
> die Speicherung meiner Variablen.

Dürfte das sei im zusammenhang mit dem zu knappen Timing sein. Das 
enabled den Interrupt bevor die Aufräumarbeiten des Stacks fertich sind 
-> Stack overflow.

Man sollte auch daran denken dass da signifikant Zyklen zum Sichern und 
Wiederherstellen von Registern nötig sind - 15 Clocks sind für die ISR 
deutlich zuwenig.

von blinksdinks (Gast)


Lesenswert?

Danke Jim für die Erläuterung... Es freut mich immer sehr, wenn Leute 
dieses Forum sich die Zeit für sowas nehmen.
Ach, diese Mikrocontroller. Es ist zwar -wenn man sich alles selbst 
beibringt - saukompliziert, aber es macht auch dolle Spaß sich die 
Architektur der kleinen Biester zu erarbeiten! Als nächstes kommt dann 
jetzt wohl der stack, dann weiß ich bald endlich was der berühmte stack 
overflow ist! Und mit dem Timing und der Antsteuerung des TLC hab ich 
grad auch noch zu kämpfen, aber diese Geschichte wird in einem 
Extrathread weitergeschrieben.
Schönen Sonntag euch allen!

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.