ADC high DC voltage with a PIC

Discussion in 'The Projects Forum' started by El3ctroded, Sep 12, 2009.

  1. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    I'm using a PIC16F883 and need to do analog conversion on a 48V battery pack.

    I thought that I could use the +Vref pin of the mcu connected to +12v, and then a 36V Zener on the 48V pack to give me a range of 48V-36V=12V, so that it could read the battery pack from 36-48V.

    However, I'm having problems. I assumed that the +12V to the +Vref pin would work, however because of some weird things happening, I'm beginning to fear that the +Vref cannot be more than Vcc, which is 3V in my case... Is that true?

    If that is true, How do I measure a 12V swing from a 48V pack?

    I'm stuck and on a deadline! Help please!
     
  2. steinar96

    Active Member

    Apr 18, 2009
    239
    4
    You could perhaps use a op-amp with gain smaller then 1 to scale the signal down to level the pic is capable of measuring.
     
  3. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    If you connected 48 volts to the PIC is probably damaged. You will need to scale the 48 volts down so that it is not greater than the Vcc of the PIC.

    hgmjr
     
  4. SgtWookie

    Expert

    Jul 17, 2007
    22,182
    1,728
    It is virtually certain that you have destroyed either your PIC, the Zener, or both.

    Vref can't be higher than the PIC's supply.

    If the 48v battery bank is made up of lead-acid type batteries, the voltage across them during charge may reach 56v or even higher; you will have to plan for that.

    A 22k 1/4W resistor connected to V+ in series with a 1.2k resistor to ground will give you a voltage divider that will output 2.897v when 56v is applied. Use metal film resistors for greater accuracy and less noise. You will need to use a 10nF to .1uF cap from the junction of the resistors to ground to eliminate resistor noise, and to provide a low-impedance source for the ADC in the PIC. Current in the voltage divider will be a tad over 2.4mA after the cap is charged. If you want lower current consumption, increase the size of the resistors, but you will need to increase the time between sampling the voltage level as it will take longer for the cap to charge.
     
  5. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    I was afarid of that; In any event, Vref seems almost useless if it can't be higher than the supply voltage...

    I had the zener reverse biased with a 10k resistor between the zener and the analog input, as well as a 10k between the +12V and the +Vref, so I doubt I fried anything.

    Sgt Wookie:
    The mcu's datasheet says to keep the input impedance for the analog pins to a maximum of 10k ohms. So will that 22k resistor cause a problem? Or is that what you were referring to by saying that the cap would provide a low-impedance source for the ADC input?

    Is this what you meant:
    Code ( (Unknown Language)):
    1.  
    2.          22k         1.2k
    3. +48V-----VVVV--------VVVVV----GND
    4.                  |
    5. to Analog Input__|---------|(------GND
    6.  
     
    Last edited: Sep 12, 2009
  6. SgtWookie

    Expert

    Jul 17, 2007
    22,182
    1,728
    It might seem that way at first glance. However, you can use the Vref input to supply a voltage from a precision voltage source that's isolated from the noise on the uC's Vdd input. You can get much more accurate readings that way.

    OK, the uC (PIC) very likely survived then. PIC I/O pins have protection diodes, but they're limited to <10mA current. Even if the Zener was shorted, you would've had less than 5mA current flowing through the protection diodes.

    That is precisely what the cap is for; to present a low impedance source to the ADC in, as well as to eliminate any resistor noise.

    You should not perform an ADC read more frequently than once per millisecond to ensure that the cap is fully charged.

    Yes, that's what I meant.

    If you really want to, you could use a 10k 1W resistor on top, and a 510 or 560 Ohm resistor on the ground side. However, that will increase the current drain to about 5.33mA from 2.4mA, and heat from the 10k resistor will be more than double than the 22k resistor.
     
    Last edited: Sep 12, 2009
  7. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    Ah, Ok, now I understand Vref.

    Timing won't be an issue, it already has more than enough delay built-in with the state-machines and software timers...

    Thank you very much for the (as always) very informative posts. It really helps clear up a few things, and thankfully, doing this the "right" way requires very minimal changes! (PCB was already laid out). I've used microcontrollers a LOT, just never the ADC on high voltages before.

    One last thing ADC: If I wanted to use a thermistor with the adc port, how do you think would be the best way? I purchased a couple to play with, PN NTCLE100E3103JB0 from Digikey. Looking at the datasheet, if I understand it correctly, the resistance ranges from 182.6ohms at 150degC to 332094ohms at -40degC, and is a nominal 10kohms at 25degC. I thought maybe to do a voltage divider like so: +3v to a 10k resistor to the thermistor to gnd, and take the signal between the 10k and the thermistor to the ADC, and a 0.1uf cap on the adc pin:
    Code ( (Unknown Language)):
    1.  
    2.           10k       thermistor
    3. +3v-----VVVV--------XXXX-----gnd
    4.                |
    5. ADC------------|---|(-------gnd
    6.  
    That sound about right?

    El3ctroded
     
    Last edited: Sep 12, 2009
  8. mik3

    Senior Member

    Feb 4, 2008
    4,846
    63
    Vref is not useless. If you want to read a voltage of 1V maximum with the ADC you can set Vref=1V and achieve a higher resolution.

    For example, if your ADC is 10 bits and

    1) Vref=5V

    then resolution =5/(1024-1)

    2) Vref=1V

    then resolution =1/(1024-1)

    As you can see the resolution is multiplied by 5.
     
  9. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    Yes, I knew it was usable for a smaller voltage, which was the reason I said "almost useless". Another reason for the statement is that I suspect that the vast majority need adc for higher voltages than the vcc for the chip, not somewhere between Gnd and Vcc, wouldn't you agree? Well, it's a non issue, thanks to Sgt Wookie.

    I guess everyone missed the questions about the temperature sensor, from my last post?
     
  10. SgtWookie

    Expert

    Jul 17, 2007
    22,182
    1,728
    You could use an NTC thermistor if you wanted.
    They don't have a linear response curve. You could either connect them in parallel with another resistor to get a portion of the curve linear, or you could generate a large table of values or derive a formula to add into the PIC programming to convert the thermistor value to a real value.
    Vishay has curve calculators available on their website:
    http://www.vishay.com/thermistors/curve-computation-list/

    Another option is to use a dedicated temp sensor, like an LM34, LM35, LM134, LM135, LM335 and others.

    You probably know that you will need to measure the internal temp of the battery bank to determine what the actual charge state is. The easiest way to get the internal temp is to put the temp sensor in physical contact with the positive terminal.

    Battery internal temp is very slow to change, unless they are being charged/discharged at a high rate. It takes quite a while for the temp to come down after they are heated. Internal chemical activity increases greatly when they are warm, which shortens their life considerably. Charging at low current (6 amps or less) is a good way to keep them from getting hot rapidly.
     
  11. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    Thanks, got that working, even the temp sensor and a horribly long derived formula ;) to calculate the temp.

    Now I've got an odd problem. I have a function that writes to the EEPROM that I have used in the past, and it works, never made a change to it.

    Now, my code initiates a write to the EEPROM from a received serial command. Receiving the serial command works, because if I replace the call to write to the EEPROM with a command to turn on an LED, it works perfect. However, as soon as I write to the EEPROM, the serial port stops working! It will not receive or transmit!

    I thought it may be something wrong with the parts or board, so I built up another board and have the exact same problem. I'm at my wit's end with this problem! I've done everything I can think of, including disabling the serial port and re-enabling it, commenting out vasts sections of code, checking the errata on the 16F883, all to no avail.

    Any ideas?
     
  12. SgtWookie

    Expert

    Jul 17, 2007
    22,182
    1,728
    Just a guess, but it could be an addressing problem.

    You're not giving us much to go on.
     
  13. El3ctroded

    Thread Starter Active Member

    Feb 4, 2008
    63
    0
    Nope, I've taken that possibility out of the equation by hard-coding in a 0x10 as an address and 0x50 as data.

    I have a function called WriteEEPROM that accepts an address byte as a uint and an data byte as another uint. This function is identical to Microchip's recommendation in the datasheet, except it's in C, and I have all interrupts turned off so I'm polling the WR and EEIF bits to determine when the write is complete, and yes I clear the EEIF bit once it gets set.

    My serial receive code is also taken from other projects that work. It was modified some, but all that tests Ok. I've used this chip quite a bit before, but I've never tried to do serial IO and write to the EEPROM before on this chip.

    I've been working on this piece of code off and on for two days, and finally found a workaround tonight, which I put in a function called resetSerial().

    Following is what I had to do; all of it may not be necessary, but I am afraid of touching the code now that it's working!

    1) After writing to EEPROM, I disabled the serial port transmitter (TXEN=0), receiver (CREN=0), and uart (SPEN=0), and set SYNC=1.
    2) I then paused for 10ms. (shorter delay may work, but for me 10ms didn't matter).
    3) I then re-wrote all serial port initialization registers: WUE=0, BRGH=1, BRG16=0, SPBRGH=0, SPBRG=0x89.
    4) I then re-enabled the serial port: TXEN=1, CREN=1, SYNC=0, SPEN=1.

    After completing that, it works.

    Now you're likely thinking that I've inadvertently altered one of those registers in code, but I've run searches on my entire program looking for each and every one of those registers or bits, and I only reference them in my init() function (which is the first thing called from main to setup the chip) and now in my resetSerial() function, so they're not being altered by some spurious code. I've also got the watchdog running, and am not getting spurious resets.

    I think I may have found a bug in the 16F883... I'm going to report my complete configuration to Microchip and see if they can duplicate the problem.

    Thoughts? Opinions? Criticism?
     
Loading...