Секретний вольтметр Arduino - вимірювання напруги батареї засобами мікроконтролера. Створення зарядного пристрою, керованого Arduino

Arduinoмає кілька аналогових входів, використовуючи які можна вимірювати параметри аналогових величин. Це може бути напруга, струм, опір, температура, світло і таке інше. У деяких випадках для перетворення фізичних величин електричні сигнали можуть знадобитися спеціальні датчики. Сьогодні я розповім про використання та проведу тест продуктивності аналого-цифрового перетворювача (АЦП) Arduino. Тест я робитиму, використовуючи оригінальну плату Arduino Mega 2560, в основі якої лежить мікроконтролер ATMega 2560, що працює на частоті 16 МГц. Мікроконтролер ATMega328, на якому засновані Arduino Unoі Arduino Nano, також працює на частоті 16 МГц, так що все вищевикладене, швидше за все, справедливе і для цих та аналогічних плат.

analogRead

Давайте подивимося скільки часу займає аналого-цифрове перетворення з використанням стандартної функції analogRead.

Для визначення моментів початку і кінця перетворення я використовуватиму 12 висновок як маркер. Для початку повторимо експеримент, який я описував у статті. Змінюватимемо рівень напруги на 12 цифровому піні між станами LOWі HIGH. Для чистоти експерименту я поміщу всередину loopбезкінечний цикл.

Скетч, що реалізує прості перемикання на 12 цифровому виведенні виглядає так:

