Главная > Программирование, Радиоэлектроника > Мониторинг напряжения батареи в микроконтроллерах AVR

Мониторинг напряжения батареи в микроконтроллерах AVR

При разработке автономных малопотребляющих устройств довольно часто возникает проблема контроля заряда батареи. Существует довольно много проектов, где тупо ставится делитель из двух резисторов на ногу АЦП. Если делитель будет 470к/100к — то при питании от 3В уже выходит ток порядка 5мка. Обычно ставят сопротивление на порядок меньше, что иногда дает ток утечки на этих резисторах соизмеримый со средним током потребления всего устройства.

В современных микроконтроллерах AVR есть недокументированная возможность, про которую почему-то мало пишут в интернетах. Есть возможность в качестве опорного напряжения выбрать AVCC, а в качестве измеряемого — опору Vbg (обычно, 1.1В) В таком случае имеем несколько плюсов: не требуется постоянная утечка тока на делителе, экономится, как минимум одна нога (что очень критично в восьминогих tiny-контроллерах) и не требуется никаких внешних компонентов.
Пока что этот вариант был опробован на МК ATTiny25V. Для вычисления напряжения питания можно воспользоваться слудующей формулой

Uavcc = 1.1*1024/ADC

Конечно, тут требуется калибровка, потому можно не заниматься вычислениями, а просто забить в EEPROM несколько значений, соответствуюзих различным уровням напряжения батареи.
Еще одно важное замечание. Переключение мультиплексора АЦП в таком режиме происходит не сразу, из-за чего первые 5-6 результатов измерения будут недостоверными (в режиме Free-Run). У меня обычно АЦП работает в непрерывном режиме с усреднением. И при переключении входов отбрасываются 1-2 выборки, но в данном случае пришлось отбрасывать 8 первых выборок.
Осталось проверить, как это будет работать на других контроллерах.

комментариев 8 to “Мониторинг напряжения батареи в микроконтроллерах AVR”

  1. maksim:

    Здравствуйте. А можно поподробнее про эту особенность, так как сейчас делаю индикатор разряда и одной ноги нехватает, ресет отключать нехочу так-как нет восстановителя фьюз и программатора HV — и если что то не так то покупать новый.

    Uavcc = 1.1*1024/ADC неясно как происходит замер напряжения. можете указать кусок кода как это реализовать. К примеру так я делаю с внешним делителем.

    int volt;
    volt=read_adc(2);
    volt=(1100/1024)*volt;

    а как сделать без него?

  2. Klim:

    что-то мне сдается, что ваш код будет неправильно работать, потому как (1100/1024) будет давать 1, потому как int.
    У меня АЦП работает на прерываниях, например, для tiny261:

    
    //main:
    	ADMUX= 0x1e;
    	ADCSRA=0xEF;
    	ADCSRB =0x00;
    //прерывание:
    	battery = ADCW;
    

    Собственно, само напряжение меня мало интересует, по этому как в следующей статье — battery сравнивается с некоторыми границами.
    Но если сильно надо именно напряжение, то:

    int voltage=112640/battery;
    //112640 = 1024*1.1*100
    //напряжение будет в 10мв единицах: при 4,2В voltage=4200
    

    также, как я уже писал — если АЦП используется в других режимах, то после переключения на измерение батарейки, следует отбросить 5-8 первых значений — они будт крайне недостоверными.

  3. maksim:

    да код давал неверные значения, я его для примерв привел. я делаю вот так

    unsigned int read_adc(unsigned char adc_input)
    {
    ADMUX=(adc_input & 0x0f) | ADC_VREF_TYPE;
    delay_us(10);
    ADCSRA|=0x40;
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
    }

    ну а затем вызываем
    int volt;
    volt=read_adc(2);
    volt=ADCW;
    volt=volt/0.935;

    int округлит результат и всё 🙂 это я делал с делителем внешним (на ADC2)
    но не пойму как таким образом мерить как в статье, у меня как раз на 25 тиньке нехватает 1 ноги, хотел попробовать ваш способ. Вообще это первая моя прошивка, с прерываниями я не работал хотя представляю себе что это такое.

  4. Klim:

    неправильно это: первом случае оно округлит сразу, в случае, если /0.935 — то тут включается вещественная арифметика, которая не нужна в принципе и может съесть половину флеша.
    Более правильно будет что-то в этом роде:

    batteryLevel = ((long int)1100*adcValue)>>10;
    

    Хотя, не стоит рассчитывать, что опора будет четко 1100мВ.

    Для тини25 надо выставить ADMUX=0x0C; и провести несколько «холостых» измерений.

  5. maksim:

    В протеусе. В реале не вшивал, доберусь до дома тогда в реальный контроллер загоню прошивку и посмотрю, может и протеус некорректно работает с этой особенностью.

Оставить комментарий

Или