Rechnen mit Variablen klappt nicht.

Hallo,

Ich bin sehr neu in der Arduino Welt und habe ein Problem welches ich nicht alleine gelöst bekommen. Aus diesem Grunde frage ich euch in der Hoffnung auf eine Lösung.

Ich möchte in meinem Skript eine Berechnete Delay Zeit verwenden.

//Definiere Variablen
int StartMittagDimOn      =  10;
int AusDim                   =   255; 

MyMilliSec = StartMittagDimOn * 60 * 1000 / AusDim;
delay(MyMilliSec);

MyMilliSec müsste in diesem Fall 2352,941176470588 beinhalten ( also ~ 2 Sekunden Pause)

Durch eine Schleife gehe ich immer wieder da rein ganze AusDim mal :) Leider bleibt mein Skript beim erstem mal stehen und läuft nicht mehr weiter. Kommentiere ich die Zeilen aus läuft es durch nur halt ohne mein gewünschtes Delay.

Wo liegt mein Fehler?

Vielen lieben Dank

Integer Überlauf. Schau mal nach was in eine vorzeichenbehaftete 16 Bit Zahl geht

Korrekt:

MyMilliSec = StartMittagDimOn * 60*UL* * 1000 / AusDim;

MyMilliSec ist übrigens nicht definiert...

unsigned long MyMilliSec = StartMittagDimOn * 60*UL* * 1000 / AusDim;

Bei int als Variablentyp besteht immer der Verdacht, dass das nur aus Tipp-Faulheit so definiert wird.

P.S. Bist du sicher, dass du durch 255 teilen willst ?

Wow na das geht ja hier schnell bei euch.... erschrocken

Die Variable habe ich oben in meinem Skript definerit. nur vergessen es hier in das Bsp. mit zu übernehmen.

int Dimmung; int MyMilliSec; int Leiste; int PinNum;      // Deklaration von im skript verwendeten Variablen

die 255 sind die Dimmsteps die der Arduino wohl kann. Jenachdem wer das Skript mal nutzt kann über die Variable AusDimm auch andere Werte hinzufügen.

Als Standard würde ich aber 255 stehen lassen. Wieso fragst du? Und was meinst du mit Tipp-Faulheit55

tipp - faulheit heisst in diesem fall, man schaut gar nicht, welchen Variabeltyp dass man braucht, sondern man nimmt einfach int, da man den ja immer nimmt... :D

beim arduino ist ein Integer 2 Bytes gross, kann also 2^16 Zahlen auffassen.

der long ist 4 Bytes gross und kann demendsprechend 2^32 auffassen.

diese Zaheln gehen ins negative und ins positive, aussert du definierst den Variabelntyp als unsigned.

wenn ich dich wäre würde ich also einen unsigned long nehmen, dann ist das risiko auf einen overflow am geringsten.

Grüsse j

Ob ein Überlauf auftritt hat aber nichts mit dem Datentyp der Zielvariablen zu tun! Man kann das als unsigned long deklarieren und der Überlauf tritt immer noch auf wenn die Zahlen mit denen man rechnet nur int sind. Deshalb das "UL". Nur damit (oder einem Cast) wird auch in unsigned long gerechnet.

-Jonas-: tipp - faulheit heisst in diesem fall, man schaut gar nicht, welchen Variabeltyp dass man braucht, sondern man nimmt einfach int, da man den ja immer nimmt... :D

beim arduino ist ein Integer 2 Bytes gross, kann also 2^16 Zahlen auffassen.

der long ist 4 Bytes gross und kann demendsprechend 2^32 auffassen.

diese Zaheln gehen ins negative und ins positive, aussert du definierst den Variabelntyp als unsigned.

wenn ich dich wäre würde ich also einen unsigned long nehmen, dann ist das risiko auf einen overflow am geringsten.

Grüsse j

Der Tipp sollte nicht beachtet werden. Man sollte schon die Variablen für den entsprechenden Wertebereich anlegen. Der Atmega hat zwar schon recht viel Speicher, aber gerade bei dem Attiny wirds dann schnell kanpp.