void setup() ( DDRB = B01000000; //встановлюємо 12 пін в режим виходу ) void loop() ( while(1) ( PORTB = B01000000; // встановлюємо пін 12 в стан HIGH PORTB = B00000000; // встановлюємо пін 12 стан LOW ) )

Скористаємося осцилографом та подивимося на часові параметри роботи цієї програми:

Звідси видно, що час перемикання стану піна займає в нас 62 нс (тривалість позитивного імпульсу).

Тепер трохи змінимо скетч та додамо між перемиканнями функцію читання аналогового сигналу analogReadна 3 аналоговому піні:

int analogPin = 3; // Вхідний аналоговий пін int analogValue = 0; void setup () (DDRB = B01000000; // встановлюємо 12 пін в режим виходу) void loop () (while (1) (PORTB = B01000000; // встановлюємо пін 12 в стан HIGH analogValue = analogRead (analogPin); // читає) аналоговий сигнал PORTB = B00000000; // встановлюємо пін 12 в стан LOW analogValue = analogRead(analogPin); // читаємо аналоговий сигнал

int analogPin = 3; // вхідний аналоговий пін

int analogValue = 0; // значення аналогового сигналу

void setup()

DDRB = B01000000; // встановлюємо 12 пін у режим виходу

void loop ()

while (1 )

PORTB = B01000000; // встановлюємо пін 12 стан HIGH

// читаємо аналоговий сигнал

PORTB = B00000000; // встановлюємо пін 12 стан LOW

analogValue = analogRead (analogPin); // читаємо аналоговий сигнал

Осцилограма сигналу на 12 цифровому піні тепер виглядатиме так:

Тривалість перемикання в 62 нс і час циклічного повернення до початку програми в 124 нс не перевищують похибку вимірювання на цьому тимчасовому масштабі і ми можемо знехтувати цими тимчасовими проміжками. Звідси видно, що час, що витрачається на аналого-цифрове перетворення, приблизно дорівнює 112 мкс, тому максимальна частота вибірки при використанні функції analogReadвбирається у 8.9 кГц.

Недоліком використання analogReadє ще й те, що Arduinoне може виконувати інший код під час очікування результату перетворення.

Використовуємо переривання АЦП

Так як ATMega2560не використовує ядро ​​процесора під час захоплення аналогових сигналів, то це марна витрата можливостей обробки. Особливо, коли нам потрібна безперервна вибірка сигналу. Таку вибірку можна реалізувати дещо складнішим способом, використовуючи переривання. Так як немає вбудованої функції для встановлення аналогового перетворення з перериваннями, то регістри, пов'язані з АЦП повинні бути оброблені вручну.

Разова вибірка

Разова вибірка - це насправді те, що Arduinoробить під час виклику функції analogRead. Ми не зможемо отримати значних переваг, реалізувавши одноразову вибірку за допомогою інших засобів. Оскільки перед запуском АЦП, в першу чергу перевіряється прапор готовності АЦП, це означає, що перевірка прапора в циклі нічим не відрізняється від того, що робить Arduino.

Безперервна вибірка

Хорошою ідеєю при безперервній вибірці сигналу є використання переривань. Мікроконтролери ATMega328і ATMega2560можуть бути переведені в режим безперервної вибірки ( free running mode). У цьому режимі АЦП запускається автоматично після завершення попередньої обробки. Щоразу перетворення закінчується генеруванням переривання, яке викликає функцію обробки переривання ISR (ADC_vect), В якій результат аналого-цифрового перетворення може бути рахований та оброблений.

Для включення режиму безперервної вибірки необхідно встановити три регістри: ADMUX, ADCSRAі ADCSRB. Детальний описцих регістрів можна знайти у технічних посібниках до мікроконтролерів.

Внутрішня опорна напруга 1.1 і вхідний аналоговий канал ADC3вибираються за допомогою ADMUX. Тактова частота задається за допомогою ADCSRAі в нашому прикладі встановлена ​​у вигляді дільника ÷16. Одне аналогове перетворення займає 13 тактових періодів. Частота дискретизації може бути обчислена, виходячи з тактової частотимікроконтролера: 16 Мгц/(16*13) ≈ 77 кГц. Установкою 6 біта регістру ADCSRAу стан HIGH, запускається безперервна вибірка.

Результат аналого-цифрового перетворення зчитується у функцію обробки переривання ISR (ADC_vect). Оскільки результат має довжину 10 біт, то він ділиться на два регістри ADCLі ADCHрозміром в один байт кожен. Для коректного читання значення спочатку слід вважати значення регістру ADCL, а потім - регістра ADCH.

Приклад скетчу, в якому результат, отриманий з АЦП, копіюється в цілочисленну змінну. analogValue:

int analogValue = 0; // значення аналогового сигналу void setup() (DDRB = B01000000; // pin 12 в режимі OUTPUT DIDR0 = 0x3F; // відключаємо цифрові входи ADMUX = 0x43; // вимірюємо на ADC3, використовуємо внутрішнє опорне напр. = 1.1В ADRA 0xAC; // включаємо АЦП, дозволяємо переривання, дільник = 16 ADCSRB = 0x40; // включаємо АЦ конали MUX, режим ковзної вибірки bitWrite(ADCSRA, 6, 1); sei(); ( ) /*** Процедура обробки переривання АЦП ***/ ISR(ADC_vect) ( PORTB = B00000000; // пін 12 переводимо в стан LOW analogValue = ADCL; // зберігаємо молодший байт результату АЦП analogValue += ADCH<< 8; // сохраняем старший байт АЦП PORTB = B01000000; // пин 12 переводим в состояние HIGH }

int analogValue = 0; // значення аналогового сигналу

void setup()

DDRB = B01000000; // pin 12 у режимі OUTPUT

DIDR0 = 0x3F; // відключаємо цифрові входи

ADMUX = 0x43; // Вимірюємо на ADC3, використовуємо внутрішнє опорне напр. = 1.1В

ADCSRA = 0xAC; // Включаємо АЦП, дозволяємо переривання, дільник = 16

ADCSRB = 0x40; // Включаємо АЦ конали MUX, режим ковзної вибірки

bitWrite (ADCSRA, 6, 1); // Запускаємо перетворення установкою біта 6 (= ADSC) ADCSRA

sei(); // встановлюємо прапор переривання

void loop ()

/*** Процедура обробки переривання АЦП ***/

ISR (ADC_vect)

PORTB = B00000000; // пін 12 переводимо у стан LOW

analogValue = ADCL; // Зберігаємо молодший байт результату АЦП

analogValue + = ADCH<< 8 ; // Зберігаємо старший байт АЦП

PORTB = B01000000; // пін 12 переводимо у стан HIGH

Результат роботи програми на екрані осцилографа:

Для вимірювання часу виконання ми переводимо стан піна в LOWпотім зчитуємо АЦП, після чого знову встановлюємо високий рівень. На виклик обробника переривання потрібен час, з цим пов'язана досить велика тривалість позитивної частини періоду.

Цикл loopтепер повністю вільний і може використовуватися для обробки будь-якого коду.

Опорна напруга

Для вимірювання аналогового сигналу у нас має бути певний рівень напруги, з яким ми будемо порівняти. У мікроконтролерах ATMega328і ATMega2560, які використовуються в Arduinoопорна напруга також є максимальною напругою, яка може бути виміряна. Напруги завжди вимірюються щодо землі. У Arduinoє три можливі джерела опорної напруги: AV cc- яке з'єднується з цифровою лінією живлення 5 В, внутрішня напруга 1.1 В (для Arduino Megaможливий ще варіант 2.56) і зовнішнє джерело опорної напруги. Через те, що вимірювання вхідних напруг виробляються щодо опорної напруги, флуктуації опорної напруги впливають на результат.

Опорну напругу можна встановити за допомогою функції або за допомогою бітів REFTу регістрі ADMUX.

Опорна напруга AV cc

AV ccє опорною напругою за умовчанням і воно використовується коли напруги, що вимірюваються, безпосередньо залежать від напруги джерела живлення. Наприклад, у випадку, де потрібно виміряти напругу в резисторному напівмості, як показано на малюнку нижче.

Використання опорної напруги 5В при вимірі опору в напівмості

Якщо з якихось причин напруга джерела живлення впаде, то напруга в точці з'єднання двох резисторів впаде пропорційно. Через те, що тепер опорна та вхідна напруга змінюються пропорційно, то і результат АЦП залишиться таким самим.

Внутрішня опорна напруга 1.1

Використовуйте внутрішню опорну напругу 1.1 для точних вимірювань зовнішніх напруг. Опорна напруга 1.1 більш стабільно і не залежить від зміни напруги живлення або температури. Таким чином, можна проводити вимірювання абсолютних значень. У Arduino Megaтакож можливий варіант опорної напруги 2.56 В. Приклад на малюнку нижче використовується опорна напруга 1.1 В і дільник напруги 10:1 для вимірювання зовнішньої напруги в діапазоні від 0 до 11 В.

Використання зовнішньої опорної напруги або внутрішньої напруги 1.1 при вимірюванні зовнішніх напруг

Похибка

Відповідно до технічного посібника для мікроконтролерів ATMega328і ATMega2560опорна напруга становить 1.1±0.1 В. Це досить великий допуск. Виміряна опорна напруга тестованої Arduino Mega 2560 було 1.089 при температурі навколишнього повітря 21 °С і температура корпусу мікроконтролера була 29 ºC.

Я охолодив корпус мікроконтролера, що не проводить струм охолоджуючим спреєм Kontakt Chemie FREEZE 75/200до температури -18 °С, при цьому виміряна опорна напруга знизилася до 1.084 В. Таким чином, температурний дрейф становив приблизно 100 ppm(Мільйонних часток) / °C.

Тестовий скетч:

int analogPin = 3; // вхідний аналоговий пін void setup() ( analogReference(INTERNAL1V1); // вибираємо внутрішню опорну напругу 1.1В Serial.begin(9600); ) void loop() ( int analogValue = analogRead(analogPin); // читаємо значення на аналоговому вході Serial.println(analogValue); // виводимо його в послідовний порт delay(300);

int analogPin = 3; // вхідний аналоговий пін

void setup()

// вибираємо внутрішню опорну напругу 1.1В

Serial. begin (9600);

void loop ()

// Читаємо значення на аналоговому вході

Serial. println (analogValue); // Виводимо його в послідовний порт

delay (300);

Аналоговий пін 3 був підключений до джерела напруги 0.545 В. За температури 29 °C результат повинен бути: (0.545/1.089)*1024 = 512 (реально отримане значення - 511). При температурі -18 °C має бути (0.545/1.084) * 1024 = 515 (реально отримане значення також 515).

Як показав експеримент, температурний дрейф невеликий і для точних вимірів при використанні Arduinoйого потрібно відкалібрувати через його велику загальну невизначеність опорної напруги, що становить близько 10%.

Шум

Одним із способів виміряти рівень шуму є визначення розкиду значень, які отримують з АЦП. Для цього подамо стабілізовану постійну напругу на один із аналогових входів і перетворені за допомогою АЦП значення використовуємо для побудови гістограми.

Тестовий ланцюг

Схема на малюнку нижче забезпечує тестову напругу для Arduino.

Схема, що подає регульовану постійну напругу на аналоговий вхід Arduino

Стабілізований регульований джерело живлення видає напругу 0.55, що становить половину від опорної напруги в 1.1 В. На фотографії нижче видно, що вбудований в моє регульоване джерело живлення вольтметр явно прибріхує, показуючи напругу на виході 0.4 В.

Сигнал додатково фільтрується за допомогою ланцюжка R1, C1, C2та підключається через резистор R2, що має опір 100 Ом до аналогового входу A3 Arduino. Земля підключається до піна GND Arduino.

Шумова складова на вході Arduinoвиглядає наступним чином:

Звідси видно, що середньоквадратичне значення амплітуди змінної складової вимірюваної напруги на вході АЦП Arduinoстановить лише одиниці мілівольт.

Біннінг

АЦП мікроконтролерів ATMega328і ATMega2560має роздільну здатність 2 10 = 1024 біта. Ідея бінінга полягає у підрахунку частоти спостереження певного значення. Створюється масив з 1024 значеннями, які називаються бінами, які представляють кожне з можливих значень АЦП. Так як доступна пам'ять обмежена, можуть бути створені бины лише розміром байт. Число відліків, отже, обмежується 255.

Програми

Протестуємо шум, використовуючи функцію analogRead, а потім використовуємо переривання. Дві програми, по суті, роблять те саме: визначають масив, що складається з 1024 бін. У функції setupвсі біни ініціалізуються нулем і вибирається опорна напруга 1.1.

Обидві програми виробляють 10 000 фіктивних операцій читання аналогового значення. Після цього запускається біннінг і кожному результаті АЦП, відповідний бін збільшується на одиницю. Якщо один із 1024 бінів досягне максимуму з 255 значень, вибірка зупиняється і всі 1024 біни відправляються на комп'ютер.

Код прикладу бінгінгу виміряних значень, використовуючи функцію analogRead:

Показати/приховати код

int analogPin = 3; // Вхідний аналоговий пін int sendStatus = 0; // Статус передачі int startDelay = 0; byte valueBin; // значення бінів void setup() (analogReference(INTERNAL1V1); // вибираємо опорну напругу 1.1В for (int i=0; i<=1023; i++) valueBin[i] = 0; // очищаем бины Serial.begin(9600); Serial.println("Start"); } void loop() { int analogValue = analogRead(analogPin); // выборка аналогового входа if (sendStatus == 0) { // ничего не делаем первые 10000 выборок if (startDelay < 10000) startDelay++; else { valueBin += 1; // увеличиваем значение бина if (valueBin == 255) sendStatus = 1; } } if (sendStatus == 1) { for (int i=0; i<=1023; i++) { // выводим значение бина Serial.print(i); Serial.print("\t"); Serial.println(valueBin[i]); } Serial.println("Done"); sendStatus = 2; } }

int analogPin = 3; // вхідний аналоговий пін

int sendStatus = 0; // Статус передачі

int startDelay = 0;

byte valueBin [1024]; // значення бінів

void setup()

analogReference (INTERNAL1V1); // Вибираємо опорну напругу 1.1В

for (int i = 0; i<= 1023 ; i ++ ) valueBin [ i ] = 0 ; // очищаем бины

Serial. begin (9600);

void loop ()

int analogValue = analogRead (analogPin); // Вибірка аналогового входу

if (sendStatus == 0 )

// нічого не робимо перші 10000 вибірок

if (startDelay< 10000 ) startDelay ++ ;

else

valueBin [analogValue] + = 1; // збільшуємо значення бина

// зупиняємось, якщо бін повний

if (valueBin [analogValue] == 255) sendStatus = 1;

if (sendStatus == 1 )

for (int i = 0; i<= 1023 ; i ++ )

// виводимо значення бина

Serial. print(i);

Serial. print ("\t");

Serial. println (valueBin [i]);

Serial. println ("Done");

sendStatus = 2;

Код прикладу бінгінгу виміряних значень, використовуючи переривання:

Показати/приховати код

int sendStatus = 0; // Статус передачі int startDelay = 0; byte valueBin; // значення бінів void setup() ( TIMSK0 = 0x00; // відключаємо таймер (через переривання) DIDR0 = 0x3F; // відключаємо цифрові входи ADMUX = 0xC3; // вимірюємо на ADC3, без коригування, внутр.опорне напр. 1.1В ADCSRA = 0xAC; // включаємо АЦП, дозволяємо переривання, дільник = 128 ADCSRB = 0x40; // Включаємо канали MUX АЦП, режим постійної вибірки bitWrite(ADCSRA, 6, 1); ) ADCSRA sei(); // встановлюємо глобальний прапор переривань for (int i=0; i<=1023; i++) valueBin[i] = 0; // очищаем бины Serial.begin(9600); Serial.println("Start"); } void loop() { if (sendStatus == 1) { for (int i=0; i<=1023; i++) { // выводим значения бинов Serial.print(i); Serial.print("\t"); Serial.println(valueBin[i]); } Serial.println("Done"); sendStatus = 2; } } /*** Процедура обработки прерывания АЦП ***/ ISR(ADC_vect) { int analogValue = ADCL; // сохраняем младший байт АЦП analogValue += ADCH << 8; // сохраняем старший байт АЦП if (sendStatus == 0) { // ничего не делаем первые 10000 выборок if (startDelay < 10000) startDelay++; else { valueBin += 1; // увеличиваем значение бина if (valueBin == 255) sendStatus = 1; { // останавливаемся, если бин полон } } }

int sendStatus = 0; // Статус передачі

int startDelay = 0;

byte valueBin [1024]; // значення бінів

void setup()

TIMSK0 = 0x00; // відключаємо таймер (через переривання)

DIDR0 = 0x3F; // відключаємо цифрові входи

ADMUX = 0xC3; // Вимірюємо на ADC3, без коригування, внутр.опорне напр. 1.1В

ADCSRA = 0xAC; // Включаємо АЦП, дозволяємо переривання, дільник = 128

ADCSRB = 0x40; // Включаємо канали MUX АЦП, режим постійної вибірки

bitWrite (ADCSRA, 6, 1); // Запускаємо перетворення установкою біта 6 (= ADSC) ADCSRA

sei(); // встановлюємо глобальний прапор переривань

for (int i = 0; i<= 1023 ; i ++ ) valueBin [ i ] = 0 ; // очищаем бины

Serial. begin (9600);

Serial. println ("Start");

void loop ()

if (sendStatus == 1 )

for (int i = 0; i<= 1023 ; i ++ )

{ // Виводимо значення бінів

Serial. print(i) ;

Serial. print("\t") ;

Serial. println(valueBin[ i] ) ;

}

Serial. println("Done") ;

sendStatus= 2 ;

// зупиняємось, якщо бін повний

}

}

}

