help

Discussion in 'Programmer's Corner' started by tracecom, Jan 2, 2014.

  1. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    Excuse the stupid title, but apparently I am the victim of the notorious "too long title" bug. I wanted the title to be, "PBP ADC to voltage conversion help."

    I want to read a pot, and convert its ADC10 digital value to voltage. Each step represents .004V. My conversion routine works up through a digital value of 999, but is wrong at 1000 and above. For example a digital value of 903 converts to a voltage of 3.612 (correct), but a digital value of 1007 converts to 4.24V when it should be 4.024V. The PicBasic Pro code follows; please tell me how to correct it. Thanks.

    Code ( (Unknown Language)):
    1. start:
    2. ADCIN 0, left_pot 'Reads analog voltage on AN0, converts it to 10-bit
    3.     'digital value, and stores it as left_pot.
    4. y = (left_pot*4)
    5. whole = y/1000
    6. decimal = y//1000              
    7. LCDOUT $FE,1,"Left Pot = ", DEC left_pot 'Clears LCD screen, displays
    8.     '"Left Pot = " and the decimal value of left_pot.
    9. lcdout $FE,$C0,"Voltage = ", #whole, ".", #decimal
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Decimal is only two digits - the leading zero is lopped off.

    Either lcdout a zero before printing the remainder if decimal < 100, or divide for each digit value and print it out for each decimal place...
     
  3. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    Thanks. Would you show me how to do that division? I can figure out how to print it.
     
  4. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Sure....
    Where result = raw_ADC *4

    Thousands = (result MOD 10000)/1000
    Hundreds = (result MOD 1000)/100
    Tens = (result MOD 100)/10
    Units = (result MOD 10)

    Or there are better algorithms out there...
     
    tracecom likes this.
  5. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    Okay, it is working as I had hoped. I need to study the MOD operator in an effort to understand exactly what's happening.

    On a side note, I have my external reference quite steady at 4.096V as measured with my Fluke 115. When I use that same meter to measure the voltage out of the pot, it is consistently different by .006V from the calculated voltage. Do you have any idea why that is?

    Thanks again for the code help.
     
  6. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Sorry, I shouldn't assume - it is commonly called a mod operator(like the mod counter) and, like the mod counter, is actually the modulus operation (or taking the modulo) - essentially the "//" division you were doing in your code.

    I'm afraid I'm not familiar with your setup, but assuming you are just using the potentiometer as a voltage divider, I would suspect the difference to be from the quantization error of each of the measuring devices.
     
  7. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    I want to be sure I understand how the modulus operation works in my code.

    Code ( (Unknown Language)):
    1. ADCIN 0, left_pot 'Reads analog voltage on AN0, converts it to 10-bit digital value, and stores it as left_pot.
    2. lpot = (left_pot*4)
    3. lthousands = (lpot//10000)/1000
    4. lhundreds = (lpot//1000)/100
    5. ltens = (lpot//100)/10
    6. lunits = (lpot//10)
    If lpot = 3456, then lthousands is calculated as follows.

    3456 is divided by 10000
    quotient is 0
    remainder is 3456
    remainder is divided by 1000
    quotient is 3 (because .456 is truncated)
    lthousands is therefore 3

    Correct?

    Thanks.
     
  8. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Yup, you just need to be careful that the number is an integer type, or is at least truncated properly.

    You don't need to do the modulus on the thousands place since it will never be in the ten thousands digit - you can just divide by 1000 (I put it in for consistency). Of course, leaving it in won't hurt anything but cycle time, but the modulus on the highest digit position doesn't give you any new information.
     
    tracecom likes this.
  9. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    Thanks for the help. It's really nice to know how code works (even if I didn't write it myself.)

    Here's a photo of my test setup. The little assembly toward the top left is my TL431A 4.096V reference circuit.
     
    absf likes this.
  10. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Wow, you really enjoy making modular setups!:)

    I had assumed you wrote it, had I not, I would have been more thorough in my initial explanation, sorry.

    The double dabble approach (the alternative I linked to before) is faster, but not as clear when looking at the code. It doesn't seem like you are too concerned with speed now, but a good thing to know for future endeavors...
     
  11. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    I did write the original that I posted, if one can really say he wrote any code. It's more accurate to say that I cobbled it together from bits and pieces. That's pretty much the way all my code comes together...a bit at a time...with help from people like you.
     
  12. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    From my stint as a software engineer, I'd say that's how all code is written!:p

    The key is understanding what the Frankencode means...
     
  13. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Doesn't the compiler already have a function to convert a unsigned 16bit variable into an ascii text number?

    In C you just use itoa() or WordToString() etc.
     
  14. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    I don't know, but I just posted the question over on the picbasic pro forum. I'll post the answer if/when it comes. Thanks for wording the question for me. :)
     
  15. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    Here is what appears to be the shortest way to what I needed. Thanks to all for your input.

    Code ( (Unknown Language)):
    1. ' Aliases and Modifiers:
    2.  
    3. ' Program Code:
    4. PAUSE 1000 'Pauses 1 second to allow LCD to setup.
    5. start:
    6. ADCIN 0, left_pot 'Reads analog voltage on AN0, converts it to 10-bit digital
    7.     'value, and stores it as left_pot.
    8. lpot = (left_pot*4) 'Multiplies left_pot times 4 to get 1000x voltage.
    9.  
    10. ADCIN 1, right_pot 'Reads analog voltage on AN1, converts it to 10-bit digital
    11.     'value and stores it as right_pot.
    12. rpot = (right_pot*4) 'Multiplies right_pot times 4 to get 1000x voltage.
    13.  
    14. LCDOUT $FE,1,"Left Pot  = ", DEC left_pot 'Clears LCD screen, displays
    15.     '"Left Pot = " and the decimal ADC of left_pot.
    16. LCDOUT $FE,$C0, "Voltage = ", DEC lpot/1000, ".", DEC3 lpot//1000
    17.     'Displays result to 3 decimal places.
    18.  
    19. LCDOUT $FE,$94,"Right Pot = ", DEC right_pot 'Sets LCD to beginning of
    20.     'second line and displays "Right Pot = " and the decimal ADC of
    21.     'right_pot.
    22. LCDOUT $FE,$D4, "Voltage = ", DEC rpot/1000, ".", DEC3 rpot//1000
    23.     'Displays result to 3 decimal places.
     
    Last edited: Jan 5, 2014
  16. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Nicely done! :)

    You've used the ability of the LCDOUT function to display multiple strings in sequence. Neat and clean.

    If I was to find something to criticise, what are the "magic hex numbers" after LCDOUT?
    LCDOUT $FE,$D4

    I assume the second one is the line and column indexing, is the first one a move command? ie; FE=move D4=whereto?

    It would be a nice fix to replace those with text constants if possible. That makes the code easier to read and more importantly easier to write. ;)
     
  17. tracecom

    Thread Starter AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    The $FE indicates that what follows is a control code; the next $XX is the line indicator for the display. Thanks for the compliment, but I got a lot of help. The upside is that I know how to do it now!
     
Loading...