how to compare values using if statement

Thread Starter

susan007

Joined Jun 26, 2013
8
I have the following code(shorted) and want to compare values from timer register after converting to decimal in the if statement, how to do this? its for PIC16F877A using XC8 compiler...

Code:
time_taken = (TMR1L | (TMR1H<<8));
distance= (0.0272*time_taken)/2;

d1 = (distance/100)%10;
        d2 = (distance/10)%10;
        d3 = (distance/1)%10;

//then want to compare and take action using if statement

if( ){
        RB4 = 1;
        }
     else{   
        RB4 = 0;
        }
 

AlbertHall

Joined Jun 4, 2014
12,625
You want to compare d1, d2, and d3 to some other value.
Is the other value also in decimal form?
Do you want to check for equality, or greater or less?

If the other value is k1, k2, and k3 and you want to check for equality:
if ((d1==k1) && (d2==k2) && (d3=k3)
{some code}

It gets more complicated to check for greater or less.
 

ci139

Joined Jul 11, 2016
1,989
is there any specific reason you need to compare decimal digits with something

besides - if distance gets double type by 0.0272*...
... then you should find out whether the compiler translates (159.73/10)%10 --as-- 16 idiv 10 --or-- as what you expect --or-- neither
. . .
online C++ compiler Test
 
Last edited:

Analog Ground

Joined Apr 24, 2019
460
Use "Relational", Equality" and "Logical" operators. > >= < <= == != && || Use them to compare d1, d2 and d3 to each other or to constants and other variables and set logical conditions between comparisons. I suggest using lots of parentheses, ( ), to clearly show the precedence as AlbertHall above.
 

Analog Ground

Joined Apr 24, 2019
460
Something bothers me here. "distance" looks like a float but I thought you could not use the mod operator (%) on a float. Should the compiler throw off an error? Perhaps the TS can show the variable types?
 

AlbertHall

Joined Jun 4, 2014
12,625
Something bothers me here. "distance" looks like a float but I thought you could not use the mod operator (%) on a float. Should the compiler throw off an error? Perhaps the TS can show the variable types?
I hadn't spotted that. I would expect a compiler error for that.

[EDIT] Using mod (%) on a float does generate an error:
error: (205) integral type required
 
Last edited:

MrChips

Joined Oct 2, 2009
34,812
TS is having a misconception that is all too common with the uninitiated.
ALL information stored on a digital computer is binary.

TMR1H and TMR1L are both stored in binary, each as 8-bit values.
In order to combine the two into a single 16-bit variable, mathematically we can perform

value16 = TMR1H * 256 + TMR1L

An optimizing compiler might be able to reduce this to a more efficient form, such as:

value16 = (TMR1H << 8) + TMR1L

You can calculate the distance traveled via:

distance = time * velocity

The variable distance can be any data type you choose. Inherently, the data is still stored on the computer as a binary value, occupying as many bytes as it takes.

To perform a conditional relation such as in an if statement, use any of the following:

( distance > min_distance)
( distance >= min_distance)
( distance < max_distance)
( distance <= max_distance)

DO NOT test for equality or non-equality if your data type is float.

There is no need to deconstruct the value into separate BCD (binary coded decimal) digits.
 

djsfantasi

Joined Apr 11, 2010
9,237
Something bothers me here. "distance" looks like a float but I thought you could not use the mod operator (%) on a float. Should the compiler throw off an error? Perhaps the TS can show the variable types?
It’s not a difficult problem. If one is unsure, there are two easy steps.
  1. Make sure the integer part of distance (divided by 10) in this code can fit into an integer variable (there are other choices, too. But let’s keep it simple)
  2. “Cast” the result of the division as an integer before applying the mod operator.
d1 = (int)(distance/100.0)%10​

I added the dot zero to the hundred, so the compiler will perform the division as a float. Then (int) converts the result to an integer so it is compatible with the % operator.
 

Analog Ground

Joined Apr 24, 2019
460
It’s not a difficult problem. If one is unsure, there are two easy steps.
  1. Make sure the integer part of distance (divided by 10) in this code can fit into an integer variable (there are other choices, too. But let’s keep it simple)
  2. “Cast” the result of the division as an integer before applying the mod operator.
d1 = (int)(distance/100.0)%10​

I added the dot zero to the hundred, so the compiler will perform the division as a float. Then (int) converts the result to an integer so it is compatible with the % operator.
Absolutely! However, the code as written will break. Now, the next thing.
  1. d1 = (distance/100)%10;
  2. d2 = (distance/10)%10;
  3. d3 = (distance/1)%10;
I wonder what physical information is provided by these calculations. I think I see where the integer part of distance/n is useful. Sort of putting the result into ranges. However, mod? I am curious what is going on here.
 

402DF855

Joined Feb 9, 2013
271
Since we aren't given the declaration of "distance" it may be integer or floating point. The latter seems more likely, but if declared as an integer its assignment would generate a warning, but otherwise compile successfully.

It is unclear what exactly the TS is trying to do; seems like after some "distance" is exceeded, a digitial output discrete is changed from 0 to 1 (I guess).
C:
RB4 = distance > SOMEVALUE;
 

Thread Starter

susan007

Joined Jun 26, 2013
8
hi,
thanks all for replies...should have posted the complete code which now i have provided below....basically, i got a ultrasensor and got the value of distance in decimal value, now i want to turn off a motor using a switch if the distance is for example 50cm using if statement. i tried like if(d1==0 && d2==5 && d3==0) and if(d1==0 && d2<=5) etc but its not working....

Code:
#define _XTAL_FREQ 20000000

#define Trigger RB1
#define Echo RB2
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include <xc.h>
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

//LCD Functions Developed by Circuit Digest.
void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
if(data_bit& 1)
D4 = 1;
else
D4 = 0;
if(data_bit& 2)
D5 = 1;
else
D5 = 0;
if(data_bit& 4)
D6 = 1;
else
D6 = 0;
if(data_bit& 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0;          
Lcd_SetBit(a); //Incoming Hex value
EN  = 1;        
        __delay_ms(4);
        EN  = 0;        
}
void Lcd_Clear()
{
Lcd_Cmd(0); //Clear the LCD
Lcd_Cmd(1); //Move the curser to first position
}
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a== 1)
{
temp = 0x80 + b - 1; //80H is used to move the curser
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
else if(a== 2)
{
temp = 0xC0 + b - 1;
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
}
void Lcd_Start()
{
  Lcd_SetBit(0x00);
  for(int i=1065244; i<=0; i--)  NOP(); 
  Lcd_Cmd(0x03);
  __delay_ms(5);
  Lcd_Cmd(0x03);
  __delay_ms(11);
  Lcd_Cmd(0x03);
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x08); //Select Row 1
  Lcd_Cmd(0x00); //Clear Row 1 Display
  Lcd_Cmd(0x0C); //Select Row 2
  Lcd_Cmd(0x00); //Clear Row 2 Display
  Lcd_Cmd(0x06);
}
void Lcd_Print_Char(char data)  //Send 8-bits through 4-bit mode
{
   char Lower_Nibble,Upper_Nibble;
   Lower_Nibble = data&0x0F;
   Upper_Nibble = data&0xF0;
   RS = 1;             // => RS = 1
   Lcd_SetBit(Upper_Nibble>>4);             //Send upper half by shifting by 4
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP();
   EN = 0;
   Lcd_SetBit(Lower_Nibble); //Send Lower half
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP();
   EN = 0;
}
void Lcd_Print_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
  Lcd_Print_Char(a[i]);  //Split the string using pointers and call the Char function
}
/*****End of LCD Functions*****/
int time_taken;
int distance;
char t1,t2,t3,t4,t5;
char d1,d2,d3;

int main()
{
   TRISBbits.TRISB1 = 0;
   TRISBbits.TRISB2 = 1;
   TRISBbits.TRISB4 = 1;
   TRISDbits.TRISD2 = 0;
   TRISDbits.TRISD3 = 0;
   TRISDbits.TRISD4 = 0;
   TRISDbits.TRISD5 = 0;
   TRISDbits.TRISD6 = 0;
   TRISDbits.TRISD7 = 0;
  
   T1CON=0x20;

    Lcd_Start();
   
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Ultrasonic sensor");
    Lcd_Set_Cursor(2,1);
    Lcd_Print_String("with PIC16F877A");
   
    __delay_ms(2000);
    Lcd_Clear();
   
    while(1)
    {
       TMR1H =0;
       TMR1L =0; //clear the timer bits
       
        Trigger = 1;
        __delay_us(10);          
        Trigger = 0; 
       
        while (Echo==0);
            TMR1ON = 1;
        while (Echo==1);
            TMR1ON = 0;
       
        time_taken = (TMR1L | (TMR1H<<8));
        distance= (0.0272*time_taken)/2;
           
        time_taken = time_taken * 0.8;
       
        t1 = (time_taken/1000)%10;
        t2 = (time_taken/1000)%10;
        t3 = (time_taken/100)%10;
        t4 = (time_taken/10)%10;
        t5 = (time_taken/1)%10;
        d1 = (distance/100)%10;
        d2 = (distance/10)%10;
        d3 = (distance/1)%10;
       
        Lcd_Set_Cursor(1,1);
        Lcd_Print_String("Time_taken:");
        Lcd_Print_Char(t1+'0');
        Lcd_Print_Char(t2+'0');
        Lcd_Print_Char(t3+'0');
        Lcd_Print_Char(t4+'0');
        Lcd_Print_Char(t5+'0');
       
         Lcd_Set_Cursor(2,1);
        Lcd_Print_String("distance:");
        Lcd_Print_Char(d1+'0');
        Lcd_Print_Char(d2+'0');
        Lcd_Print_Char(d3+'0');    

     if(d1==0 && d2==5 && d3==0){
        RB4 = 1;
        }
     else{ 
        RB4 = 0;
        }
    }
    return 0;
}
 