Тестовані частоти

Тест проводився з використанням функції analogRead та використовуючи режим безперервної вибірки. Так як в останньому випадку частоту вибірки можна змінювати, тестувалися чотири різні частоти вибірки, що задаються шляхом зміни значення в рядку ADCSRA = 0xAC. Тестовані частоти: 9.6 кГц (тактова частота) clk÷128), 19.2 кГц ( clk÷64), 38.4 кГц ( clk÷32) та 76.9 кГц ( clk÷16). Частота вибірки під час використання функції analogReadЯк ми з'ясували вище приблизно дорівнює 8.9 кГц.

Результати

Результати для обох способів та різних частот вибірки виявилися схожими. Вибірки розділилися на 2 бина і лише деякі вибіркові значення потрапили до третього біну. Це означає, що рівень шуму завжди досить низький.

Перемикання між входами

Вибір аналогового входу здійснюється у рядку analogPin=nде nє номером аналогового піна або зміною бітів вибору аналогового каналу MUXу регістрі ADMUX. Особливу увагу слід приділити при використанні режиму безперервної вибірки: аналоговий канал потрібно вибрати перед стартом нового аналогового перетворення. У процедурі обробки переривання вибирається аналоговий вхід, який зчитуватиметься в момент наступного переривання.

Щоб перевірити рівень шуму та похибку при перемиканні входів, потрібно трохи змінити представлені вище програми. Друга напруга подається на аналоговий вхід 5. Крім того, проводиться бінгінг виміряних значень, як і при тестуванні шуму.