sorry. wollte da wirklich kein falschen tipp abgeben..

mit

wenn ich dich wäre würde ich also einen unsigned long nehmen, dann ist das risiko auf einen overflow am geringsten.

meint ich nur, da er geschriben hat, er weiss nicht wie gross das "StartMittagDimOn" sein kann.

die 255 sind die Dimmsteps die der Arduino wohl kann. Jenachdem wer das Skript mal nutzt kann über die Variable AusDimm auch andere Werte hinzufügen.

Als Standard würde ich aber 255 stehen lassen. Wieso fragst du?

… weil ich mir das schon so ungefähr gedacht habe :wink:

“Die Dimmsteps die der Arduino wohl kann” sind 256 ( 0 … 255 sind 256 Steps ).
Durch 256 teilen kann ein kleiner Controller ( und der dafür optimierte c Compiler ) viel besser als durch jede andere Zahl. Wenn das als eine Konstante deklariert wäre.

[b]const[/b] int DimBereich = 256; // ist was ganz anderes als int Dimbereich = 256;

Was das Dimmen (PWM ?) mit der Division / 256 zu tun hat, wäre aber nochmal eine Klärung wert ( Du meinst nicht zufällig eine Multiplikation ? )

//Beispiel: Eine Zahl < 60000 auf 0 .. 255 skalieren

const unsigned int DimBereich = 256;
const unsigned long EingangsBereich = 60*1000UL;
unsigned long x = 30000; // variabler Beispielwert
byte DimWert = x * DimBereich / EingangsBereich; // 0 .. 59999 -> 0 .. 255  ( 30000 -> 128 )
analogWrite(PWMPIN, DimWert);

Es soll Leute geben, die x * 255 / 1023 rechnen,
wenn sie eigentlich x*256/1024 oder x/4 oder x>>2 meinen. :stuck_out_tongue:

Hallo,

Ich habe immer noch Probleme mit dem rechnen bzw. mit dem umsetzen der Formel damit das heraus kommt was ich möchte.

Was ich möchte.
Angabe der Gesamt Dimmdauer pro Leiste in Minuten pro Sektion in Zeile 23, 33, 43, 53

Formel:

MyMilliSec = StopAbendDimOff * 60UL * 1000 / Steps

Klartext:
5 x 60 x 1000 : 255 = 1176,470588235294

Es müssten also 1176,470588235294 Millisekunden zwischen jeden Dimmschritt vergehen. Vergehen aber nicht.

Laut Log ist MyMilliSec = 92 zugewiesen!?

sketch_mar20a.ino (15.3 KB)

Kein Wunder bei “byte MyMilliSec”

Wie soll da 1176 reinpassen?

Facepalm!

Das kam jetzt durchs rum testen. Hatte vorher unsigned long drin stehen und das funktionierte auch nicht.

Mit unsigned int kommt nun 10588 raus. damit kann ich leben :)

DerMatze79: Klartext: 5 x 60 x 1000 : 255 = 1176,470588235294

Es müssten also 1176,470588235294 Millisekunden zwischen jeden Dimmschritt vergehen. Vergehen aber nicht.

Hallo, nach meiner Überlegung ist 5 x 60 x 1.000 = 300.000, was nicht in unsigned int passt. Oder?

Ich kenne mich wie gesagt ja nicht so aus, da ich gerade erst anfange aber ich würde behaupten es passt!?

Integer Types Following table gives you details about standard integer types with its storage sizes and value ranges:

Type Storage size Value range char 1 byte -128 to 127 or 0 to 255 unsigned char 1 byte 0 to 255 signed char 1 byte -128 to 127 int 2 or 4 bytes -32,768 to 32,767 or -2,147,483,648 to 2,147,483,647 unsigned int 2 or 4 bytes 0 to 65,535 or 0 to 4,294,967,295 short 2 bytes -32,768 to 32,767 unsigned short 2 bytes 0 to 65,535 long 4 bytes -2,147,483,648 to 2,147,483,647 unsigned long 4 bytes 0 to 4,294,967,295

Bitte klärt mich auf wenn ich mich irre!

