Forum: Mikrocontroller und Digitale Elektronik Popelige Rechnung oder doch nicht?


von Seijsschmeer (Gast)


Lesenswert?

Hallo liebe Gemeinde!
Vorab, ich bin kein Profi in diesem Gebiet, hatte nur einige Stunden 
µController in der Schule. Deswegen seit bitte nicht zu hart.

Jetzt zu meinem Problem, ich wollte eine Witterungsbedingte 
Temperatursteuerung simulieren. Jetzt "hängt" der sich nur schon bei der 
Rechnung für die Solltemperatur auf, die Formel funktioniert 
einwandfrei, bis ich die Division durch 10 einfüge, danach springt der 
mir in die disassembly Tabelle! Dies bezog sich jetzt auf die Rechnung 
mit der Variable "sollwert". Bei der Variable "b" funktioniert eine 
Division bzw rechnet er hier auch mit 1.2 warum eigentlich? Da er aber, 
sobald ich Variablen ins spiel bringe, nicht mehr mit 1.2 rechnet 
sondern abrundet auf 1, muss ich eben mal 12 multiplizieren und dann 
später durch 10 dividieren. Die Rechnung soll mit Integervariablen 
erfolgen kein float!

Ich benutze AVR Studio 6.0, und einen Atmega8A

Quelltext:

int main(void)
{
 int heizkurve = 12;
 int sollwert = 0;
 int aussentemp = 100;
 int konstante = 500;

  while(1)
    {
     int b = ((500-600)*1.2)+500;
     sollwert = (((konstante-aussentemp)*heizkurve)+konstante)/10;

  }
}

von Sebastian H. (technik_freak)


Lesenswert?

Seijsschmeer schrieb:
>
> Bei der Variable "b" funktioniert eine
> Division bzw rechnet er hier auch mit 1.2 warum eigentlich? Da er aber,
> sobald ich Variablen ins spiel bringe, nicht mehr mit 1.2 rechnet
> sondern abrundet auf 1, muss ich eben mal 12 multiplizieren und dann
> später durch 10 dividieren.

Hallo,

Im Fall mit den 1.2 rechnest Du mit einer konstanten, packst Du diese 
aber in eine Integer-Variable, die nur Ganzzahlen kann, dann wird der 
Wert gerundet.

Du kannst also, wie Du es schon versucht hast, deinen Wert mal 12 nehmen 
und dann durch 10 teilen.

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

Seijsschmeer schrieb:
>      int b = ((500-600)*1.2)+500;

In diesem Fall rechnet der Mikrocontroller überhaupt nicht. Es wird nur 
die Variable b mit dem Wert 380 initialisiert. Mehr nicht.

Die Rechenarbeit übernimmt der Compiler während der Übersetzungszeit.

Wahrscheinlich rechnet aber auch der Compiler nichts, denn die Variable 
b wird nirgends verwendet und daher "wegoptimiert".

von ich, nicht du (Gast)


Lesenswert?

Außerdem ist anzumerken dass die Formeln für b und Sollwert verschieden 
sind, denn die Division durch 10 ist in Sollwert falsch gesetzt.

von Seijsschmeer (Gast)


Lesenswert?

Danke schonmal für die antworten. Wobei mein eigentliches problem bei 
der zweiten rechnung liegt, die mit der variablen "sollwert". Sobald ich 
durchsteppe, hängt sich das programm an dieser stelle auf. Und es hat 
irgendwas mit der division durch 10 zu tun. Ich weiß nur nicht was. 
Sobald ich die division herausnehme, funktioniert die rechnung. Mfg

von Seijsschmeer (Gast)


Lesenswert?

Wie sollte es denn aussehen? @ich, nicht dau

von ich, nicht du (Gast)


Lesenswert?

... *Heizkurve)÷10)+ konstante

Ansonsten würdest du nämlich nicht die konstante addieren sondern nur 
(konstante/10)

von Seijsschmeer (Gast)


Lesenswert?

