Вольтамперметр на Мега8
- Войдите на сайт для отправки комментариев
Пт, 04/02/2022 - 17:04
Доброго времени. Делаю вольтамперметр для электронной нагрузки. У нее 4 канала с шунтами. Соответственно решил собрать простенький показометр Вольт, Ампер, Ватт (4 канала тока и 1 напряжения). Но вылезла непонятка с АЦП. Почему-то в 0 канале АЦП показания зависят от показаний канала 4 (Вольты). Грешу на код, т.к. при изменении числа отсчетов (строка 31), изменяется и величина этих показаний и равна ADC0 (ток 1 канал) = ADC4 (напряжение) / кол-во замеров. Причем при подключении делителя показания этого канала и "левые" суммируются. Выложил функцию обработки АЦП, переменные. В основном цикле только вывод на дисплей.
#define U_REF 2.56f // опорное напряжение для мега8а (внутренний ИОН или TL431) #define RSH1 0.1f // сопротивление токового шунта 1 линии #define RSH2 0.1f // сопротивление токового шунта 2 линии #define RSH3 0.1f // сопротивление токового шунта 3 линии #define RSH4 0.1f // сопротивление токового шунта 4 линии #define RNVD 3600 // сопротивление резистора делителя напряжения к минусу (Ом) #define RPVD 100000 // сопротивление резистора делителя напряжения к плюсу (Ом) volatile uint8_t messCount = 0; // счетчик кол-во измерений АЦП volatile uint8_t analogPin = 0; // номер входа АЦП volatile uint8_t recovMUX = 0; // переменная для сохранения исходного значения регистра ADMUX volatile uint16_t voltADCTmp = 0; // вр. перем. для получения ср. ариф. АЦП volatile float voltage = 0; // напряжение volatile float amperage = 0; // общий ток volatile uint8_t trueValue = false; // флаг переключения канала АЦП volatile uint16_t ADC_V = false; // отладка volatile uint16_t ADC_A1 = false; // отладка volatile uint16_t ADC_A2 = false; // отладка volatile uint16_t ADC_A3 = false; // отладка volatile uint16_t ADC_A4 = false; // отладка volatile uint16_t voltADCRes[5]; // массив для хранание значений с АЦП (4 линии тока и напряжение) ISR(ADC_vect) { uint16_t result = ADCL | ADCH << 8; // Получаем 10-битный результат if (trueValue) { // 10 измерений для исключения скачков if (messCount < 10) { voltADCTmp += result; messCount++; }// end if else { voltADCRes[analogPin] = voltADCTmp / messCount; // усредняем результат, присваиваем значения с АЦП ячейкам массива voltADCTmp = 0; // обнуляем messCount = 0; // обнуляем analogPin++; // Перебираем входные пины по кругу (А0...А4 - их может быть больше) if (analogPin > 4) { amperage = U_REF / 1024 * (voltADCRes[0] / RSH1 + voltADCRes[1] / RSH2 + voltADCRes[2] / RSH3 + voltADCRes[3] / RSH4); voltage = U_REF / 1024 * voltADCRes[4] * (RPVD + RNVD) / RNVD; analogPin = 0; // Все нужные перебрали...возвращаемся к первому ADC_A1 = voltADCRes[0]; // отладка ADC_A2 = voltADCRes[1]; // для ADC_A3 = voltADCRes[2]; // вывода ADC_A4 = voltADCRes[3]; // на ADC_V = voltADCRes[4]; // экран (1602) for (uint8_t i = 0; i < 4; i++) voltADCRes[i] = 0; // обнуляем ячейки массива показаний АЦП }//end if ADMUX = recovMUX | (analogPin & 0x07); // Устанавливаем новый вход для преобразования trueValue = false; // Устанавливаем флаг смены входного пина - следующее прерывание пропускаем }// end else }// end if (trueValue) else trueValue = true; // Первый раз пропускаем считывание и устанавливаем флаг на чтение в следующий раз }// ISR(ADC_vect)
Возможно ,ошибка в стр.57. Надо не просто добавить новое значение, но и убрать старое, т.е. избежать наложения новых битов на старые через "ИЛИ"
Кто-то забыл прочитать даташит касательно требований ацп по входному току.
Переменная recovMUX содержит исходное состояние регистра ADMUX. Здесь как раз регистру присваивается начальное состояние и через ИЛИ активируется нужный порт АЦП через мультиплексор.
Я думал так :если recovMUX = 0; то не совсем ясно, зачем он нужен. Тогда ADMUX = analogPin;
а если recovMUX != 0; то
При инициализации сохраняю состояние в эту переменную (настройки ИОН, старшие 3 бита), сейчас не смогу код выложить, пишу с телефона.
Для тупых, или слепых, или даже не знаю каких, повторю:
Кто-то забыл прочитать даташит касательно требований ацп по входному току.
Ну да, если только при инициализации, и если при этом первые три бита = 0, то этот вариант отпадает и моё предположение не верно.
Для тупых, или слепых, или даже не знаю каких, повторю:
Кто-то забыл прочитать даташит касательно требований ацп по входному току.
А какие там требования по входному току, если все входы АЦП заземлены? Честно говоря не нашел ничего про ток, но по крайней мере в том дш, который у меня есть.
;)
Заземлены? Ну это же всё меняет!
-------------
Ркит, как всегда, лаконичен не в меру. АЦП в мегах рассчитан на выходное сопротивление источника до 10К. Просто поставь повторитель на 358-ом ОУ и будет счастье! (если 358 подходит, конечно).
В принципе можно переделывать код под высокоомный выход. Но работа будет неустойчивой. Повторитель - проще.
В принципе можно переделывать код под высокоомный выход. Но работа будет неустойчивой. Повторитель - проще.
АЦП в меге не слишком точный, а главное не слишком стабильный. Если уж ставить дополнительные детали, так лучше добавить ADS 1015. Cтоит недорого, меряет гораздо точнее и стабильнее. Есть встроенный усилитель регулируемый програмно. Не шибко быстрый, правда, десятки, максимум сотни выборок в секунду, но для вольтметра больше и не надо.
В данный момент токовые входы заземлены, вход напряжения подключен через делитель 3.6 и 100к, т.е в 10к все входит. Здесь какая-то программная ошибка, которую я не могу найти, т.к. значение 0 канала АЦП ровно в "кол-во измерений" меньше показаний АЦП 4 канала. Т.е. если к примеру на 4 канале 523 и кол-во измерений 10, но 0 канал показывает 52. Если кол-во измерений уменьшаю до 5, то АЦП0 показывает 104. Все остальные каналы также заземлены и стоят на 0. Даже, если подклячаю любой из каналов к делитель, то 4 канал на них никак не влияет, только на 0.
1015 есть, но ставить его на планировал изначально, т.к хочу по максимуму сделать простой показометр, сверх точность мне не нужна.
Если это только для показометр и кроме измерений ниечего особо не делает, то зачем использовать прерывания?
Если же хочется прерываний, то делать внутри него рассчеты с умножением и делением, да еще float, крайне нежелательно. Это надо делать в основной программе по флагу выставленному в прерывании. Иначе рискуете нарваться пропуск прерывания. Что у вас скорее всего и происходит. На какой частоте работает АЦП?
Ну и весь код надо выкладывать. Может там чего не так.
Желательно, после переключения канала, первый результат отбросить.
нобелевка по матетике
нобелевка по матетике
Да там даже не входное важно, оно будет влиять на точность измерения, КМК... От зависимости каналов я бы попробовал двойное чтение, дабы "перезарядить" конденсатор АЦП. Т.е., первое измерение канала отбрасываешь, а со вторым работаешь. Не?
Я имел ввиду, что резистор между выводом и землёй 3.6к, т.е. в диапазон до 10к, укладывается. Как я понял из даташита, это указано для того, чтобы ёмкость вывода успевала разряжаться между измерениями и не влияла на результаты измерений.
Про float в прерывании тоже думал, что ему там не место, но пока вывод у меня через делай сделан, потому пока так. Думаю тоже сделать все расчеты в основной программе, и вообще уйти от прерываний. Никаких обработок кнопок я не планирую, ну может какую-нибудь калибровку при включении. А так, будет просто вывод на дисплей.
ASAM спрашивал - У вас АЦП на какую частоту настроено? Сколько выборок в секунду?
125кГц. Тут, как мне показалось, при переключении каналов АЦП с 4 на 0, переменная 0 канала, хватает 1 измерение 4 канала, но не пойму почему... Попробую поиграться с количеством каналов и последовательностью. Возьму за измерение напряжения 0 канал, а на ток с 1 по 4. И посмотрю, что будет. Такое подключение и частоту АЦП применял уже в нескольких проектах и всё работает нормально(причем там там сопротивление источника напряжение на пару порядков выше рекомендованного 10к), но там максимум 2 канала было
В 54 строке всё правильно?
Ее я уже после добавил - она не влияет не на что. Товарищи, там же даже в комментах есть, что после переключения пропускаем 1 чтение, а потом уже считываем. Т.е. переключили канал, зашли в обработчик, вышли, а на следующий раз уже присваиваем значение АЦП переменной.
Попробуйте перенести переключение каналов в начало блока (до float вычислений).
Перенес обработку АЦП из прерывания, все стало нормально. Теперь все каналы работают, как нужно:
Осталось прикрутить калибровку. Всем спасибо за помощь!