# Measuring negative voltages with a PIC

Discussion in 'Microcontrollers' started by bigal_scorpio, Jul 3, 2012.

1. ### Mr RBWell-Known Member

Joined:
Jul 22, 2008
Messages:
4,716
Likes:
194
Location:
Out there
Hi BigAl if you are talking about using the voltage divider referenced to Vdd 5v the math should be quite easy.

The voltage measured by the divider->ADC will be referenced to +5v.
-12v in = 17v less than ref
-5v in = 10v less than ref
as you can see there is an offset of 5v you need to subtract from both ADC values.

Then you just scale the result with one scaling value (which fixes the resistor divider and also convers ADC units to real volts in one scaling operation).

The easy way is to setup the divider and connect it to 0v, it will display the ADC offset which you can then subtract. Then connect it to -12v etc and display the result, and that gives you the scaling factor.

If you want to work it all out in math first before trimming it then you need to provide the Vref voltage and the 2 resistor values. But you may still need to trim the values later in testing anyway.

Last edited: Jul 4, 2012
2. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Giys,

At the moment I am swayed towards the op-amp design as it means I can use my original board and math with no offsets and such. With that in mind I have been looking through my components for a good while and am missing one part.

Eric, a quick question. The nearest zener I have is 18v instead of 17.5v. Will this make any significant difference to the circuit or readings?

Al

3. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,240
Likes:
645
Location:
Ex Yorks' Hants UK
ONLINE
hi Al,

The 18Vzener will be fine., no change to readings.

E.

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

5. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England

Hi to all,

Thanks to you guys I now have a functioning unit. Though its not yet quite finished it is near enough that I can use it again, its been a pain since I stripped the original PSU, no power source to try things on etc.

Anyway below is my code that is working just about perfectly, though I am open to suggestions on how to tweek the conversion values in code better.

Thanks again to all you guys and please advise me how to go about linking this finale to the other two threads I started that are connected to this subject, just so anyone reading any of them could see that the hard work put in was not for nothing.

PS. Photo's will follow, as soon as the wife gets the camera out I promise.

Al
Code (text):

'****************************************************************
'*  Name    : 16f872 multi ADC.BAS                              *
'*  Author  : Platform = PicBasicPro Program written by BigAl   *
'*  Notice  : With help from many, too numerous to list         *
'*          : No Rights Reserved                                *
'*  Date    : 18/06/2012                                        *
'*  Version : 3.0                                               *
'*  Notes   : Program to display both negative and positive of  *
'*          : PSU 15-0-15                                       *
'****************************************************************

DEFINE OSC 8

' Define LCD pins
Define  LCD_DREG        PORTB
Define  LCD_DBIT        4
Define  LCD_RSREG       PORTB
Define  LCD_RSBIT       2
Define  LCD_EREG        PORTB
Define  LCD_EBIT        3

' Define ADCIN parameters
DEFINE  ADC_BITS        10      ' Set number of bits in result
DEFINE  ADC_CLOCK       3       ' Set clock source (3=rc)
DEFINE  ADC_SAMPLEUS    50      ' Set sampling time in uS

TRISA = %00000111
'  variables
posval       var     WORD
negval       var     WORD
static       var     WORD
adval        Var     Word       ' Create adval to store result

ADCON1 = %10000010      ' Set PortA  to A/D inputs

Pause 100               ' Wait for LCD to start

Goto    mainloop        ' Skip subroutines

' Subroutine to read a/d converter
PAUSEUS 50                      ' Wait for A/D channel acquisition time
ADCON0.2 = 1                    ' Start conversion
WHILE ADCON0.2                  ' Wait for it to complete
adval = (adval */ 500)>>2        ' Equates to: (adval * 500)/1024
WEND
Return

' Subroutine to get pot x value
getposval:
ADCON0 = \$49            ' Set A/D to Fosc/8, Channel 0, On
posval = (adval * 41)
Return

' Subroutine to get pot negval value
getnegval:
ADCON0 = \$41             ' Set A/D to Fosc/8, Channel 1, On
negval = (adval * 46)
Return

' Subroutine to get static value  : not implemented yet
getstatic:
ADCON0 = \$51            ' Set A/D to Fosc/8, Channel 2, On
Return

mainloop:
Gosub   getposval            ' Get + value
Gosub   getnegval            ' Get - value
'Gosub   getstatic           ' Get 5v value

LCDOut \$fe,1,"POS Volts= ",DEC (posval/1000),".", DEC3 posval   ' Display the decimal value
LCDOut \$fe,\$c0,"NEG Volts= ",DEC (negval/1000),".", DEC3 negval ' Display the decimal value

Pause   200             ' Do it about 5 times a second

Goto    mainloop        ' Do it forever

End
Pics as promised.

The centre knobs will eventually be the same as the others and will control what the display shows, current or voltage, rail to rail voltage etc. Just need a bit more work on the other bits.

The front panel is entirely cut by hand, well a stanley knife anyway and will be having decals on it to show what the knobs and switches do. There will also be a couple more switches somewhere to turn off various parts of the PSU when not required as cleverly suggested by Eric Gibbs.

Well I hope that you all think the pain of teaching me things was worth it and thanks again to all.

Al

PPS. I've been waiting about 4 years to use that neon illuminated mains switch I got from RS and this seemed just the right project!

Last edited: Jul 6, 2012
• Like x 1
6. ### languerActive Member

Joined:
Oct 26, 2010
Messages:
193
Likes:
25
Location:
Arizona
Kudos for an excellent project. If you still have some energy left and some sleepless nights , document your progress/steps in the Blog section (or Article section). It allows you to show all the steps you took, assumptions, pitfalls, etc.

7. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,240
Likes:
645
Location:
Ex Yorks' Hants UK
ONLINE
hi Al,
Nice looking Bench PSU, I didn't realise you were so close to having it finished.!

Lets know how the 5V current sensing circuit/display turns out.

E.

8. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Eric and languer,

Thanks for the compliments guys. This is part of a sort of vision I had some time ago that started because my old PSU was such a weird and awkward shape. It also has to do with the fact that my old one didn't have a display until I made an LED 4 digit one and fitted it into the front. The only problem with that was that it probably used more power than most of the projects I build! hehehe

So the idea for a new supply was born! Using most of the parts inside my own and the majority of the controls and switches I drew one up. The only things I omitted were switches for each rail as Eric suggested, but that was soon cured last night by putting them on the back.

There are a few cosmetic touches to finish like all the legends etc. What I would like is comments on my code and ideas on integrating the other features I envisioned like cooling and summing. The summing is simple enough once I fine tune the actual ADC readings.

One question I would like to ask is if there is an accepted way in the community of multiplying by decimal points I.E. in my code I multiply by 41 and 46 to get the conversion when it should ideally be 41.2 and 46.33?

Though the integer gives reasonable accuracy I would like to get it exact. How do you do it?

Anyway guys I' off for a joyful half hour of bathroom cleaning with She who must be obeyed! So have a ponder on my code and stuff and give me some options of how to do the things I've done but better!

BTW here is my original drawing of my PSU and its displays, you can see how I intend to show the details etc.

Al

9. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,240
Likes:
645
Location:
Ex Yorks' Hants UK
ONLINE
Hi Al,

One option, if your Basic allows, is to multiply the ADC count value by 10 [ or a 100] , then do your 'sums' .

Insert the decimal point in the appropriate position in the display, to 'divide' the result by 10 or 100.

E

10. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Eric,

Doh! I seem to always miss these obvious bits. Strangely enough I have done a similar thing to put the decimal point in too.

What do you think of the four display options? Have I missed anything or could I have used better names etc?

Al

11. ### Mr RBWell-Known Member

Joined:
Jul 22, 2008
Messages:
4,716
Likes:
194
Location:
Out there
To multiply by 46.33 you can multiply by 4633, then keep the data stored at that same *100 resolution until you need to display it.

Then if you need to display rounded to the integer (need to divide by 100) you add half the divisor before dividing down, which will round up or down to the nearest integer;
blah = 4633;
final_int = ((blah + 50) / 100)

If you are after accuracy in the display you should multiply up using the largest value you can to make use of your variable's maximum size. If you are using a 32bit var that can go up to >1billion, and your max ADC value is 1023, you can use a multiplier like 463333 (and your data will be stored with a resolution *10000).

Last edited: Jul 7, 2012
12. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Roman,

This is not a dig mate but I just don't get the add half divisor thing at all. Doing that gives 46.83 instead of without it 46.33. How is that rounding the integer? I could have understood it if the formula gave a result of 46.3 that to me would be rounding off.

