do...while exiting when it shouldn't?

I think my loop is exiting when it shouldn't...here's the code...

    int contact_new = 0;
    int contact_old = 0;
    int changepoint = 0;
    int livelog = 0; //(set to zero for contact change only log)
    int RVal = random(50,255);
    int GVal = random(50,255);
    int BVal = random(50,255);
    int p=0; //pixel number;
    float start = millis();
    long total1;
    long total2;
do {    

do {
total1 =  cs_4_2.capacitiveSensor(1);
total2 =  cs_4_6.capacitiveSensor(1);
if ((total1 < 15) && (total2 < 15)) contact_new = 0;
if ((total1 > 15) && (total2 < 15)) contact_new = 1;
if ((total1 < 15) && (total2 > 15)) contact_new = 2;
if ((total1 > 15) && (total2 > 15)) contact_new = 3;
   Serial.print ("no change");
   Serial.print ("\t");
   Serial.print (contact_new);
   Serial.print ("\t");
   Serial.println (contact_old);
   delay(500);
}while (contact_new = contact_old);
 
  Serial.print ("input valid, processing");
  Serial.print ("\t");
  Serial.print (contact_new);
  Serial.print ("\t");
  Serial.println (contact_old);
  delay(1000);

it's only part of it...as far as I'm aware, this should keep getting the total1 and total2 values, then based on their conditions only exit the loop to the "input valid" stage if contact_new is different to contact_old.

But without changing anything on the pins in question, it processes the "input valid" command, even when both contact_old and contact_new are zero.

What am I doing wrong? If you need all the code let me know, though I'll have to edit it some...

    float start = millis();

Why? millis() does NOT return a float.

What am I doing wrong?

  1. Not posting all of your code.
  2. Not posting any serial data.
  3. Not printing enough data. Some proof that the inner do/while loop is being exited prematurely would be useful.

the statement

}while (contact_new = contact_old);

assigns contact_new the value of contact_old then tests the result
did you intend to compare the values with the == operator

}while (contact_new == contact_old);

horace...you are a genius.

and it's not the only damned place I've done it either...

thanks, pretty sure that will fix it...

It did.

PaulS, you’re absolutely right about what I posted, I was in the process of adding more detail when Horace came up with the answer. I’ve now gone (probably) way over the top with my serial outputs on the project. As such, I’ve given you karma as well as Horace.

By the way, I added “millis()” as a float because I wanted to use it in an equation...I’m very new at Arduino programming having done most of my work in VB...and even there I’m self-taught, so there may well be some woolly thinking going on, but here was my logic;

If I set millis as an integer, it remains an integer...so if it’s “5” and I want to divide it by two...I get “2”, where actually I need the true “2.5”.

Please feel free to correct me if I’m wrong.

If I set millis as an integer, it remains an integer...so if it's "5" and I want to divide it by two...I get "2", where actually I need the true "2.5".

Please feel free to correct me if I'm wrong.

You are. If you divide an int by an int, you get an int. But, that does not mean that you need to divide the int by an int, if you want a float. 5/2 is 2, but 5/2.0 is 2.5.

I’ve been using (float) before my ints to get around it, which works well enough, but I am curious about your specification of decimal places; if I have

int five = 5;
int two = 2;

How do I tell the Arduino that it’s to use one decimal place for the “two” value. Also, if I’m to assign the answer to a variable, do I have to declare that as a float?

You will have to explain that question better. Like you are talking to another person.

Delta_G yeah I said I’ve used float...I was interested in what Paul said about specifying decimals because (I think) if I use (float) there is a possibility of rounding errors so that (float)five/two might actually come out as 2.50000001 or some such...I’d like to curtail itvto maybe 2dp to avoid.

Ok Aarg here’s my second try.

Paul says do 5/2 in Arduino and you get 2, but if you 5/2.0,the decimal in the divisor “tells” Arduino that you want one decimal in the answer, so you get 2.5. I’m assuming by extension if I did 5/2.00, I’d get 2.50 as my answer and so on.

But if those values are held in variables called “five” and “two” respectively...I’m assuming “five/two.0” is not going to work.

Is there something like “five/two(2)” that is an equivalent for variables?

GreyArea:
Ok Aarg here’s my second try.

Paul says do 5/2 in Arduino and you get 2, but if you 5/2.0,the decimal in the divisor “tells” Arduino that you want one decimal in the answer, so you get 2.5. I’m assuming by extension if I did 5/2.00, I’d get 2.50 as my answer and so on.
[...]
Is there something like “five/two(2)” that is an equivalent for variables?

The decimal in the divisor only "tells" the compiler that the divisor is a float.

There is no "true" 2.5, it is the same number as 2.50000...

Aarg; not with my Mega right now or I’d test...but from what you say, in that case would

2/3.0

return 0.66667 or 0.7?

I guess my question is;

“Is there a (simple) way to control the number of decimal places that are returned when dividing one variable by another?”

As suggested I guess it could be done by multiplying by 10, 100, 1000 etc prior to division...but that seems a little “clunky”...?

"Is there a (simple) way to control the number of decimal places that are returned when dividing one variable by another?"

No. There isn't even a complicated way. The result will be as accurate as possible. If you want rounding, don't use floats.

you could multiply the float by say 100 then use ceil() or floor() to convert it to an int

then assign the int to a float and divide by 100

I cannot see why one would wish to do this though?

I had a routine that checked if a number was a perfect square by comparing the value of its square root as an integer to the value of its square root as a float...the only occasion they would be equal would be if the number was a perfect square...but then someone told me that the float could be slightly out, which breaks the routine. Limiting the float variable to 2dp (or even 1) would fix that.

I assume floor rounds down and ceiling rounds up? Arduino seems to lack a rounding command of the normal convention (ie digits up to 4 rounded down, 5 and over rounded up...)

Hi,
If all you are worried about is how your resultant variable is displayed in Serial.print, then just specify how many decimal places you want it displayed.

Let the code work in full float, then use this.

Tom.... :slight_smile:

floor() rounds down, ceil() rounds up and round() rounds to the nearest intteger

as you say comparing floating point values directly can fail due to small rounding errors - in practice you can look for a difference, e.g.

  if(fabs(x-y) < 1.0E-6)  .... ;
  if(fabs((x-y)/x) < 1.0E-6)  .....  ;

for the former you have to have some idea of the size of x and y (are you comparing very small numbers or very large) and the later can give division by zero

Arduino seems to lack a rounding command of the normal convention (ie digits up to 4 rounded down, 5 and over rounded up...)

Like round()?

I had a routine that checked if a number was a perfect square by comparing the value of its square root as an integer to the value of its square root as a float

If you get the square root of a number as an int, and multiply it by itself, you either get the original number (i.e. it was a perfect square) or you don't (well, duh, it wasn't). No need to try to force a number to have one decimal place - which you can't.

Karma given for last answer...perfect solution.

I’m confused though...you say you can’t force a number to one dp, but earlier you said use round()...what am I missing?

I'm confused though...you say you can't force a number to one dp, but earlier you said use round()...what am I missing?

What does round() do, to a value like 3.14159? What does it return? How many decimal places in the value returned?