WBahn

Joined Mar 31, 2012
32,836
hi,
thanks all for replies...should have posted the complete code which now i have provided below....basically, i got a ultrasensor and got the value of distance in decimal value, now i want to turn off a motor using a switch if the distance is for example 50cm using if statement. i tried like if(d1==0 && d2==5 && d3==0) and if(d1==0 && d2<=5) etc but its not working....

Code:
#define _XTAL_FREQ 20000000

#define Trigger RB1
#define Echo RB2
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include <xc.h>
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

//LCD Functions Developed by Circuit Digest.
void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
if(data_bit& 1)
D4 = 1;
else
D4 = 0;
if(data_bit& 2)
D5 = 1;
else
D5 = 0;
if(data_bit& 4)
D6 = 1;
else
D6 = 0;
if(data_bit& 8)
D7 = 1;
else
D7 = 0;
}
void Lcd_Cmd(char a)
{
RS = 0;        
Lcd_SetBit(a); //Incoming Hex value
EN  = 1;      
        __delay_ms(4);
        EN  = 0;      
}
void Lcd_Clear()
{
Lcd_Cmd(0); //Clear the LCD
Lcd_Cmd(1); //Move the curser to first position
}
void Lcd_Set_Cursor(char a, char b)
{
char temp,z,y;
if(a== 1)
{
temp = 0x80 + b - 1; //80H is used to move the curser
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
else if(a== 2)
{
temp = 0xC0 + b - 1;
z = temp>>4; //Lower 8-bits
y = temp & 0x0F; //Upper 8-bits
Lcd_Cmd(z); //Set Row
Lcd_Cmd(y); //Set Column
}
}
void Lcd_Start()
{
  Lcd_SetBit(0x00);
  for(int i=1065244; i<=0; i--)  NOP();
  Lcd_Cmd(0x03);
  __delay_ms(5);
  Lcd_Cmd(0x03);
  __delay_ms(11);
  Lcd_Cmd(0x03);
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x08); //Select Row 1
  Lcd_Cmd(0x00); //Clear Row 1 Display
  Lcd_Cmd(0x0C); //Select Row 2
  Lcd_Cmd(0x00); //Clear Row 2 Display
  Lcd_Cmd(0x06);
}
void Lcd_Print_Char(char data)  //Send 8-bits through 4-bit mode
{
   char Lower_Nibble,Upper_Nibble;
   Lower_Nibble = data&0x0F;
   Upper_Nibble = data&0xF0;
   RS = 1;             // => RS = 1
   Lcd_SetBit(Upper_Nibble>>4);             //Send upper half by shifting by 4
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP();
   EN = 0;
   Lcd_SetBit(Lower_Nibble); //Send Lower half
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP();
   EN = 0;
}
void Lcd_Print_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
  Lcd_Print_Char(a[i]);  //Split the string using pointers and call the Char function
}
/*****End of LCD Functions*****/
int time_taken;
int distance;
char t1,t2,t3,t4,t5;
char d1,d2,d3;