= 0xC3;

intanalogValue= ADCL;

. . .

Результати

Обидва виміряні напруги видно як два виступи на гістограмах. На малюнку нижче представлені гістограми п'яти тестів: з використанням функції analogRead, безперервна вибірка з clk÷128, clk÷64, clk÷32 та clk÷16. Виміряні значення першого напруження (результат обробки АЦП = 511) не відхиляються від попереднього тесту шуму. Вимірювання, як і раніше, точне. Навколишніх бінів дуже мало, це означає, що рівень шуму не збільшився.

На кожній з п'яти гістограм показано дві області з виступами, що представляють дві виміряні напруги

Частота вибірки та дозвіл

Коди, що реалізують бінгінг, використані і для аналізу дозволу і частоти вибірки. Для цього тесту до аналогового входу Arduinoбув підключений генератор функцій, як показано на малюнку нижче.

Генератор функцій подає з напругою розмаху 25 мВ і напругою зміщення (= середньому значенню) 0.55 В. На кожному вимірі частота сигналу вибирається таким чином, щоб частота вибірки була в 163 рази вище.

Трикутний сигнал вибраний через те, що кожне значення при квантуванні зустрічається однаково часто. При біннінгу такого сигналу кожне значення бина з мінімальним і максимальним значеннями напруги може мати те саме число повторень.

Результати

Результати тестування показали, що функція analogRead, що працює з низькою частотою дискретизації та безперервна вибірка з частотою clk÷128 мають достатню плоску вершину: всі значення в діапазоні зустрічаються з одним і тим самим числом повторень. Але на вищих частотах дискретизації ( clk÷64, clk÷32 та clk÷16) виникають провали в області бінінгу і зі зростанням частоти ситуація погіршується.

Велика частота вибірки призводить до провалів

У технічних описах на мікроконтролери ATmega

У цій статті наводиться цікава схема для любителів експериментів та Arduino. У ній представлений простий цифровий вольтметр, який може безпечно вимірювати постійну напругу в діапазоні від 0 до 30 В. Сама платня Arduino може живитися від стандартного джерела 9 В.



Як відомо, за допомогою аналогового входу Arduino можна виміряти напругу від 0 до 5 (при стандартному опорному напрузі 5 В). Але цей діапазон можна розширити, скориставшись дільником напруги.


Дільник знижує вимірювану напругу до прийнятного для аналогового входу рівня. Потім спеціально написаний код вираховує фактичну напругу.



Аналоговий датчик у складі Arduino визначає напругу на аналоговому вході і перетворює його на цифровий формат, що сприймається мікроконтролером. До аналогового входу A0 ми підключаємо дільник напруги, утворений опорами R1 (100K) та R2 (10K). З такими значеннями опорів на Arduino можна подавати до 55, оскільки коефіцієнт поділу в даному випадку виходить 11, тому 55В/11=5В. Для того, щоб бути впевненим у безпеці вимірів для плати, краще проводити вимір напруги в діапазоні від 0 до 30 В.



Якщо показання дисплея не відповідають показанням повіреного вольтметра, слід використовувати цифровий прецизійний мультиметр для знаходження точних значень R1 і R2. При цьому в коді потрібно буде замінити R1=100000.0 та R2=10000.0 своїми значеннями. Потім варто перевірити живлення, вимірявши на платі напругу між 5V та GND. Напруга може бути 4.95 В. Тоді в коді vout=(value*5.0)/1024.0 потрібно замінити 5.0 на 4.95. Бажано використовувати прецизійні резистори з похибкою трохи більше 1%. Пам'ятайте, що напруга вище 55 В може вивести плату Arduinoз ладу!



