Go Down

Topic: 4051 reading problem (Read 585 times) previous topic - next topic



What I'm trying to do is actually a little more complex than just reading sensors.

The circuit is made of 2 tact switches, 2 sensors (1 LDR, 1 pot) and 2 LEDs.

What the code is supposed to do is read the sensors and map the results to a 0-255 range according to calibration values.
Calibration mode is activated for a sensor when its associated tact switch (there is one per sensor) is pressed for more than 500ms. It is active until the switch is pressed again. Until that time, it records the minimum and maximum values for that sensor and its associated LED blinks.
A short press of a switch toggles its sensor's "freeze" function on/off. When freeze is on, the reading is not done and the sensor's value is not updated. When freeze is off, the reading is updated at each loop. The data is sent over serial.
There is one LED per sensor that indicates the mode (off = reading, on = freeze, blinking = calibrating).

The problems I'm having are:
- At startup, the mode is "freeze" (1) for ech sensor, although I specified it should be "reading" (0).
- When the pot (sensor 1) is in "freeze" mode I can read correctly the LDR (sensor 0) value, but when both sensors are in "reading" mode, I get the pot value instead of the LDR. Looks like a problem in my code, but it takes about one second for the value to drop down to that of the LDR when I switch the pot's "freeze" mode off, which made me thought it might be a problem in the circuit (see attached file).

Here's the code:

Code: [Select]

// switch & sensor management
const int sensors_number = 2;   // number of sensors to use
boolean last_switch_state[] = {0, 0};
boolean current_switch_state[sensors_number];
int sensor_min[] = {0, 0};      // default min value
int sensor_max[] = {1023, 1023};// default max value
int sensor_value[sensors_number];            // needs to be global to work with switch{} below
int output_sensor_value[sensors_number];     // needs to be global if we want to freeze it
int last_sensor_value[sensors_number];       // because we will only send data if there is a change in the reading

// time management
long debounce_millis[sensors_number];
int debounce_threshold = 50;    // above 20ms the reading will be considered valid
long high_press_timer[sensors_number];
int calibration_trigger = 500;  // a 500ms press will activate calibration mode

//  LED management
long led_timer[sensors_number];
int led_blinking_time = 300;    // blinking time set to 300ms
boolean led_state[] = {0, 0};  // default LED state

// modes
/* 0 = reading
   1 = freeze
   2 = calibration */
int sensor_mode[] = {0, 0};

// Arduino pins
int switchPin[] = {2, 3};
int ledPin[] = {12, 13};
int commonPin = 0;       // the pin we will read from, connected to the 4051
int s0 = 5;              // these following 3 are connected to the 4051 select pins
int s1 = 6;
int s2 = 7;
int displayButtonPin = 8;// for troubleshooting

// the bits we will write to select the 4051 to read from
boolean r0;
boolean r1;
boolean r2;

// troubleshooting
boolean display_button;

