Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] Getting wrong distance values from Ultrasonic Sensor frequently

Status
Not open for further replies.

speedEC

Full Member level 6
Joined
Apr 1, 2011
Messages
337
Helped
23
Reputation
46
Reaction score
21
Trophy points
1,298
Activity points
4,324
Dear friends,

I am using PIC16F1938 & ULTRASONIC SENSOR. I have coded in C (MPLAB v8.63). If I put a object in front of ultrasonic sensor [preset (>2 CM and < 100 CM) range], it shows correct distance. But if I move the object back and forth, it displays wrong values. For example, if object placed at 10CM from Sensor, it correctly displays 10CM. If we move 2CM front or back, it displays as 115 CM or so, frequently. What could be the problem? Even after I have checked 3 times the value of sensor, it shows wrong values. Do we need any other measure to correct the sensor reading? I have tried using delays of about 500ms between reads. But same result. Any idea?

code:
No interrupts used. Only polling RB0.

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <htc.h>
 
__CONFIG (FCMEN_OFF & CPD_OFF & CP_OFF & LVP_OFF & MCLRE_OFF & PWRTE_OFF & \
          WDTE_OFF & WRT_OFF & BOREN_OFF & FOSC_INTOSC);
 
#define LED RC6
#define TRIGGER RC1
#define ECHO RB0
#define OPEN_DOOR() {RC2 = 1; RC3 = 0; __delay_ms(1000); RC2 = 0; RC3 = 0;}
#define CLOSE_DOOR() {RC2 = 0; RC3 = 1; __delay_ms(1000); RC2 = 0; RC3 = 0;}
 
#ifndef _XTAL_FREQ
    // Unless already defined assume 4MHz system frequency
    // This definition is required to calibrate __delay_us() and __delay_ms()
    #define _XTAL_FREQ 4000000
#endif
 
int distance;
int checkValue;
char readPortB;
volatile bit BRAKE_ON;
 
void main (void){
    
    INTCON = 0;
    
    TRISA = 00000000;
    TRISB = 00000001;
    TRISC = 00000000;
    TRISE = 00000000;
    
    PORTA = 00000000;
    PORTB = 00000000;
    PORTC = 00000000;
    PORTE = 00000000;
    
    ANSELA = 00000000;
    ANSELB = 00000000;
    
    IRCF3 = 1; // 4MHz CLOCK
    IRCF2 = 1;
    IRCF1 = 0;
    IRCF0 = 1;
    
    SCS0 = 0; // 00 = Clock determined by FOSC<2:0> in Configuration Word 1.
    SCS1 = 0;
    
    __delay_ms(10);
    
    // TIMER1 MODULE SETTINGS
    T1CON = 0x00;
    // TMR1CS = 00; // 00 = Timer1 clock source is instruction clock (FOSC/4)
    // T1CKPS = 00; // 10 = 1:1 Prescale value
    // T1OSCEN = 0;
    // T1SYNC = 0;
    // TMR1ON = 0; // Timer1 OFF
    
    TMR1L = 0;
    TMR1H = 0;
    
    LED = 1;
    __delay_ms(500);
    LED = 0;
    
    BRAKE_ON = 0;
    
    while(1){
        
        TMR1L = 0;
        TMR1H = 0;
        TRIGGER = 0; //TRIGGER LOW
        __delay_us(2); // 2uS delay
        
        // ACTIVATE ULTRASONIC SENSOR 
        TRIGGER = 1; //TRIGGER HIGH
        __delay_us(10); // 10uS delay
        TRIGGER = 0; //TRIGGER LOW
        while(!ECHO);
        TMR1ON = 1;
        while(ECHO);
        TMR1ON = 0;
        
        distance = ((TMR1L | (TMR1H << 8)) / 59); // in CM (58.82)
        
        //DISTANCE BETWEEN 2 & 100 CM
        if((distance >= 2 && distance <= 100) && !BRAKE_ON){
            for(int i = 0; i < 3; i++){ // check values 3 times
                TMR1L = 0;
                TMR1H = 0;
                TRIGGER = 0; //TRIGGER LOW
                __delay_us(2); // 2uS delay
                
                // ACTIVATE ULTRASONIC SENSOR 
                TRIGGER = 1; //TRIGGER HIGH
                __delay_us(10); // 10uS delay
                TRIGGER = 0; //TRIGGER LOW
                while(!ECHO);
                TMR1ON = 1;
                while(ECHO);
                TMR1ON = 0;
                
                distance = ((TMR1L | (TMR1H << 8)) / 59); // in CM (58.82)
                
                if((distance >= 2 && distance <= 100) && !BRAKE_ON){
                    checkValue++;
                }   
            }
            if (checkValue > 1){ // 2 out 3, same ranges
                BRAKE_ON = 1;
                LED = 1;
                __delay_ms(500);
                LED = 0;
                
                OPEN_DOOR();
            }
        }
        // > 100 CM && < 400 CM
        else if(distance > 101 && distance < 400 && BRAKE_ON){
            for(int i = 0; i < 3; i++){ // check values 3 times
                TMR1L = 0;
                TMR1H = 0;
                TRIGGER = 0; //TRIGGER LOW
                __delay_us(2); // 2uS delay
                
                // ACTIVATE ULTRASONIC SENSOR 
                TRIGGER = 1; //TRIGGER HIGH
                __delay_us(10); // 10uS delay
                TRIGGER = 0; //TRIGGER LOW
                while(!ECHO);
                TMR1ON = 1;
                while(ECHO);
                TMR1ON = 0;
                
                distance = ((TMR1L | (TMR1H << 8)) / 59); // in CM (58.82)
                
                if(distance > 101 && distance < 400 && BRAKE_ON){
                    checkValue++;
                }   
            }
            if (checkValue > 1){ // 2 out 3, same ranges
                BRAKE_ON = 0;
                LED = 1;
                    __delay_ms(500);
                LED = 0;
                
                CLOSE_DOOR();
            }
        }
    checkValue = 0;
    readPortB = PORTB;
    }
}