int main()
{
   TRISBbits.TRISB1 = 0;
   TRISBbits.TRISB2 = 1;
   TRISBbits.TRISB4 = 1;
   TRISDbits.TRISD2 = 0;
   TRISDbits.TRISD3 = 0;
   TRISDbits.TRISD4 = 0;
   TRISDbits.TRISD5 = 0;
   TRISDbits.TRISD6 = 0;
   TRISDbits.TRISD7 = 0;

   T1CON=0x20;

    Lcd_Start();
 
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Ultrasonic sensor");
    Lcd_Set_Cursor(2,1);
    Lcd_Print_String("with PIC16F877A");
 
    __delay_ms(2000);
    Lcd_Clear();
 
    while(1)
    {
       TMR1H =0;
       TMR1L =0; //clear the timer bits
     
        Trigger = 1;
        __delay_us(10);        
        Trigger = 0;
     
        while (Echo==0);
            TMR1ON = 1;
        while (Echo==1);
            TMR1ON = 0;
     
        time_taken = (TMR1L | (TMR1H<<8));
        distance= (0.0272*time_taken)/2;
         
        time_taken = time_taken * 0.8;
     
        t1 = (time_taken/1000)%10;
        t2 = (time_taken/1000)%10;
        t3 = (time_taken/100)%10;
        t4 = (time_taken/10)%10;
        t5 = (time_taken/1)%10;
        d1 = (distance/100)%10;
        d2 = (distance/10)%10;
        d3 = (distance/1)%10;
     
        Lcd_Set_Cursor(1,1);
        Lcd_Print_String("Time_taken:");
        Lcd_Print_Char(t1+'0');
        Lcd_Print_Char(t2+'0');
        Lcd_Print_Char(t3+'0');
        Lcd_Print_Char(t4+'0');
        Lcd_Print_Char(t5+'0');
     
         Lcd_Set_Cursor(2,1);
        Lcd_Print_String("distance:");
        Lcd_Print_Char(d1+'0');
        Lcd_Print_Char(d2+'0');
        Lcd_Print_Char(d3+'0');  

     if(d1==0 && d2==5 && d3==0){
        RB4 = 1;
        }
     else{
        RB4 = 0;
        }
    }
    return 0;
}
So, you want to do something if the distance is EXACTLY 50 cm and you want to do something else if it is 51 cm or greater or if it is 49 cm or less?

If your distance is 50 cm (or rounds to it after your floating point expression is coerced to an integer), then it will be equal to 50 and you can simply test if it is equal to 50 (if that is REALLY what you want to do). So just do

if (50 == distance)
RB4 = 1;
else
RB4 = 0;

Or, even better, just do

RB4 = (50 == distance);

since a relational expression evaluates to 1 if true and 0 if false.
 

Thread Starter

susan007

Joined Jun 26, 2013
8
want to add question, would the distance be exactly 50cm practically for the following? from timer register content!
Code:
if(distance<=50){
RB4=1;
}
else{
RB4=0;
}
 

WBahn

Joined Mar 31, 2012
32,836
want to add question, would the distance be exactly 50cm practically for the following? from timer register content!
Code:
if(distance<=50){
RB4=1;
}
else{
RB4=0;
}
What do you mean by "exactly 50 cm practically"?

This will set RB4 to 1 if distance is anything less than or equal to 50, which would include 0 or 1 or 20 or 49 or 50. If all of those are "practically" exactly 50 cm then the answer would be yes.
 

ci139

Joined Jul 11, 2016
1,989
← not too much that kind of stuff avail in www
about → https://escholarship.org/content/qt9cx397x2/qt9cx397x2.pdf (some 1-st chapters describe the situation)
= you have to math out your position -- accounting startup and stop non-linearities - which can be get experimentally
--- in that case we must assume the motion is always independent from misc. resistance (to motion)
or implement some sort of position feedback

e.g -- it's never likely to be exactly 50cm
 

jayanthd

Joined Jul 4, 2015
945
This forum does not exist as a platform for you to solicit business. If you wish to contribute something to the thread, then contribute it. Don't go fishing for people to do business with you off site.
I can provide you a better working code if you are interested.
 
Top