Aber er rechnet doch IMMER NOCH falsch! Es müssten ~1176 Millisekunden (1,18 Sekunden) herauskommen! Aber es werden jetzt 10588 Millisekunden (10,59 Sekunden) errechnet!

Ein weiteres Problem ist, dass das Skript die Schleife nicht verlässt und wieder von vorne beginnt. Aktuelle Systemzeit 13:30:40 13:30:40 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 253 10588 Aktuelle Systemzeit 13:30:50 13:30:50 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 254 10588 Aktuelle Systemzeit 13:31:1 13:31:1 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 255 10588 Aktuelle Systemzeit 13:31:12 13:31:12 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 0 10588 Aktuelle Systemzeit 13:31:22 13:31:22 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 1 10588 Aktuelle Systemzeit 13:31:33 13:31:33 Stelle Beleuchtung auf Port: 3 der Leiste: 0 auf den Wert: 2

Echt ich verstehe es nicht ;(

Hilfe, Danke!

Matze

Fragen wir mal meinen UNO, was er zu “unsigned int” meint:

void setup() {
  Serial.begin(9600);
  unsigned int wert = 65530;
  unsigned long wertLong = 65530;
  for (byte i = 0; i < 20; i++) {
    Serial.print("Wert1: ");
    Serial.println(wert);
    wert++;
  }
  wert = 5 * 60UL * 1000;
  Serial.print("Wert2: ");
  Serial.println(wert);
  wert = wert / 255;
  Serial.print("Wert3: ");
  Serial.println(wert);
  wertLong = 5 * 60UL * 1000;
  Serial.print("Wert4: ");
  Serial.println(wertLong);
  wertLong = wertLong / 255;
  Serial.print("Wert5: ");
  Serial.println(wertLong);
}

void loop() {
}

Wert1: 65530
Wert1: 65531
Wert1: 65532
Wert1: 65533
Wert1: 65534
Wert1: 65535
Wert1: 0
Wert1: 1
Wert1: 2
Wert1: 3
Wert1: 4
Wert1: 5
Wert1: 6
Wert1: 7
Wert1: 8
Wert1: 9
Wert1: 10
Wert1: 11
Wert1: 12
Wert1: 13
Wert2: 37856
Wert3: 148
Wert4: 300000
Wert5: 1176

Mehr als 65535 passt nicht rein, danach Überlauf, keine Fehlermeldung. Dein Zwischenergebnis von 300.000 ist also zu gross für unsigned int. Hilft Dir das weiter?

Die Wertebereiche sind hier auch gut aufgelistet.

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

Würde auch die Schreibweise int8_t bzw uint8_t bevorzugen. Denn ein einfacher int muss nicht 16Bit groß sein!

Hallo, schöner Link, merke ich mir. Aber was ist der Vorteil von "uint16_t" gegenüber "unsigned int"?

sschultewolter: Denn ein einfacher int muss nicht 16Bit groß sein!

Ich dachte, "int" hat immer 16 Bit, mal mit, mal ohne Vorzeichen?

Auf einem 8 Bit AVR ja. Auf 32 Bit Prozessoren allerdings nicht.

Ich dachte, “int” hat immer 16 Bit, mal mit, mal ohne Vorzeichen?

Nur bei avr 8Bit controllern.
Das ist jedem c Compiler freigestellt, was bei sizeof(int) (meist 2 oder 4) rauskommt und hängt in der Regel davon ab, für welche Hardware du übersetzt. Am PC sind es üblicherweise 32 Bit.

Wenn es drauf ankommt, ist uint16_t usw. eindeutig.

Meine Erfahrung hier: Wenn jemand eine Variable als int deklariert, dann weil das so einfach einzutippen ist und er nicht nachgedacht hat,

oder weil er noch was lernen kann :wink:

Für ein C-Programm, das auf irgendeiner Umgebung läuft, ist also "uint16_t" eindeutig. Da habe ich jetzt was gelernt, mal wieder. Möglicherweise rührt ja daher die Irritation des Threadschreibers.

michael_x: ... und er nicht nachgedacht hat ...

Da bin ich aber froh, "unsigned int" genommen zu haben :grin: