Shop OBEX P1 Docs P2 Docs Learn Events
Setting ADC range on MCP3208 — Parallax Forums

Setting ADC range on MCP3208

DiverBobDiverBob Posts: 1,110
edited 2013-12-16 18:17 in Propeller 1
I'm using MCP3208 8 channel ADC to read the wiper on a 10K multi-turn pot. I get no output from the ADC using the 'jm_mcp3208_ez' object for most of the range of the pot. I'm using 5v across the pot for the voltage. Is there a way to adjust the low end of the output so I get a value? The pot is reading about 500 ohm at the low end with an ADC output of 0.

The code listed below works but the value output to the PST is 0 for quite a bit of the pots rotation. Once the pot starts registering an output it keeps up for the rest of the rotation. It just doesn't want to read the low values. Looking to see if I'm overlooking something basic... The output of the pot wiper feeds directly to the channel 1 inpit of the ADC. The ADC is powered by 5V and the output of the ADC is fed to the prop through a 1k resistor.
obj
  ADC: "jm_mcp3208_ez"
  PST : "parallax serial terminal

Pub main
  ADC.init(7,8,9)
  PST.start(115200)
  Waitcnt(MS_001 + cnt)
  Adctest

Pub ADCTest | t! check, temp! I
  T:= cnt
  ch := 1
  repeat
    I := 0
    Repeat temp from 0 to 9
      I := I + ADC.read(ch, 0)
    I := I/10
    PST.str(string(pst#NL, "ADC: "))
    PST.dec(I)
    Waitcnt(t += constant(MS_001 * 250))

Bob

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-12-15 19:19
    Have you tried it without the averaging?

    I've had trouble with the MCP3208. I'm pretty sure the trouble was caused by my reading samples to frequently. The MCP3208 doesn't like high impedance sources. I think 10K is a bit too high of a resistance for frequent sampling.

    It was suggested I use a small cap on the ADC input pin in order to aid in getting stable readings when I asked about this problem once.

    I think a cap and slower sampling rate should help.

    Have you measured the wiper with a voltmeter?

    You really should have a 3K or better resistor on a Prop input pin from a 5V source. I know 1K was used a lot early on but it was determined that it wasn't really safe to do so. The current through the clamping diode shouldn't be more than 500uA.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-15 19:37
    Mea culpa.

    Somehow, I ended up putting a bogus mcp320x library into ObEx -- will take it down ASAP. I've attached a fixed-up mcp3208 object that should work for you. Note that there was also an error in the documentation: the mode value for single-ended is 1, not 0.

    Give this code snippet a try.
    pub adc_test | t, ch
    
      t := cnt
      repeat
        pst.char(pst#HM)                                            ' move cursor home
        repeat ch from 0 to 7                                       ' loop through 8 channels
          pst.char(idx + "0")                                       ' display channel #
          pst.char(":") 
          pst.char(" ")
          pst.dec(adc.read(ch, adc#SE))                             ' display channel level
          pst.char(pst#CE)                                          ' clean-up end-of-line
          pst.char(pst#NL)                                          ' next line
          
        waitcnt(t += (clkfreq >> 2))                                ' update every 250ms
    


    Note, too, that .init and .finalize have been properly renamed .start and .stop (this was a clue you had very old code). Again, sorry I posted an old file -- I guess some system purging is in order.

    EDIT: Updated files posted in ObEx (16 DEC 2013)
    -- http://obex.parallax.com/object/315
  • PropGuy2PropGuy2 Posts: 360
    edited 2013-12-15 21:07
    Here is a code snippet that works very well for me. Reading the MCP3208 data sheet gives the correct SPI timing sequence to get solid readings. See code example attached.
  • kwinnkwinn Posts: 8,697
    edited 2013-12-15 22:25
    Here is the spin code I use to read the MCP and place the 8 channels in an array of 8 words.
    Worked well for reading the pot values, although I think they may have been 500 ohms.
    pri mcpread | i
    '********************************************************************************************************
    ' read all 8 channels from the ADC and store them.     in(channel) : sample   
    '********************************************************************************************************
      repeat i from 0 to 7 step 1
        mcpch[i] := mcp.in(i)
    

    The object I used was chip's original MCP3208 demo, although it seems to have been updated. The link for the updated object is: http://obex.parallax.com/object/370
  • kwinnkwinn Posts: 8,697
    edited 2013-12-15 22:34
    BTW, there is no range setting on the MCP. The reference voltage to the MCP determines the maximum voltage the chip can measure. If you connect it to +5V that is the maximum voltage it can measure. To measure higher voltages requires a voltage divider and doing a calculation to give the actual voltage value. The output from the chip is a 12 bit binary number that presents the input voltage as a fraction of the reference voltage.
  • DiverBobDiverBob Posts: 1,110
    edited 2013-12-16 02:49
    Thanks for all the quick responses. I'll try them out tonight after work. For some reason I thought the 3208 was a 5v device, looking over the data sheet last night for a clue I saw it could run as low as 2.7v. So I'm going to wire it up to the 3.3v power instead. That should cut down the input current.
    I'll report back on my results later.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-16 09:51
    I make it a habit to put a 3.3K resistor between DOUT and DIN, then connect to the DIN pin (calling it DIO). This lets me work with 3.3v and 5v settings (have one design with a voltage selection for the ADC).
  • DiverBobDiverBob Posts: 1,110
    edited 2013-12-16 10:21
    I didn't mention this before but I have been using a 3.3K resistor between the data in and out pins on the 3208.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-16 10:55
    As I'm presently working on a commercial design (sign controller) that uses the MCP3202, this gave me the opportunity to review all three objects for correctness and consistency. I also made an improvement to the .scale() method by adding the .map() method (which I liberated from the Arduino library).

    I have updated my libary in ObEx.
    -- http://obex.parallax.com/object/315

    Again, I'm sorry I provided a bad file that gave you a bit of trouble.
  • ratronicratronic Posts: 1,451
    edited 2013-12-16 11:38
    Bob I tried a 3.3K resistor in series with the input from the pots wiper. I didn't get any difference in the readings with or without the resistor. This is the program I used with Jon's object posted today. This will show all the channels at

    the same time without scrolling the screen or anything.

    Edit: I misread your post you only need one 3.3k between DOUT and DIN and make the Propeller connection on DIN only not on DOUT.
    Con                        
                               
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000
    
    
    Var
    
      long Samples[8]  
      
    Obj
      ADC: "jm_mcp3208_ez"
      PST : "parallax serial terminal"
      
    Pub Main | channel
    
      ADC.start(7,8,9)
      
      PST.start(115200)
      Waitcnt(clkfreq + cnt)
      
      repeat
        GetAllChannels
        pst.char(pst#HM)
        pst.dec(Samples[0])
        pst.char(pst#CE)
        pst.char(pst#NL)                       
        pst.dec(Samples[1])  
        pst.char(pst#CE)
        pst.char(pst#NL)         
        pst.dec(Samples[2])  
        pst.char(pst#CE)
        pst.char(pst#NL)                 
        pst.dec(Samples[3])  
        pst.char(pst#CE)         
        pst.char(pst#NL)         
        pst.dec(Samples[4])  
        pst.char(pst#CE)         
        pst.char(pst#NL)         
        pst.dec(Samples[5])  
        pst.char(pst#CE)         
        pst.char(pst#NL)         
        pst.dec(Samples[6])  
        pst.char(pst#CE)         
        pst.char(pst#NL)         
        pst.dec(Samples[7])  
        pst.char(pst#CE)         
        waitcnt(clkfreq/100 + cnt)
              
    Pub GetAllChannels | channel
    
      repeat channel from 0 to 7
      
        Samples[channel] := ADC.read(channel, 1)
    
  • DiverBobDiverBob Posts: 1,110
    edited 2013-12-16 18:17
    JonnyMac wrote: »
    As I'm presently working on a commercial design (sign controller) that uses the MCP3202, this gave me the opportunity to review all three objects for correctness and consistency. I also made an improvement to the .scale() method by adding the .map() method (which I liberated from the Arduino library).

    I have updated my libary in ObEx.
    -- http://obex.parallax.com/object/315

    Again, I'm sorry I provided a bad file that gave you a bit of trouble.

    Thanks for the rapid turn around. I replaced the old object and everything is working as expected! Made for a much better evening spent testing programming. This is for a robot I'm building (see the Next Large Robot thread in the robotics forum for more details). I've been able to test and calibrate the femur and tibia motors. Next stop is the Coxa motor which will use the same routines.

    I appreciate everyone else's input also, I can see a place for some of the other code fragments later.

    Bob
Sign In or Register to comment.