Al

13. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi to all,

Eric. A quick question mate. Since the op-amp I used for the neg sense is a dual one can I use the other side of it for measuring the current on the 5v rail. I am just worried that it would then have a 23v supply rather than the 8v on the schematic. Would this make any difference to the result or is it even possible?

Al

14. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,240
Likes:
645
Location:
Ex Yorks' Hants UK
ONLINE
hi Al,
The OPA will be OK with a single 23V supply.

E.

15. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Eric,

I have just made and tested the 5v sense circuit and I am getting some strange results.

At 1A load I set the ADC pot to give 4.8v but when I unhook the load the reading goes up slightly to 4.9.

What should I be expecting at any particular place? If there is anything I can check to find the problem let me know.

I think the circuit is as your schematic. I have checked and rechecked it and find no errors. Any ideas mate?

Al

16. ### Mr RBWell-Known Member

Joined:
Jul 22, 2008
Messages:
4,716
Likes:
194
Location:
Out there
Hi Al, adding half the divisor rounds up or down to the nearest integer;
4600 +50 / 100 = 46.50 (integers always round down to); 46
4649 +50 / 100 = 46.99 (integers always round down to); 46
4650 +50 / 100 = 47.00 (integers always round down to); 47
4699 +50 / 100 = 47.49 (integers always round down to); 47

Last edited: Jul 8, 2012
17. ### languerActive Member

Joined:
Oct 26, 2010
Messages:
193
Likes:
25
Location:
Arizona
This is one of those old numerical tricks in software computing. Before floating point processors and all that jazz, to round up or down you would simply add 5 to the resolution you were trying to achieve. Just like Roman showed it.

If you want to round to the nearest integer; you want to make sure that you break into the next integer boundary for anything half way there or more.

As an example:
39.4 and 39.5 would both be represented in integer as 39; rounding to the nearest integer
39.4 + 0.5 = 39.9 is still integer 39;
39.5 + 0.5 = 40 which is integer 40. Notice the rounding effect.

If you want to round to the nearest 1st decimal place: 39.54 and 39.55
39.54 + 0.05 = 39.59; rounded to the nearest 1st decimal place is 39.5
39.55 + 0.05 = 39.60; rounded to the nearest 1st decimal place is 39.6

Now to do all this in integer logic; you need to convert the fractional part into integer and carry it all the way through until you're ready to display it. The easiest way to do this (if you have enough numerical resolution to carry this through) is to multiply by the number of decimal places you require. That is: if you need one decimal place you multiply everything by 10 and perform all your calculations in this new numerical system; when you're ready to display it you can get the integer by dividing by ten and the decimal by using the modulus. The same goes for two decimal places - multiply by 100, calculated everything, and at the end divide by 100 (and modulus if you require decimal places). If you need to round; you do the rounding on the new number system (i.e. after the multiplication and before the final division).

18. ### ericgibbsWell-Known MemberMost Helpful Member

Joined:
Jan 4, 2007
Messages:
21,240
Likes:
645
Location:
Ex Yorks' Hants UK
ONLINE
hi Al,
If you recall I did point out [ in the MAX IC posts] as you are using a 0.1R as the series sense resistor, it will drop 0.1 volt when passing a 1 amp current into the external load, so the output voltage across the load would fall by 0.1 volt.

When you remove the 1 amp load, there will be no voltage drop across the 0.1R sense resistor , so the output voltage will rise by 0.1 volt , to 4.9V

The only way to 'reduce' this voltage drop would be to reduce the Rsense to say 0.01R, in that way you would only lose 0.01V at 1 amp loading.

Problem with that is that Vadc would would be only one tenth of its present value.

If you you have a 0.01Rsense resistor, let me know and I will try to modify the OPA circuit.

Eric

19. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Morning Eric,

If Maplin have a 0.01r I will pick one up today.

Al

20. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi Roman and Languer,

I think I get it now guys. I have never heard of it before and I was overthinking it. I was thinking it involved the decimal points too not just the integer.

Al

21. ### bigal_scorpioActive Member

Joined:
Oct 6, 2007
Messages:
1,072
Likes:
4
Location:
Rotherham South Yorkshire England
Hi again guys,

Eric,

I have just made a 0.01r resistor. It does have a small inductance of 0.7uH, will this be a problem?

Al