#include LiquidCrystal lcd(7, 8, 9, 10, 11, 12); int analogInput = 0; float vout = 0.0; float vin = 0.0; float R1 = 100000.0; // опір R1 (100K) float R2 = 10000.0; // Опір R2 (10K) int value = 0; void setup()( pinMode(analogInput, INPUT); lcd.begin(16, 2); lcd.print("DC VOLTMETER"); ) void loop()( // зчитування аналогового значення value = analogRead(analogInput); vout = (value * 5.0) / 1024.0; vin = vout / (R2/(R1+R2));<0.09) { vin=0.0;// обнуляем нежелательное значение } lcd.setCursor(0, 1); lcd.print("INPUT V= "); lcd.print(vin); delay(500); }


Використовувані елементи:


Плата Arduino Uno
Резистор 100 кому
Резистор 10 кім
Резистор 100 Ом
Потенціометр 10 КІМ
LCD-дисплей 16×2

Із деякими доповненнями.

Мало відома фішка Ардуїно та багатьох інших AVR чіпів це можливість виміряти внутрішнє джерело опорної напруги 1.1 Ст. Ця функція може бути використана для підвищення точностіфункції Arduino - analogRead при використанністандартної опорної напруги 5 В (на платформах з напругою живлення 5 В) або 3.3 (на платформах з напругою живлення 3.3 В).Вона також може бути використана для вимірювання Vcc, поданого на чіп, забезпечуючи засіб контролю напруги батареї без використаннядорогоцінних аналогових висновків.

Мотивація

Є, принаймні принаймні дві причинидля виміру напруги, що живитьнаш Arduino (Vcc). Одним із них є наш проект, який живиться від батареї, якщо ми хочемо стежити за рівнем напруги батареї. Крім того, коли живлення від батареї (Vcc) не може бути 5,0 вольт (наприклад живлення від 3-х елементів 1.5 В), а ми хочемо зробити аналогові вимірювання більш точними - ми повинні використовувати або внутрішнє джерело опорної напруги 1,1 В або зовнішнє джерело опорної напруги. Чому?

Зазвичай припускають при використанні analogRead() те, що аналогова напруга живлення контролера становить 5.0 вольт, коли насправді це може бути зовсім не так (наприклад живлення від 3 елементів 1.5 В). Офіційна документація Arduino може навіть привести нас до цього неправильного припущення. Справа в тому, що харчування не обов'язково 5,0 вольт, незалежно від поточного рівня, це харчування подано на Vcc чіпа. Якщо наше живлення не стабілізоване або якщо ми працюємо від акумулятора, ця напруга може змінюватись зовсім небагато. Ось приклад коду, що ілюструє цю проблему:

Double Vcc = 5.0; // Необов'язково правда int value = analogRead(0); / читаємо показання з А0 double volt = (value/1023.0) * Vcc; // Правильно тільки якщо Vcc = 5.0 вольт Для того щоб виміряти напругу точно, необхідна точна опорна напруга. Більшість чіпів AVR забезпечує три джерела опорної напруги:

  • 1,1 від внутрішнього джерела, в документації він проходить як bandgap reference (деякі з них 2,56 В, наприклад ATMega 2560). Вибір здійснюється функцією analogReference() з параметром INTERNAL: analogReference(INTERNAL);
  • зовнішнє джерело опорного натягу, на ардуїнці підписано AREF. Вибір: analogReference(EXTERNAL);
  • Vcc – джерело живлення самого контролера. Вибір: analogReference(DEFAULT).

В Arduino не можна просто взяти і підключити Vcc до аналогового піна безпосередньо - за замовчуванням AREF пов'язаний з Vcc і ви завжди отримуватимете максимальне значення 1023, від якої напруги ви не харчувалися. Рятує підключення до AREF джерела напруги із заздалегідь відомою, стабільною напругою, але це - зайвий елемент у схемі.

Ще можна з'єднати Vcc з AREF через діод: падіння напруга на діоді заздалегідь відомо, тому обчислити Vcc не важко. Однак, за такої схеми через діод постійно протікає струмскорочуючи життя батареї, що теж не дуже вдало.

Джерело зовнішньої опорної напруги є найточнішим, але потребує додаткових апаратних засобів. Внутрішній ІОН стабільний, але не точний +/- 10% відхилення. Vcc є абсолютно ненадійним у більшості випадків. Вибір внутрішнього джерела опорної напруги є недорогим і стабільним, але більшу частину часу, ми хотіли б виміряти більшу напругу ніж 1.1 В, так що використання Vcc є найбільш практичним, але потенційно найменш точним. У деяких випадках воно може бути дуже ненадійним!

Як це зробити

Багато чіпів AVR, включаючи серію ATmega і ATtiny, забезпечують засоби для вимірювання внутрішньої опорної напруги. Навіщо це потрібно? Причина проста - шляхом вимірювання внутрішньої напруги ми можемо визначити значення Vcc. Ось як:

  1. Встановити джерело опорної напруги за промовчанням: analogReference(DEFAULT); . Використовуємо як джерело – Vcc.
  2. Зняти показання АЦП для внутрішнього джерела 1.1.
  3. Розрахувати значення Vcc ґрунтуючись на вимірі 1.1 за формулою:

Vcc * (Покази АЦП) / 1023 = 1.1 В

З чого випливає:

Vcc = 1,1 В * 1023/(Покази АЦП)

Збираємо всі разом та отримуємо код:

long readVcc() ( // Read 1.1V reference against AVcc // set reference to Vcc and measurement to internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega25 (REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); (MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | MUX2) |_BV(MUX1);#endif delay(75);// Wait for Vref to settle ADCSRA |= _BV(ADSC); ADCL;// must read ADCL first - it then locks ADCH uint8_t high = ADCH;// unlocks both long result = (high<<8) | low; result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts }

Використання

Перевірка напруги Vcc чи батареї

Ви можете назвати цю функцію – readVcc(), якщо Ви бажаєте моніторити Vcc. Прикладом може бути перевірка рівня заряду батареї. Ви також можете використовувати її для визначення підключення до джерела живлення або працюєте від батареї.

Вимір Vcc для опорної напруги

Ви також можете використовувати її, щоб отримати правильне значення Vcc для використання з analogRead(), коли ви використовуєте опорну напругу (Vcc). Поки Ви не використовуєте стабілізоване джерело живлення, Ви не можете бути впевнені, що Vcc = 5.0 V. Ця функція дає змогу отримати правильне значення. Хоча є один нюанс.

В одній із статей я зробив заяву, що ця функція може використовуватися, щоб покращити точність аналогових вимірів у тих випадках, коли Vcc було не зовсім 5.0 вольт. На жаль, ця процедура не даватиме точний результат. Чому? Це залежить від точності внутрішнього джерела опорної напруги. Специфікація дає номінальну напругу 1.1 вольт, але говориться, що вона може відрізнятися до 10%. Такі вимірювання можуть бути менш точними, ніж джерело живлення Arduino!

Підвищуємо точність

Поки великі допуски внутрішнього джерела живлення 1.1 Ст значно обмежують точність вимірювань при використанні в серійному виробництві, для індивідуальних проектів ми можемо досягти більшої точності. Зробити це просто, просто вимірявши Vcc за допомогою вольтметра та нашої функції readVcc(). Далі замінюємо константу 1125300L новою змінною:

scale_constant = internal1.1Ref * 1023 * 1000

internal1.1Ref = 1.1 * Vcc1 (покази_вольтметра) / Vcc2 (покази_функції_readVcc())

Це значення, що калібрується, буде хорошим показником для вимірювань AVR чіпом, але може залежати від змін температури. Не соромтеся експериментувати з власним вимірюванням.

Висновок

З цією маленькою функцією можна зробити багато. Ви можете використовувати стабільну опорну напругу близьку до 5.0 В не маючи насправді 5.0 на Vcc. Ви можете вимірювати напругу батареї або навіть побачити на якому ви живлення від батареї або стаціонарного джерела живлення.

І нарешті, код підтримуватиме всі Arduino, включаючи новий Leonardo, а також чіпи ATtinyX4 та ATtinyX5 серій.

Просте рішення для систем охорони та автоматики!

BM8039D, MP8036, MA3401

Є в наявності

Купити оптом

Даний модуль розроблений спеціально для пристроїв з каталогу Майстер Кіт BM8039D, MP8036, MA3401 і т.п. Але з успіхом може використовуватися з будь-якою домашньою автоматикою та сигналізацією.

Пристрій має опто-гальванічну розв'язку, це дозволяє підключати модуль безпосередньо до виведення мікроконтролера.

Модуль буде корисний для проектів користувачів на базі мікроконтролерів та Arduino та Raspberry.

Технічні характеристики

Напруга живлення (В) 220
Кількість вбудованих реле керування (шт) 1
Тип харчування змінний
Кількість входів (шт) 1
Кількість виходів (шт) 1
Рекомендована температура експлуатації (°С) -30...+60
Довжина (мм) 42
Ширина (мм) 25
Висота (мм) 17
Вага, не більше (г) 20
Напруга комутації (В) 220
Потужність навантаження, що підключається, максимальна (Вт) 1
Вага 38

Особливості

  • Оптогальванічна розв'язка. Напруга ізоляції 1500В
  • Можливість прямого підключення до мікроконтролера.
  • Можливість керування обмоткою реле потужністю до 1 Вт.
  • Напруга комутації до 350В

Принцип роботи

За наявності на вході модуля змінної напруги 220V відбувається замикання реле контактів. Завдяки застосуванню оптореле модуль може безпосередньо підключатися до ліній контролю мікроконтролера.

Конструкція пристрою

Модуль виконаний у вигляді датчика, що вбудовується. Модуль має невеликі розміри 40х25х15 мм. При необхідності модуль може виконувати роль безтрансформаторного джерела живлення, з робочою напругою 5В/12В і струмом до 80 мА.

Схеми

Підключення

Комплект поставки

  • Модуль MP220V – 1 шт.
  • Інструкція – 1 шт.

Що потрібно для складання

  • Для підключення знадобиться: провід, викрутка, бокоріз.

Підготовка до експлуатації

  • Увімкніть мультиметр у режим вимірювання опору. Підключіть щупи до лінії контролю модуля.
  • Підключіть до клем «IN 220V» шнур живлення з вилкою.
  • Увімкніть вилку в мережу 220В.
  • На платі засвітиться індикатор, а мультиметр повинен показати 0 Ом.
  • Перевірку завершено. Приємної експлуатації

Умови експлуатації

  • Температура –30С до +50С.
  • Відносна вологість 20-80% без утворення конденсату.
  • Tutorial

Вступ

Всім привіт! Після завершення циклу датчиками були питання різного плану з вимірювання параметрів споживання побутових і не дуже електроприладів. Хто скільки споживає, як підключати щоб виміряти, які бувають тонкощі і так далі. Настав час розкрити всі карти в цій галузі.
У цьому циклі статей розглянемо тему вимірювання параметрів електроенергії. Цих параметрів насправді дуже велика кількість, про які я постараюся поступово розповісти невеликими серіями.
Поки що у планах три серії:
  • Вимірювання електроенергії.
  • Якість електроенергії.
  • Пристрої вимірювання параметрів електроенергії.
У процесі розбору вирішуватимемо ті чи інші практичні завдання на мікроконтролерах до досягнення результату. Зрозуміло, більша частина даного циклу буде присвячена вимірюванню змінної напруги і може стати у нагоді всім любителям контролювати електроприлади свого розумного будинку.
За підсумками всього циклу ми виготовимо розумний електролічильник з виходом в інтернет. Дуже запеклі любителі контролювати електроприлади свого розумного будинку можуть надати посильну допомогу в реалізації комунікаційної частини на базі, наприклад MajorDomo. Зробимо OpenSource розумний будинок краще, так би мовити.
У цій серії у двох частинах ми розберемо такі питання:
  • Підключення датчиків струму та напруги в пристроях постійного струму, а також однофазних та трифазних ланцюгів змінного струму;
  • Вимірювання діючих значень струму та напруги;
  • Вимірювання коефіцієнта потужності;
  • Повна, активна та реактивна потужність;
  • Споживання електроенергії;
Підкатом ви знайдете відповіді на перші два питання цього списку. Я навмисно не торкаюся питання точності вимірювання показників і з цієї серії лише тішуся отриманими результатами з точністю плюс-мінус лапоть. Цьому питанню я обов'язково присвячую окрему статтю у третій серії.

1. Підключення датчиків


У минулому циклі про датчики напруги і струму я розповів про види датчиків, але не розповів про те, як ними користуватися і куди їх ставити. Настав час це виправити
Підключення датчиків постійного струму
Зрозуміло, що весь цикл буде присвячений системам змінного струму, але швидко пробіжимося і по ланцюгах постійного струму, оскільки це може стати в нагоді при розробці джерел живлення постійного струму. Візьмемо наприклад класичний понижувальний перетворювач із ШІМ :


Рис 1. Знижувальний перетворювач із ШІМ
Нашим завданням є забезпечення стабілізованої вихідної напруги. Крім того, на підставі інформації з датчика струму можливо контролювати режим роботи дроселя L1, не допускаючи його насичення, а також реалізовувати захист струму перетворювача. І чесно кажучи, варіантів встановлення датчиків особливо немає.
Датчик напруги у вигляді резистивного дільника R1-R2, який єдиний здатний працювати на постійному струмі, встановлюється на виході перетворювача. Як правило, спеціалізована мікросхема перетворювача має вхід зворотного зв'язку, і докладає всіх зусиль для того, щоб на цьому вході (3) виявився певний рівень напруги, прописаний у документації на мікросхему. Наприклад, 1,25В. Якщо наша вихідна напруга з цим рівнем збігається – все добре – ми прямо подаємо вихідну напругу на цей вхід. Якщо ні, то встановлюємо дільник. Якщо нам треба забезпечити вихідну напругу в 5В, то дільник повинен забезпечувати коефіцієнт розподілу 4, тобто. Наприклад, R1 = 30к, R2 = 10к.
Датчик струму зазвичай встановлюється між джерелом живлення та перетворювачем і на мікросхему. По різниці потенціалів між точками 1 і 2 і при відомому опорі резистори Rs можливо визначити поточне значення струму нашого дроселя. Встановлювати датчик струму між джерел та навантаженням не найкраща ідея, оскільки конденсатор фільтра буде відрізаний резистором від споживачів імпульсних струмів. Встановлення резистора в розрив загального дроту теж не обіцяє нічого хорошого - буде два земляних рівня з якими возитися те ще задоволення.
Проблеми падіння напруги можна уникнути шляхом використання безконтактних датчиків струму - наприклад, датчиків холу:


Рис 2. Безконтактний датчик струму
Однак є хитріший спосіб вимірювання струму. Адже на транзисторі так само падає напруга і через нього тече той самий струм як і індуктивність. Отже, за падінням напруги на ньому можна також визначити поточне значення струму. Чесно кажучи, якщо подивитися на внутрішню структуру мікросхем перетворювачів, наприклад, від Texas Instruments - такий спосіб зустрічається так само часто як і попередні. Точність такого способу звичайно не найвища, але для роботи струмового відсічення цього цілком достатньо.


Рис 3. Транзистор як датчик струму
Аналогічно надаємо в інших схемах подібних перетворювачів, чи це підвищує або інвертує.
Однак необхідно окремо згадати про трансформаторні прямоходові та зворотноходові перетворювачі.


Рис 4. Підключення датчиків струму у зворотноходових перетворювачах
Вони точно також може використовуватися або зовнішній опір, або транзистор у його ролі.
На цьому із підключенням датчиків у перетворювачі постійного струму ми закінчили. Якщо у вас є пропозиції щодо інших варіантів - із задоволенням доповню ними статтю.
1.2 Підключення датчиків до однофазних ланцюгів змінного струму
У ланцюгах змінного струму ми маємо набагато більший вибір можливих датчиків. Розглянемо кілька варіантів.
Найпростіший - використання резистивного дільника напруги та струмового шунта.


Рис 5. Підключення резисторних датчиків
Однак, у неї усть пара істотних недоліків:
По-перше, або ми забезпечимо значну амплітуду сигналу з струмового шунта, виділивши велику кількість потужності на ньому, або задовольнятимемося малою амплітудою сигналу і згодом посилюватимемо його. А по-друге, резистор створює різницю потенціалів між нейтраллю мережі та нейтраллю приладу. Якщо прилад ізольований - це не має значення, якщо ж у приладу є висновок заземлення, то ми ризикуємо залишитися без сигналу з датчика струму, оскільки закоротимо його. Мабуть, варто спробувати датчики, що працюють на інших принципах.
Наприклад, скористаємося трансформаторами струму та напруги, або датчиком струму на ефекті холу та трансформатором напруги. Тут набагато більше можливостей по роботі з обладнанням, так як нульовий провід не має втрат, а головне - в обох випадках є гальванічна розв'язка вимірювального обладнання, що часто може стати в нагоді. Однак, необхідно враховувати, що трансформаторні датчики струму та напруги мають обмежену частотну характеристику і якщо ми захочемо виміряти гармонійний склад спотворень, то у нас це не факт, що вийде.


Рис 6. Підключення трансформаторних та безконтактних датчиків струму та напруги
1.3 Підключення датчиків до багатофазних ланцюгів мереж змінного струму
У багатофазних мережах наші можливості щодо підключення датчиків струму трохи менші. Пов'язано це з тим, що струмовий шунт використовувати зовсім не вийде, оскільки різниця потенціалів між шунтами фаз коливатиметься в межах сотень вольт і мені не відомий жоден контролер загального застосування, аналогові входи якого здатні витримати такий знущання.
Один спосіб використовувати струмові шунти, звичайно, є - для кожного каналу необхідно зробити гальванічно розв'язаний аналоговий вхід. Але набагато простіше та надійніше використовувати інші датчики.
У своєму аналізаторі якості я використовую резистивні дільники напруги та виносні датчики струму на ефекті холу.

Рис 7. Датчики струму в трифазній мережі
Як видно з малюнка, ми використовуємо чотирипровідне підключення. Зрозуміло, замість датчиків струму на ефекті холу можна взяти трансформатори струму або петлі Рогівського.
Замість резистивних дільників можна використовувати трансформатори напруги, причому як для чотирипровідної, так і для трипровідної системи.
У разі первинні обмотки трансформаторів напруги підключаються трикутником, а вторинні зіркою, загальна точка яких є загальною точкою вимірювального ланцюга


Рис 8.Використання трансформаторів напруги в трифазній мережі

2 Чинне значення струму та напруги


Настав час вирішити завдання вимірювання наших сигналів. Практичну значущість для нас представляє насамперед діюче значення струму та напруги.
Нагадаю матчасть із циклу за датчиками. За допомогою АЦП нашого мікроконтролера через рівні проміжки часу ми фіксуватимемо миттєве значення напруги. Таким чином, за період вимірювання ми матимемо масив даних рівня миттєвого значення напруги (для струму все аналогічно).


Рис 9. Серія миттєвих значень напруги
Наше завдання – зробити підрахунок чинного значення. Для початку скористаємося формулою інтегралу:
(1)
У цифровій системі доводиться обмежуватися якимось квантом часу, тож ми переходимо до суми:
(2)
Де – період дискретизації нашого сигналу, а – число відліків за період вимірювання. Десь тут я у відео починаю втирати дичину про рівність площ. Треба було виспатися того дня. =)
У мікроконтролерах MSP430FE4252, які застосовуються в однофазних електролічильниках Меркурій, за період вимірювання дорівнює 1, 2 або 4 секунди виробляється 4096 відліків. На T = 1с і N = 4096 ми і спиратимемося в подальшому. Більше того, 4096 пікселів за секунду дозволять нам використовувати алгоритми швидкого перетворення фур'є для визначення гармонійного спектру аж до 40 гармоніки, як того вимагає ГОСТ. Але про це у наступній серії.
Накидаємо алгоритм нашої програми. Нам потрібно забезпечити стабільний запуск АЦП кожну 1/8192 секунд, тому що у нас два канал і вимірювати ми будемо ці дані поперемінно. Для цього налаштуємо таймер і сигнал переривання автоматично перезапускатиме АЦП. Усі АЦП так уміють.
Писатиме майбутню програму на arduino, тому що вона у багатьох під рукою. У нас поки що суто академічний інтерес.
Маючи частоту системного кварцу 16МГц і 8-разрядный таймер (щоб життя медом не здавалося) нам потрібно забезпечити частоту спрацьовування будь-якого переривання таймера з частотою 8192Гц.
Сумуємо з приводу того, що 16МГц ціло не ділиться як нам треба і підсумкова частота роботи таймера 8198Гц. Закриваємо очі на похибку 0,04% і все одно зчитуємо по 4096 вибірок на канал.
Засмучуємося з приводу того, що переривання з переповнення в arduino зайняте розрахунком часу (відповідає за millis і delay, так що це працювати нормально перестане), так що користуємося перериванням порівняно.
А ще раптово розуміємо, що сигнал до нас приходить біполярний, і що msp430fe4252 з ним чудово справляється. Ми ж задовольняємося уніполярним АЦП, тому на операційному підсилювачі збираємо простий перетворювач біполярного сигналу на уніполярний:


Рис 10. Перетворювач біполярного сигналу в уніполярний
Причому наше завдання забезпечити коливання нашої синусоїди щодо половини опорної напруги – тоді ми або заберемо половину діапазону або активуємо опцію в налаштуваннях АЦП та отримаємо знакові значення.
В Arduino 10-розрядний АЦП, тому з беззнакового результату в межах 0-1023 будемо віднімати половину і отримаємо -512-511.
Перевіряємо модель, зібрану в LTSpiceIV і переконуємося, що все працює як слід. У відеоматеріалі додатково переконуємось експериментально.


Рис 11. Результат моделювання. Зеленим вихідний сигнал, синім – вихідний

Скетч для Arduino для одного каналу

void setup() ( autoadcsetup(); DDRD |=(1<

Програма написана серед Arduino IDE для мікроконтролера ATmega1280. На моїй налагоджувальній платі перші 8 каналів розведені для внутрішніх потреб плати, тому використовується канал ADC8. Можна використовувати цей скетч і для плати з ATmega168, але потрібно вибрати правильний канал.
Усередині переривань пересмикуємо пару службових пінів, щоб наочно бачити робочу частоту оцифрування.
Пару слів про те, звідки взявся коефіцієнт 102. При першому запуску з генератора подавався сигнал різної амплітуди, з осцилографа зчитувалося показ діючого значення напруги, а з консолі забиралося розраховане значення в абсолютних одиницях АЦП.

Umax, В Urms, В Counted
3 2,08 212
2,5 1,73 176
2 1,38 141
1,5 1,03 106
1 0,684 71
0,5 0,358 36
0,25 0,179 19

Розділивши значення третього стовпця на значення другого отримуємо в середньому 102. Це і буде наш калібрувальний коефіцієнт. Однак можна помітити, що при зниженні напруги точність різко знижується. Це відбувається через низьку чутливість нашого АЦП. Фактично 10 розрядів для точних розрахунків катастрофічно мало і якщо напруга в розетці виміряти таким чином цілком вдасться, то поставити 10-розрядний АЦП на вимірювання струму, що споживається навантаженням, буде злочином проти метрології.

На даний момент ми перервемося. У наступній частині розглянемо інші три питання даної серії і плавно переходитимемо до створення безпосередньо самого пристрою.

Представлену прошивку, а також інші прошивки для даної серії (оскільки відеоматеріали я знімаю швидше ніж готую статті) ви знайдете в репозиторії на GitHub.