thank you all,
pmk
 

distance = ((TMR1L | (TMR1H << 8)) / 59); // in CM (58.82)
looks suspicious to me.

I see two problems, the first is that 'distance' is an integer so the result of dividing by 59 will give truncated value. It will at best ignore decimal places.
The second problem to check, and it may work anyway, is the result of ORing TMR1L and shifted TMR1H values. I would add them instead. I'm not sure if that rather old version of MPLAB will promote TMR1H to a 16-bit value.

Also check your bracketing, for example:
if(distance > 101 && distance < 400 && BRAKE_ON)
is ambiguous, it would be better written as:
'if((distance > 101) && (distance < 400) && BRAKE_ON)'

Brian.
 

In addition to the above said, the code snippet below, due for not considering a timeout, is not failsafe:

while(!ECHO);
TMR1ON = 1;
while(ECHO);
TMR1ON = 0;

In the absence of one or more pulses (which would be expected mainly depending on target geometry, as well as the transmiter/receiver ultrasound capsules arrangement and its correct power/sensitivity), it would account only the next pulse, showing a larger distance than the actual. What I would recommend to implement is some kind of 'intelligence', as a filter for example, such as a moving average, or any other feature that do not accept abrupt changes in the measured value.
 
such as a moving average, or any other feature that do not accept abrupt changes in the measured value
Now my code works correctly. I have modified the code as "read 3 times and Average" method. Also, I have increased the interval between object detection and object moved out. Say, detect object is < 100 CM and detect object moved away is > 150 CM [considering our body width]. I also suspect the Module's distance limit. I think its maximum limit is 240 CM or something. I actually implemented interrupt routine earlier. But there was also same errors I got. Thats why I changed the code as Polling method. Now I have to move back to interrupt method.

thanks,
pmk
 

A small change as below should be made in the code for working correctly in Hi-TECH - C compiler [ in order to differentiate between binary and octal].

Wrong code:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
TRISA = 00000000;
TRISB = 00000001;
TRISC = 00000000;
TRISE = 00000000;
    
PORTA = 00000000;
PORTB = 00000000;
PORTC = 00000000;
PORTE = 00000000;
    
ANSELA = 00000000;
ANSELB = 00000000;



Correct one:


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
TRISA = 0b00000000;
TRISB = 0b00000001;
TRISC = 0b00000000;
TRISE = 0b00000000;
    
PORTA = 0b00000000;
PORTB = 0b00000000;
PORTC = 0b00000000;
PORTE = 0b00000000;
    
ANSELA = 0b00000000;
ANSELB = 0b00000000;




Also instead of writes to PORT (though works well many times), writes should be made to LAT registers as recommended by datasheet.

Instead of :

Code C - [expand]
1
2
#define LED     RC6
LED  = 1; // ON LED which is connected on RC6 of PORTC



Use like this:

Code C - [expand]
1
2
#define LED     LATCbits.LATC6
LED  = 1; // ON LED which is connected on RC6 of PORTC



for better dynamic code (even in polling method)

Instead of waiting for indefinte period.


Code C - [expand]
1
2
3
4
while(!ECHO);
TMR1ON = 1;
while(ECHO);
TMR1ON = 0;



We can use the following code. If the pin does not receive ECHO within 120 mS,
exit the loop and continue. [*The delay period should be chosen according to our distance calculation]


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int j = 0;
 
do{
       if(ECHO_STARTED_SENSOR4){
       IOCBN2 = 1;
       ECHO_BIT2 = 1;
       TMR1ON = 1;
       }
       if(ECHO_COMPLETED_SENSOR4 && ECHO_BIT2){
          TMR1ON = 0;
          IOCBP2 = 1;
          ECHO_BIT2 = 0;
        break;
      }
    j++;
}while(j < 4800); // 120mS delay [FOR 4MHz CLOCK]



Also, MPLAB v8.63/V8.89, HI-TECH-C v9.80/V9.83,
Instead of using the following code;

Code C - [expand]
1
distance = (int) ((TMR1L | (TMR1H << 8)) / 59); // in CM (58.82)


We can use,

Code C - [expand]
1
2
distance = (int) (TMR1 / 59) // in CM [if Timer prescaler 1:1]
distance = (int) (TMR1 / 14.70); // in CM [if Timer prescaler 1:4]


we don't need to bother about the reading squence of 16 bit register.

thanks to all,
pmk
 
Last edited:

In addition to the above modifications in the code, I have added timer0 module for precise operations. In my earlier code,
person detection period works correctly (100%) as I desired, for example, 100 mS or so. As far as detecting person moved out, 95% detected in Seconds. But sometime (5%), it takes much more time to detect the person moved away, for example, 8, 10 seconds or sometime even more than that. May be due to Sensor Error readings. So, to obtain 100% accurate and immediate detection of person moved out using timer0. It gives 100% result now.

Note: Utrasonic Sensors works great on Flat objects using simple code without timer0 method. But when it comes to irregular shapes like human or other things, it is better to use timer0 to detect moved out. Sequence -> After the detection, start the timer0. Resetting Timer count, as long as the person is within the range. If person moved out from the range, check the Timer count. If it is elapsed, means person is moved out and do the necessary things.

like this

Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//DISTANCE BETWEEN 2 & 100 CM
    if((distance >= 2 && distance <= 100) && !BRAKE_ON){
       for(int i = 0; i < 3; i++){ // check values 3 times
                TMR0COUNT = 0; // RESET TMR0 COUNTER
        .
        .
        .
        average[i] =  distance;
        
        }
        .
        .
            .   
        if ( (distance <= (average + 1)) ||
        (distance >= (average - 1)) ){
                BRAKE_ON = 1;
        start_TIMER0(); // START TIMER0
        .
        .
        .
        }
    }
    if( (TMR0COUNT > 45) && BRAKE_ON) { // 3 SECONDS ELASPED AFTER PERSON MOVED OUT 
        TMR0COUNT = 0; // RESET TMR0 COUNTER
        off_TIMER0(); // OFF TIMER0
        .
        .
        .
    }
    .
    .



thanks,
pmk
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top