void setup() {
  // pins setting
  for (int i = 0; i < sensors_number; i++) {
    pinMode(ledPin[i], OUTPUT);
    pinMode(switchPin[i], INPUT);
  pinMode(commonPin, INPUT);
  // troubleshooting
  pinMode(displayButtonPin, INPUT);

  // initialize serial communication

void loop() {
  // we will repeat the whole thing once per sensor
  for (int i = 0; i < sensors_number; i++) {
    // read switch
    current_switch_state[i] = digitalRead(switchPin[i]);
    // if state changed
    if (current_switch_state[i] != last_switch_state[i])
      debounce_millis[i] = millis();

    // if the counter is above the debouncing threshold
    if ((millis() - debounce_millis[i]) > debounce_threshold) {
      // if switch is HIGH (pressed)
      if (current_switch_state[i] == HIGH) {
        // if high press timer not set, set it
        if (high_press_timer[i] == 0) high_press_timer[i] = millis();
        //  if it is set, compare to calibration activation threshold. If over:
        else if (millis() - high_press_timer[i] >= calibration_trigger) {
          // reset previous end values
          sensor_min[i] = analogRead(commonPin);
          sensor_max[i] = analogRead(commonPin);
          // activate calibration mode
          sensor_mode[i] = 2;
          // start led blink timer
          led_timer[i] = millis();
          led_state[i] = -led_state[i] + 1;  // toggle led_state to show we're entering calibration mode

      // if switch is LOW (released)
      else {
        // if we had a short press
        if (  millis()-high_press_timer[i] < calibration_trigger
              && millis()-high_press_timer[i] > 0) {
          // go from calibration to freeze mode if applicable
          if (sensor_mode[i] == 2) sensor_mode[i] = 1;  // will be toggled to 0 in the next line
          // and toggle anyway (so eventually we get from calibration to continuous reading mode)
          sensor_mode[i] = -sensor_mode[i] + 1;
          led_state[i] = sensor_mode[i];  // so if mode = 0, led is off, and if mode = 1 led is on
        // we then reset the high press timer to enable calibration mode again
        high_press_timer[i] = 0;
    // print high press timer
    // save switch state
    last_switch_state[i] = current_switch_state[i];
    switch (sensor_mode[i]) {
      // continuous reading mode
      case 0:
        // select sensor: these are sent to the 4051 to tell it which of its pins we want to read
        r0 = bitRead(i,0); // we convert the sensor number into a 3 bit number
        r1 = bitRead(i,1); // if 0: r0 = 0, r1 = 0, r2 = 0
        r2 = bitRead(i,2); // if 1: r0 = 1, r1 = 0, r2 = 0
        digitalWrite(s0, r0);
        digitalWrite(s1, r1);
        digitalWrite(s2, r2);
        // read sensor
        sensor_value[i] = analogRead(commonPin);
        // in case the value is beyond the min or max
        sensor_value[i] = constrain(sensor_value[i], sensor_min[i], sensor_max[i]);
        // then map to calibration values
        output_sensor_value[i] = map(sensor_value[i], sensor_min[i], sensor_max[i], 0, 255);
        // no break because in both freeze and continuous reading modes we will use the serial out
      // freeze and continuous reading modes
      case 1:
        Serial.println(String(0) + ": " + String(output_sensor_value[0]));

      // calibration mode   
      case 2:
        // read sensor
        sensor_value[i] = analogRead(commonPin);
        // store new values if applicable
        if (sensor_value[i] < sensor_min[i]) sensor_min[i] = sensor_value[i];
        if (sensor_value[i] > sensor_max[i]) sensor_max[i] = sensor_value[i];
        // print current ends
        Serial.println("Min: " + String(sensor_min[i]) + " - Max: " + String(sensor_max[i]));
        // toggle the led if the time has come
        if (millis() - led_timer[i] > led_blinking_time) {
          led_state[i] = -led_state[i] + 1;
          // and reset the timer for the next blink
          led_timer[i] = millis();
    }  // endswitch
    // print mode
    //Serial.println(String(i) + " mode: " + String(sensor_mode[i]));
    digitalWrite(ledPin[i], led_state[i]);
  }  // endfor

I checked the code and circuit numerous time and I really don't get what's wrong. I'm in desperate need of help :)

Thanks in advance to anyone willing to help me out!


This is complex code. The first thing you should do is to write something simple that checks out the hardware so you can remove that as an issue.
Next start off with something simple and work towards your final system in small steps.
The big bang approach of writing it all and then wondering why it doesn't is not advised.

If you don't feel like that then add lots of debug print statements to see the values you expect are the ones you actually get.

for example:-
At startup, the mode is "freeze" (1) for ech sensor, although I specified it should be "reading" (0).

So put print statements to track this. You might find it is not set right or that it is being changed after the first time round the loop or indeed something.


Thanks, following your advice I finally got to read the sensors as expected (simply forgot to set the select pins as outputs!), still have to fix the startup mess (which has evolved now by the way), will do later!

Go Up