NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Sensors, Actuators, and Robotics » ADC reading 807411

May 01, 2010
by 59zoocat
59zoocat's Avatar

I'm stumped. I'm using two Freescale MPX5010 pressure sensors to measure static pressure of standing water in a tube. Their specs output a voltage of 4.413mV/mmH2O. Offset voltage is approx 200mV. The #2 sensor has a very linear ADC reading of 50-500. However the #1 sensor goes from 50-255 then takes an immediate jump to 807411 and stays there. Using a voltmeter to check actual Vout on sensor 1, I get a reading of 1.7v. This calculates to 1.7V / 4.413mV = 362mmH2O not 807411. I'm not too concerned about making a ADC-to-pressure conversion as I'm displaying in 'Percent Full'. Saving the max reading in EEPROM and then just dividing the current ADC reading by max. With the reading of 807411 I'm getting 500%-700% displayed. Again the other sensor seems perfectly correct. One more thing, yes I already swapped sensors and the problem stays the same meaning both sensors are working correctly. Code snippets:

uint16_t EEMEM  sensor1_max, sensor2_max;

double p_temp(uint16_t last_samp, uint8_t count) {
  uint16_t max = 0;     
  if (count == 0)   
max = eeprom_read_word(&sensor1_max);
  if (count == 1) 
    max = eeprom_read_word(&sensor2_max);

  return (last_samp / max);
}
double GetSens(uint8_t count) {

ADMUX = count;

uint16_t last_samp;
double samp_now = 0;
double samp_avg = 0;
uint8_t i;

for(i=0; i<100; i++) { // take 100 samples and average them!
  last_samp = adc_read();

  if (count < 2)
    samp_now = (p_temp(last_samp , count) * 100);
    samp_avg += samp_now /100.0;
    }
return samp_avg;
}

TIA fellow Nerds, Keith

May 02, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Keith,

That is a strange one. The first that jumps out is that mention it goes crazy after 255, which is the largest number that can be held in an 8 bit integer. I don't see in your bits of code where you write the values to the EEPROM, perhaps somewhere something is being cast down to an 8 bit integer.

Humberto

May 03, 2010
by 59zoocat
59zoocat's Avatar

Hey thanks for the reply Humberto. While I'm shaving down the bloated code to post I was thinking. I'm using MUX 0-4 now, I should try another ADC channel. Here's a few more snippets:

ADMUX = 0;
sensor1_max = adc_read();
lcd_home();
fprintf_P(&lcd_stream, PSTR("Max1 Pres. = %d    "), sensor1_max);
// lcd displays 50-255,then 807411
eeprom_write_word(&sensor1_max,sensor1_max);

ADMUX = 1;
sensor2_max = adc_read();
lcd_home();
fprintf_P(&lcd_stream, PSTR("Max2 Pres. = %d   "), sensor2_max);
// lcd displays 50-500 correctly
eeprom_write_word(&sensor2_max,sensor2_max);

double p_temp(uint16_t last_samp, uint8_t count) { // Pressure Ratio
  uint16_t max = 0;
  if (count == 0)   
    max = eeprom_read_word(&sensor1_max);
  if (count == 1) 
    max = eeprom_read_word(&sensor2_max);       
  return (last_samp / max); // current adc_read() / stored max
}

This gets averaged and displayed again just like in the comments. I had the fprintf function messed up but didn't effect it after I fixed it.

confused - keith

May 04, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi 59zoocat,

I think the problem is that you are attempting to reuse the sensor_max variables. Although it is good practice to reuse global variables when it makes sense, in this case I think it is causing problems because of the eeprom trickiness. The EEPROM directive causes the variable to be allocated in the eerprom space, not the RAM space where global variables are normally stored. When you do you

sensor1_max = adc_read();

It puts the value of adc_read(); in the address of sensor1_max in RAM, but space for the variable was allocated in EEPROM. It mostly works because you are writing the variable and using it right away, so nothing is using the unallocated RAM space you are borrowing to store the value. However sometimes something else writes to that space and your numbers go haywire. At least that is my theory. Try allocating a normal uint16 in RAM to hold your adc_reading and let me know if that fixes it.

For the most part you only want to interact with the EEPROM variables through the eeprom_read and eeprom_write routines, or unpredictable bugs may ensue.

Humberto

May 04, 2010
by 59zoocat
59zoocat's Avatar

(Thank You)^2! Now it works! After what you said, I realized I was using my EEPROM variables as scratch pad variables. I declared a couple of local variables inside my function and used them for scratch, then eventually wrote those to the EEPROM vars. Much better now.

void Calib(void) { // Calibrate
    uint16_t sens1 = 0, sens2 = 0;
    sens1 = adc_read();
    fprintf_P(&lcd_stream, PSTR("Max Tank1 Pres. = %d    "), sens1);
    eeprom_write_word(&sensor1_max,sens1);

Now on to interrupts, sleep, and wake. Thanks, Keith

Post a Reply

Please log in to post a reply.

Did you know that the microcontroller's crystal oscillator can be used to keep accurate time? Learn more...