Очень точный вольтметр на arduino
- Войдите на сайт для отправки комментариев
Похожих тем много, но у меня возникла необходимость измерять постоянное напряжение с высокой точностью. Имеющийся Fluke 17B меня не устраивал, нужный мне прибор стоит дорого. Поэтому покопал интернет и сделал свой. Корпус от китайца. Индикатор 16х2 I2C. Дуина Nano V3. И главная деталь "автомобиля" - 24 битный АЦП с хорошим источником опорного напряжения на борту, куплен с ebay. Название модуля LTC2400 24bit analog to digital converter ADC module temp sensor SPI AVR arduino. Стоимость тысяча рублей. Кому интересны весьма приличные характеристики этого модуля, поиском на ebay, и внизу в описании товара есть ссылка на документацию. Получился вольметр с одним диапазоном измерения от 0 до 17 вольт. При постройке прибора потребовался более менее хороший источник опорного напряжения желательно с невысокой ценой (1000 руб) , и он был найден и куплен там же на ebay. Имеет четыре переключаемых опорных напряжения. Купленый источник опорного напряжения и мой вольтметр были проверены на служебных Fluke с ценниками от самолетов. Я остался доволен. Пять знаков после запятой совпадают. Шестой знак я программно убрал, из за неверного его измерения связанного с паразитной емкостью измерительного канала. Написание софта не представит сложности для начинающего ардуинщика.
Так выглядит вольтметр.

Замер напряжения на Li-Pol аккуме.

Так выглядит АЦП 24 бит с опорником.

Это китайский источник опорного напряжения на 2.5 5.0 7.5 10.0 вольт. Удобен для настройки всякой всячины.

На тыльной стороне китайца напряжения измерянные на заводе изготовителе.

Ну и конечно же данные можно передавать в компьютер по USB.
Если кому будет полезен мой опыт, то удачных проектов!
если не секрет зачем такая высокая точность? что за прибор такой
Ай, яй, яй.. поставили такую хорошую начинку, а корпус всё портит. Уж можно что-то готовое было в чип-дипе взять, коли способностей корпуса клеить нет.
Тоже уже давно вынашиваю идею подобного девайса, но пока что всё ещё балуюсь:
0..3.3000 В, но всё это несерьёзно, ибо программное растяжение разрядности.
... программное растяжение разрядности.
Поясните, пожалуйста, что это значит?
... программное растяжение разрядности.
Поясните, пожалуйста, что это значит?
http://arduino.ru/forum/proekty/mnogokanalnyi-voltmetr-c-lcd-displeem-na...
К сожалению оверсэмплинг имеет два существенных недостатка:
1. Абсолютно беспомощен против систематической ошибки, уменьшая лишь случайную.
2. Случайную погрешность он тоже снижает гораздо в меньшей степени, чем, как правило, считают те, кто его применяет. Например, по указанной выше ссылке утверждается о "соответствии 14-битному АЦП", что сразу вызывает вопрос: А по какому именно параметру соответствует?
[quote=mik.
Так выглядит АЦП 24 бит с опорником.
Это китайский источник опорного напряжения на 2.5 5.0 7.5 10.0 вольт. Удобен для настройки всякой всячины.
На тыльной стороне китайца напряжения измерянные на заводе изготовителе.
Если кому будет полезен мой опыт, то удачных проектов!
[/quote]
Если возможно - адреса магазинов этих девайсов.
Привет всем. Прикупил такойже ацп но не могу залить стандартный скетч для просмотра напряжения в мониторенге порта.
Подчеркивает строчку b0 = SPI_read(); // read 4 bytes adc raw data with SPI
И выдает ошибку Arduino: 1.6.10 (Windows 10), Плата:"Arduino Nano, ATmega328"
C:\Users\РЃР¶РёРє\Desktop\LTC2400\Arduino sketch\LTC2400_ADC_Serial_out\LTC2400_ADC_Serial_out.ino: In function 'void loop()':
LTC2400_ADC_Serial_out:71: error: 'SPI_read' was not declared in this scope
LTC2400_ADC_Serial_out:98: error: 'printFloat' was not declared in this scope
exit status 1
'SPI_read' was not declared in this scope
Может кто сталкивался ?
Dron_S я бы русские буквы из путей убрал, для начала
Куда такая точнось? неужели последние разряды не бегают при измерении к примеру лития ?
// есть гораздо распространенные варианты точных АЦП , к примеру MCP3421 - 18бит , корпус sot23-6 , 3в мериет до 4го знака
стоимость на али за 10шт около 500руб. используют в дешевых точных волтметрах 0-3.0000 здесь
по форуму много есть по поиску MCP3421
Привет всем удалось победить данную проблему установкой Arduino: 1.6.08, может еще винда 10-я забитая всякой хренью. Но возникла другая проблема. После заливки программы в мониторинге порта показывает 2,051343 Вольт, но никакой источник питания не подключен. Если подключить 1,5 вольтовою батарейку то показывает точно 1,5 и т.д. все как бы работает. Но вот от куда 2,051343 ?
Ребятки, может кому-то понадобится, тут есть подробная и очень простая схема вольтметра на Arduino
Dron_S, я начинал с кода
//LTC2400 24bit ADC Module // //Application Demo: 7 digit voltmeter //24bit ADC IC: LTC2400 //4.096 precision reference: TI REF3040 // //By coldtears electronics // //LTC2400 code is adapted from Martin Nawrath //Kunsthochschule fuer Medien Koeln //Academy of Media Arts Cologne // #include <Stdio.h> #include<stdlib.h> #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif #ifndef sbi #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif #define LTC_CS 0 // LTC2400 Chip Select Pin on Portb 2 * CS mega 0 uno 2 #define LTC_MISO 3 // LTC2400 SDO Select Pin on Portb 4 * Miso mega 3 uno 4 #define LTC_SCK 1 // LTC2400 SCK Select Pin on Portb 5 * SCK mega 1 uno 5 void setup() { cbi(PORTB,LTC_SCK); // LTC2400 SCK low sbi (DDRB,LTC_CS); // LTC2400 CS HIGH cbi (DDRB,LTC_MISO); sbi (DDRB,LTC_SCK); Serial.begin(57600); // init SPI Hardware sbi(SPCR,MSTR) ; // SPI master mode sbi(SPCR,SPR0) ; // SPI speed sbi(SPCR,SPR1); // SPI speed sbi(SPCR,SPE); //SPI enable //Serial.println("LTC2400 ADC Test"); } float volt; float v_ref=4.094; // Reference Voltage, 5.0 Volt for LT1021 or 3.0 for LP2950-3 long int ltw = 0; // ADC Data ling int int cnt; // counter byte b0; // byte sig; // sign bit flag char st1[20]; // float voltage text /********************************************************************/ void loop() { cbi(PORTB,LTC_CS); // LTC2400 CS Low delayMicroseconds(1); if (!(PINB & (1 << 4))) { // ADC Converter ready ? // cli(); ltw=0; sig=0; b0 = SPI_read(); // read 4 bytes adc raw data with SPI if ((b0 & 0x20) ==0) sig=1; // is input negative ? b0 &=0x1F; // discard bit 25..31 ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; ltw <<= 8; b0 = SPI_read(); ltw |= b0; delayMicroseconds(1); sbi(PORTB,LTC_CS); // LTC2400 CS Low if (sig) ltw |= 0xf0000000; // if input negative insert sign bit ltw=ltw/16; // scale result down , last 4 bits have no information volt = ltw * v_ref / 16777216; // max scale char tmp[10]; dtostrf(volt,6,6,tmp); tmp[8]='V'; tmp[9]='\n'; Serial.print(cnt++); Serial.print("; "); printFloat(volt,6); // print voltage as floating number Serial.println(" "); } sbi(PORTB,LTC_CS); // LTC2400 CS hi delay(200); } /********************************************************************/ byte SPI_read() { SPDR = 0; while (!(SPSR & (1 << SPIF))) ; /* Wait for SPI shift out done */ return SPDR; } /********************************************************************/ // printFloat from tim / Arduino: Playground // printFloat prints out the float 'value' rounded to 'places' places //after the decimal point void printFloat(float value, int places) { // this is used to cast digits int digit; float tens = 0.1; int tenscount = 0; int i; float tempfloat = value; // if value is negative, set tempfloat to the abs value // make sure we round properly. this could use pow from //<math.h>, but doesn't seem worth the import // if this rounding step isn't here, the value 54.321 prints as // calculate rounding term d: 0.5/pow(10,places) float d = 0.5; if (value < 0) d *= -1.0; // divide by ten for each decimal place for (i = 0; i < places; i++) d/= 10.0; // this small addition, combined with truncation will round our tempfloat += d; if (value < 0) tempfloat *= -1.0; while ((tens * 10.0) <= tempfloat) { tens *= 10.0; tenscount += 1; } // write out the negative if needed if (value < 0) Serial.print('-'); if (tenscount == 0) Serial.print(0, DEC); for (i=0; i< tenscount; i++) { digit = (int) (tempfloat/tens); Serial.print(digit, DEC); tempfloat = tempfloat - ((float)digit * tens); tens /= 10.0; } // if no places after decimal, stop now and return if (places <= 0) return; // otherwise, write the point and continue on Serial.print(','); for (i = 0; i < places; i++) { tempfloat *= 10.0; digit = (int) tempfloat; Serial.print(digit,DEC); // once written, subtract off that digit tempfloat = tempfloat - (float) digit; } }Этот код нормально работал у меня.
Из за большого времени преобразования АЦП LTC2400 , я свой вольтметр переделал на ads1115 ( 16 bit I2C ). Сделал два входа, один дифференцияльный +/- 5.2 вольт с индикацией 4 знака после точки , второй обычный single с делителем напряжения на 11 и диапазоном измерения до 55 вольт с индикацией 2 знака после точки. Питание от двух аккумуляторов 18650 . И добавил вывод на сериал порт в формате ZeroFormat LogView. Этот вариант вольтметра мне нравиться намного больше.
Также сама ардуина через делитель измеряет напряжение аккумуляторов , и в процентах показывает заряд ,по уравнению полученному при контрольной разрядке аккумуляторов.
Интересный материал по машиностроению.
Интересный материал по машиностроению.
mikelari Если не трудно, не могли бы выложить скетч на ads1115 ?
Тоже прикупил себе ads1115 (еще INA219), есть подобная надобность сделать логгер с хорошим разрешением до 50В на зарядное устройство (либо зарядное с внешним АЦП) ну и ток на шунте мерить, желательно в диф режиме, чтобы мерить в обе стороны (заряд/разряд). Правда сразу возникли вопросы - как правильно реализовать в коде, чтобы разрешение было по максимуму.. к тому же важно не потерять скорость сэмплирования - 800 сэмплов.. и т.д.
Хотелось еще спросить, формат ZeroFormat LogView - это значит можно смотреть в стандартной программе для зарядников LogView?
Поделитесь пожалуйста схемой включения Вашего вольтметра для АЦП LTC2400. И возможно ли сделать вольамперметр на его основе?
Вот http://www.dropbox.com/s/tlvosmpspz9b9nb/Adafruit_ADS1X15.zip?dl=0 исправленная библиотека для ADS1115 (860 samples per second) . На 100кГц I2C у меня измерял 435 раз в секунду . На 400кГц I2C не пробовал. Примеры из библиотеки работают нормально.
Скетч-пожалуйста, но писал его давно, и в нем не самые красивые решения
#include <Adafruit_ADS1015.h> // #include <Wire.h> // #include "rgb_lcd.h" // rgb_lcd lcd; // Adafruit_ADS1115 ads; // //************************************************************************************************* // П Е Р Е М Е Н Н Ы Е int adcD[100]; // массив для записи Diff измерений в память ардуино int adcS[100]; // массив для записи Singl измерений в память ардуино int nomb=100; // сколько провести измерений для усреднения float voltsD = 0; // переменная для Diff напряжения float voltsS = 0; // переменная для Singl напряжения long time = 0; long volts = 0; String UstrS="" ; //стринг для получения напряжения с точкой и со всеми значащими цифрами String UstrD="" ; //стринг для получения напряжения с точкой и со всеми значащими цифрами long Ubat; //переменная для измерения напряжения батарей byte UbatProc; //переменная для напряжен бат в процентах String UbatProcS = "" ; //стринг для напряжения батарей в процентах //************************************************************************************************* void setup() { lcd.begin(16, 2); // set up the LCD's number of columns and rows lcd.setRGB(255, 255, 0); // установка желтого цвета LCD lcd.setCursor(0, 0); // начали вывод версии программы на LCD lcd.print("firmware_v7 "); lcd.setCursor(0, 1); // начали вывод на LCD Serial speed знать скорость для логгирования на компе lcd.print("Serial_9600 "); delay(1000); lcd.setCursor(0, 0); // через 1 секунду чистим LCD lcd.print(" "); lcd.setCursor(0, 1); // lcd.print(" "); Serial.begin(9600); ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) ads.begin(); //начинаем работу АЦП } //***************************************************************************************************** void loop() { Get_Ubat(); // идем на подпрограмму измерения напряжения батарей вольтметра Find_UbatProcS(); // идем на подпрограмму сборки стринга с напряжением батарей в процентах Get_ADC(); // идем на подпрограмму получения данных из АЦП в переменную //Printscreen (); // подпрограмма вывода напряжений на экран Find_UstrS(); // идем на подпрограмму получения стринга UstrS это напряжение с точкой и со всеми значащими цифрами Find_UstrD(); // идем на подпрограмму получения стринга UstrD это напряжение с точкой и со всеми значащими цифрами LCDout (); // идем на подпрограмму вывода на LCD OFout(); // идем на подпрограмму вывода в LOGVIEW } /*****************************************************************************************************************************/ void Get_Ubat(){ // подпрограмма измеряет напряжение батарей через делитель на входе А1 Ubat = analogRead(A1); Ubat = ((Ubat * 1000 / 1023 * 5) * 2.019 + 5) / 10 ; // 2.019 коэф деления резисторного делителя UbatProc = map(Ubat, 660 , 840 , 0 , 99); // находим напряжение в процентах ,напряжение от 6.6 до 8.40 вольт //if (UbatProc > 99) UbatProc = 0; //if (UbatProc <= 1) UbatProc = 1; //Serial.print("Ubat="); //Serial.println(UbatProc); } /*****************************************************************************************************************************/ void Find_UbatProcS(){ // подпрограмма собрать в стринг UbatProcS данные по заряду батарей в процентах char buffer [10]; // буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa(UbatProc, buffer, 10); // забросили в char буффер цифры из UbatProc k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе UbatProc UbatProcS = ""; if (UbatProc < 10 ) UbatProcS += " "; // i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr UbatProcS += buffer [i]; // i++; } UbatProcS +="%"; if (UbatProc > 99) UbatProcS = "???"; if (UbatProc < 1) UbatProcS = "???"; //Serial.println(UbatProcS); } /*****************************************************************************************************************************/ //подпрограмма для получения данных из АЦП в переменные voltsD и voltS void Get_ADC(){ long results01 = 0; // временная переменая для суммирования рез-ов Diff измерения ADC и вычисления ср. значения long results3 = 0; // временная переменая для суммирования рез-ов Singl измерения ADC и вычисления ср. значения float multiplierD = 187.531 ; // множитель для Diff 187.528 188.346; float multiplierS = 2076 ; // множитель для Singl long tekmillis=millis(); // переменная содержит время начала работы цикла for(int x = 0; x < nomb; x ++){ // цикл от 0 до nomb раз проводит измерения adcD[x] = ads.readADC_Differential_0_1(); // в массив заполняем результат измерения Diff adcS[x] = ads.readADC_SingleEnded(3); // в массив заполняем результат измерения Singl } // цикл закончен time = (millis()-tekmillis); // вычисляем время которое ушло на nomb раз измерения ADC и запись в память for(int x = 0; x < nomb; x ++){ // цикл от 0 до nomb раз берет данные из массива adcD и adcS results01 = results01 + adcD[x]; // суммирует их results3 = results3 + adcS[x]; } voltsD = (results01/nomb * multiplierD/1000000); // из суммы вычисляем среднее значение измерений Diff voltsS = (results3 /nomb * multiplierS/1000000); // из суммы вычисляем среднее значение измерений Singl } /*****************************************************************************************************************************/ void Printscreen (){ Serial.print(time); // вывод потраченного времени Serial.print(" mS : Singl "); Serial.print (voltsS,2); // Singl с двумя знаками Serial.print(" : Diff "); Serial.println(voltsD,4); // Diff с четырмя знаками Serial.println(""); } /*****************************************************************************************************************************/ //подпрограмма для получения стринга UsrtS напряжения с точкой и со всеми значащими цифрами void Find_UstrS(){ char buffer [10]; //буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa((abs(voltsS)+0.005) *100, buffer, 10); // забросили в char буффер цифры из volts k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус UstrS = ""; // в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (voltsS < 0) UstrS += "-"; //минус if (voltsS >= 0) UstrS += " "; //плюс if (k == 4) { // если есть 4 значащих цифр i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 2) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 3) { // если есть 3 значащих цифр UstrS += " "; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 1) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 2) { // если есть 2 значащих цифр UstrS += " 0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 1) { // если есть 1 значащих цифр UstrS += " 0.0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } /*Serial.print("voltsS="); Serial.print(voltsS); Serial.print(" UstrS="); Serial.print(UstrS); Serial.print(" : k="); Serial.println(k); */ //x++; // } // delay(10000); } /*****************************************************************************************************************************/ //подпрограмма для получения стринга UsrtD напряжения с точкой и со всеми значащими цифрами void Find_UstrD(){ char buffer [10]; //буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa((abs(voltsD)+0.00005) *10000, buffer, 10); // забросили в char буффер цифры из volts k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус UstrD = ""; // в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (voltsD < 0) UstrD += "-"; //минус if (voltsD >= 0) UstrD += " "; //плюс UstrD += " "; //просто форматирование if (k == 5) { // если есть 5 значащих цифр i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 4) { // если есть 4 значащих цифр UstrD += "0."; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 2) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 3) { // если есть 3 значащих цифр UstrD += "0.0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 2) { // если есть 2 значащих цифр UstrD += "0.00"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 1) { // если есть 1 значащих цифр UstrD += "0.000"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } /*Serial.print("voltsD="); Serial.print(voltsD,4); Serial.print(" UstrD="); Serial.print(UstrD); Serial.print(" : k="); Serial.println(k); x++; } */ } /****************************************************************************************************************************/ void LCDout(){ lcd.setCursor(0, 0); // начали вывод напряжения на LCD lcd.print("S "); lcd.print(UstrS); lcd.print(" V bat"); lcd.setCursor(0, 1); // начали вывод во вторую строку LCD lcd.print("D "); lcd.print(UstrD); lcd.print(" V "); lcd.print(UbatProcS); //напряжение батарей в процентах } /*********************************************************************************************************************/ void OFout(){ // подпрограмма вывода данных на USB порт для логирования в LOGVIEW Serial.print("$1;1;0;"); Serial.print(voltsS,2); Serial.print(";"); Serial.print(voltsD,4); Serial.print(";0"); Serial.println(13,DEC); } /*******************************************************************************************/И да, можно смотреть в стандартной программе для зарядников LogView. Нужно только сделать ini файл для вольтметра. Нужно будет, скину свой ini файл.
При написании разных измерялок часто требуется применение различных фильтров. Мне понравился вариант описаный в статье https://geektimes.ru/post/269202/ но в этом измерятеле такой фильтр еще не реализован.
По АЦП LTC2400 включен был по схеме
Схема модуля http://www.dropbox.com/s/qtsn966we7rpmny/PCB%20schematic.pdf?dl=0
Vin1 измеряет до 4.096 В
Vin2 измеряет до 17 вольт (предварительно замкнуть перемычку JP2)
Можно сделать свой делитель, и измерить сколько нужно.
Вольтамперметр на его основе? Сделать можно всё что угодно, где АЦП можно впихнуть и если устраивает 24bit c Conversion Time 160 mS.
По АЦП LTC2400 включен был по схеме
Схема модуля http://www.dropbox.com/s/qtsn966we7rpmny/PCB%20schematic.pdf?dl=0
Vin1 измеряет до 4.096 В
Vin2 измеряет до 17 вольт (предварительно замкнуть перемычку JP2)
Можно сделать свой делитель, и измерить сколько нужно.
Вольтамперметр на его основе? Сделать можно всё что угодно, где АЦП можно впихнуть и если устраивает 24bit c Conversion Time 160 mS.
По этому АЦП не знаю. Готовое решение https://ru.aliexpress.com/item/RD-DPS3012-Constant-Voltage-current-Step-down-Programmable-Power-Supply-module-buck-Voltage-converter-color-LCD/32685179404.html?spm=2114.03020208.3.2.bYXiNa&ws_ab_test=searchweb0_0,searchweb201602_2_10065_10068_10000009_10084_10083_10080_10082_10081_10060_10062_10056_10055_10037_10054_10059_10032_10099_10078_10079_10077_10093_426_10103_10073_10102_10096_10052_10108_10053_10107_10050_10106_10051,searchweb201603_3,afswitch_5&btsid=c0d04963-448a-42f8-b86a-b114d7171ad8
Да я находил этот модуль, но дело в том что уже готова плата будущего двухканального блока питания и трансформатор 2х24х15В 10А. Было опробовано много популярных ВАметров на PIC и Atmega8 и у всех в какой то части диапазона была приличная нелинейность. А по задуму хочется сделать ВАметр с режимом внешнего измерения посредством отключения входа с блока питания и переключения на внешний источник напряжения. Такой себе вольтметр+блок питания. Купил бы готовый модуль если б знал заранее что будет такая возня и плохие результаты ВАметров. Потому увидев возможности Вашего АЦП понадеялся что есть хотя бы фрагмент схемы на пике или атмеге, на той же ардуине нано.
MitsuokaOroshi, вам эти 24 бита ни к чему. Совершенно. Простой расчёт - точность вольтмера в составе БП должна быть чуть лучше, чем уровень помех БП. Если взять среднестатический импульсный БП , то примерный уровень шума у них 100мв. Т.е. нет смысла отображать напряжения после одной цифры за запятой, т.к. там заведомо мусор. Соответссно минимальная разрядность АЦП должна быть 30 /0.1 = 300 градаций, или с запасом - 9 битное (512 градаций) АЦП. Если БП трансформаторный-линейный, то средний шум у них 10мв. Соответссно нужно не менее 3000 градаций, или 12-битный АЦП.
Так же много пробовал ( в том числе строить ваттметр на ads 1115 с нормальными шунтами и также были вопросы с нелинейностью), поэтому INA226 http://arduino.ru/forum/proekty/vattmetr-3-kh-kanalnyi-s-perspektivoi и далее смогу наращивать мясо на этот скелет, впрочем уже этим занимаюсь. Возможности/хотелки ограничиваются деньгами и фантазией.
Для трансформаторного блока питания - да, не нужен. Но я же писал что хочется применить его и как внешний вольтметр. Ну да ладно, благодарю за потраченное время.
Так же много пробовал ( в том числе строить ваттметр на ads 1115 с нормальными шунтами и также были вопросы с нелинейностью), поэтому INA226 http://arduino.ru/forum/proekty/vattmetr-3-kh-kanalnyi-s-perspektivoi и далее смогу наращивать мясо на этот скелет, впрочем уже этим занимаюсь. Возможности/хотелки ограничиваются деньгами и фантазией.
Может кому пригодится черновик работа с ads1115 без библиотеки Adafruit. Только биты конфига сами выбираем по даташиту.
#include <Wire.h> #define ADR_ASD1115 0x48 //адрес ads1115 byte writeBuf[3]; //для конфигурирования АЦП три байта byte readBuf[3]; //для чтения данных из АЦП три байта float myfloat; const float VPS = 6.144 / 32768.0; //вольт на шаг в зависимости от PGA усиления АЦП тут для 6.144 unsigned int val = 0; //------------------------------------------------------------------------------- void setup() { Serial.begin(9600); Wire.begin(); // begin I2C } //-------------------------------------------------------------------------------- void loop() { config_ads115(); // Конфигурирование и запуск преобразования ads1115 get_config(); // Прочитать конфиг биты и вывести на экран get_voltage(); // Прочитать регистр преобразования, пересчитать в напряжение } //------------------------------------------------------------------------------- void config_ads115(){ // Конфигурирование и запуск преобразования ads1115 writeBuf[0] = 1; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг writeBuf[1] = 0b10000000; // биты с 15 по 8 конфигурации смотрим в даташите сами writeBuf[2] = 0b10000011; // биты с 7 по 0 конфигурации смотрим в даташите сами Wire.beginTransmission(ADR_ASD1115); //конфигурируем АЦП записью трех байт Wire.write(writeBuf[0]); // Указатель регистра Wire.write(writeBuf[1]); // биты с 15 по 8 конфигурации Wire.write(writeBuf[2]); // биты с 7 по 0 конфигурации Wire.endTransmission(); delay(500); } //------------------------------------------------------------------------------- void get_voltage(){ // Прочитать регистр преобразования, пересчитать в напряжение readBuf[0] = 0; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011)т.е. указали Conversion Wire.beginTransmission(ADR_ASD1115); // Начали читать данные из регистра преобразования Wire.write(readBuf[0]); // pointer указал в readBuf[0] записан 0 т.е. регистр преобразования Wire.endTransmission(); Wire.requestFrom(ADR_ASD1115, 2); // читаем из АЦП два байта readBuf[1] = Wire.read(); // readBuf[2] = Wire.read(); // Wire.endTransmission(); val = readBuf[1] << 8 | readBuf[2]; // собираем два байта в кучу в переменную int val if (val > 32768) val = 0; myfloat = val * VPS; // пересчитываем в напряжение Serial.print("Sensor voltage = "); // вывод на экран результата Serial.println(myfloat); } //-------------------------------------------------------------------------------- void get_config(){ // взять все биты конфига и вывести на экран readBuf[0] = 1; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали config Wire.beginTransmission(ADR_ASD1115); // Начали читать данные из регистра конфига Wire.write(readBuf[0]); // pointer указал в readBuf[0] записан 1 т.е. регистр config Wire.endTransmission(); Wire.requestFrom(ADR_ASD1115, 2); // читаем из АЦП два байта readBuf[1] = Wire.read(); // readBuf[2] = Wire.read(); // Wire.endTransmission(); Serial.print("Config = "); //выводим на экран все биты конфига Serial.print(readBuf[1],BIN); Serial.print("_"); Serial.println(readBuf[2],BIN); } //-------------------------------------------------------------------------------Причесал немного софт, вернее в части работы с ads1115 сильно переделал:
- отказался от библиотеки ads1115
- конфиг теперь 128 SPS
- запускается каждое измерение, а не цикличный режим работы АЦП
- пусто-гон по кругу ожидает окончание каждого измерения
- добавлен фильтр измерений типа как я описывал выше
- переменными Filter_read и Filter_get устанавливается настройки фильтра. У меня примерно около 480mS круг и выдача данных на свой дисплей и в порт для LogView
- прилагаю ini файл для LogView
http://www.dropbox.com/s/cgslaod0kjfb74h/LogView_ini.zip?dl=0
Код еще можно чистить и править, но работает нормально на nano
#include <Wire.h> // #include "rgb_lcd.h" // rgb_lcd lcd; // #define ADR_ASD1115 0x48 //адрес ads1115 #define Filter_read 24 //!!! только четное число сколько читать значений из АЦП для работы фильтра #define Filter_get 4 //!!! только четное число сколько взять значений для расчета среднего фильтром float float_voltsD = 0; // переменная для Diff напряжения float float_voltsS = 0; // переменная для Singl напряжения String UstrS="" ; //стринг для получения напряжения с точкой и со всеми значащими цифрами String UstrD="" ; //стринг для получения напряжения с точкой и со всеми значащими цифрами long Ubat; //переменная для измерения напряжения батарей byte UbatProc; //переменная для напряжен бат в процентах String UbatProcStr = "" ; //стринг для напряжения батарей в процентах byte writeBuf[3]; //для конфигурирования АЦП три байта byte readBuf[3]; //для чтения данных из АЦП три байта int raw; //для получения одного значения ads raw из регистра преобразования АЦП после чтения long filter_raw; //для получения множества значений raw из регистра преобразования АЦП после чтения по значениям Filter_read и Filter_get long time_start; long time_end; //************************************************************************************************* void setup() { Wire.begin(); // begin I2C Serial.begin(9600); lcd.begin(16, 2); // set up the LCD's number of columns and rows lcd.setRGB(255, 255, 0); // установка желтого цвета LCD lcd.setCursor(0, 0); // начали вывод версии программы на LCD lcd.print("firmware_v9 "); lcd.setCursor(0, 1); // начали вывод на LCD Serial speed знать скорость для логгирования на компе lcd.print("LogView_9600 "); delay(1000); lcd.setCursor(0, 0); // через 1 секунду чистим LCD lcd.print(" "); lcd.setCursor(0, 1); // lcd.print(" "); } //***************************************************************************************************** void loop() { time_start = micros(); Get_Ubat_328(); // идем на подпрограмму измерения напряжения батарей питания вольтметра Find_UbatProcStr_328(); // идем на подпрограмму сборки стринга с напряжением батарей в процентах filter_raw_calc_D(); // фильтр с дифф входа 0-1 прочитает множество измерений raw по float_voltsD = 187.5420001; // значениям Filter_read и Filter_get и в перменную filter_raw поместит среднее float_voltsD *= filter_raw / Filter_get; // значение вычислений. Остается пересчитать это сырое значение АЦП в напряжение float_voltsD /= 1000000; // 187.5420001 это калибровка датчика опытным путем filter_raw_calc_S(); // фильтр с несимм входа GND-3 прочитает множество измерений raw по float_voltsS = 2074.000001; // значениям Filter_read и Filter_get и в перменную filter_raw поместит среднее float_voltsS *= filter_raw / Filter_get; // значение вычислений. Остается пересчитать это сырое значение АЦП в напряжение float_voltsS /= 1000000; // 2074.000001 это калибровка датчика с делителем напряжения опытным путем Find_UstrS(); // идем на подпрограмму получения стринга UstrS это напряжение с точкой и со всеми значащими цифрами Find_UstrD(); // идем на подпрограмму получения стринга UstrD это напряжение с точкой и со всеми значащими цифрами LCDout (); // идем на подпрограмму вывода на LCD OFout(); // идем на подпрограмму вывода в LOGVIEW time_end = micros(); //Printscreen (); // подпрограмма вывода напряжений на экран } /*****************************************************************************************************************************/ void Get_Ubat_328(){ // подпрограмма измеряет напряжение батарей через делитель на входе А1 Ubat = analogRead(A1); Ubat = ((Ubat * 1000 / 1023 * 5) * 2.019 + 5) / 10 ; // 2.019 коэф деления резисторного делителя UbatProc = map(Ubat, 660 , 840 , 0 , 99); // находим напряжение в процентах ,напряжение от 6.6 до 8.40 вольт //if (UbatProc > 99) UbatProc = 0; //if (UbatProc <= 1) UbatProc = 1; //Serial.print("Ubat="); //Serial.println(UbatProc); } /*****************************************************************************************************************************/ void Find_UbatProcStr_328(){ // подпрограмма собоать в стринг UbatProcStr данные по заряду батарей в процентах char buffer [10]; // буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa(UbatProc, buffer, 10); // забросили в char буффер цифры из UbatProc k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе UbatProc UbatProcStr = ""; if (UbatProc < 10 ) UbatProcStr += " "; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr UbatProcStr += buffer [i]; i++; } UbatProcStr +="%"; if (UbatProc > 99) UbatProcStr = "???"; if (UbatProc < 1) UbatProcStr = "???"; //Serial.println(UbatProcStr); } //-------------------------------------------------------------------------------- void read_config(){ // Читаем конфиг и по 15 биту ожидаем окончание преобразования АПЦ (можно читать один 1-й байт readBuf[1] если не нужен весь конфиг) readBuf[0] = 1; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали config do { Wire.beginTransmission(ADR_ASD1115); // Начали читать данные из регистра конфига Wire.write(readBuf[0]); // pointer указал в readBuf[0] записан 1 т.е. регистр config Wire.endTransmission(); Wire.requestFrom(ADR_ASD1115, 2); // читаем из АЦП два байта readBuf[1] = Wire.read(); readBuf[2] = Wire.read(); Wire.endTransmission(); } while(bitRead(readBuf[1],7)==0); //читаем байты пока 15-й бит не станет равен 1 что значит одно измерение закончено /*Serial.print("Config = "); Serial.print(readBuf[1],BIN); Serial.print("_"); Serial.print(readBuf[2],BIN); Serial.print("_"); Serial.print(time_end-time_start); */ } //------------------------------------------------------------------------------- void ads1115_config_Differential_0_1(){ writeBuf[0] = 1; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг writeBuf[1] = 0b10000001; // биты с 15 по 8 конфигурации writeBuf[2] = 0b10000011; // биты с 7 по 0 конфигурации Wire.beginTransmission(ADR_ASD1115); //конфигурируем АЦП записью трех байт Wire.write(writeBuf[0]); // Указатель регистра Wire.write(writeBuf[1]); // биты с 15 по 8 конфигурации Wire.write(writeBuf[2]); // биты с 7 по 0 конфигурации Wire.endTransmission(); //delay(10); // } //------------------------------------------------------------------------------- void ads1115_config_Single_GND_3(){ writeBuf[0] = 1; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг writeBuf[1] = 0b11110001; // биты с 15 по 8 конфигурации writeBuf[2] = 0b10000011; // биты с 7 по 0 конфигурации Wire.beginTransmission(ADR_ASD1115); //конфигурируем АЦП записью трех байт Wire.write(writeBuf[0]); // Указатель регистра Wire.write(writeBuf[1]); // биты с 15 по 8 конфигурации Wire.write(writeBuf[2]); // биты с 7 по 0 конфигурации Wire.endTransmission(); //delay(10); // } //----------------------------------------------------------------------------------------------------------------------- void filter_raw_calc_D () { // подпрограмма считывания и фильтрации значений с дифф входа 0-1 int sortedValues[Filter_read]; //назначили массив с sortedValues[Filter_read] for (int i = 0; i < Filter_read; i++) { //цикл от 0 до Filter_read //delay(25); // ads1115_config_Differential_0_1(); //идем на конфигурирование и старт одного измерения дифф входа 0-1 read_config(); //читаем конфиг и при чтении его ждем окончания преобразования read_ads_raw(); //идем на чтение результата одного измерения raw ads int value = raw ; //value получает значение одного измерения raw ads int j; //переменная "j" куда вставлять значение при сортировке if (value < sortedValues[0] || i == 0) { //если полученое значение valve < sortedValues[0] или это самое начало "i",то j = 0; //"j"= 0 это первая позиция } //конец if else { //иначе for (j = 1; j < i; j++) { //цикл j от 1 до j < i искать "j" if (sortedValues[j - 1] <= value && sortedValues[j] >= value) { //ищем место"j" в sortedValues[]куда вставить value break; //"j" найдено,остановить выполнение цикла } //конец if } //конец цикла j } //конец else for (int k = i; k > j; k--) { //все значения от "i" до "j" (вниз к--) нужно поднять на одну позицию вверх sortedValues[k] = sortedValues[k - 1]; //чтобы освободить место "j" для valve } //конец цикла sortedValues[j] = value; //вставить считаное valve в sortedValues[] в позицию "j" } //конец цикла от 0 до Filter_read //расчет среднего знач из Filter_get. Эти значения взяты после отброса лишних значений filter_raw = 0; for (int i = Filter_read / 2 - Filter_get/2; i < (Filter_read / 2 + Filter_get/2); i++) { filter_raw += sortedValues[i]; } } //----------------------------------------------------------------------------- void filter_raw_calc_S () { // подпрограмма считывания и фильтрации значений с дифф входа 0-1 int sortedValues[Filter_read]; //назначили массив с sortedValues[Filter_read] for (int i = 0; i < Filter_read; i++) { //цикл от 0 до Filter_read //delay(25); // ads1115_config_Single_GND_3(); //идем на конфигурирование и старт одного измерения несимметр входа GND-3 read_config(); //читаем конфиг и при чтении его ждем окончания преобразования read_ads_raw(); //идем на чтение результата одного измерения raw ads int value = raw ; //value получает значение одного измерения raw ads int j; //переменная "j" куда вставлять значение при сортировке if (value < sortedValues[0] || i == 0) { //если полученое значение valve < sortedValues[0] или это самое начало "i",то j = 0; //"j"= 0 это первая позиция } //конец if else { //иначе for (j = 1; j < i; j++) { //цикл j от 1 до j < i искать "j" if (sortedValues[j - 1] <= value && sortedValues[j] >= value) { //ищем место"j" в sortedValues[]куда вставить value break; //"j" найдено,остановить выполнение цикла } //конец if } //конец цикла j } //конец else for (int k = i; k > j; k--) { //все значения от "i" до "j" (вниз к--) нужно поднять на одну позицию вверх sortedValues[k] = sortedValues[k - 1]; //чтобы освободить место "j" для valve } //конец цикла sortedValues[j] = value; //вставить считаное valve в sortedValues[] в позицию "j" } //конец цикла от 0 до Filter_read //расчет среднего знач из Filter_get. Эти значения взяты после отброса лишних значений filter_raw = 0; for (int i = Filter_read / 2 - Filter_get/2; i < (Filter_read / 2 + Filter_get/2); i++) { filter_raw += sortedValues[i]; } } //----------------------------------------------------------------------------- void read_ads_raw(){ raw = 0; readBuf[0] = 0; // Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001, // Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011)т.е. указали Conversion Wire.beginTransmission(ADR_ASD1115); // Начали читать данные из регистра преобразования Wire.write(readBuf[0]); // pointer указал в readBuf[0] записан 0 т.е. регистр преобразования Wire.endTransmission(); Wire.requestFrom(ADR_ASD1115, 2); // читаем из АЦП два байта readBuf[1] = Wire.read(); // readBuf[2] = Wire.read(); // Wire.endTransmission(); raw = readBuf[1] << 8 | readBuf[2]; // собираем два байта в кучу в переменную int val if (raw > 32768) raw = 0; } /*****************************************************************************************************************************/ void Printscreen (){ Serial.print((time_end-time_start)/1000); // вывод потраченного времени Serial.print(" mS : Singl "); Serial.print (float_voltsS,5); // Singl с двумя знаками Serial.print(" : Diff "); Serial.println(float_voltsD,5); // Diff с четырмя знаками Serial.println(""); } /*****************************************************************************************************************************/ //подпрограмма для получения стринга UsrtS напряжения с точкой и со всеми значащими цифрами void Find_UstrS(){ // float_voltsS = -10.999 ; // int x=0; // while (x <= 10000) { // float_voltsS = float_voltsS + 0.01; char buffer [10]; //буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa((abs(float_voltsS)+0.005) *100, buffer, 10);// забросили в char буффер цифры из volts k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус UstrS = ""; // в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (float_voltsS < 0) UstrS += "-"; //минус if (float_voltsS >= 0) UstrS += " "; //плюс if (k == 4) { // если есть 4 значащих цифр i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 2) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 3) { // если есть 3 значащих цифр UstrS += " "; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 1) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 2) { // если есть 2 значащих цифр UstrS += " 0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } if (k == 1) { // если есть 1 значащих цифр UstrS += " 0.0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrS += buffer [i]; // i++; } } /*Serial.print("float_voltsS="); Serial.print(float_voltsS); Serial.print(" UstrS="); Serial.print(UstrS); Serial.print(" : k="); Serial.println(k); */ //x++; // } // delay(10000); } /*****************************************************************************************************************************/ //подпрограмма для получения стринга UsrtD напряжения с точкой и со всеми значащими цифрами void Find_UstrD(){ //float_voltsD = -1.9999 ; //int x=0; //while (x <= 10000) { //float_voltsD = float_voltsD + 0.001; char buffer [10]; //буфер для преобразований Long-Char int k=0; // разные временные цифры int i=0; // разные временные цифры ltoa((abs(float_voltsD)+0.00001) *10000, buffer, 10); // забросили в char буффер цифры из volts k=(strlen(buffer)); // k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус UstrD = ""; // в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (float_voltsD < 0) UstrD += "-"; //минус if (float_voltsD >= 0) UstrD += " "; //плюс UstrD += " "; //просто форматирование if (k == 5) { // если есть 5 значащих цифр i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 4) { // если есть 4 значащих цифр UstrD += "0."; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 2) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 3) { // если есть 3 значащих цифр UstrD += "0.0"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 2) { // если есть 2 значащих цифр UstrD += "0.00"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } if (k == 1) { // если есть 1 значащих цифр UstrD += "0.000"; i=0; while (i <= (k-1)) { // из буфера берем K цифр и вставляем их в Ustr //if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт UstrD += buffer [i]; // i++; } } /*Serial.print("float_voltsD="); Serial.print(float_voltsD,4); Serial.print(" UstrD="); Serial.print(UstrD); Serial.print(" : k="); Serial.println(k); x++; } */ } /****************************************************************************************************************************/ void LCDout(){ lcd.setCursor(0, 0); // начали вывод напряжения на LCD lcd.print("S "); lcd.print(UstrS); lcd.print(" bat"); lcd.setCursor(0, 1); // начали вывод во вторую строку LCD lcd.print("D "); lcd.print(UstrD); lcd.print(" "); lcd.print(UbatProcStr); //напряжение батарей в процентах } /*********************************************************************************************************************/ void OFout(){ // подпрограмма вывода данных на USB порт для логирования в LOGVIEW Serial.print("$1;1;0;"); Serial.print(float_voltsS,2); Serial.print(";"); Serial.print(float_voltsD,4); Serial.print(";0"); Serial.println(13,DEC); } /*******************************************************************************************/Схема модуля http://www.dropbox.com/s/qtsn966we7rpmny/PCB%20schematic.pdf?dl=0
Vin1 измеряет до 4.096 В
Vin2 измеряет до 17 вольт (предварительно замкнуть перемычку JP2)
тоже брал такую платку. опора там никуда не годится, менял на даташитную lt1021 на проводках, затем стало проще переразвести плату.
на ltc2400 интересный проект милливольтметра есть https://www.youtube.com/watch?v=CiTPUmqE3Yg
Купил опору TI LM4040 A41IDBZR 4.096V 0.1%, (дорогие заразы) тоже хочу попробовать поменять на этом модуле, чтоб модуль использовать для милливольтметра/миллиомметра.
да не так чтобы очень с учетом какая точность требуется
по-моему lm4040 не очень сюда годится с ее 100ppm/C
это, конечно, лучше, чем то, что в платку поставили китайцы, но гораздо хуже, чем недорогие (ну, относительно) ref198/lt1021, не говоря уже о lt1027/max6341
dimax как-то Вы пессимистично смотрите на шум линейников.
у наиболее частого случая, древней 7815 Output Noise Voltage B =10Hz to 100KHz TJ = 25°C - max 40 μV/VO, это 600мкВ на 15В выходного напряжения, но никак не десятки миллиВольт.
sls, это собственный шум голой микрухи, А я имел ввиду средний суммарный уровень помех линейных бп. Даже если отдельные лабораторники имеет уровень пульсаций не хуже 1мв, то всё равно эта цифра весьма иллюзорная, т.к. касается только клемм выхода при статической нагрузке.
sls, это собственный шум голой микрухи, А я имел ввиду средний суммарный уровень помех линейных бп.
в общем-то у линейников основной источник шума и есть ИОН, далее по общему вкладу идет делитель напряжения с него, остальные части схемы шумят мало
предлагаю помириться на том, что для нормально спроектированного и собранного линейного ЛБП в случае необходимости вполне можно использовать измеритель напряжения с тремя цифрами после запятой, но никак не одной :)
sls, да я не против, сам люблю попугаев за запятой. Как говорится: "Ах, обмануть меня не трудно, я сам обманываться рад..."(С) Пушкин :-)
dimax, я их тоже полюбляю, в особенности стабильные и достоверные :)
Добрый день, собрал измеритель напряжения.
Врет при увеличении напряжения, погрешность достигает 0,12 вольта..
На ареф замедены опорные 2,5 В с REF192FS ( пальцем ее обозначил). Подключил по datasheet, опорное напряжение стабильно во всем диапазоне измеряемых напряжений.
в скетче указал, что analogReference ( EXTERNAL )
Питается хозяйство от импульсного стабилизатора. напряжение снимается с делителя 1к и 14 к ( тоже пальцами указал). До этого пробовал 430 к и 36 к , такой же результат.
Рассчет происходит тупо умножением измеренного напряжения на экспериментально подобранный коэффициент
Что я могу делать не так?