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] How to stabilize ADC using PIC

Status
Not open for further replies.

djc

Advanced Member level 1
Joined
Jan 27, 2013
Messages
402
Helped
3
Reputation
6
Reaction score
2
Trophy points
1,298
Location
India
Activity points
4,554
Hello,
I am writing a C code using mikroc and PIC16F676. Here is the code,
Code:
#define Dl_Relay PORTC.B2
#define Relay_1  PORTC.B1
#define Relay_2  PORTC.B2
#define Relay_3  PORTC.B3
#define test     PORTC.B1
char i=0,j=0,cycle=1,Flag=0,biggest_val[5];
unsigned int mains_val=0,a=0,b=0,k=0,d=0,Average=0;

void peak_detector(){
     while(a<b){
     a = ADC_Read(0);
     //Delay_us(750);
     b = ADC_Read(0);
     //Delay_us(750);
     }
     
      k = a; 
     biggest_val[i++]=k; 
     
     if(i==5){
              Average = (biggest_val[0] +biggest_val[1] +biggest_val[2] +biggest_val[3] +biggest_val[4])/5;
              
              if(Average<155) Dl_Relay = 0;
              if((Average>155) && (Average<200)) Dl_Relay = 1;
              if(Average>200) Dl_Relay = 0;
     i=0;
     }

}
void falling_edge(){
     while(a>b){
     a = ADC_Read(0);
     //Delay_us(750);
     b = ADC_Read(0);
     //Delay_us(750);       
     }
}

void led(){
     PORTC.B5 = 0;                   //LED ON-OFF
     PORTC.B4 = 1;
     Delay_ms(200);
     PORTC.B4 = 0;
     Delay_ms(200);
}

void main() {
     TRISA = 0x11111101;
     TRISC = 0x00;                       //PORTC as O/p
     ADC_Init();
     led();
     led();
     
     while(1){
              
              mains_val = ADC_Read(0);
              //Delay_us(200);
             
              while(mains_val<5){
              mains_val = ADC_Read(0);
              //Delay_us(200);
              }
              
              if(mains_val>5){
              a = ADC_Read(0);
              //Delay_us(200);
              b = ADC_Read(0);
              //Delay_us(70);
             
              if(a<b) peak_detector();
              if(a>b) falling_edge();
              }
     
     }

}

However when i test it on board, Dl_Relay pin transit between ON and OFF multiple times for particular ADC value,showing glitches on oscilloscope. Dl_Relay pin gets ON and OFF for 2-3 different ADC values. When i test it on hardware, same thing happens. D_relay pin switches ON and OFF for different ADC values. Why is the happening? Can any one guide me?
 

Hi,

Some rules to follow:
* use a solid GND plane as rock solid ground reference
* stabilize VCC, especially there should be no influence when switching the relay.
* stabilize ADC_Vref, same as above
* stabilize the ADC input voltage, same as above.

Now you should have stable ADC readings.
But even then you might see the LSB to flicker. Impossible to avoid this.
Therefore you can't decide with a simple "<" operation.
Therefore you need to include software hysteresis when switching the relay.
You need two thresholds: one for switchin the relay ON, another to swich the relay OFF. And between both there is a gap where you simply do nothing.

Something like:
Code:
if(Average<154) Dl_Relay = 0;
..don't change relay state when 154 and 155
if(Average >156) Dl_Relay = 1;
Maybe you need to adjust the two thresholds

Klaus
 

As Klaus explained, if you have a fixed threshold there will always be 'flicker' as it is crossed, even if you do averaging first. The averaging takes out variations due to noise and measurement consistency but if the result is still a fixed value, there will be a problem with the exact point it is exceeded. You need to adjust the thresholds (either electronically or in software) so the relay operating point is slightly moved between it's upward threshold and downward threshold. It creates a small 'dead' zone around the trip point where the relay will remain in it's present state before changing.

Brian.
 

You are operating a relay in a narrow band of 9mV (approx assuming you are using +5V supply as adc reference). A relay should always be operated with clear definition of hysteresis and 9mV is too little for that. When a relay operates, it would generate a glitch on 5V line during which time you should not be measuring inputs. This glitch could be lasting for may be 100ms. Introduce a reasonably long 'pause' after each relay operation. That should work.
 

so does that mean adding a small delay after relay operation will do? And approximately how much delay?
 

No,

A delay makes the switching frequency slower, and maybe it reduces the flickering during relay switching,

But it does not solve the hysteresis problem.

Indeed i recognized you aready have one LSB hysteresis, but this seems not to be enough.

Without hysteresis even the noise of the ADC may cause one LSB to flicker. The input even doesn't need to change..

Klaus
 

Now relay is operating at 2 points. it gets ON at near about 0.75V and gets OFF at 0.85V. Again gets ON somewhere at 1.02 V and OFF at 1.11 V. How Kalman filter is implemented?
 

I used different ADC values for different steps. It is working now.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top