Shop OBEX P1 Docs P2 Docs Learn Events
RCTIME help. Reading 0 to 5V and need steady results. — Parallax Forums

RCTIME help. Reading 0 to 5V and need steady results.

eagletalontimeagletalontim Posts: 1,399
edited 2012-01-15 20:29 in Propeller 1
Hello once again! I am using the BS2.RCTIME function and am trying to read positive voltage from 0 to 5V. I know RCTIME returns a value from 0 to 255, but I am having problems getting it to read correctly. For one, I cannot figure out the correct resistor values to get RCTIME to respond between 0 and 255 for the range I am looking for.

Currently, this is what I am using :
[PHP]
10K 10K
Throttle in >----/\/\/\/\/----0---/\/\/\/\/
> Prop Pin
|
= .1uf Cap
|
V
GND
[/PHP]

Here is my code :
[PHP]PUB ReadThrottle
BS2.start (31,30)
repeat
dira[5]~~ ' Set as output
outa[5]:=1 ' Set high
BS2.Pause(10) ' Allow to charge
throttle := BS2.RCTime(5,1) ' Measure RCTime[/PHP]

What would be the correct way to read a 0 to 5v source with a steady result using RCTIME?
«1

Comments

  • pedwardpedward Posts: 1,642
    edited 2012-01-14 14:45
    Tim, your TPS is connected to the ECU, so it already has a +5v coming off of it. This means you can't use RCTIME because the Prop cannot charge/discharge the cap. You need to use the ADC.spin object or an external ADC chip. The ADC.spin object implements the sigma delta ADC, which works very similar to RCTIME, but it can read an external voltage without controlling the current flow.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 14:58
    I was sort of able to get it using the above circuit and changed the resistor from the throttle side to a 440K and the one going to the Prop is now a 100 Ohm. The reading is a steady 63 to 105, but it is just not quite sensitive enough for me. I will have to put it in my converter so I can see 0 to 100% to see how accurate it is against another device in my car that reads throttle input as well.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 15:41
    Ok, the RCTIME seems to fluctuate with temperature and how long the circuit is on as well which I can't have. Where can I find the ADC.spin and some information on how to hook it up? I am trying to keep away from having to order more parts if I can help it, so I would rather the Prop handle the conversion if at all possible.
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-01-14 15:57
    There is an app note for the prop ADC. You can find the app notes at www.paralaxsemiconductor.com here Probably you will have to create a new login.
    Here is a direct link (in case login is not required) http://www.parallaxsemiconductor.com/an008

    Seems there is no other way to get to the app notes. If you cannot get to them let me know and I wil download and post here (because I am certain parallax do not intend to have the app notes locked away).
  • LeonLeon Posts: 7,620
    edited 2012-01-14 15:57
    It's in the Propeller Tool Library directory.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 16:02
    Just found it :) now to figure out how to get it to work properly to read 0 to 5 volts and return a percentage value like 2.5v = 50%
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 16:55
    Now that I have switched to ADC instead, I can't seem to figure out how to populate a variable or which variable to read for a result. I have found a tutorial on how to implement ADC here : http://gadgetgangster.com/tutorials/382 but it does not explain what it returns and how to use it. Can someone explain this to me?

    I think I got it. It updates the variable adcsample. Now one question I have is since I am reading voltage from 0 to 5 volts, I need to connect the Vdd input of the ADC circuit to 5v correct?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 17:18
    Along with my previous question. If I hook it to 5v coming from the 7805, sometimes the voltage is different from each component.... it could be 4.98 to 5.02 vdc. Wouldn't that change the returned value of the ADC function?
  • JonnyMacJonnyMac Posts: 9,198
    edited 2012-01-14 17:54
    You're always going to have some amount of noise in a system. You should consider filtering and multi-sample averaging, especially when you're getting signals from an automotive environment.
    I think I got it. It updates the variable adcsample. Now one question I have is since I am reading voltage from 0 to 5 volts, I need to connect the Vdd input of the ADC circuit to 5v correct?

    Yes, and Vref, too. Any pin that outputs to the Propeller needs to be coupled with a 3.3K (or higher) resistor to limit the current into the pin.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 18:36
    There is quite a bit of noise in the wire already which is what I am confused on. With nothing connected to the input side of the circuit, the reading jumps +/- 1,000 within a second. Pulling it down to ground shows around 36000 but jumps +/- 1,000. Is there any way to stabilize that?

    Also.... If I connect the input of the circuit to the 3.3v output of the regulator, it will max out at 65535. That is with the Vdd connected to the 5v output of the 7805. If it maxes out at that low voltage, reading 5v will not work since I will only get about 60% reading. I have checked out the calculator here : http://www.pulsedpower.net/Applets/Electronics/SigmaDeltaADC/SigmaDelta.html but it does not specify what caps to use. I have some .01, .001, and one .1 on hand. I have 11,000 resistors on hand in all different sizes as well, but I have no idea what size to use to get the stability out of the ADC function. If I put the Vdd at 12 volts, will that give me a better range so I can read the full 5V without maxing out the ADC function?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-14 20:08
    It appears as though I am not going to be able to achieve the accuracy i am wanting from the ADC function. Are external ADC chips more accurate for my project since this is in an automotive environment? I am needing to read the 0 to 5v output of the TPS and display it on the LCD in 0 to 100%. So far, RCTIME seemed to be the most stable, but not as accurate. Now with ADC, at 5% throttle (According to my logger that attaches to the vehicle), I am showing a jump between 3% and 6% which is definitely not accurate enough for my needs. Does anyone have any advice on what I should do? Is there a surface mount ADC chip that would fit my needs? This is all new to me but I have to get it done, so I am cramming as much stuff in my head as we go.
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-01-14 21:47
    It appears as though I am not going to be able to achieve the accuracy i am wanting from the ADC function. Are external ADC chips more accurate for my project since this is in an automotive environment? I am needing to read the 0 to 5v output of the TPS and display it on the LCD in 0 to 100%. So far, RCTIME seemed to be the most stable, but not as accurate. Now with ADC, at 5% throttle (According to my logger that attaches to the vehicle), I am showing a jump between 3% and 6% which is definitely not accurate enough for my needs. Does anyone have any advice on what I should do? Is there a surface mount ADC chip that would fit my needs? This is all new to me but I have to get it done, so I am cramming as much stuff in my head as we go.

    Consider this, (an MCP3201 has 12 bits for 4096 values from 0 to vref) it may not be the fault of the ADC, rather the environment. If you are taking the leads off of the pot or ECM, use shielded 3 conductor cable. Ground only one end of the shield to prevent noise induced into the sense line from loop current flow in the shield. Pot wiper of course. The third wire, connect to the high side of the pot (or ECM) and run that to Vref of the ADC and that may give you better a better representation by compensating for the length of the supply lead. The shielding may help with the instability caused by all the electronic noise in the system. Also, bypass the supplies including the reference source, and low pass filter the input to the ADC as your TPS signal is not a very fast signal and keeping some of the high frequency transients out will help performance as well. As I mentioned in the other thread, you should look up the 2010 contest entry for DAQPac. It is an impressive little system that does much of the instrumentation your are needing.

    FF
  • chetw77cruiserchetw77cruiser Posts: 12
    edited 2012-01-14 22:58
    Here is a little something that I am playing with right now. Don't worry about the lcd, just use what ever output you want. This is for one channel at the moment.
    {{
    *************************************
    * Digital Dashboard ADC code segment                 *
    * Author: Chet*
    *************************************
    {{--------------------------REVISION HISTORY--------------------------
     v0.1
    ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    }}
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      'VFD_PIN        = 0
      'VFD_BAUD       = 38400    ' For Debug LCD
      LCD_BAUD  = 9600
      LCD_LINES = 4  
      #0, CLS, HOME, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR           ' PST formmatting control
    ' Pin assingments
      LCD_PIN   = 17
      adcdata   = 2                     '
      adcclk    = 3
      adcsel    = 1    
    VAR
       long  curadc,volts
       
    OBJ
      adc           : "mcp3208"
      lcd           : "bpp-420"
      SN            : "simple_numbers"
    '  term          : "jm_txserial"
            
    pub start
       
        
    if lcd.start(LCD_PIN, LCD_BAUD, LCD_LINES)                    
        pause_ms(10)                                                                      ' open connection to lcd 
       'term.init(30, 115_200)
        'pause_ms(10)
        adc.start(27,26,28,%11111111)                                          ' start adc controller
        lcd.cls                                                                                  ' clear screen
        lcd.backlight(1)
        main    
    PUB Main 
    
        
    repeat
      curadc:= adc.in(0)                                      ' convert raw to volts without decimal
      curadc := curadc*100000
      volts := curadc/81900
          lcd.str(string(lcd#lcd_crsr_pos,97))       ' display volts
          lcd.str(SN.decx(volts, 4))
      waitcnt(clkfreq/15 + cnt)
    PRI Pause_ms(msDelay)
      waitcnt(cnt + ((clkfreq / 1000) * msDelay))
    

    I quess I posted this correctly, let me know.
  • pedwardpedward Posts: 1,642
    edited 2012-01-14 23:18
    Tim,

    Your TPS is a 0-5v output, the Propeller can only do 0-3.3v with the ADC unless you put a resistor divider into the circuit. Run a 10k resistor from the TPS to the ADC input circuit (the part showed in the app note), then run a 10k resistor from the input to ground. This makes a voltage divider which converts the TPS to a 0-2.5v range, which is within the Prop's abilities without railing the input.

    The ADC.spin object has more than enough precision, in fact you determine how much precision you need, then tell the driver to sample at that frequency.
    asm_cycles    long      $FFFF                           '(use $FFFF for 16-bit, $FFF for 12-bit, or $FF for 8-bit)
    

    Also, the AN008 app note has details on how this works:
    The scale factor of the result and the size of any offset will both be proportional to the
    number used for interval. The magnitude of interval determines the precision of the
    result. For eight bits of precision, say, interval would ideally equal 256; for nine bits, 512;
    and so forth. In other words, for eight bits of precision, the PHSx register would contain a
    count of how many times in 256 internal clocks the counter input was above the logic
    threshold. But, because the input gain is less than unity, those eight bits will encompass
    more than a 0-to-Vdd analog input range. Therefore, it will be necessary to increase the
    value of interval to scale the desired input range to eight bits.
    
    tim_adc.jpg
    1024 x 718 - 45K
  • chetw77cruiserchetw77cruiser Posts: 12
    edited 2012-01-14 23:24
    Here is another version of what I posted earlier. This one has averaging and converted to a percentage, well, for the most part.
    {{
    *************************************
    * Digital Dashboard ADC code segment                 *
    * Author: Chet
    *************************************
    {{--------------------------REVISION HISTORY--------------------------
     v0.3
    ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    }}
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      'VFD_PIN        = 0
      'VFD_BAUD       = 38400    ' For Debug LCD
      LCD_BAUD  = 9600
      LCD_LINES = 4  
      #0, CLS, HOME, #8, BKSP, TAB, LF, CLREOL, CLRDN, CR           ' PST formmatting control
    ' Pin assingments
      LCD_PIN   = 17
      adcdata   = 2                     '
      adcclk    = 3
      adcsel    = 1    
    VAR
       long  curadc,volts,percent
       
    OBJ
      adc           : "mcp3208"
      lcd           : "bpp-420"
      SN            : "simple_numbers"
    '  term          : "jm_txserial"
            
    pub start
       
        
    if lcd.start(LCD_PIN, LCD_BAUD, LCD_LINES)                     ' start terminal
        pause_ms(10)                                   ' open connection to vfd
        'term.init(30, 115_200)
        'pause_ms(10)
        adc.start(27,26,28,%11111111)            ' start adc controller
        lcd.cls                                  ' clear screen
        lcd.backlight(1)
        main    
    PUB Main 
    
        
    repeat
      curadc:= adc.average(0,1000)
      curadc := curadc*100000
      volts := curadc/81900
      percent := curadc/4095
      percent := percent/1000
      
       lcd.str(string(lcd#lcd_crsr_pos,97))
       lcd.str(SN.decx(percent, 3))
      waitcnt(clkfreq/15 + cnt)
    
    PRI Pause_ms(msDelay)
      waitcnt(cnt + ((clkfreq / 1000) * msDelay))
    
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 08:07
    I just traced the factory controller circuit which is pretty simple. It basically has a 900k? that pulls it down to ground, then a 4.7k on the main signal coming in which goes to another 4.7k before entering the main processor unit. It does not go to an external ADC processor. There is only one signal wire coming in from the TPS and no TPS Vref. There are also no caps connected to that circuit. Is there a reason why? Are the caps necessary?
  • RaymanRayman Posts: 14,849
    edited 2012-01-15 08:09
    I'm curious as to whether RC time could work or not... I think it could.
    If you got rid of the 10k going to the Prop pin and increased the other resistor to 100k.

    Now, you can directly charge or discharge the cap to GND or Vdd with the Prop pin.
    I think you'd have to do two readings then.
    One to with the cap charged to Vdd and see if comes down below threshold in some time (for low throttle voltages).
    Second with the cap at GND has see how long it takes to get to threshold (for high throttle voltages).
    Shouldn't that work?
  • T ChapT Chap Posts: 4,223
    edited 2012-01-15 08:12
    The main processor you are talking about may have a built in ADC.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 08:33
    RCTIME does work, but in cold temps, it shows a different reading than with warm temps. It is not accurate enough for what I need.

    I just went out and tested the circuit as posted above without the TPS Vref and it is still way to jumpy. At 0% throttle, the voltage is 0.51v. At full throttle, it is 5.00V. The way I have it hooked up now, the display shows 1356 and sits there till about 1/4 throttle. When it hits that, it starts jumping from ~1800 to ~3400 while holding the throttle steady. It does the same at any position above 1/4 throttle all the way up to full throttle. It is like it is not picking up something correctly. I have checked all connections to ensure they are secure and connected to correct places. This is frustrating :p All a learning experience though! Is there a different design to the circuit that I could use the ADC with?

    I am using the 12 bit output since that should be all I need. the 8 bit is really jumpy and it would be hard to get an average.
  • T ChapT Chap Posts: 4,223
    edited 2012-01-15 08:48
    How difficult would it be to add an encoder? Temperature would not affect it.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 08:49
    Out of curiosity, does it matter what caps I use? I am currently using 102 ceramic caps (.001uf). Do I need to use something different?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 09:05
    What do you mean by encoder? An external ADC?

    I tried using 104 ceramic caps (.1) and those did not change anything either. I must be doing something wrong since I cannot get even close to a steady reading at all from the ADC function. Since I am using the voltage divider resistor, do I need to move the Vdd to the 3.3V rail instead of the 5v? Is that what is throwing everything off for me?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 09:24
    I traced my circuit and have attached how it is hooked up. The attached image is how I have it.

    Here is the code I have for the ADC :

    [PHP]CON
    SDF = 5 'sigma-delta feedback PROP OUTPUT
    SDI = 6 'sigma-delta input PROP INPUT

    PUB SigmaDelta (sample)
    cognew(@asm_entry, sample) 'launch assembly program in a COG

    DAT
    org

    asm_entry mov dira,#1<<SDF 'make SDF pin an output

    movs ctra,#SDI 'POS W/FEEDBACK mode for CTRA
    movd ctra,#SDF
    movi ctra,#%01001_000
    mov frqa,#1

    mov asm_c,cnt 'prepare for WAITCNT loop
    add asm_c,asm_cycles


    :loop waitcnt asm_c,asm_cycles 'wait for next CNT value
    '(timing is determinant after WAITCNT)

    mov asm_new,phsa 'capture PHSA

    mov asm_sample,asm_new 'compute sample from 'new' - 'old'
    sub asm_sample,asm_old
    mov asm_old,asm_new

    wrlong asm_sample,par 'write sample back to Spin variable "sample"
    '(WRLONG introduces timing indeterminancy here..)
    '(..since it must sync to the HUB)

    jmp #:loop 'wait for next sample



    asm_cycles long $FFF '(use $FFFF for 16-bit, $FFF for 12-bit, or $FF for 8-bit)

    asm_c res 1 'uninitialized variables follow emitted data
    asm_cnt res 1
    asm_new res 1
    asm_old res 1
    asm_sample res 1
    asm_temp res 1[/PHP]
  • T ChapT Chap Posts: 4,223
    edited 2012-01-15 09:27
    http://www.usdigital.com/products/encoders/incremental/rotary/kit/e2

    An optical encoder as shown in the link. It would require it to be mounted on a shaft, ie 1/4" shaft. You then read he values from the encoder into the Prop with the quadrature object. This is very easy to do, but I am not sure if your throttle would allow the hardware since it is not shown. You need to have a voltage range of 0 - 3v3 only to the Prop. Can you draw the exact schematic you are testing this with?
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 09:35
    The previous post has the exact schematic I am using to test this with :) Here my most recent updated code :

    [PHP]
    CON
    _CLKMODE = XTAL1 + PLL16X
    _XINFREQ = 5_000_000
    solenoida = 2
    solenoidb = 3
    upbutton = 0
    downbutton = 1

    VAR
    LONG LCDstack
    LONG ThrottleStack[100]
    LONG lastWritten
    LONG adcsample
    LONG rpm
    BYTE EVal1
    BYTE throttle
    BYTE gear

    OBJ
    adc : "ADC"
    i2c : "Basic_I2C_Driver"
    BS2 : "BS2_Functions"
    lcd : "Serial_Lcd"
    getrpm : "jm_freqin"
    num : "simple_numbers"

    PUB Main
    rpm := 0
    gear := 1

    shiftgear(gear)
    adc.SigmaDelta(@adcsample)
    cognew(LCDupdate, @LCDstack)
    'cognew(ReadThrottle, @ThrottleStack)

    repeat
    if ina[upbutton] == 1
    gear++
    gear := shiftgear(gear)
    if ina[downbutton] == 1
    gear--
    gear := shiftgear(gear)
    repeat while ina[downbutton] == 1 or ina[upbutton] == 1
    waitcnt(3_000_000 + cnt)

    waitcnt(10_000_000 + cnt)

    PUB LCDupdate
    getrpm.init(15)
    lcd.init(8, 9600, 2)
    lcd.displayOn
    lcd.backLight(true)
    waitcnt(2_000_000 + cnt)
    lcd.gotoxy(0,0)
    lcd.str(string("Testing Version "))
    lcd.gotoxy(0,1)
    lcd.str(string("Tims shifter V3 "))
    waitcnt(200_000_000 + cnt)
    lcd.cls
    lcd.str(string("Gear: "))
    lcd.gotoxy(0,1)
    lcd.str(string("RPM : "))

    repeat
    rpm := getrpm.freq * 3
    lcd.gotoxy(5,0)
    lcd.str(num.dec(gear))
    lcd.gotoxy(5,1)
    lcd.str(string(" "))
    lcd.gotoxy(5,1)
    lcd.str(num.dec(rpm))
    lcd.gotoxy(10, 0)
    lcd.str(string(" "))
    lcd.gotoxy(10, 0)
    lcd.str(num.dec(adcsample)) ' Display
    waitcnt(10_000_000 + cnt)

    PUB ReadThrottle | thr, lt, ht, athr
    repeat
    dira[5]~~ ' Set as output
    outa[5]:=1 ' Set high
    BS2.Pause(10) ' Allow to charge
    thr := BS2.RCTime(5,1) ' Measure RCTime
    thr := ht - thr
    athr := ht - lt
    thr := thr * 100
    thr := thr / athr
    throttle := 100 - thr

    PUB shiftgear(tmp)
    if tmp > 4
    tmp := 4
    if tmp < 1
    tmp := 1

    dira[solenoida]~~
    dira[solenoidb]~~
    outa[16..23]~
    dira[16..23]~~

    if tmp == 1
    outa[solenoida] := 1
    outa[solenoidb] := 1
    if tmp == 2
    outa[solenoida] := 0
    outa[solenoidb] := 1
    if tmp == 3
    outa[solenoida] := 0
    outa[solenoidb] := 0
    if tmp == 4
    outa[solenoida] := 1
    outa[solenoidb] := 0
    outa[16..23] := numbers[tmp]
    saveval(tmp)
    'lcd.gotoxy(5,0)
    'lcd.str(num.dec(tmp))
    return tmp

    PUB saveval(tmp) | temp, startTime
    temp := tmp
    if temp <> lastWritten and temp <> 0
    if i2c.WritePage(i2c#BootPin, i2c#EEPROM, @EVal1, @tmp, 4)
    abort ' an error occured during the write
    startTime := cnt ' prepare to check for a timeout
    repeat while i2c.WriteWait(i2c#BootPin, i2c#EEPROM, @tmp)
    if cnt - startTime > clkfreq / 10
    abort ' waited more than a 1/10 second for the write to finish
    lastWritten := temp
    return

    DAT
    numbers byte %0000_0000, %0101_0000, %1100_1110, %1101_1010, %0101_0011[/PHP]
  • T ChapT Chap Posts: 4,223
    edited 2012-01-15 09:44
    Try this:

    Lose the 10k you have on GND.
    Find a trim pot( 1k, 10k etc).
    Put one side of the pot to GND
    Put the other side of the pot to your throttle output(0-5)
    Set throttle to max output(5v)
    Adjust trim pot until you have 3v3 on the wiper.
    Send wiper to the 10k as you have it on the circuit input.

    This will allow a precise conversion of your 5v to 3v3.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 10:27
    Just did that and it is staying at 1365 ouput until 1/4 throttle. After that it jumps all over the place +/- 1000. This is really frustrating!

    EDIT : I tried a 1k Pot and a 10K pot. I don't have any higher than that.
  • LeonLeon Posts: 7,620
    edited 2012-01-15 10:31
    How long are the connections to the ADC components? They need to be as close as possible to the Propeller pins.
  • T ChapT Chap Posts: 4,223
    edited 2012-01-15 10:35
    Have you confirmed that the output of the throttle is behaving nicely, by putting a volt meter on it to watch the output? I would use about 10-20 samples as an average, while compiling the average, throw out any value that is greater or less than X of the previous value. This may be similar to a MEAN value of a sample, not an average.

    Oh yeah, what Leon said. Breadboards would be a possible problem for doing ADC.
  • eagletalontimeagletalontim Posts: 1,399
    edited 2012-01-15 10:42
    Right now, it is about 1ft from the prop. I have the ADC circuit on a breadboard and the prop development board is the main part. Since I am constantly removing components, it would be tough to keep soldering and unsoldering components. Would that cause the loss of pickup less than 1/4 throttle? it does not change at all from 1365 until 1/4 throttle.
Sign In or Register to comment.