Измерение Vcc
- Войдите на сайт для отправки комментариев
Сб, 13/02/2021 - 17:48
Стоит задача мониторить состояние Vcc на Mega. В сети нашел код, код рабочий. Судя по описанию, в качестве опорного напряжения выбирается Vcc и измеряется внутреннее напряжение 1.1В. Из этого и вычисляется само Vcc.
long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif delay(75); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA,ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high<<8) | low; result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts }
Однако в проекте используется библиотекa Blynk. И похоже с ее таймером код конфликтует. По крайней мере, после команды timer.run(), код стабильно выдает -1.0
Насколько я знаю, таймер от Blynk аналогичен библиотеке SimpleTimer. Он меняет значение analogReference?
Как их подружить?
Насчёт конфликта Ваших библиотек ничего сказать не могу, а вот VCC Вы таким кодом измерите с точностью ±10% и не лучше. Почитайте статью Ника Гэммона о том, как это делать правильно.
Что же до библиотеки, не думаю, что она меняет refference. Скорее, проблема в чём-то другом. Но, поскольку код секретный, ничего сказать не могу.
Насчёт конфликта Ваших библиотек ничего сказать не могу, а вот VCC Вы таким кодом измерите с точностью ±10% и не лучше. Почитайте статью Ника Гэммона о том, как это делать правильно.
Что же до библиотеки, не думаю, что она меняет refference. Скорее, проблема в чём-то другом. Но, поскольку код секретный, ничего сказать не могу.
ссылку на статью дайте пожалуйста.
ссылку на статью дайте пожалуйста.
Там поищите поиском заголовок "Detecting low voltage".
Код брал отсюда.
10% меня устраивает. Плюс есть возможность калибровки для конкретной платы. Мне важно отследить понижение Vcc, так как есть подозрение что радиатор на LM7805 не справляется. Короче, ищу причины нерегулярных перезагрузок девайса иногда и через сутки работы. Код не секретный, но оочень длинный 2300 строк, соответственно не особо оформленный для демонстрации. Мне такое выставлять слегка неудобно, хотя и не жалко. Но и вам копаться в таком стогу вряд ли захочется.
На первом выводе результат нормальный, на втором -1.0
Библиотеки
Подскажите хоть пути решения нужной задачи.
Подскажите хоть пути решения нужной задачи.
Ну, я уже попытался подсказать, но Вы же не хотите.
Путь тут один, взять Ваши 2300 строк и последовательно кусок за куском выбрасывать лишнее до тех пор пока проблема не исчезнет. Как только исчезнет, восстановить последнее выброшенное, убедиться, что проблема появилась снова и пытаться выбрасывать что-то другое. Этот процесс продолжать до тех пор, пока в коде не останется строк 20-30. Тогда проблема станет очевидной, а если не станет, то уже тот код (из 20-30 строк) выложить сюда, чтобы любой желающий мог воспроизвести проблему и попытаться понять её причины.
Я всегда так делаю (вернее наоборот - я никогда не пишу 2300 строк без того, чтобы по ходу дела проверять каждый новый кусок в пару десятков строк и добавлять его только тогда, когда в нём уверен). Других путей не знаю.
Ок. Думал, что приведенный пример достаточно локализует проблему. Походу, для начала надо будет выковырять все таймеры, которые изобильно разбросаны по коду. Как сделаю, отпишусь.
Ок. Думал, что приведенный пример достаточно локализует проблему.
Ну вот, очевидная мысль, что после команды timer.run() начинают выполнятся мои таймеры, содержание которых и приводят к конфликту, меня сразу не посетила.
Ошибка возникает из-за подпрограммы, которая выполняется раз в 500мс, и в которой три команды analogRead(). Выполнение любой из них и приводит к ошибке. Если убрать все три - результат верный. В Setup стоит analogRefenece(default). Код все еще нужен?
Код все еще нужен?
Коллеги, вам как? - мне не нужен
ТС, можете выкидывать...
Ок. Считаю это за тонкий вежливый намек.
И что?
Расскажите, что с этим кодом не так?
Что он, по-Вашему, должен делать? Что реально делает? Чем отличается одно от другого?
Там в комментах вроде указано. Результат функции readVcc должен показывать соответственно Vcc. Что и показывает в строке 11.
Но после запуска таймера, результат -1 ( в строке 44 ). Причина - в выполняющейся команде analogRead() стр.15
Leopoll - это троллинг?
- Вы взяли низкоуровневый код для ADC чипов АВР, запускаете его на ЕСП и спрашиваете "Что не так?"
Запускаю на Меге. Esp там отдельно болтается и примере не используется. Поскольку таймер используется встроенный в Blynk, то и библиотеки в примере ихние.
Запускаю на Меге
тогда я бы после строки 33 добавил маленькую задержку (2-5мс) и еще одно чтение из АDc - скорее всего , со второго раз должно выдаваться правильное значение
В низкоуровневневом коде плохо понимаю. Чтение из ADC это и есть строка 33? Если да, то не помогло.
Библиотек Blynk в природе более, чем одна. Дайте ссылку на ту, которую Вы используете. И вообще, на всё, чтобы можно было у себя запустить.
Чтение из ADC это и есть строка 33?
нет, 31-33
и выложите полный код после исправления
первую библиотеку убрал - не используется.
Blynk - последней версии 0.6.1
и как - работает?
Найн. Нихт. Результат тот же.
А каким образом вы скрестили ежа с удавом? Как у вас мега передает данные в Blynk?
В данном примере никак. В исходном коде через модуль Esp.
Возможно дело в том, что в мега 2560 имеется 16 аналоговых входов и для включения с ADC8 по ADC15 используется дополнительный бит в регистре ADCSRB. А поскольку на 1.1 v вы переключаете руками, то бит в регистре ADCSRB не сбрасывается, и вы читаете из несуществующего входа. Я бы написал, что уверен, что дело в этом, но проверить не могу.
.
Если напишите как его сбросить и в каком месте кода, я бы проверил.
В ваших рассуждениях не увидел на что влияет analogRead(), а ведь именно после этой команды код выдает неверный результат.
Если напишите как его сбросить и в каком месте кода, я бы проверил.
В ваших рассуждениях не увидел на что влияет analogRead(), а ведь именно после этой команды код выдает неверный результат.
Если бы вы написали в вопросе не analogRead() а analogRead(A10) ответ бы был более очевиден А10 > A7 и для его включения используется бит MUX5 в регистре ADCSRB. Надо добавить сброс этого бита. Или измените analogRead(A10) на analogRead(A1) и проблема должна уйти.
ОБНОВЛЕНО - написанное ниже неверно: analogRead(30) использовать нельзя.
Судя по описанию на мега 2560 analogRead(30) должно считывать напряжение источника 1.1. Можно попробовать вообще отказаться от readVcc() а дважды читать analogRead(30) с паузой между вызовами и брать результат второго вызова. Паузу между вызовами подобрать экспериментально.
ОБНОВЛЕНО - написанное выше неверно: analogRead(30) использовать нельзя.
Или измените analogRead(A10) на analogRead(A1) и проблема должна уйти.
Полностью подтвердилось.
дважды читать analogRead(30) с паузой между вызовами
Походу работает и с первого раза. Или все таки лучше сделать два?
ОБНОВЛЕНО - написанное ниже неверно: analogRead(30) и analogRead(31) использовать нельзя.
Попробуйте без цикла в тестовой программе сначала прочитать analogRead(31) - это чтение напряжения 0. Потом несколько раз analogRead(30) и на каком разе результат перестанет расти, или растет на устраивающую вас погрешность, там и остановитесь.
Для интереса можно сделать тоже самое но вместо analogRead(31) сделать analogRead(пин подключенный к 5В) тогда последовательные чтения значения analogRead(30) должны уменьшаться.
Я не использовал измерение 1.1 поэтому своего опыта у меня нет, но читал, что у источника 1.1 очень малая нагрузочная способность и с первого раза он может не зарядить целиком конденсатор АЦП.
ОБНОВЛЕНО - написанное выше неверно: analogRead(30) и analogRead(31) использовать нельзя.
Можно поправить readVcc() Добавить строчку сброса MUX5
ADCSRB = (ADCSRB & ~(1 << MUX5));
перед
delay(75); // Wait for Vref to settle
А вот это уже для меня за гранью. В тестовом примере analogRead (30) выдавало правдоподобный результат. Абсолютно то же самое, перенесенное в основной скетч выдает результат примерно ( а может и точно ) в два раза больше.
ADCSRB = (ADCSRB & ~(1 << MUX5)); работает.
Я ошибся когда предлагал использовать analogRead(30) и analogRead(31)
Так делать нельзя.
Дело в том что в функции analogRead(uint8_t pin)
есть строка в которой "нижний" адрес канала ограничивается тремя битами.
ADMUX = (analog_reference << 6) | (pin & 0x07);
и MUX5 рассчитывается в этом случае тоже не верно.
Спасибо. Тогда самое лучшее использовать все таки функцию readVcc? Теперь она работает. Ей задержки не нужны?