Leider funktioniert das so auch nicht. Sobald ich eine Variable 
dividieren möchte funktionierts nicht, also avr studio springt in die 
disassembly tabelle und das Prog hängt sich auf. Habe jetzt einfach mal 
folgende Zeile hineingeschrieben.

int test = konstante (hat der wert von 500) /10;

funktioniert auch nicht. Wenn ich die 10 selbst als Int Variable 
deklariere und dieser den Wert 10 zuweise geht es auch nicht, also z.B.

int div = 10;
int konstante =500;

int test=konstante/div;

Ich verzweifel noch, bei sowas simplen eigentlich oder eher doch 
nicht...
MfG

von ich, nicht du (Gast)


Lesenswert?

Poste doch mal den disassenmby des Programms hier hin. Hast du eventuell 
(aus versehen) in die folgezeile einen breakpoint gesetzt?

von Seijsschmeer (Gast)


Lesenswert?

00000063 97.fb                BST R25,7    Bit store from register to T

Auf diese Zeile werde ich direkt verwiesen

von ich, nicht du (Gast)


Lesenswert?

du solltest schonmal etwas mehr posten als das

also z.b. die komplette while schleife

von Seijsschmeer (Gast)


Lesenswert?

Da ich nicht genau weiß was du brauchst, das hier ist alles von Anfang 
bis zu der Zeile in der ich verwiesen werde.

--- No source file 
-------------------------------------------------------------
00000000 12.c0                RJMP PC+0x0013    Relative jump
00000001 2c.c0                RJMP PC+0x002D    Relative jump
00000002 2b.c0                RJMP PC+0x002C    Relative jump
00000003 2a.c0                RJMP PC+0x002B    Relative jump
00000004 29.c0                RJMP PC+0x002A    Relative jump
00000005 28.c0                RJMP PC+0x0029    Relative jump
00000006 27.c0                RJMP PC+0x0028    Relative jump
00000007 26.c0                RJMP PC+0x0027    Relative jump
00000008 25.c0                RJMP PC+0x0026    Relative jump
00000009 24.c0                RJMP PC+0x0025    Relative jump
0000000A 23.c0                RJMP PC+0x0024    Relative jump
0000000B 22.c0                RJMP PC+0x0023    Relative jump
0000000C 21.c0                RJMP PC+0x0022    Relative jump
0000000D 20.c0                RJMP PC+0x0021    Relative jump
0000000E 1f.c0                RJMP PC+0x0020    Relative jump
0000000F 1e.c0                RJMP PC+0x001F    Relative jump
00000010 1d.c0                RJMP PC+0x001E    Relative jump
00000011 1c.c0                RJMP PC+0x001D    Relative jump
00000012 1b.c0                RJMP PC+0x001C    Relative jump
00000013 11.24                CLR R1    Clear Register
00000014 1f.be                OUT 0x3F,R1    Out to I/O location
00000015 cf.e5                LDI R28,0x5F    Load immediate
00000016 d4.e0                LDI R29,0x04    Load immediate
00000017 de.bf                OUT 0x3E,R29    Out to I/O location
00000018 cd.bf                OUT 0x3D,R28    Out to I/O location
--- 
C:\home\tools\hudson\workspace\avr8-gnu-toolchain\src\gcc\gcc\config\avr 
\libgcc.S
     1:
00000019 10.e0                LDI R17,0x00    Load immediate
     1:
0000001A a0.e6                LDI R26,0x60    Load immediate
     1:
0000001B b0.e0                LDI R27,0x00    Load immediate
     1:
0000001C e8.ed                LDI R30,0xD8    Load immediate
     1:
0000001D f0.e0                LDI R31,0x00    Load immediate
--- 
C:\home\tools\hudson\workspace\avr8-gnu-toolchain\src\gcc\gcc\config\avr 
\libgcc.S
     1:
0000001E 02.c0                RJMP PC+0x0003    Relative jump
     1:
0000001F 05.90                LPM R0,Z+    Load program memory and 
postincrement
     1:
