Очень точный вольтметр на 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, я начинал с кода
001
//LTC2400 24bit ADC Module
002
//
003
//Application Demo: 7 digit voltmeter
004
//24bit ADC IC: LTC2400
005
//4.096 precision reference: TI REF3040
006
//
007
//By coldtears electronics
008
//
009
//LTC2400 code is adapted from Martin Nawrath
010
//Kunsthochschule fuer Medien Koeln
011
//Academy of Media Arts Cologne
012
//
013
014
015
#include <Stdio.h>
016
#include<stdlib.h>
017
018
019
#ifndef cbi
020
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
021
#endif
022
#ifndef sbi
023
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
024
#endif
025
026
#define LTC_CS 0 // LTC2400 Chip Select Pin on Portb 2 * CS mega 0 uno 2
027
#define LTC_MISO 3 // LTC2400 SDO Select Pin on Portb 4 * Miso mega 3 uno 4
028
#define LTC_SCK 1 // LTC2400 SCK Select Pin on Portb 5 * SCK mega 1 uno 5
029
030
031
void
setup
() {
032
033
cbi(PORTB,LTC_SCK);
// LTC2400 SCK low
034
sbi (DDRB,LTC_CS);
// LTC2400 CS HIGH
035
036
cbi (DDRB,LTC_MISO);
037
sbi (DDRB,LTC_SCK);
038
039
Serial
.begin(57600);
040
041
// init SPI Hardware
042
sbi(SPCR,MSTR) ;
// SPI master mode
043
sbi(SPCR,SPR0) ;
// SPI speed
044
sbi(SPCR,SPR1);
// SPI speed
045
sbi(SPCR,SPE);
//SPI enable
046
047
//Serial.println("LTC2400 ADC Test");
048
049
}
050
float
volt;
051
float
v_ref=4.094;
// Reference Voltage, 5.0 Volt for LT1021 or 3.0 for LP2950-3
052
053
long
int
ltw = 0;
// ADC Data ling int
054
int
cnt;
// counter
055
byte
b0;
//
056
byte
sig;
// sign bit flag
057
char
st1[20];
// float voltage text
058
059
/********************************************************************/
060
void
loop
() {
061
062
cbi(PORTB,LTC_CS);
// LTC2400 CS Low
063
delayMicroseconds(1);
064
if
(!(PINB & (1 << 4))) {
// ADC Converter ready ?
065
// cli();
066
ltw=0;
067
sig=0;
068
069
b0 = SPI_read();
// read 4 bytes adc raw data with SPI
070
if
((b0 & 0x20) ==0) sig=1;
// is input negative ?
071
b0 &=0x1F;
// discard bit 25..31
072
ltw |= b0;
073
ltw <<= 8;
074
b0 = SPI_read();
075
ltw |= b0;
076
ltw <<= 8;
077
b0 = SPI_read();
078
ltw |= b0;
079
ltw <<= 8;
080
b0 = SPI_read();
081
ltw |= b0;
082
083
delayMicroseconds(1);
084
085
sbi(PORTB,LTC_CS);
// LTC2400 CS Low
086
087
if
(sig) ltw |= 0xf0000000;
// if input negative insert sign bit
088
ltw=ltw/16;
// scale result down , last 4 bits have no information
089
volt = ltw * v_ref / 16777216;
// max scale
090
char
tmp[10];
091
dtostrf(volt,6,6,tmp);
092
tmp[8]=
'V'
;
093
tmp[9]=
'\n'
;
094
Serial
.print(cnt++);
095
Serial
.print(
"; "
);
096
printFloat(volt,6);
// print voltage as floating number
097
Serial
.println(
" "
);
098
099
100
}
101
sbi(PORTB,LTC_CS);
// LTC2400 CS hi
102
delay(200);
103
104
}
105
/********************************************************************/
106
byte
SPI_read()
107
{
108
SPDR = 0;
109
while
(!(SPSR & (1 << SPIF))) ;
/* Wait for SPI shift out done */
110
return
SPDR;
111
}
112
/********************************************************************/
113
// printFloat from tim / Arduino: Playground
114
// printFloat prints out the float 'value' rounded to 'places' places
115
//after the decimal point
116
void
printFloat(
float
value,
int
places) {
117
// this is used to cast digits
118
int
digit;
119
float
tens = 0.1;
120
int
tenscount = 0;
121
int
i;
122
float
tempfloat = value;
123
124
// if value is negative, set tempfloat to the abs value
125
126
// make sure we round properly. this could use pow from
127
//<math.h>, but doesn't seem worth the import
128
// if this rounding step isn't here, the value 54.321 prints as
129
130
// calculate rounding term d: 0.5/pow(10,places)
131
float
d = 0.5;
132
if
(value < 0)
133
d *= -1.0;
134
// divide by ten for each decimal place
135
for
(i = 0; i < places; i++)
136
d/= 10.0;
137
// this small addition, combined with truncation will round our
138
139
tempfloat += d;
140
141
if
(value < 0)
142
tempfloat *= -1.0;
143
while
((tens * 10.0) <= tempfloat) {
144
tens *= 10.0;
145
tenscount += 1;
146
}
147
148
// write out the negative if needed
149
if
(value < 0)
150
Serial
.print(
'-'
);
151
152
if
(tenscount == 0)
153
Serial
.print(0, DEC);
154
155
for
(i=0; i< tenscount; i++) {
156
digit = (
int
) (tempfloat/tens);
157
Serial
.print(digit, DEC);
158
tempfloat = tempfloat - ((
float
)digit * tens);
159
tens /= 10.0;
160
}
161
162
// if no places after decimal, stop now and return
163
if
(places <= 0)
164
return
;
165
166
// otherwise, write the point and continue on
167
Serial
.print(
','
);
168
169
for
(i = 0; i < places; i++) {
170
tempfloat *= 10.0;
171
digit = (
int
) tempfloat;
172
Serial
.print(digit,DEC);
173
// once written, subtract off that digit
174
tempfloat = tempfloat - (
float
) digit;
175
}
176
}
Этот код нормально работал у меня.
Из за большого времени преобразования АЦП 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 не пробовал. Примеры из библиотеки работают нормально.
Скетч-пожалуйста, но писал его давно, и в нем не самые красивые решения
001
#include <Adafruit_ADS1015.h> //
002
#include <Wire.h> //
003
#include "rgb_lcd.h" //
004
rgb_lcd lcd;
//
005
Adafruit_ADS1115 ads;
//
006
007
//*************************************************************************************************
008
// П Е Р Е М Е Н Н Ы Е
009
010
int
adcD[100];
// массив для записи Diff измерений в память ардуино
011
int
adcS[100];
// массив для записи Singl измерений в память ардуино
012
int
nomb=100;
// сколько провести измерений для усреднения
013
float
voltsD = 0;
// переменная для Diff напряжения
014
float
voltsS = 0;
// переменная для Singl напряжения
015
long
time = 0;
016
long
volts = 0;
017
018
String UstrS=
""
;
//стринг для получения напряжения с точкой и со всеми значащими цифрами
019
String UstrD=
""
;
//стринг для получения напряжения с точкой и со всеми значащими цифрами
020
021
long
Ubat;
//переменная для измерения напряжения батарей
022
byte
UbatProc;
//переменная для напряжен бат в процентах
023
String UbatProcS =
""
;
//стринг для напряжения батарей в процентах
024
//*************************************************************************************************
025
void
setup
() {
026
lcd.begin(16, 2);
// set up the LCD's number of columns and rows
027
lcd.setRGB(255, 255, 0);
// установка желтого цвета LCD
028
029
lcd.setCursor(0, 0);
// начали вывод версии программы на LCD
030
lcd.print(
"firmware_v7 "
);
031
lcd.setCursor(0, 1);
// начали вывод на LCD Serial speed знать скорость для логгирования на компе
032
lcd.print(
"Serial_9600 "
);
033
delay(1000);
034
lcd.setCursor(0, 0);
// через 1 секунду чистим LCD
035
lcd.print(
" "
);
036
lcd.setCursor(0, 1);
//
037
lcd.print(
" "
);
038
039
Serial
.begin(9600);
040
ads.setGain(GAIN_TWOTHIRDS);
// 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default)
041
ads.begin();
//начинаем работу АЦП
042
}
043
044
//*****************************************************************************************************
045
void
loop
() {
046
Get_Ubat();
// идем на подпрограмму измерения напряжения батарей вольтметра
047
Find_UbatProcS();
// идем на подпрограмму сборки стринга с напряжением батарей в процентах
048
Get_ADC();
// идем на подпрограмму получения данных из АЦП в переменную
049
//Printscreen (); // подпрограмма вывода напряжений на экран
050
051
Find_UstrS();
// идем на подпрограмму получения стринга UstrS это напряжение с точкой и со всеми значащими цифрами
052
Find_UstrD();
// идем на подпрограмму получения стринга UstrD это напряжение с точкой и со всеми значащими цифрами
053
LCDout ();
// идем на подпрограмму вывода на LCD
054
OFout();
// идем на подпрограмму вывода в LOGVIEW
055
056
057
058
}
059
/*****************************************************************************************************************************/
060
void
Get_Ubat(){
// подпрограмма измеряет напряжение батарей через делитель на входе А1
061
Ubat = analogRead(A1);
062
Ubat = ((Ubat * 1000 / 1023 * 5) * 2.019 + 5) / 10 ;
// 2.019 коэф деления резисторного делителя
063
UbatProc = map(Ubat, 660 , 840 , 0 , 99);
// находим напряжение в процентах ,напряжение от 6.6 до 8.40 вольт
064
//if (UbatProc > 99) UbatProc = 0;
065
//if (UbatProc <= 1) UbatProc = 1;
066
//Serial.print("Ubat=");
067
//Serial.println(UbatProc);
068
069
}
070
071
/*****************************************************************************************************************************/
072
void
Find_UbatProcS(){
// подпрограмма собрать в стринг UbatProcS данные по заряду батарей в процентах
073
char
buffer [10];
// буфер для преобразований Long-Char
074
int
k=0;
// разные временные цифры
075
int
i=0;
// разные временные цифры
076
077
ltoa(UbatProc, buffer, 10);
// забросили в char буффер цифры из UbatProc
078
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе UbatProc
079
080
UbatProcS =
""
;
081
if
(UbatProc < 10 ) UbatProcS +=
" "
;
//
082
i=0;
083
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
084
UbatProcS += buffer [i];
//
085
i++;
086
}
087
UbatProcS +=
"%"
;
088
if
(UbatProc > 99) UbatProcS =
"???"
;
089
if
(UbatProc < 1) UbatProcS =
"???"
;
090
//Serial.println(UbatProcS);
091
}
092
/*****************************************************************************************************************************/
093
//подпрограмма для получения данных из АЦП в переменные voltsD и voltS
094
void
Get_ADC(){
095
long
results01 = 0;
// временная переменая для суммирования рез-ов Diff измерения ADC и вычисления ср. значения
096
long
results3 = 0;
// временная переменая для суммирования рез-ов Singl измерения ADC и вычисления ср. значения
097
float
multiplierD = 187.531 ;
// множитель для Diff 187.528 188.346;
098
float
multiplierS = 2076 ;
// множитель для Singl
099
long
tekmillis=millis();
// переменная содержит время начала работы цикла
100
101
for
(
int
x = 0; x < nomb; x ++){
// цикл от 0 до nomb раз проводит измерения
102
adcD[x] = ads.readADC_Differential_0_1();
// в массив заполняем результат измерения Diff
103
adcS[x] = ads.readADC_SingleEnded(3);
// в массив заполняем результат измерения Singl
104
}
// цикл закончен
105
time = (millis()-tekmillis);
// вычисляем время которое ушло на nomb раз измерения ADC и запись в память
106
107
for
(
int
x = 0; x < nomb; x ++){
// цикл от 0 до nomb раз берет данные из массива adcD и adcS
108
results01 = results01 + adcD[x];
// суммирует их
109
results3 = results3 + adcS[x];
110
}
111
voltsD = (results01/nomb * multiplierD/1000000);
// из суммы вычисляем среднее значение измерений Diff
112
voltsS = (results3 /nomb * multiplierS/1000000);
// из суммы вычисляем среднее значение измерений Singl
113
}
114
115
/*****************************************************************************************************************************/
116
void
Printscreen (){
117
Serial
.print(time);
// вывод потраченного времени
118
Serial
.print(
" mS : Singl "
);
119
Serial
.print (voltsS,2);
// Singl с двумя знаками
120
Serial
.print(
" : Diff "
);
121
Serial
.println(voltsD,4);
// Diff с четырмя знаками
122
Serial
.println(
""
);
123
}
124
/*****************************************************************************************************************************/
125
126
//подпрограмма для получения стринга UsrtS напряжения с точкой и со всеми значащими цифрами
127
void
Find_UstrS(){
128
129
130
char
buffer [10];
//буфер для преобразований Long-Char
131
int
k=0;
// разные временные цифры
132
int
i=0;
// разные временные цифры
133
134
ltoa((abs(voltsS)+0.005) *100, buffer, 10);
// забросили в char буффер цифры из volts
135
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус
136
137
UstrS =
""
;
// в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
138
139
if
(voltsS < 0) UstrS +=
"-"
;
//минус
140
if
(voltsS >= 0) UstrS +=
" "
;
//плюс
141
142
143
if
(k == 4) {
// если есть 4 значащих цифр
144
i=0;
145
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
146
if
(i == 2) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
147
UstrS += buffer [i];
//
148
i++;
149
}
150
}
151
152
if
(k == 3) {
// если есть 3 значащих цифр
153
UstrS +=
" "
;
154
i=0;
155
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
156
if
(i == 1) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
157
UstrS += buffer [i];
//
158
i++;
159
}
160
}
161
162
if
(k == 2) {
// если есть 2 значащих цифр
163
UstrS +=
" 0"
;
164
i=0;
165
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
166
if
(i == 0) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
167
UstrS += buffer [i];
//
168
i++;
169
}
170
}
171
172
if
(k == 1) {
// если есть 1 значащих цифр
173
UstrS +=
" 0.0"
;
174
i=0;
175
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
176
//if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
177
UstrS += buffer [i];
//
178
i++;
179
}
180
}
181
182
/*Serial.print("voltsS=");
183
Serial.print(voltsS);
184
Serial.print(" UstrS=");
185
Serial.print(UstrS);
186
Serial.print(" : k=");
187
Serial.println(k);
188
*/
189
190
191
//x++;
192
// }
193
// delay(10000);
194
195
}
196
/*****************************************************************************************************************************/
197
//подпрограмма для получения стринга UsrtD напряжения с точкой и со всеми значащими цифрами
198
void
Find_UstrD(){
199
200
201
char
buffer [10];
//буфер для преобразований Long-Char
202
int
k=0;
// разные временные цифры
203
int
i=0;
// разные временные цифры
204
205
ltoa((abs(voltsD)+0.00005) *10000, buffer, 10);
// забросили в char буффер цифры из volts
206
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус
207
208
UstrD =
""
;
// в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
209
210
if
(voltsD < 0) UstrD +=
"-"
;
//минус
211
if
(voltsD >= 0) UstrD +=
" "
;
//плюс
212
UstrD +=
" "
;
//просто форматирование
213
214
if
(k == 5) {
// если есть 5 значащих цифр
215
i=0;
216
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
217
if
(i == 1) UstrD +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
218
UstrD += buffer [i];
//
219
i++;
220
}
221
}
222
223
if
(k == 4) {
// если есть 4 значащих цифр
224
UstrD +=
"0."
;
225
i=0;
226
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
227
//if (i == 2) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
228
UstrD += buffer [i];
//
229
i++;
230
}
231
}
232
233
if
(k == 3) {
// если есть 3 значащих цифр
234
UstrD +=
"0.0"
;
235
i=0;
236
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
237
//if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
238
UstrD += buffer [i];
//
239
i++;
240
}
241
}
242
243
if
(k == 2) {
// если есть 2 значащих цифр
244
UstrD +=
"0.00"
;
245
i=0;
246
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
247
//if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
248
UstrD += buffer [i];
//
249
i++;
250
}
251
}
252
253
if
(k == 1) {
// если есть 1 значащих цифр
254
UstrD +=
"0.000"
;
255
i=0;
256
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
257
//if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
258
UstrD += buffer [i];
//
259
i++;
260
}
261
}
262
263
/*Serial.print("voltsD=");
264
Serial.print(voltsD,4);
265
Serial.print(" UstrD=");
266
Serial.print(UstrD);
267
Serial.print(" : k=");
268
Serial.println(k);
269
270
x++;
271
}
272
*/
273
}
274
/****************************************************************************************************************************/
275
void
LCDout(){
276
lcd.setCursor(0, 0);
// начали вывод напряжения на LCD
277
lcd.print(
"S "
);
278
lcd.print(UstrS);
279
lcd.print(
" V bat"
);
280
281
lcd.setCursor(0, 1);
// начали вывод во вторую строку LCD
282
lcd.print(
"D "
);
283
lcd.print(UstrD);
284
lcd.print(
" V "
);
285
lcd.print(UbatProcS);
//напряжение батарей в процентах
286
}
287
/*********************************************************************************************************************/
288
void
OFout(){
// подпрограмма вывода данных на USB порт для логирования в LOGVIEW
289
Serial
.print(
"$1;1;0;"
);
290
Serial
.print(voltsS,2);
291
Serial
.print(
";"
);
292
Serial
.print(voltsD,4);
293
Serial
.print(
";0"
);
294
Serial
.println(13,DEC);
295
}
296
/*******************************************************************************************/
И да, можно смотреть в стандартной программе для зарядников 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. Только биты конфига сами выбираем по даташиту.
01
#include <Wire.h>
02
#define ADR_ASD1115 0x48 //адрес ads1115
03
04
byte
writeBuf[3];
//для конфигурирования АЦП три байта
05
byte
readBuf[3];
//для чтения данных из АЦП три байта
06
07
float
myfloat;
08
const
float
VPS = 6.144 / 32768.0;
//вольт на шаг в зависимости от PGA усиления АЦП тут для 6.144
09
unsigned
int
val = 0;
10
//-------------------------------------------------------------------------------
11
void
setup
() {
12
Serial
.begin(9600);
13
Wire.begin();
// begin I2C
14
}
15
//--------------------------------------------------------------------------------
16
17
void
loop
() {
18
config_ads115();
// Конфигурирование и запуск преобразования ads1115
19
get_config();
// Прочитать конфиг биты и вывести на экран
20
get_voltage();
// Прочитать регистр преобразования, пересчитать в напряжение
21
22
}
23
//-------------------------------------------------------------------------------
24
void
config_ads115(){
// Конфигурирование и запуск преобразования ads1115
25
26
writeBuf[0] = 1;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
27
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг
28
29
writeBuf[1] = 0b10000000;
// биты с 15 по 8 конфигурации смотрим в даташите сами
30
31
32
writeBuf[2] = 0b10000011;
// биты с 7 по 0 конфигурации смотрим в даташите сами
33
34
Wire.beginTransmission(ADR_ASD1115);
//конфигурируем АЦП записью трех байт
35
Wire.write(writeBuf[0]);
// Указатель регистра
36
Wire.write(writeBuf[1]);
// биты с 15 по 8 конфигурации
37
Wire.write(writeBuf[2]);
// биты с 7 по 0 конфигурации
38
Wire.endTransmission();
39
40
delay(500);
41
}
42
43
//-------------------------------------------------------------------------------
44
void
get_voltage(){
// Прочитать регистр преобразования, пересчитать в напряжение
45
readBuf[0] = 0;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
46
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011)т.е. указали Conversion
47
48
Wire.beginTransmission(ADR_ASD1115);
// Начали читать данные из регистра преобразования
49
Wire.write(readBuf[0]);
// pointer указал в readBuf[0] записан 0 т.е. регистр преобразования
50
Wire.endTransmission();
51
52
Wire.requestFrom(ADR_ASD1115, 2);
// читаем из АЦП два байта
53
readBuf[1] = Wire.read();
//
54
readBuf[2] = Wire.read();
//
55
Wire.endTransmission();
56
57
58
val = readBuf[1] << 8 | readBuf[2];
// собираем два байта в кучу в переменную int val
59
60
if
(val > 32768) val = 0;
61
62
myfloat = val * VPS;
// пересчитываем в напряжение
63
64
Serial
.print(
"Sensor voltage = "
);
// вывод на экран результата
65
Serial
.println(myfloat);
66
67
}
68
//--------------------------------------------------------------------------------
69
void
get_config(){
// взять все биты конфига и вывести на экран
70
readBuf[0] = 1;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
71
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали config
72
73
Wire.beginTransmission(ADR_ASD1115);
// Начали читать данные из регистра конфига
74
Wire.write(readBuf[0]);
// pointer указал в readBuf[0] записан 1 т.е. регистр config
75
Wire.endTransmission();
76
77
Wire.requestFrom(ADR_ASD1115, 2);
// читаем из АЦП два байта
78
readBuf[1] = Wire.read();
//
79
readBuf[2] = Wire.read();
//
80
Wire.endTransmission();
81
82
Serial
.print(
"Config = "
);
//выводим на экран все биты конфига
83
Serial
.print(readBuf[1],BIN);
84
Serial
.print(
"_"
);
85
Serial
.println(readBuf[2],BIN);
86
87
}
88
89
//-------------------------------------------------------------------------------
Причесал немного софт, вернее в части работы с ads1115 сильно переделал:
- отказался от библиотеки ads1115
- конфиг теперь 128 SPS
- запускается каждое измерение, а не цикличный режим работы АЦП
- пусто-гон по кругу ожидает окончание каждого измерения
- добавлен фильтр измерений типа как я описывал выше
- переменными Filter_read и Filter_get устанавливается настройки фильтра. У меня примерно около 480mS круг и выдача данных на свой дисплей и в порт для LogView
- прилагаю ini файл для LogView
http://www.dropbox.com/s/cgslaod0kjfb74h/LogView_ini.zip?dl=0
Код еще можно чистить и править, но работает нормально на nano
001
#include <Wire.h> //
002
#include "rgb_lcd.h" //
003
rgb_lcd lcd;
//
004
#define ADR_ASD1115 0x48 //адрес ads1115
005
006
#define Filter_read 24 //!!! только четное число сколько читать значений из АЦП для работы фильтра
007
#define Filter_get 4 //!!! только четное число сколько взять значений для расчета среднего фильтром
008
009
010
float
float_voltsD = 0;
// переменная для Diff напряжения
011
float
float_voltsS = 0;
// переменная для Singl напряжения
012
013
014
String UstrS=
""
;
//стринг для получения напряжения с точкой и со всеми значащими цифрами
015
String UstrD=
""
;
//стринг для получения напряжения с точкой и со всеми значащими цифрами
016
017
long
Ubat;
//переменная для измерения напряжения батарей
018
byte
UbatProc;
//переменная для напряжен бат в процентах
019
String UbatProcStr =
""
;
//стринг для напряжения батарей в процентах
020
byte
writeBuf[3];
//для конфигурирования АЦП три байта
021
byte
readBuf[3];
//для чтения данных из АЦП три байта
022
023
int
raw;
//для получения одного значения ads raw из регистра преобразования АЦП после чтения
024
long
filter_raw;
//для получения множества значений raw из регистра преобразования АЦП после чтения по значениям Filter_read и Filter_get
025
026
long
time_start;
027
long
time_end;
028
//*************************************************************************************************
029
void
setup
() {
030
Wire.begin();
// begin I2C
031
Serial
.begin(9600);
032
lcd.begin(16, 2);
// set up the LCD's number of columns and rows
033
034
035
lcd.setRGB(255, 255, 0);
// установка желтого цвета LCD
036
lcd.setCursor(0, 0);
// начали вывод версии программы на LCD
037
lcd.print(
"firmware_v9 "
);
038
lcd.setCursor(0, 1);
// начали вывод на LCD Serial speed знать скорость для логгирования на компе
039
lcd.print(
"LogView_9600 "
);
040
delay(1000);
041
lcd.setCursor(0, 0);
// через 1 секунду чистим LCD
042
lcd.print(
" "
);
043
lcd.setCursor(0, 1);
//
044
lcd.print(
" "
);
045
046
047
}
048
049
//*****************************************************************************************************
050
void
loop
() {
051
time_start = micros();
052
053
Get_Ubat_328();
// идем на подпрограмму измерения напряжения батарей питания вольтметра
054
Find_UbatProcStr_328();
// идем на подпрограмму сборки стринга с напряжением батарей в процентах
055
056
filter_raw_calc_D();
// фильтр с дифф входа 0-1 прочитает множество измерений raw по
057
float_voltsD = 187.5420001;
// значениям Filter_read и Filter_get и в перменную filter_raw поместит среднее
058
float_voltsD *= filter_raw / Filter_get;
// значение вычислений. Остается пересчитать это сырое значение АЦП в напряжение
059
float_voltsD /= 1000000;
// 187.5420001 это калибровка датчика опытным путем
060
061
filter_raw_calc_S();
// фильтр с несимм входа GND-3 прочитает множество измерений raw по
062
float_voltsS = 2074.000001;
// значениям Filter_read и Filter_get и в перменную filter_raw поместит среднее
063
float_voltsS *= filter_raw / Filter_get;
// значение вычислений. Остается пересчитать это сырое значение АЦП в напряжение
064
float_voltsS /= 1000000;
// 2074.000001 это калибровка датчика с делителем напряжения опытным путем
065
066
Find_UstrS();
// идем на подпрограмму получения стринга UstrS это напряжение с точкой и со всеми значащими цифрами
067
Find_UstrD();
// идем на подпрограмму получения стринга UstrD это напряжение с точкой и со всеми значащими цифрами
068
LCDout ();
// идем на подпрограмму вывода на LCD
069
OFout();
// идем на подпрограмму вывода в LOGVIEW
070
071
time_end = micros();
072
//Printscreen (); // подпрограмма вывода напряжений на экран
073
074
}
075
/*****************************************************************************************************************************/
076
077
void
Get_Ubat_328(){
// подпрограмма измеряет напряжение батарей через делитель на входе А1
078
Ubat = analogRead(A1);
079
Ubat = ((Ubat * 1000 / 1023 * 5) * 2.019 + 5) / 10 ;
// 2.019 коэф деления резисторного делителя
080
UbatProc = map(Ubat, 660 , 840 , 0 , 99);
// находим напряжение в процентах ,напряжение от 6.6 до 8.40 вольт
081
//if (UbatProc > 99) UbatProc = 0;
082
//if (UbatProc <= 1) UbatProc = 1;
083
//Serial.print("Ubat=");
084
//Serial.println(UbatProc);
085
086
}
087
088
/*****************************************************************************************************************************/
089
void
Find_UbatProcStr_328(){
// подпрограмма собоать в стринг UbatProcStr данные по заряду батарей в процентах
090
char
buffer [10];
// буфер для преобразований Long-Char
091
int
k=0;
// разные временные цифры
092
int
i=0;
// разные временные цифры
093
094
ltoa(UbatProc, buffer, 10);
// забросили в char буффер цифры из UbatProc
095
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе UbatProc
096
097
UbatProcStr =
""
;
098
if
(UbatProc < 10 ) UbatProcStr +=
" "
;
099
i=0;
100
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
101
UbatProcStr += buffer [i];
102
i++;
103
}
104
UbatProcStr +=
"%"
;
105
if
(UbatProc > 99) UbatProcStr =
"???"
;
106
if
(UbatProc < 1) UbatProcStr =
"???"
;
107
//Serial.println(UbatProcStr);
108
}
109
110
//--------------------------------------------------------------------------------
111
void
read_config(){
// Читаем конфиг и по 15 биту ожидаем окончание преобразования АПЦ (можно читать один 1-й байт readBuf[1] если не нужен весь конфиг)
112
readBuf[0] = 1;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
113
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали config
114
115
do
{
116
Wire.beginTransmission(ADR_ASD1115);
// Начали читать данные из регистра конфига
117
Wire.write(readBuf[0]);
// pointer указал в readBuf[0] записан 1 т.е. регистр config
118
Wire.endTransmission();
119
120
Wire.requestFrom(ADR_ASD1115, 2);
// читаем из АЦП два байта
121
readBuf[1] = Wire.read();
122
readBuf[2] = Wire.read();
123
Wire.endTransmission();
124
125
}
while
(bitRead(readBuf[1],7)==0);
//читаем байты пока 15-й бит не станет равен 1 что значит одно измерение закончено
126
127
/*Serial.print("Config = ");
128
Serial.print(readBuf[1],BIN);
129
Serial.print("_");
130
Serial.print(readBuf[2],BIN);
131
Serial.print("_");
132
Serial.print(time_end-time_start);
133
*/
134
}
135
136
//-------------------------------------------------------------------------------
137
void
ads1115_config_Differential_0_1(){
138
writeBuf[0] = 1;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
139
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг
140
141
writeBuf[1] = 0b10000001;
// биты с 15 по 8 конфигурации
142
writeBuf[2] = 0b10000011;
// биты с 7 по 0 конфигурации
143
144
Wire.beginTransmission(ADR_ASD1115);
//конфигурируем АЦП записью трех байт
145
Wire.write(writeBuf[0]);
// Указатель регистра
146
Wire.write(writeBuf[1]);
// биты с 15 по 8 конфигурации
147
Wire.write(writeBuf[2]);
// биты с 7 по 0 конфигурации
148
Wire.endTransmission();
149
150
//delay(10); //
151
152
}
153
154
//-------------------------------------------------------------------------------
155
void
ads1115_config_Single_GND_3(){
156
writeBuf[0] = 1;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
157
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011) т.е. указали конфиг
158
159
writeBuf[1] = 0b11110001;
// биты с 15 по 8 конфигурации
160
writeBuf[2] = 0b10000011;
// биты с 7 по 0 конфигурации
161
162
Wire.beginTransmission(ADR_ASD1115);
//конфигурируем АЦП записью трех байт
163
Wire.write(writeBuf[0]);
// Указатель регистра
164
Wire.write(writeBuf[1]);
// биты с 15 по 8 конфигурации
165
Wire.write(writeBuf[2]);
// биты с 7 по 0 конфигурации
166
Wire.endTransmission();
167
168
//delay(10); //
169
170
}
171
172
//-----------------------------------------------------------------------------------------------------------------------
173
void
filter_raw_calc_D () {
// подпрограмма считывания и фильтрации значений с дифф входа 0-1
174
175
int
sortedValues[Filter_read];
//назначили массив с sortedValues[Filter_read]
176
for
(
int
i = 0; i < Filter_read; i++) {
//цикл от 0 до Filter_read
177
//delay(25); //
178
ads1115_config_Differential_0_1();
//идем на конфигурирование и старт одного измерения дифф входа 0-1
179
read_config();
//читаем конфиг и при чтении его ждем окончания преобразования
180
read_ads_raw();
//идем на чтение результата одного измерения raw ads
181
int
value = raw ;
//value получает значение одного измерения raw ads
182
int
j;
//переменная "j" куда вставлять значение при сортировке
183
if
(value < sortedValues[0] || i == 0) {
//если полученое значение valve < sortedValues[0] или это самое начало "i",то
184
j = 0;
//"j"= 0 это первая позиция
185
}
//конец if
186
else
{
//иначе
187
for
(j = 1; j < i; j++) {
//цикл j от 1 до j < i искать "j"
188
if
(sortedValues[j - 1] <= value && sortedValues[j] >= value) {
//ищем место"j" в sortedValues[]куда вставить value
189
break
;
//"j" найдено,остановить выполнение цикла
190
}
//конец if
191
}
//конец цикла j
192
}
//конец else
193
194
for
(
int
k = i; k > j; k--) {
//все значения от "i" до "j" (вниз к--) нужно поднять на одну позицию вверх
195
sortedValues[k] = sortedValues[k - 1];
//чтобы освободить место "j" для valve
196
}
//конец цикла
197
sortedValues[j] = value;
//вставить считаное valve в sortedValues[] в позицию "j"
198
}
//конец цикла от 0 до Filter_read
199
200
201
202
//расчет среднего знач из Filter_get. Эти значения взяты после отброса лишних значений
203
filter_raw = 0;
204
for
(
int
i = Filter_read / 2 - Filter_get/2; i < (Filter_read / 2 + Filter_get/2); i++) {
205
filter_raw += sortedValues[i];
206
}
207
208
}
209
210
//-----------------------------------------------------------------------------
211
void
filter_raw_calc_S () {
// подпрограмма считывания и фильтрации значений с дифф входа 0-1
212
213
int
sortedValues[Filter_read];
//назначили массив с sortedValues[Filter_read]
214
for
(
int
i = 0; i < Filter_read; i++) {
//цикл от 0 до Filter_read
215
//delay(25); //
216
ads1115_config_Single_GND_3();
//идем на конфигурирование и старт одного измерения несимметр входа GND-3
217
read_config();
//читаем конфиг и при чтении его ждем окончания преобразования
218
read_ads_raw();
//идем на чтение результата одного измерения raw ads
219
int
value = raw ;
//value получает значение одного измерения raw ads
220
int
j;
//переменная "j" куда вставлять значение при сортировке
221
if
(value < sortedValues[0] || i == 0) {
//если полученое значение valve < sortedValues[0] или это самое начало "i",то
222
j = 0;
//"j"= 0 это первая позиция
223
}
//конец if
224
else
{
//иначе
225
for
(j = 1; j < i; j++) {
//цикл j от 1 до j < i искать "j"
226
if
(sortedValues[j - 1] <= value && sortedValues[j] >= value) {
//ищем место"j" в sortedValues[]куда вставить value
227
break
;
//"j" найдено,остановить выполнение цикла
228
}
//конец if
229
}
//конец цикла j
230
}
//конец else
231
232
for
(
int
k = i; k > j; k--) {
//все значения от "i" до "j" (вниз к--) нужно поднять на одну позицию вверх
233
sortedValues[k] = sortedValues[k - 1];
//чтобы освободить место "j" для valve
234
}
//конец цикла
235
sortedValues[j] = value;
//вставить считаное valve в sortedValues[] в позицию "j"
236
}
//конец цикла от 0 до Filter_read
237
238
239
240
//расчет среднего знач из Filter_get. Эти значения взяты после отброса лишних значений
241
filter_raw = 0;
242
for
(
int
i = Filter_read / 2 - Filter_get/2; i < (Filter_read / 2 + Filter_get/2); i++) {
243
filter_raw += sortedValues[i];
244
}
245
246
}
247
248
//-----------------------------------------------------------------------------
249
250
void
read_ads_raw(){
251
raw = 0;
252
253
254
readBuf[0] = 0;
// Указатель регистра (Conversion register is 0b00000000; config register is 0b00000001,
255
// Lo_thresh register is 0b00000010;Hi_thresh register is 0b00000011)т.е. указали Conversion
256
257
Wire.beginTransmission(ADR_ASD1115);
// Начали читать данные из регистра преобразования
258
Wire.write(readBuf[0]);
// pointer указал в readBuf[0] записан 0 т.е. регистр преобразования
259
Wire.endTransmission();
260
261
Wire.requestFrom(ADR_ASD1115, 2);
// читаем из АЦП два байта
262
readBuf[1] = Wire.read();
//
263
readBuf[2] = Wire.read();
//
264
Wire.endTransmission();
265
266
267
raw = readBuf[1] << 8 | readBuf[2];
// собираем два байта в кучу в переменную int val
268
269
if
(raw > 32768) raw = 0;
270
271
272
}
273
/*****************************************************************************************************************************/
274
void
Printscreen (){
275
Serial
.print((time_end-time_start)/1000);
// вывод потраченного времени
276
Serial
.print(
" mS : Singl "
);
277
Serial
.print (float_voltsS,5);
// Singl с двумя знаками
278
Serial
.print(
" : Diff "
);
279
Serial
.println(float_voltsD,5);
// Diff с четырмя знаками
280
Serial
.println(
""
);
281
}
282
/*****************************************************************************************************************************/
283
284
//подпрограмма для получения стринга UsrtS напряжения с точкой и со всеми значащими цифрами
285
void
Find_UstrS(){
286
287
// float_voltsS = -10.999 ;
288
// int x=0;
289
// while (x <= 10000) {
290
// float_voltsS = float_voltsS + 0.01;
291
292
293
char
buffer [10];
//буфер для преобразований Long-Char
294
int
k=0;
// разные временные цифры
295
int
i=0;
// разные временные цифры
296
297
ltoa((abs(float_voltsS)+0.005) *100, buffer, 10);
// забросили в char буффер цифры из volts
298
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус
299
300
UstrS =
""
;
// в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
301
302
if
(float_voltsS < 0) UstrS +=
"-"
;
//минус
303
if
(float_voltsS >= 0) UstrS +=
" "
;
//плюс
304
305
306
if
(k == 4) {
// если есть 4 значащих цифр
307
i=0;
308
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
309
if
(i == 2) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
310
UstrS += buffer [i];
//
311
i++;
312
}
313
}
314
315
if
(k == 3) {
// если есть 3 значащих цифр
316
UstrS +=
" "
;
317
i=0;
318
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
319
if
(i == 1) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
320
UstrS += buffer [i];
//
321
i++;
322
}
323
}
324
325
if
(k == 2) {
// если есть 2 значащих цифр
326
UstrS +=
" 0"
;
327
i=0;
328
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
329
if
(i == 0) UstrS +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
330
UstrS += buffer [i];
//
331
i++;
332
}
333
}
334
335
if
(k == 1) {
// если есть 1 значащих цифр
336
UstrS +=
" 0.0"
;
337
i=0;
338
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
339
//if (i == 0) UstrS += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
340
UstrS += buffer [i];
//
341
i++;
342
}
343
}
344
345
/*Serial.print("float_voltsS=");
346
Serial.print(float_voltsS);
347
Serial.print(" UstrS=");
348
Serial.print(UstrS);
349
Serial.print(" : k=");
350
Serial.println(k);
351
*/
352
353
354
//x++;
355
// }
356
// delay(10000);
357
358
}
359
/*****************************************************************************************************************************/
360
//подпрограмма для получения стринга UsrtD напряжения с точкой и со всеми значащими цифрами
361
void
Find_UstrD(){
362
//float_voltsD = -1.9999 ;
363
//int x=0;
364
//while (x <= 10000) {
365
//float_voltsD = float_voltsD + 0.001;
366
367
368
char
buffer [10];
//буфер для преобразований Long-Char
369
int
k=0;
// разные временные цифры
370
int
i=0;
// разные временные цифры
371
372
ltoa((abs(float_voltsD)+0.00001) *10000, buffer, 10);
// забросили в char буффер цифры из volts
373
k=(strlen(buffer));
// k это кол-во цифр в буффере т.е. в числе volts и в том числе знак минус
374
375
UstrD =
""
;
// в Ustr начинаем собирать напряжение с точкой !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
376
377
if
(float_voltsD < 0) UstrD +=
"-"
;
//минус
378
if
(float_voltsD >= 0) UstrD +=
" "
;
//плюс
379
UstrD +=
" "
;
//просто форматирование
380
381
if
(k == 5) {
// если есть 5 значащих цифр
382
i=0;
383
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
384
if
(i == 1) UstrD +=
"."
;
// номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
385
UstrD += buffer [i];
//
386
i++;
387
}
388
}
389
390
if
(k == 4) {
// если есть 4 значащих цифр
391
UstrD +=
"0."
;
392
i=0;
393
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
394
//if (i == 2) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
395
UstrD += buffer [i];
//
396
i++;
397
}
398
}
399
400
if
(k == 3) {
// если есть 3 значащих цифр
401
UstrD +=
"0.0"
;
402
i=0;
403
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
404
//if (i == 1) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
405
UstrD += buffer [i];
//
406
i++;
407
}
408
}
409
410
if
(k == 2) {
// если есть 2 значащих цифр
411
UstrD +=
"0.00"
;
412
i=0;
413
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
414
//if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
415
UstrD += buffer [i];
//
416
i++;
417
}
418
}
419
420
if
(k == 1) {
// если есть 1 значащих цифр
421
UstrD +=
"0.000"
;
422
i=0;
423
while
(i <= (k-1)) {
// из буфера берем K цифр и вставляем их в Ustr
424
//if (i == 0) UstrD += "."; // номер i определяет где вставить точку т.е измерение 4 вольт или 17 вольт
425
UstrD += buffer [i];
//
426
i++;
427
}
428
}
429
430
/*Serial.print("float_voltsD=");
431
Serial.print(float_voltsD,4);
432
Serial.print(" UstrD=");
433
Serial.print(UstrD);
434
Serial.print(" : k=");
435
Serial.println(k);
436
437
x++;
438
}
439
*/
440
}
441
/****************************************************************************************************************************/
442
void
LCDout(){
443
lcd.setCursor(0, 0);
// начали вывод напряжения на LCD
444
lcd.print(
"S "
);
445
lcd.print(UstrS);
446
lcd.print(
" bat"
);
447
448
lcd.setCursor(0, 1);
// начали вывод во вторую строку LCD
449
lcd.print(
"D "
);
450
lcd.print(UstrD);
451
lcd.print(
" "
);
452
lcd.print(UbatProcStr);
//напряжение батарей в процентах
453
}
454
/*********************************************************************************************************************/
455
void
OFout(){
// подпрограмма вывода данных на USB порт для логирования в LOGVIEW
456
Serial
.print(
"$1;1;0;"
);
457
Serial
.print(float_voltsS,2);
458
Serial
.print(
";"
);
459
Serial
.print(float_voltsD,4);
460
Serial
.print(
";0"
);
461
Serial
.println(13,DEC);
462
}
463
/*******************************************************************************************/
Схема модуля 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 к , такой же результат.
Рассчет происходит тупо умножением измеренного напряжения на экспериментально подобранный коэффициент
Что я могу делать не так?