Hallo Forum, ich habe ein Problem mit der im Betreff stehende Sache. Ich möchte innerhalb der ISR des Timers1 des Atmega32 gern einen per SPI ausgelesenen Wert von einem Sensor mittels eines Pointers in ein Array schreiben. Zum Verständnis ein wenig Code: Signal(SIG_OUTPUT_COMPARE1) { getaccl(); //Werte aus dem Sensor auslesen *pdata= Werte; //Die ausgelesenen Werte mittels Pointer dem array zuweisen } Nun erstmal die Hauptfrage: Geht das einfach so? Ich habe es natürlich schon probiert und es geht bei mir nicht. Ich weiß aber nicht woran es liegt. Zeitkritisch ist es nicht, da der Interrupt nur alle 30ms aufgerufen wird. Wenn ich das Zuweisen der Werte weglasse und stattdessen noch aufwendige Funktionen in der ISR aufrufe, macht er das auch ohne Probleme. Also nochmal, weiß jemand, warum er bei dem Wertezuweisen Probleme hat? Gruß, Marian
Klaus Peter wrote: > schreiben. Zum Verständnis ein wenig Code: > Signal(SIG_OUTPUT_COMPARE1) > { > getaccl(); //Werte aus dem Sensor auslesen > *pdata= Werte; //Die ausgelesenen Werte mittels Pointer dem array > zuweisen > } > > Nun erstmal die Hauptfrage: Geht das einfach so? Im Prinzip ja. Der Teufel steckt, wie immer, im Detail. Zb. Darin, dass Arrays nicht als Ganzes zugewiesen werden können etc. > Ich habe es natürlich schon probiert und es geht bei mir nicht. Dann hast du einen Fehler gemacht. > Ich weiß aber nicht woran es liegt. Wir auch nicht. Es ist nur so, dass du uns gegenüber einen Vorteil hast: Du siehst deinen konkreten Code, wir nicht. Wenn überhaupt, dann kannst also nur du deinen Fehler finden. Oder aber du zeigst deinen richtigen Code her, dann können auch wir den mal durchstöbern.
@Klaus Peter >schreiben. Zum Verständnis ein wenig Code: >Signal(SIG_OUTPUT_COMPARE1) >{ > getaccl(); //Werte aus dem Sensor auslesen > *pdata= Werte; //Die ausgelesenen Werte mittels Pointer dem array Das ist so oder so Quark. entweder pdata[index] = Wert; // EIN einzelner Wert oder *(pdata+index) = Wert; >Nun erstmal die Hauptfrage: Geht das einfach so? Ich habe es natürlich Ja, aber wie bereits von Karl Heinz gesagt, die Details sind der Knackpunkt. 1.) Dass Array muss global und volatile definiert sein volatile uint8_t pdata[10]; 2.) Du musst die einzelnen Elemente einzeln zuweisen, ggf. über ne Schleife. >schon probiert und es geht bei mir nicht. Ich weiß aber nicht woran es >liegt. Zeitkritisch ist es nicht, da der Interrupt nur alle 30ms >aufgerufen wird. Wenn ich das Zuweisen der Werte weglasse und Na dann sollte aber das Auslesen per SPI weniger als 30ms dauern. MFG Falk
Ok, dann hat sich meine Hauptfrage ja erledigt, es muss also gehen. Da ich nicht den vollständigen Code hier zeigen darf, werde ich versuchen alles nötige darzustellen.
1 | #define SIZE 128 // Defines size of input array
|
2 | |
3 | volatile int32_t acclx=0,accly=0,acclz=0; //Beschleunigungswerte |
4 | volatile double dataraw[SIZE]={0}; |
5 | volatile double *pdata; |
6 | void getaccl(void) |
7 | {
|
8 | /*Beschleunigungswerte der x-Achse vom SMB360 holen*/
|
9 | smb360_read_register(0x9A,0x9B); // Register des Bese auslesen |
10 | zweier_Komplement_umrechnen(data1,data2); //Die Werte vom Bese in dezimal umrechen (-512 bis 511) |
11 | acclx = accl; //Den aktuell ausgelesenen Beschleunigungswert der x-Achse zuweisen |
12 | /*Beschleunigungswerte der y-Achse vom SMB360 holen*/
|
13 | smb360_read_register(0x9E,0x9F); // Register des Bese auslesen |
14 | zweier_Komplement_umrechnen(data1,data2); //Die Werte vom Bese in dezimal umrechen (-512 bis 511) |
15 | accly = accl; //Den aktuell ausgelesenen Beschleunigungswert der y-Achse zuweisen |
16 | /*Beschleunigungswerte der z-Achse vom SMB360 holen*/
|
17 | smb360_read_register(0x9C,0x9D); // Register des Bese auslesen |
18 | zweier_Komplement_umrechnen(data1,data2); //Die Werte vom Bese in dezimal umrechen (-512 bis 511) |
19 | acclz = accl; //Den aktuell ausgelesenen Beschleunigungswert der z-Achse zuweisen |
20 | }
|
21 | SIGNAL(SIG_OUTPUT_COMPARE1) |
22 | {
|
23 | if (zeitgeber==30) |
24 | {
|
25 | getaccl(); //Auslesen der Beschleunigungswerte |
26 | *pdata = (acclx*acclx) + (accly*accly) + (acclz*acclz); //Zuweisen der Beschleunigungswerte |
27 | pdata++; //Den Pointer auf das nächste Feld im Array zeigen lassen |
28 | zeitgeber=0; |
29 | }else |
30 | {
|
31 | zeitgeber++; |
32 | }
|
33 | }
|
So ich hoffe, dass dieser Ausschnitt schon reicht. Die verwendeten Funktionen funktionieren soweit alle, das alte Programm ansich läuft auch schon seit einiger Zeit. In diesem Programm habe ich die Werte immer in der main ausgelesen und dann zugewiesen, ohne Probleme. Ich will jetzt "nur" mein altes Programm umbauen, so wie ich es oben beschrieben habe. Leider klappt das nicht so ganz. Sobald ich die Wertezuweisung mittels *pdata einbaue, gibt mir mein Atmega32 seltsame Sonderzeichen per Uart aus. Wenn ich es rauskommentiere, funktioniert alles super. Kann mir, mit dem was ich bis jetzt beschrieb, schon jemand weiter helfen?
Falk wrote:
> 1.) Dass Array muss global und volatile definiert sein
global ja, volatile sehr wahrscheinlich nicht (aber das hängt vom
Rest ab).
Wo/Wie wird der Speicher angelegt, auf den pdata zeigt? Liegt das Array in Data, Bss oder im Stack? Besteht die Gefahr, dass die Endgrenze vom Array überschritten wird? Dein Code enthält kein Zurücksetzen von pdata. Was passiert, wenn du die lange Berechnung durch eine kurze Zuweisung ersetzt z.B. *pdata = 42; ?
Achso, ich habe noch vergessen die main zu zeigen.
1 | int main(void) |
2 | {
|
3 | SPI_MasterInit(); //SPI Initialisation |
4 | UART_Init(); //Uartinitialisation |
5 | Timerinit1(); //Timerinitialisierung des Timers1 |
6 | stdout = &mystdout; //Verlinken des Ausgabestreams für printf |
7 | DDRC=0xFF; //PortC auf Ausgang stellen, indem das gesamte DataDirectionRegister auf 1 gesetzt wird |
8 | while(A<999) PORTC &=~(1<<PC5); //eine Sekunde lang die LED leuchten lassen |
9 | zeitgeber=0; //Variable für das Timing des Auslesen auf 0 setzen |
10 | PORTC |=(1<<PC5); |
11 | pdata=&dataraw[0]; |
12 | while(1) |
13 | {if (pdata ==&dataraw[SIZE]) |
14 | { PORTC &= ~(1<<PC5); |
15 | anzahl=0; |
16 | pdata=&dataraw[0]; |
17 | PORTC |=(1<<PC5); |
18 | }
|
19 | }
|
20 | }
|
Also das Array liegt meines Wissens nach in data. Nein die Grenzen werden nicht überschritten, wie meine vergessene main zeigt :). Hab ich auch getestet. Das mit der einfachereren Zuweisung hatte ich nur so getestet: *pdata = acclx; Ich probiere es mal mit der 42.
Hm sehr interessant. Ich habe gerade die Sache mit *pdata=42; getestet. Nun kann ich keine Verbindung mehr mit dem Controller herstellen, das Programm bleibt sofort hängen, die LED, die eigentlich nach einer Sekunde ausgeht, leuchtet ständig. Wenn ich *pdata=acclx; schreibe, kann ich mich wieder vebinden aber die Sonderzeichen sind anders als bei der oben genannten Zuweisung.
>Also das Array liegt meines Wissens nach in data. Nein die Grenzen >werden nicht überschritten, wie meine vergessene main zeigt :). Hab ich >auch getestet. Das mit der einfachereren Zuweisung hatte ich nur so >getestet: *pdata = acclx; Die Arraygrenzen werden sehr wohl überschritten, sobald aus Deinem Testprogramm ein "richtiges" main wird: Wenn main mal länger beschäftigt ist als Deine 30ms UND während dieser Zeit der Pointer > &dataraw[SIZE] wird, überschreibst Du den Speicher hinter dem Array. Und noch schlimmer: weil Du in main auf pdata == &dataraw[SIZE] testest, wird Dein main() diesen Überlauf nichtmal bemerken, Dein koompletter Speicher wird ab diesem Zeitpunkt sukzessive zugemüllt. Deshalb: Den Pointer immer an der Stelle testen, wo er auch verändert wird, also in Deinem Fall in der ISR. Und: Nie auf ==, sondern auf >= testen. Stefan
Ok danke für den Hinweis, daran hatte ich noch nicht gedacht. Ich habe es nun geändert, aber an meinem Problem hat sich nichts getan, er verhält sich immer noch genau so.
int index=0; // global SIGNAL(SIG_OUTPUT_COMPARE1) { if (zeitgeber==30) { getaccl(); //Auslesen der Beschleunigungswerte dataraw[index]=(acclx*acclx) + (accly*accly) + (acclz*acclz); //Zuweisen der Beschleunigungswerte index++; if (index >= SIZE) index=0; zeitgeber=0; } else { zeitgeber++; } }
Ähhh, du musst erst ALLE Variablen (und vor allem deinen Pointer) initialisieren, bevor du die Interrupts freigibst. Ich nehme an, dass Timerinit1(); //Timerinitialisierung des Timers1 den Timer initialisiert und freigibt. Allerdings wird dein Pointer erst nach einer Sekunde LED Blinken initialisiert! pdata=&dataraw[0]; Es muss definiv umgekehrt sein. MFG Falk
SUPER! Genau das war der Knackpunkt, danke Falk. Ich habe jetzt den Pointer gleich als erstes initialisiert und nun macht er alles, wie ich es will. Endlich...nochmals vielen dank! Gruß, Marian
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.