Понятно, спасибо.
Поделюсь идеями/моментами из реализации своего цифрового модуля для ЛБП:
Я сделал на Atmega(168/328) процессоре и семисегментных индикаторах (делал замену индикатору китайского линейного ЛБП).
В канале вольтметра использовал oversampling чтобы получить 12бит / 4096 отсчетов. ОУ/делители подстроены таким образом, чтобы 1 отсчет выходил на 10мВ, в программе микроконтроллера не используются вычисления с плавающей точкой.
Диапазон выходных напряжений моего БП - от 0 до 30В, значение отображается тремя разрядами, с динамическим переключением поддиапазонов по порогам 9.80 В / 09.5 В (т.е 0.00-9.80 В + 09.5-30.0 В).
Канал измерения тока - 10битный, без оверсемплинга, 1 отсчет соответствует 5мА, диапазон БП: от миллиампер (с шагом 5мА) до 5А, значение отображается в поддиапазонах 0-600мА и 0.40-5.00 А.
Оверсемплингом шаг в 1мА на всем диапазоне вытащить не пытался, т.к 12 бит не хватит для измерения 5А.
Но для ЛБП на 3А - можно пробовать.
Опорное напряжение АЦП - 4В на TL431 (также была идея использовать прецизионный ИОН на 4.096В, но в данном случае это было бы излишне)
Запуск АЦП синхронизирован с переключением сегментов динамической индикации (чтобы переключение сегментов не давало помех на процесс измерения). 1 сегмент отображается примерно 2.2мс. (Это дает примерно 75Гц частоту "обновления" экрана из 6 индикаторов).
За это время АЦП делает 16 отсчетов, суммарно этот процесс занимает 1.85мс.
Измерения идут в бесконечном цикле по кругу, измеряется три канала (выходные напряжение, ток, и третий канал - задатчик ограничения выходного тока). Соответственно, каждый канал за секунду измеряется 1000/2.2/3 = ~150 раз (Т.е. за секунду берется 150 * 16 = 2400 отсчетов по каждому каналу).
Полученные 16 отсчетов суммируются и передаются в формулу "скользящее среднее":
average_u = (average_u * (AVERAGE_U - 1) + sum_adc) / AVERAGE_U;
где AVERAGE_U задано как 8 (для каналов измерения токов используется значение 4, подбиралось эмпирически).
Затем из получившегося среднего значения формируется значение для отображения:
- вычитается значение, соответствующее напряжению смещения,
- выполняется деление для приведения значения к нужной разрядности - если измеряем ток - делим на 16, если напряжение - делим на 4.
На случай быстрого изменения измеряемой величины предусмотрен "сброс интегратора".
Накопленное среднее значение замещается текущим измеренным, если разница между ними составляет 60мВ.
Возможно, это излишне, т.к. даже на минимальные изменения реакция быстрая.
В целом я доволен качеством измерений (получилась высокая точность и быстрый отклик), хотя всегда есть что улучшить.
Например, отклик возможно даже слишком быстрый и надо уменьшить частоту измерений, чтобы частота обновления отображаемых значений была 3 обн/сек, как это принято у "старших товарищей".
Но ... =)
Пример кода:
- Код:
static void display_U(uint16_t sum_adc) { #на входе сумма 16 измерений
#define AVERAGE_U 8
static uint32_t average_u = 0;
if ((average_u > sum_adc) && (average_u - sum_adc > 25)) {
average_u = sum_adc;
}
else if ((average_u < sum_adc) && (sum_adc - average_u > 25)) {
average_u = sum_adc;
}
else {
average_u = (average_u * (AVERAGE_U - 1) + sum_adc) / AVERAGE_U;
}
uint16_t display_u = average_u;
//Компенсация начального смещения
//Минимальное отображаемое значение - 30мВ
if (display_u >= (23 + 3 * 4))
display_u -= 23;
else
display_u = 0;
display_u = display_u >> 2; //Получаем значение 12 битной разрядности
[отображаем значение]
}
в целом, если кому-то интересно, могу выложить полный исходник (это только измерительная панель!!, задатчики уставок - полностью аналоговые, индикаторы - семисегментные).