# help

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

1. ### tracecom Thread Starter AAC Fanatic!

Apr 16, 2010
3,925
1,424
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,527
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,925
1,424
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,527
675
Sure....

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,925
1,424
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,527
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,925
1,424
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,527
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,925
1,424
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.

• ###### DSC01567 (lo res).jpg
File size:
101.7 KB
Views:
21
absf likes this.
10. ### tshuck Well-Known Member

Oct 18, 2012
3,527
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,925
1,424
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,527
675
From my stint as a software engineer, I'd say that's how all code is written!

The key is understanding what the Frankencode means...

13. ### THE_RB AAC Fanatic!

Feb 11, 2008
5,435
1,309
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,925
1,424
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,925
1,424
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,309
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,925
1,424
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!