Archiv verlassen und diese Seite im Standarddesign anzeigen : Dividieren
Arexx-Henk
04.01.2006, 20:12
Hallo,
Mein Program lauft nicht wenn die Zeile mit code:
MeinVar1 = MeinVar2 / 100;
anwesend ist.
In die Listdatei sehe ich folgendes:
rcall __udivmodqi4
Mit Google finde ich dass es sich um eine function handelt die sich in 'stdlib.h' befinded.
Wie kann ich obenstehendes dividieren ohne die library function zu benutzen? Oder bei welchen umstande oder aktionen wird '__udivmodqi4' angerufen?
Gruss
Henk
Falls ein Fehler in der Lib sein sollte, ist der sicher vom Variablentyp abhängig. Vielleicht kannst Du ja den Variblentyp einfach mal ändern, damit eine andere Divisionsroutine aufgerufen wird. Ansonsten würde ich empfehlen AVR-Studio zu installieren, da ist ein Simulator drin und man kann die Funktion mal durchsteppen.
Gruss,
stochri
Arexx-Henk
04.01.2006, 21:41
Ich habe herausgefunden dass die Funktion '__udivmodqi4' richtig angerufen wird und functioniert wenn ein dividierung statt finden soll,
aber, es functioniert nicht wenn angerufen von einen dividierung innerhalb ein Interrupt.
Dass Program hangt sich nicht aber die nachher kommende interrupt zeilen werden nicht mehr ausgefuhrt.
Dass ist etwas wass ich nicht verstehe.
Irgendwo sehe ich etwas uber dem Kopf.
Gruss
Henk
Hallo Henk,
mal ne ganz andere Frage: das Musikspielprogramm für den ASURO stammte doch von Dir, oder nicht? Villeicht könnte man eine kleine Subroutine zum Töne ausgeben machen und in die ASURO-lib
http://sourceforge.net/project/showfiles.php?group_id=155217
mit einfügen, damit man die Möglichkeit hat, in den eigenen ASURO-Programmen akkustische Effekte einzubauen.
Was hältst Du davon ?
Gruss,
stochri
Arexx-Henk
04.01.2006, 22:40
Hallo Stochri,
Ja, stimmt, dass Musikprogram stammt von mir, und eine Art Beep() function fuhr die Asuro daruber hab ich mir schon gedacht.
Meine frage ist, wer ist die Author/Besitzer vom Asuro Lib auf SourceForce?
Wenn Du die Asuro-Musik source anschaut kannst du vielleicht selbst so etwas zufugen?
gruss
Henk
SprinterSB
05.01.2006, 09:00
Kannst du mal das entsprechende Code-Stück hier reinstellen, so daß man es nachvollziehen kann? evtl aus das list-file
udivmodqi4 wird genommen für 8bit-Werte.
@henk
Meine frage ist, wer ist die Author/Besitzer vom Asuro Lib auf SourceForce?
Der Hauptmaintainer ist m.a.r.v.i.n, der hat hier im Forum vor kurzem den Vorschlag gemacht, eine gemeinsame Lib zu schaffen und er hat dann das Projekt in source-forge eingetragen.
Wo finde ich denn die Soucen zu Deinem Musik-Programm? Deine alte Seite ist ja nicht mehr erreichbar.
Gruss,
stochri
SprinterSB
05.01.2006, 12:45
Ich vermute mal der Fehler liegt woanders in deiner Interrupt-Routine. Wenn ich ne Division in einer ISR mache, sieht das asm ok aus.
Arexx-Henk
05.01.2006, 17:56
Hallo SprinterSB un storchi
Auch eine eigene einfache function zum Led steurung lief nicht wenn angerufen innerhalb ein interrupt, ich verwende den timer1 output compare interrupt dazu. Ich nutze die Asuro Robot ProgrammersNotepad2 mit Gcc.exe und eine makefile von die Asuro. Vielleicht gibts dort irgendwo die antwort. Ich vermute da geht etwas falsch beim stack. Vielleicht werden da die programcounter oder sonstiges nicht auf stack gespeichert. Es hat nicht unbedingt mit dividieren zu tun sondern mit anrufen eine function.
Meine code listing
//OCR1BL=ucMeinVar*128/110;
993 .stabn 68,0,1207,.LM159-__vector_7
994 .LM159:
995 03c6 8091 0000 lds r24,ucMeinVar
996 03ca 9927 clr r25
997 03cc 9695 lsr r25
998 03ce 982F mov r25,r24
999 03d0 8827 clr r24
1000 03d2 9795 ror r25
1001 03d4 8795 ror r24
1002 03d6 6EE6 ldi r22,lo8(110)
1003 03d8 70E0 ldi r23,hi8(110)
1004 03da 00D0 rcall __divmodhi4
vorangehend an 'rcall' keine 'stack-pop' actionen oder sonstiges!
Vielleicht sollte im makefile einige compiler flaggen zugefugt werden.
zu storchi
Die Musik sourcode ist hier zu finden:
http://www.arexx.com/downloads/Asuro_Henk/AsuroIdx.htm
irgendwo by Arexx Asuro downloads
gruss
Henk
RedBaron
05.01.2006, 18:44
Hallo Henk,
das ganze sieht nach einem Stack-Fehler aus (konkurrierende Interrupts oder so). Der Assembler-Code ist so in Ordnung. Wie leitest du die Interrupt-Routine ein? mit SIGNAL oder INTERRUPT?
Bitte 'mal die gesamten Interrupt-Routine posten (in C).
Gruß Red Baron
Arexx-Henk
08.01.2006, 11:14
Hallo RedBaron
Wie leitest du die Interrupt-Routine ein? mit SIGNAL oder INTERRUPT?
Mit SIGNAL, aber wass ist den uberhaupt INTERUPT? Die kenn ich noch nicht.
Ubrigens gibts mehr fremde Dinge mit interrupts. Ich benutze ein integer zahler im interrupt. Wenn ich die so deklariere:
static unsigned int uiMeinZahler;
Dann wird:
if(uiMeinZahler==1000){
NICHT ausgefuhrt, und wenn deklariert als globalen variabele
volatile unsigned int uiMeinZahler;
dann funktioneirt es.
Fremd...
gruss
Henk
RedBaron
08.01.2006, 14:07
Hallo Henk,
eine mit SIGNAL deklarierte Routine wird normalerweise nicht durch andere Interrupts unterbrochen. Eine mit INTERRUPT deklarierte schon, wenn der neue Interrupt eine höhere Priorität hat.
Schaltest du in deiner Routine explizit oder durch eine andere Funktion, die du aufruftst, die Interrupts wieder ein? (z.B. durch 'sei()').
-------------------
Die Lösung zum Problem mit 'uiMeinZahler' liegt im Schlüsselwort 'volatile'. Wenn eine Variable als 'volatile' gekennzeichnet ist, geht der Compiler davon aus, dass sich der Wert asynchron zum eigentlichen Programmfaden (thread) ändert (also z.B. durch einen zwischendurch aufgetauchten Interrupt). Der Variablenwert wird deshalb bei jedem Zugriff erneut aus dem Speicher geladen.
Ist eine Variable nicht als 'volatile' gekennzeichnet, geht der Compiler davon aus, dass sie sich nicht zwischendurch ändert und optimiert entsprechend. Wenn sie also einmal in einem Register ist, wird stets das Register genommen und nicht mehr nachgeladen. Wegen dieser Optimierung ist es auch sehr schwierig, die Ursache eines Problems zu erkennen, wenn die Codeschnipsel zu klein sind. Man kann dann nur raten.
Wenn du also in deinem Programm Variablen hast, die sowohl im Hauptprogramm als auch in einer Interrupt-Routine oder aber in mehreren Interruptroutinen angesprochen werden, egal ob lesend oder schreibend, must du sie als volatile deklarieren, damit es einwandfrei klappt.
Gruß Red Baron
Arexx-Henk
09.01.2006, 22:50
Hallo RedBaron,
Danke fur das Antwort,.
Das mit die 'volatile' ist mir jetzt klar.
Uber dass dividieren mochte ich noch folgendes bemerken.
Vom (SIGNAL) interrupt heraus lasst sich keine function anrufen denn dann functioniert die interrupt function nicht richtig mehr.
Wenn innerhalb die interrupt function eine complexere dividierung statt finded dann wird die complexere dividierung durch die compiler compiliert nach einen anruf von eine 'divmod' function. Weil es hier um ein anruf eines function auserhalb die interrupt function handelt wird auch hier die interrupt function nicht mehr richtig ausgefuhrt.
Warum eine function anruf vom interrupt hinaus nicht functioniert das werde ich heute oder morgen schon ausfinden.
gruss,
Henk
Arexx-Henk
14.01.2006, 11:32
Hallo RedBaron,
Die Lösung zum Problem mit 'uiMeinZahler' liegt im Schlüsselwort 'volatile'. Wenn eine Variable als 'volatile' gekennzeichnet ist, geht der Compiler davon aus, dass sich der Wert asynchron zum eigentlichen Programmfaden (thread) ändert (also z.B. durch einen zwischendurch aufgetauchten Interrupt). Der Variablenwert wird deshalb bei jedem Zugriff erneut aus dem Speicher geladen.
Wie erklarst du denn dass ein volatile variabele benutzt werden soll in main() wenn mann die variabele standig in main() abfragen will und wenn mann dieselben variabele in einen Interrupt function andert?
Was ist met der Wert gemeint? Die Wert vom C-variabele oder die Wert vom Register die fur die C-variabele vom Assembler dafur benutzt wird?
Ich meine:
Vorbild:
unsigned char MeinVar;
MeinVar=0x33;
Da wird vom Assembler irgend ein Register (z.B. R16) benutzt um die 0x33 darin zu speichern.
Ich denke, wenn nicht als 'volatile' deklariert, dann wird in main() Register R16 abgefragt und nicht die MeinVar variabele.
Was meinst du davon?
gruss
Henk
RedBaron
15.01.2006, 03:14
Hallo Henk,
Vom (SIGNAL) interrupt heraus lasst sich keine function anrufen denn dann functioniert die interrupt function nicht richtig mehr.
Doch! Das ist ohne Probleme möglich!
unsigned char MeinVar;
MeinVar=0x33;
Hier benutzt der Compiler ein Register. Das steht dann in der Interrupt-Routine nicht zur Verfügung.
volatile unsigned char MeinVar;:
hier wird ein Speicherplatz im Heap angelegt, wenn die Variable außerhalb einer Funktion (auch main()) deklariert wird. Auf den Heap kann man von jeder Stelle aus zugreifen.
Beispiel (aus asuro.c):
volatile unsigned char count72kHz;
/* uses timer2 (36kHz for IR communication */
/* counts falling and rising edge => 36kHz*2 = 72kHz */
SIGNAL (SIG_OUTPUT_COMPARE2)
{ count72kHz ++;
}
void dummy(int p){} // Damit der Compiler nicht optimieren kann.
int main(void)
{ while (count72kHz < 100)
dummy(count72kHz);
return 0;
}
Sowohl die Interrupt-Routine als auch 'main()' greifen korrekt auf 'count72kHz' zu.
------------------------------------
Interrupts erfolgen immer(!) asynchron zum Hauptprogramm, d.h. zu unvorhersehbaren Zeitpunkten. In der Interruptroutine weiß der Compiler deshalb nicht, welche Belegung die Register gerade haben.
Zum Beginn einer Interruptroutine werden deshalb zuerst alle Register, die in der Routine benutzt werden, gesichert (auf dem Stack) und am Ende wieder zurückgespeichert. Dies betrifft z.B. r24 im Beispiel:
**** SIGNAL (SIG_OUTPUT_COMPARE2)
push __zero_reg__
push __tmp_reg__
in __tmp_reg__, __SREG__
push __tmp_reg__
clr __zero_reg__
push r24
**** count72kHz ++;
lds r24, count72kHz
subi r24, lo8(-(1))
sts count72kHz, r24
pop r24
pop __tmp_reg__
out __SREG__, __tmp_reg__
pop __tmp_reg__
pop __zero_reg__
reti
**** void dummy(int p){}
ret
**** int main(void)
**** { while (count72kHz < 100)
.....
lds r24,count72kHz
cpi r24,lo8(100)
brsh .L26
.L24:
**** dummy(count72kHz);
lds r24,count72kHz
clr r25
rcall dummy
lds r24,count72kHz
cpi r24,lo8(100)
brlo .L24
Hier wird r24 mit dem Inhalt (Wert) von 'count72kHz' geladen. Das passiert auch, obwohl in 'main()' ebenfalls 'count72kHz' ins r24 geladen wird. r24 kann an anderer Stelle anderweitig benutzt worden sein. Der Compiler weiß eben nicht, ob der Interrupt nicht an dieser Stelle eintritt.
In 'main()' wird r24 zunächst für den Vergleich mit 'count72kHz' geladen. Kurz darauf für die Rarameterübergabe an 'dummy()' noch einmal, obwohl der Wert doch eigentlich schon in r24 steht. Da neue Laden ist aber notwendig, da eventuell zwischendurch der Interrupt eingetroffen sein könnte. Dieser würde den Inhalt von 'count72kHz' verändern. Theoretisch könnte es sein, dass der Vergleich (count72kHz < 100) und der Aufruf von Dummy mit unterschiedlichen Werten von 'count72kHz' erfolgen kann. Wenn man dies verhindern will, muss man 'count72kHz' in eine nicht als volatile deklarierte Variable zwischenspeichern:
unsigned char x;
x = count72kHz;
while ( x < 100)
{ dummy(x);
x = count72kHz;
}
----------------------------------------
Was ist met der Wert gemeint? Die Wert vom C-variabele oder die Wert vom Register die fur die C-variabele vom Assembler dafur benutzt wird?
Wenn eine Variable als volatile gekennzeichnet ist, benutzt der Compilier kein Register!
Gruß Red Baron
Arexx-Henk
22.01.2006, 13:59
Hallo RedBaron,
Verzeihung um die spate antwort aber ich hatte noch viele andere Sachen zu klaren.
Danke fur die Erklarung, die wird ich mich nochmal richtig ansehen.
Ich sehe in meine Interuptfunction bei einem Teilung z.B. die anruf von
'rcall divmodh14'
Meine Frage ist: soll Ich selber die benutzte register auf/vom Stack pushen und poppen oder macht dass die ' divmodh14' function selber?
Wenn ich vom innerhalb meine interrupt function eine eigene test Function anrufe (die viele variabelen benutzt) dan gibts nirgendwo ein push oder pop in die listfile zu sehen! Nicht bei die Anruf und nicht in die angerufene test Function. Wie ist dass den moglich? Vermutlich ist dies die Ursache von meinem Problem.
Auch sind keine push/pos zu sehen wenn ich meine test Function sich selber (rekursief) anrufen lass.
(Beim anfang und ende vom interrupt function sehe ich viele 'push' und 'pops'.)
Vielleicht soll ich mich die 'makefile' ansehen ob da irgendeine Compiler flage nicht anwesend ist?
Gruss
Henk
SprinterSB
23.01.2006, 14:45
Der Compiler fügt nur dort push und pop-Anweisungen in den Code ein, wo sie auch gebraucht werden.
Die Übergabe von Argumenten wird in der Regel ohne push und pop erledigt, weil die Argument in Registern übergeben werden.
In den Funktionen ist auch nicht unbedingt push/pop notwendig, sondern nur denn, wenn Register verwendet werden, die durch einen Funktionsaufruf nicht verändert werden bzw nach einem Funktionsaufruf unverändert vorliegen ("call saved regs"). Für die Register, die eine Funktion verwenden kann ohne sie vorher zu sichern ("call clobbered regs") ist natürlich kein push/pop notwendig.
Auf keinen Fall darfst du irgendwo in den Code ein "push" einfügen oder so, das führt zum Absturz -- Ausnahme ist, wenn du selber Inline Assembler einfügst und du genau weisst was du tust und genau weisst, welchen Code der Compiler sonst generiert.
Wenn du "reinen" C-Code schreibst, brauchst du dich darum nicht zu kümmern.
Das gilt auch für die (implizit aufgerufene) divmodhi4-Funktion, das erledigt alles der Compiler.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.