Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 17 of 17

Thread: Unstable analog values from multiplexing

  1. #1

    Unstable analog values from multiplexing

    Hi everybody. I'm constructing a Midicontroller. It has three basic elements, potis, flash buttons and normal buttons. I wrote my own library and with a lot of help from this forum it works pretty well now. Thanks to responsiveanalogread library my potis work very smothly and stably. Since there will be a lot of inputs I'm now doing some testing with multiplexing. My first try was with 7 potis and 7 flash buttons and I got that many confusing values that I had to restart. My very simple circuit looks like this now:

    Click image for larger version. 

Name:	circuit.jpg 
Views:	11 
Size:	115.4 KB 
ID:	15854

    This is the code:

    Code:
    #include "SkyController.h"
    
    SkyPoti poti(A0, 1, 1);
    int mpxpin1=0;
    int mpxpin2=1;
    int mpxpin3=2;
    
    void setup() {
      pinMode(mpxpin1, OUTPUT);
      pinMode(mpxpin2, OUTPUT);
      pinMode(mpxpin3, OUTPUT);
    
    }
    
    void loop() {
    digitalWrite(mpxpin1, LOW);
    digitalWrite(mpxpin2, LOW);
    digitalWrite(mpxpin3, LOW);
    delayMicroseconds(200);
    poti.send();
    digitalWrite(mpxpin1, HIGH);
    digitalWrite(mpxpin2, HIGH);
    digitalWrite(mpxpin3, HIGH);
    delayMicroseconds(200);
    
    }
    The result is not as catastrophic as with the 14 inputs I tried before, the fader works very smoothly. But I don't get any MIDI values above 110, which is very confusing to me. It's definitely not a conversion error. It seems that about 13% of the upper side of the poti deliver the same value.

    What am I doing wrong?

  2. #2
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,180
    These analog multiplexers are not ideal switches, they need time to settle and they have a nonlinear series resistance from 40 to 250 Ohms which can highly trouble these SAR ADCs with their switched capacitor inputs.
    The settling problem can be solved by adding a 1ms delay after writing the mux pins before you start reading the ADCs. For the source impedance problem, you’d ideally put one voltage follower op-amp per channel between the multiplexer and the Teensy. A cheaper way might be to increase the read resolution to 8 or 9 bit and to apply a nonlinear function to restore the correct midi values.

  3. #3
    Are there any more suitable multiplexers for analog inputs?

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    The VEE pin must be connected, either to GND or a negative voltage.

    The E pin also needs to connect to GND.

    Your diagram shows 2 wires of the pot connected to GND, which can't possibly work. Maybe just a mistake in the diagram?

  5. #5
    Quote Originally Posted by PaulStoffregen View Post
    The VEE pin must be connected, either to GND or a negative voltage.

    The E pin also needs to connect to GND.

    Your diagram shows 2 wires of the pot connected to GND, which can't possibly work. Maybe just a mistake in the diagram?

    yes, thats just on the diagram. It's connected to Y0 instead. As far as I know, on these breakout boards, E is connected to ground via a 10k resistor and Vee is connected to ground via a jumper. When I manually connect Vee to ground, everything gets worse. After that I only receive Midi Values between 83 and 115.

    Edit: Nope. I accidently connected Vee to Vcc instead. When I connect it to Ground I receive proper Values. But it seems that it's not neccesary to connect E to ground as well.

  6. #6
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,045
    Have you tried a longer delay?

    I prefer to set the mux for the next read after the current one and let the other work of your loop be the delay.

  7. #7
    Quote Originally Posted by oddson View Post
    Have you tried a longer delay?

    I prefer to set the mux for the next read after the current one and let the other work of your loop be the delay.
    I have even tried 50 milliseconds. But the strange thing is: Now everything works fine and I'm even down to 10 microseconds. But my original program still causes very weird errors. So my code is probably involved in this problem. At the moment I'm trying to figure out what it is.

  8. #8
    Quote Originally Posted by oddson View Post

    I prefer to set the mux for the next read after the current one and let the other work of your loop be the delay.
    By the way this sounds like a smart thing to do but there is not much other work in my loop

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    Quote Originally Posted by Gripporillat View Post
    As far as I know, on these breakout boards, E is connected to ground via a 10k resistor and Vee is connected to ground via a jumper.
    Ok then. Without a direct link, I didn't go look this up on Sparkfun to check. I answered based only on the info you gave.

    If you're sure those pins are covered, then fine.

    For troubleshooting, I'd recommend increasing the delays in the code to many seconds, and printing in the serial monitor so you can see which state it's in. Then measure the actual voltages at the input and output on the chip.

  10. #10
    I finally found the last cause for all my errors. Somehow my pins 0,1,2 don't get set to OUTPUT. I wrote a library to count through my multiplexer. this is the code:

    Code:
    #include "Arduino.h"
    #include "MPX74HC4051.h"
    
    //Constructor
    MPX74HC4051::MPX74HC4051(int pin1, int pin2, int pin3, int Delay) {
    	pinMode(pin1, OUTPUT);
    	pinMode(pin2, OUTPUT);
    	pinMode(pin3, OUTPUT);
    	_pin1 = pin1;
    	_pin2 = pin2;
    	_pin3 = pin3;
    	_delay = Delay;
    	
    }
    
    //Switch
    void MPX74HC4051::Switch(int number) {
    	switch (number) {
    	case 0:
    		digitalWrite(_pin1, LOW);
    		digitalWrite(_pin2, LOW);
    		digitalWrite(_pin3, LOW);
    		delayMicroseconds(_delay);
    		break;
    	case 1:
    		digitalWrite(_pin1, HIGH);
    		digitalWrite(_pin2, LOW);
    		digitalWrite(_pin3, LOW);
    		delayMicroseconds(_delay);
    		break;
    	case 2:
    		digitalWrite(_pin1, LOW);
    		digitalWrite(_pin2, HIGH);
    		digitalWrite(_pin3, LOW);
    		delayMicroseconds(_delay);
    		break;
    	case 3:
    		digitalWrite(_pin1, HIGH);
    		digitalWrite(_pin2, HIGH);
    		digitalWrite(_pin3, LOW);
    		delayMicroseconds(_delay);
    		break;
    	case 4:
    		digitalWrite(_pin1, LOW);
    		digitalWrite(_pin2, LOW);
    		digitalWrite(_pin3, HIGH);
    		delayMicroseconds(_delay);
    		break;
    	case 5:
    		digitalWrite(_pin1, HIGH);
    		digitalWrite(_pin2, LOW);
    		digitalWrite(_pin3, HIGH);
    		delayMicroseconds(_delay);
    		break;
    	case 6:
    		digitalWrite(_pin1, LOW);
    		digitalWrite(_pin2, HIGH);
    		digitalWrite(_pin3, HIGH);
    		delayMicroseconds(_delay);
    		break;
    	case 7:
    		digitalWrite(_pin1, HIGH);
    		digitalWrite(_pin2, HIGH);
    		digitalWrite(_pin3, HIGH);
    		delayMicroseconds(_delay);
    		break;
    	}
    }
    the constructor I'm setting pinMode() but this part of the code somehow doesn't get executed. In my .ino I construct the object by

    Code:
    MPX74HC4051 mpxCount(0, 1, 2, 50);
    But my errors only disappear when I write

    Code:
      pinMode(0, OUTPUT);
      pinMode(1, OUTPUT);
      pinMode(2, OUTPUT);
    in Setup()

    So at least I know how to bypass my problem but I'd like to understand why it doesn't work the way I wanted. Can anybody please explain that to me?

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    Quote Originally Posted by Gripporillat View Post
    Somehow my pins 0,1,2 don't get set to OUTPUT.
    I ran your program from msg #1 (with 3 lines commented out, since it doesn't compile as-is) and indeed those 3 pins do get configured as outputs and work properly.

    Here's the waveform from pin 1 when I use my scope.

    Click image for larger version. 