00000020 0d.92                ST X+,R0    Store indirect and 
postincrement
     1:
00000021 a0.36                CPI R26,0x60    Compare with immediate
     1:
00000022 b1.07                CPC R27,R17    Compare with carry
     1:
00000023 d9.f7                BRNE PC-0x04    Branch if not equal
     1:
00000024 10.e0                LDI R17,0x00    Load immediate
     1:
00000025 a0.e6                LDI R26,0x60    Load immediate
     1:
00000026 b0.e0                LDI R27,0x00    Load immediate
     1:
00000027 01.c0                RJMP PC+0x0002    Relative jump
     1:
00000028 1d.92                ST X+,R1    Store indirect and 
postincrement
     1:
00000029 a0.36                CPI R26,0x60    Compare with immediate
     1:
0000002A b1.07                CPC R27,R17    Compare with carry
     1:
0000002B e1.f7                BRNE PC-0x03    Branch if not equal
--- No source file 
-------------------------------------------------------------
0000002C 02.d0                RCALL PC+0x0003    Relative call 
subroutine
0000002D 3c.c0                RJMP PC+0x003D    Relative jump
0000002E d1.cf                RJMP PC-0x002E    Relative jump
--- C:\Users\Alex\Documents\Atmel 
Studio\Heizung\Heizung\Debug/.././Heizung.c --
    15: {
0000002F cf.93                PUSH R28    Push register on stack
00000030 df.93                PUSH R29    Push register on stack
00000031 00.d0                RCALL PC+0x0001    Relative call 
subroutine
00000032 00.d0                RCALL PC+0x0001    Relative call 
subroutine
00000033 cd.b7                IN R28,0x3D    In from I/O location
00000034 de.b7                IN R29,0x3E    In from I/O location
    19:  int konstante = 500;
00000035 84.ef                LDI R24,0xF4    Load immediate
00000036 91.e0                LDI R25,0x01    Load immediate
00000037 9a.83                STD Y+2,R25    Store indirect with 
displacement
00000038 89.83                STD Y+1,R24    Store indirect with 
displacement
    23:       int test = konstante/10;
00000039 89.81                LDD R24,Y+1    Load indirect with 
displacement
0000003A 9a.81                LDD R25,Y+2    Load indirect with 
displacement
0000003B 2a.e0                LDI R18,0x0A    Load immediate
--- C:\Users\Alex\Documents\Atmel 
Studio\Heizung\Heizung\Debug/.././Heizung.c --
0000003C 30.e0                LDI R19,0x00    Load immediate
0000003D b9.01                MOVW R22,R18    Copy register pair
0000003E 04.d0                RCALL PC+0x0005    Relative call 
subroutine
0000003F 9b.01                MOVW R18,R22    Copy register pair
00000040 3c.83                STD Y+4,R19    Store indirect with 
displacement
00000041 2b.83                STD Y+3,R18    Store indirect with 
displacement
    25:   }
00000042 f6.cf                RJMP PC-0x0009    Relative jump
--- 
C:\home\tools\hudson\workspace\avr8-gnu-toolchain\src\gcc\gcc\config\avr 
\libgcc.S
     1:
00000043 97.fb                BST R25,7  Bit store from register to T

von holger (Gast)


Lesenswert?

>Da ich nicht genau weiß was du brauchst,

Das komplette Projekt? So das man das auch mal selber kompilieren
könnte?

von Seijsschmeer (Gast)


Lesenswert?

Mehr ist das nicht...




#include <avr/io.h>


int main(void)
{

 int konstante = 500;

  while(1)
    {
      int test = konstante/10;
    }
}

von holger (Gast)


Lesenswert?

>Mehr ist das nicht...

Wird wegoptimiert wenn die Optimierung eingeschaltet ist.

Versuchs mal so:
1
#include <avr/io.h>
2
3
4
int main(void)
5
{
6
7
 volatile int konstante = 500;
8
9
  while(1)
10
    {
11
      volatile int test = konstante/10;
12
    }
13
}

von ich, nicht du (Gast)


Lesenswert?

also im disassembly sehe ich wie 500 und 10 in den registern landen.
ich sehe aber nirgends die ausführung der division.
schreib mal bitte unter die division

PORTA=test>>8;
PORTB=test & 0xff;

das zwingt den kompiler das ergebnis an den ports auszugeben und die 
division wird entweder ausgeführt oder durch den compiler vorberechnet.

von Seijsschmeer (Gast)


Lesenswert?

@ holger, funktioniert leider auch nicht, hatte es damit aber auch schon 
probiert gehabt, ich vergaß zu erwähnen das die Optmierung ausgeschaltet 
ist, sorry.

@ich, nicht du, leider auch kein Erfolg mit deiner Variante. In der 
disassembly Liste steht doch was über die Division, 23:.....oder nicht?

Kann es sein das Generell Divisionen einen großen Akt darstellen, habe 
ja vorher schonmal nach Lösungen gegoogelt, da wird dann 
Registerschieberei erwähnt, oder es wurden eigene Algorithmen 
geschrieben usw...z.B. hier
http://www-user.tu-chemnitz.de/~heha/Mikrocontroller/Division.htm
Versteh da leider nur Bahnhof.

von sunfloweer_seed (Gast)


Lesenswert?

Man definiert doch keine Variablen in einer Schleife oO
Zudem gewöhnte dir int ab und bedenke, das du der 10 den entsprechenden 
Variablentyp anhängen solltest...

von Seijsschmeer (Gast)


Lesenswert?

Da ist ja momentan ein reines Testprogram, ich definiere keine Variablen 
in einer Schleife, wenn ich sie vorher deklariere passiert das selbe.

sunfloweer_seed schrieb:
> Zudem gewöhnte dir int ab und bedenke, das du der 10 den entsprechenden
> Variablentyp anhängen solltest...

wie soll ich das verstehen? Falls du meinst das ich eine Integervariable 
erstellen sollte und der den Wert 10 zuweisen sollte, funktioniert auch 
nicht. Und was meinst du mit Integer abgewöhnen? Ich möchte aber damit 
rechnen...

von sunfloweer_seed (Gast)


Lesenswert?

Ein Integer ist aber nicht gleich Integer:

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Ganzzahlige_Datentypen_.28Integer.29

Du musst überlegen wie groß das Ergebnis werden soll.
Standardmäßig erzeugt die Division immer ein int16 Wert oder iwie sowas.
Eventuell musst du ein Cast machen oder zur Sicherheit einfach dem 
dividenden der Konstanten einen Datentyp zuweisen:

http://www.mikrocontroller.net/articles/FAQ
(Datentypen in Operationen und Welche Datentypen haben Konstanten)

von Wilhelm F. (Gast)


Lesenswert?

Seijsschmeer:

Probier es mit Bounenschlupp, das geht bestimmt besser. ;-)

von Hans (Gast)


Lesenswert?

Die volatile-Variablen sollten auf globaler Ebene sein. Innerhalb der 
Funktion machts nicht viel Sinn, da dort von außerhalb keine 
Zugriffsmöglichkeit besteht.

Probiers mal so:
1
volatile int konstante = 500;
2
volatile int test;
3
4
int main(void)
5
{
6
  while(1)
7
  {
8
    test = konstante / 10;
9
  }
10
}

von Seijsschmeer (Gast)


Lesenswert?

Wilhelm F. schrieb:
> Seijsschmeer:
>
> Probier es mit Bounenschlupp, das geht bestimmt besser. ;-)

Wasn das??

@ Hans funtkioniert auch nicht, alles schon probiert...

von Seijsschmeer (Gast)


Lesenswert?

@sunflower Hab sämtliche Datentypen durch, die Konstanten auch gecastet 
usw. leider kein Erfolg. Sobald ich aber durch "digitale" Zahlen 
dividiere also durch 2,4,8,16 usw funktioniert es Problemlos...habs auch 
schon mit hex Schreibweise probiert...auch nichts.

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.