Цифров волтметър с LCD16x2, управляван с Arduino

     В примера "Аналогов волтметър с Arduino" показах една твърде нетрадиционна идея за свързване на развойна платка Arduino с аналогова измервателна система за измерване на променливо напрежение. Гъделът при изработването на този проект беше именно в неговата имагинерност. Но за моите бъдещи проекти (о, повярвайте ми, вече си водя списък!) бях предвидил използването LCD индикатора 16x2. Именно поради това трябваше да изпробвам начина на свързване, скеч кода и неговата визия.

    Естествено, отново се обърнах към моята любима библиотека – интернет, където намерих тази публикация [1].

    И в настоящия пример ми се наложи да направя мой собствен програмен код, който да отразява възможностите за използване в моите бъдещи проекти. Разбира се, вие може да опитате както оригиналния скеч, така и изработения от мене. Разликите са доста, както в номерата на използваните цифрови пинове от Arduino, така и в основната идея за мащабиране на ниското напрежение на вход А0 до високото мрежово напрежение, чието измерване беше моята задача. В моя скеч, тази функция е програмирана с формули, в които е включен коефициент (константа) означен като "К0", който има стойност К0=160, но подчертавам – за мрежовия трансформатор, който аз използвам в този пример (~220/12V AC). Това е отразено в скеча със следните две простички формули:

    vout = (value * 5.0) / 1024.0; //пресмятам напрежението за едно ниво на АЦП
vin = vout * K0; //мащабирам горната стойност до входното мрежово напрежение

    Тоест, ако след трансформация и изправяне със схема "Грец”, подавам напрежение около 1,5V на аналогов вход А0, изходите на Arduino извеждат мащабирана стойност 220V към индикацията LCD 16x2. И тук, както в примера "Аналогов волтметър с Arduino", съм взел съответните предпазни мерки за вход А0 чрез паралелно свързване на ценеров диод за 4.7V. С това предпазвам входа от случайно пренапрежение.

    Принципната схема на свързване на различните елементи почти съвпадаше с тази на аналоговия волтметър. Ноооо, не съвсем. Цифровите изходи на Arduino платката бяха сериозно ангажирани в комуникацията с LCD 16x2, като шест от тях са за данни и два са за захранване. Принципната схема, по която осъществих този примерен експеримент е:

    За улеснение на монтажа и намаляване на броя на връзките монтирах тримера Р2 директно на платката на дисплея. Р2 служи за избор на подсветка на LCD дисплея и чрез регулиране можем да постигнем знаци както в черен, така и в бял цвят. Аз съм избрал белия цвят на фона на синята подсветка. Също върху самия дисплей съм запоил два моста както следва – един между минуса на захранването и катода на дисплея, втори между положителния край на захранването и анода на дисплея. Възможно е резистора R3 да не се използва, а връзката да се направи директна. С това общия брой на връзките между Arduino платката и дисплея спадна до осем заедно със захранващите шини. Това минимизиране (оптимизиране) има за цел да намали броя на пиновете, които се използват за връзка с дисплея, тъй като трябва да осигуря достатъчно много необходими за други проекти. При програмиране на показанията на LCD дисплея не трябва да забравяме, че броя на допустимите знаци е максимум – 16. Така на първи ред съм програмирал надписа:

    "MAIN AC VOLTAGE": обозначение какво измервам, с 15 знака. На втори ред на дисплея съответно надпис и отчет на стойността: "AC VOLT = " – общо 13 знака, от които три знака за отчет на мрежовото напрежение.

    С това програмирането на текстовите съобщения е завършено, но всеки би могъл да направи в скеча промени, които му харесват, съобразно целта на използването му. Но ето на следващите снимки съм показал обемния монтаж върху бредборда и показанията на дисплея:

    Приложих две снимки на които може да забележите разликата в изгледа на графичния дисплей, в единия случай със знаци, оцветени в бял цвят, а в другия - с черен. Този изглед се постига с промяната на напрежението на подсветката с тримера, монтиран директно върху платката ма LCD 16x2 и означен на принципната схема като Р2. Личните ми предпочитания са за първия изглед:

    Скечът за този пример, в който са описани значенията на командите и тяхното кратко обяснение е наименован: "Arduino_Volmeter_LCD_R1.ino".

Бих искал да отбележа, че тази разработка не е безцелна, а е предвидена за включване в бъдещите ми конструкции с микропроцесорната система Arduino и няма да описвам отново. Както и преди съм казвал, най-прекрасната възможност на развойната платка е възможността във всеки момент да се добави или премахне нещо от скеча и както се казва: "в движение" да се променя дори целия проект.

    Завършвайки текущия пример, реших да го разширя с още един експеримент, а именно – да добавя към настоящия програмен код и кода за аналогов волтметър. Това и направих. Бих казал, направих го от чисто любопитство. От една страна измерване на напрежението с аналогова измервателна система, от друга страна с цифров волтметър с LCD 16x2. Тази комбинация е интересна и с различния начин на обработка. Експериментът беше удивителен и нагледен пример за тези разлики, които може да видите на следващата снимка:

    При правилен подбор на коефициента на мащабиране (скалиране) на данните, които трябва да отразяват входното напрежение двата индикатора отразяват еднакво показание. В случая, константата, която бях заложил предварително (за напрежение на вход А0 1,4V) беше К0 = 160, но за измерване с аналоговата система това напрежение беше около 2,18V поради което при експеримента намалих мащабирането и то придоби стойност К0 = 101. По този начин изравних показанията и на двата индикатора.

    В скеча: "Arduino_Volmeter_LCD_R2.ino" подробно е описана комбинацията от двете индикаторни системи и всеки команден ред.
 

     *** Допълнение:

    С експериментите и двата скеча, описани и експериментирани по-горе, показах как може чрез скалиране (мащабиране) да се измери високо напрежение, надвишаващо значително максимално допустимото напрежение на аналоговите входове – 5V. В тези експерименти мащабирането се извършваше чрез прилагане на скалиращ коефициент "К".

    В моите скечове аз пресирах Arduino да извършва изчисления, които показах в началото на статията. В ежедневните ми разговори с колега и приятел, той непрекъснато ми повтаряше – "не карай Arduino да извършва излишни изчисления, пести ресурси". Така стигнах до нов код, в който значително намалих изчислителната дейност като изхвърлих програмните редове с участието на коефициента на мащабиране "К" и ги заместих с опростено представяне.

    Но ето идеята, която осъществих – ако Arduino се ограничава от напрежение на входовете до напрежението на захранването от 5 волта, то за да предпазя входа от случайни флуктуации свързвах ценеров диод за Uz = 4,7V също така подавах напрежение в средата на обхвата, тоест около или по-малко от 2.5 волта. Припоням, че използвах в този случай коефициент за мащабиране около 100. Сега просто замених формулите за отчета:

    vout = (value * 5.0) / 1024.0;
    vin = vout * K0;

    с:

    vin = value * 500/1024

    където числото "500" примерно съответства на 500V при максимум на вход А0 5.0V, който се получава при 1024 стъпки на АЦП. Както казах, аз подавам на вход А0 половината от това напрежение – около 2,5 волта, при стъпка 512 на АЦП, което ако се вгледате внимателно съответства на 250V.

    Друго нововъведение е, че реших да елиминирам дробната част и вместо показание за напрежението, примерно "220.43", да получа цяло число – "220". За целта използвах математическата функция "integer", която често се използва в различни програмни среди, включително в Arduino IDE като "int"

    Въведох тази команда в принтирането на показанието на дисплея, като на заместих:

    lcd.print(vin); с lcd.print(int(vin));

    В продължение на моите експерименти установих неточност на измерването, дължащо се на нелинейността на характеристиката на аналогово-цифровото преобразуване. Какво имам предвид – ако настроя показанията на волтмера на стойност 220.0, то с намаляване на напрежението скоростта на намаляване на показанието е по-висока и при 150 волта входно напрежение показанието е около 135-140 волта. Започнах отново да се ровя в световната виртуална библиотека на интернет и открих, че аз не съм първия, който се е сблъскал с проблема. Някои експериментатори с Arduino дори отиват по-далече и от мен, като съмнявайки се в качеството и точността на АЦП на платката, го заменят с външен такъв. Например, един такъв експеримент е описан тук: Arduino Tutorials, Chapter 22: The AREF pin.

    За мен, начинаещият, външния АЦП не беше цел. Но графиката на измерванoто напрежение и АЦП ме впечатли, защото просто не очаквах такава неточност:

    Тази графика обясняваше разликата в измервaната стойност и реaлното напшрежение, което установих с моите експерименти. Реших да се преборя с този проблем. Естествено, първата идея която се завъртя в главата ми беше да използвам знанията си по математика и да направя т.н. линейна отсечкова апроксимация:

    Получи се. Направих три отсечки в участъците (150-190)V, (190-230)V и над 230V. Но в точките А и В отчета подскачаше с около 3-4 волта. Останах доволен, но не съвсем. Подскоците ме дразнеха и трябваше да намеря друг начин. Гледайки горната графика "real voltage" ми хрумна друга идея – да приложа върху нея обратната математическа функция:

    y = 1/x

    Наслагването на двете следва да даде сравнително добра линейност на показанието:

    С червен цвят е графиката на функцията, която исках да приложа, а със зелен цвят резултантната сума от нея и графиката "real voltage", резултата е линеен.

    В търсене на решение на проблема споменах на колега и приятел и той съвсем ме обезвери като ми изпрати графика на случайните флуктуации на измерваните стойности, които имаха параболичен характер:

    Но точно тази графика ми помогна в търсенето на решение, защото продължих с интернет проучванията, но най-вече с проучвания на възможностите на програмната среда Arduino IDE.

    Така първо стигнах до прилагане на външен източник на опорно напрежение AREF, от което се отказах, защото целта беше да се тестват възможностите на Arduino и на втори етап до функцията "map", с която се дефинираха начална и крайна стойност на аналогов вход и начална и крайна стойност на неговото цифрово значение. Примерът, който разгледах и силно препоръчвам на всеки, който би изградил цифров волтметър с Arduino беше публикуван тук: AC Voltmeter and Temperature Monitor.

    Тази функция използвах и при експеримента си "Аналогов волтметър с Arduino" като си признавам, че изобщо не се досетих, че същата може да се използва и за други цели. Включих функция map() в скеча, като отчета придоби следния вид:

    vin = map (value, 0 ,1024, 0, 500);

    като запазих показанието на дисплея в цяло число:

    lcd.print (int(vin));

    Чрез промяна на стойностите на оцветените в червено параметри, постигнах задоволителен резултат, точността в обхвата (140-240)V беше +/- 0.5V.

    При използване на входящ трансформатор ~220/12V и резистивен делите 4,7/1kom, като последния е тример с тази стойност, в моя ексеримент горните стойности имаха следния вид:

    Vin = map (value, 0, 1024, 30, 472);

    Параметъра "472" съответства на входно напрежение 230V, (500/1024*472=230)

    Тук искам да обърна внимание, че аз съм променял във функцията map(x, a, b, c, d) само "c" и "d", с които съм скалирал (мащабирал) търсеното от мене показание. Но ако разполагаме с точни резистори на входния делител, определим точно съотношение, така че входното напрежение да се раздели с тях с точно определен коефициент, то в такъв случай е редно да преизчислим стъпките на АЦП, след което да мащабираме съответствието на долна и горна граница както на стъпките, така и на обхвата на измерваното напрежение. Тоест, имаме съответствие между (a и c) и (b и d). Така ще постигнем най-висока точност.

    Разбира се, аз не твърдя, че моите експерименти изчерпват тази тема. В интернет могат да се намерят много публикации на тази тема. Аз съм направил програмен код за моите конструкции, който всеки може да използва като "сламка" за своите.

    За експериментите си съм използвал малък (5-6VA) трансформатор с изходно променливо напрежение 12V, което след изправителя схема "Грец" добива стойност 16.8V, а чрез резиствиния делител разделям около 5,5 пъти. За да избегна необходимостта от точни резистори, вторият съм заменил с тример-потенциометър, с който избирам напрежението към аналогов вход А0 (2,2-2,5)V.

    Експериментите са осъществени с две съвместими платки Arduino Uno R3 и Arduino Pro Micro. Подобно съм използвал LCD 16x2 с паралелно управление и i2c шина. А програмния код, с който осъществих този експеримент наименувах: Arduino_Volmeter_LCD_R1_map_LIN_raboti.ino.

    На снимките по-долу е използвана платка Arduino Pro Micro:

Използвани материали: 

1. Make a Digital Voltmeter Using an Arduino
2. Arduino Tutorials, Chapter 22: The AREF pin
3. AC Voltmeter and Temperature Monitor

 

Валери Терзиев
7 юли 2016 година