Name:	file.png 
Views:	4 
Size:	28.6 KB 
ID:	15857

    This is the code I ran:

    Code:
    //#include "SkyController.h"
    
    //SkyPoti poti(A0, 1, 1);
    int mpxpin1 = 0;
    int mpxpin2 = 1;
    int mpxpin3 = 2;
    
    void setup() {
      pinMode(mpxpin1, OUTPUT);
      pinMode(mpxpin2, OUTPUT);
      pinMode(mpxpin3, OUTPUT);
    
    }
    
    void loop() {
      digitalWrite(mpxpin1, LOW);
      digitalWrite(mpxpin2, LOW);
      digitalWrite(mpxpin3, LOW);
      delayMicroseconds(200);
      //poti.send();
      digitalWrite(mpxpin1, HIGH);
      digitalWrite(mpxpin2, HIGH);
      digitalWrite(mpxpin3, HIGH);
      delayMicroseconds(200);
    
    }

    So at least I know how to bypass my problem but I'd like to understand why it doesn't work the way I wanted.
    How do you imagine anyone could have guessed this was the problem, much less explain it, when you provided a program which doesn't even compile, and doesn't show this extra C++ class you were using?

    Look, we have the "Forum Rule" here for a reason. We can't help you, and you have no way to get any help, if you keep us in the dark by not showing the actual code which is having the problem. Please, if you ask more questions here, follow the forum rule. It lets us help you, and it avoids wasting everyone's valuable time (even yours) with pointless questions lacking necessary info. Send the extra few minute to ask proper questions with the CORRECT code so anyone can actually see & reproduce the same problem.

  12. #12
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    Also, as a general suggestion from seeing the several questions you have recently asked, perhaps you should not use these extra C++ classes? They are only adding extra complexity. If you are not an expert with C++, this extra complexity can really cause even simple programs to become quite difficult.

    Sometimes special C++ classes can help. But often the best approach is to get the code working the simplest way first. Then later convert to a C++ class *after* the code is already tested and known to work.

  13. #13
    Quote Originally Posted by PaulStoffregen View Post
    How do you imagine anyone could have guessed this was the problem, much less explain it, when you provided a program which doesn't even compile, and doesn't show this extra C++ class you were using?

    ...
    I totally understand this. Within the last days I tried several ways to describe my problems and provide the neccesary informations and I got criticized for every single on of it, even for the one time I provided my whole project in a .zip. Every time I understood the criticism so I tried it differently the next time. I totally understand that many people don't want to read complex programs but get simplified versions of the part with the problem. On the other hand I also understand that sometimes it's neccesary to provide the whole project and hope that there's someone out there willing to work through it. this time I wrote a simplified version of my programm (which you can see in the first post) and showed the circuit since I was pretty sure the problem was on the hardware side. Which it was indeed. You were absolutely right, I had to connect Vee to ground. Afterwards my simplified version worked but my actual programm still had weird errors and I found out that this was due to the fact that my class seems to be unable to set the pinmode. I'm sorry for all the confusion. I am very thankful for all your help, I learned a lot from it!

    Regarding the classes: You're right, that's certainly not the most efficient way to realize my project but in my view it's a very good way to improve my understanding of c++

  14. #14
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,180
    Quote Originally Posted by Gripporillat View Post
    Regarding the classes: You're right, that's certainly not the most efficient way to realize my project but in my view it's a very good way to improve my understanding of c++
    Help in these forums is provided by unpaid volunteers (even Paul does unpaid volunteering here) who are willing to sacrifice their free time to help everybody with Teensy platform specific issues. But C++ class programming is definitely not a Teensy specific issue, but a prerequisite which should be mastered before you start whatever micro controller project, like getting a driving licence before you buy a car. There are tons of C++ tutorials and references in hundreds of different languages on the www. Mrs Google is ready to help you with finding them.

  15. #15
    Quote Originally Posted by PaulStoffregen View Post
    This is the code I ran:
    Again: Sorry for the confusion! This code should clarify my problem:

    Code:
    class MPX74HC4051 {
      public:
        MPX74HC4051(int pin1, int pin2, int pin3, int Delay);
        void Switch(int number);
      private:
        int _pin1;
        int _pin2;
        int _pin3;
        int _delay;
    };
    
    //Constructor
    MPX74HC4051::MPX74HC4051(int pin1, int pin2, int pin3, int Delay) {
      pinMode(pin1, OUTPUT);
      pinMode(pin2, OUTPUT);
      pinMode(pin3, OUTPUT);
      _pin1 = pin1;
      _pin2 = pin2;
      _pin3 = pin3;
      _delay = Delay;
      
    }
    
    //Switch
    void MPX74HC4051::Switch(int number) {
      //deleted to improve readability
    }
    
    
    int mpxpin1 = 0;
    int mpxpin2 = 1;
    int mpxpin3 = 2;
    
    MPX74HC4051 mpxCount(mpxpin1, mpxpin2, mpxpin3, 10); //I thought this should set the pins to OUTPUT because of the constructor but it doesn't
    
    void setup() {
    
    }
    
    void loop() {
      digitalWrite(mpxpin1, LOW);
      digitalWrite(mpxpin2, LOW);
      digitalWrite(mpxpin3, LOW);
      delayMicroseconds(200);
      digitalWrite(mpxpin1, HIGH);
      digitalWrite(mpxpin2, HIGH);
      digitalWrite(mpxpin3, HIGH);
      delayMicroseconds(200);
    
    }

  16. #16
    Quote Originally Posted by Theremingenieur View Post
    Help in these forums is provided by unpaid volunteers (even Paul does unpaid volunteering here) who are willing to sacrifice their free time to help everybody with Teensy platform specific issues. But C++ class programming is definitely not a Teensy specific issue, but a prerequisite which should be mastered before you start whatever micro controller project, like getting a driving licence before you buy a car. There are tons of C++ tutorials and references in hundreds of different languages on the www. Mrs Google is ready to help you with finding them.
    You're right. I will keep that in mind when posting here again.

  17. #17
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    19,248
    Quote Originally Posted by Gripporillat View Post
    Within the last days I tried several ways to describe my problems and provide the neccesary informations and I got criticized for every single on of it
    Yes, we've been critical but also helpful. We really do try to help here. But we also expect you to do a better job of giving correct & complete info.

    You have tried several ways, but almost all of those way have involved missing or inaccurate info. When you do this, it wastes the valuable time of everyone who is trying to help you, and the best help we can give is still not so good.

    Please, help us to help you. Do better if you post again. Spend a few minutes to check the code you've posted is correct and really does reproduce the problem. Check any diagrams carefully (avoid the wrong wire to GND). When you mention any non-Teensy product, give a link to the technical info. These details matter. We really do help here, but we don't like time-wasting questions with wrong & incomplete info. You can do better, if you spend a little more effort.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •