Ваттметр. Код работал а потом перестал.

questioner
Offline
Зарегистрирован: 10.06.2016

Всем привет. Программист из меня никудышний, учусь так сказать на практике. Решил сделать ваттметр, но так, чтобы я понимал, как он считает и мог корректировать.

Измеряемое напряжение подается на А0 Ардуино (nano) через резистивный делитель (делит примерно на 10), падение напряжение на токовом шунте (0,001 Ом) подается на операционный усилитель, где усиливается примерно в 100 раз и идет на А1.

Мгновенные значения апряжения и тока и мощности рассчитываются просто. Энергия считается, как сумма средних значений энергии за каждый цикл void loop(). Энергия за цикл считаеся, как произведение мощности в Ваттах на время цикла void loop() в часах.

Пока я все выводил на экран 1602А - код работал корректно (сверял по внешним приборам), но когда я решил переделать код под экран OLED I2C 0.96"  - энергия стала рассчитываться неправильно.. Я так понял это из-за i2c и ее прерываний произошло?

Прилагаю оба кода, под 1602 экран и под OLED 0.96 128х64.

/* Подключаем библиотеку для работы с LCD */
#include <LiquidCrystal.h>

/* Создаём объект LCD-дисплея, используя конструктор класса LiquidCrystal
* с 6ю аргументами. Библиотека по количеству аргументов сама определит,
* что нужно использовать 4-битный интерфейс.
* Подключаем экран: VSS к GND; VDD к +5V; VO(яркость подсветки) к делителю; RW к GND*/

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); /*Указываем, к каким пинам Arduino подключены выводы дисплея: RS, E, DB4, DB5, DB6, DB7 */

/*Выход ОУ через резистор 1кОм подключаем к A0 Arduino, + измеряемого напряжения, через делитель 10/1 на вход А1*/

float susilitelya ; /*переменная с плавающей запятой (float) для хранения напряжения с операционного усилителя - ОУ)*/
float tok ; /*переменная для посчитанного тока */
float smeshenie = 0.1819 ; /*переменная равная напряжению на выходе ОУ при нулевом токе через шунт. Измеряется мультиметром на собранной схеме*/

float koefftoka = 10 ; /*коэффициент, связывающий значение на выходе ОУ и ток на шунте. Зависит от реального номинала шунта и реального коэффициента усиления ОУ.
                       Если шунт 0,001 Ом, то при токе 1А напряжение м/у его концами будет 1А*0,001Ом=0,001В это напряжение пойдет
                       на вход ОУ, который усилит его во столько раз, какой коэфф. усиления (КУ) мы зададим ему подбором резисторов на делителе в обратной связи. У нас 100кОм и 1кОм,
                       то есть КУ = 100, значи на выходе ОУ будет напряжение усиленное в 100 раз = 0,001В*100 = 0,1В. Получается, что току 1А соответствует напряжение на на выходе ОУ 0,1В, 
                       значит коэффициент = 10. В реальности резисторы не точные, поэтому можно либо использовать потенциометр лоя подстройки, 
                       либо немного изменять значение переменной koefftoka для получения точных результатов измерения тока*/
float koeffnapr = 10.99; /*коэффициент делителя для измерения напряжения на входе А1 (измеряемое напряжение на нагрузке). 
                       При неточных показаниях напряжения, этим коэффициентом можно подогнать значения вместо подстроечного резистора*/                
float napryazhenie  ; /*напряжение на нагрузке*/
float moshnost ; /*переменная для мощности*/
float energiya ; /*переменная для суммарной энергии прошедшей через ваттметр с начала запуска*/
float energiyapred; /* переменная для энергии, прошедшей через шунт за время предыдущего цикла*/
float energiyacikla ; /*переменная для энергии, прошедшей через шунт за время текущего цикла*/
int vremyacikla; /* переменная для хранения времени цикла (измеряется автоматически при работе программы)*/
int vremyanachala; /*переменная для хранения времени начала цикла*/
int vremyakonca; /*переменная для хранения времени конца цикла*/
float opornoe = 5; /*переменная для хранения точно измеренного опорного напряжения. Это напряжение питания микроконтроллера, его нужно измерить мультиметром на готовом устройстве*/
void setup()
{

analogReference(DEFAULT); /*устанавливаем напряжение питания в качестве опорного*/

 /* Инициализируем дисплей: 2 строки по 16 символов */
 lcd.begin(16, 2);

}

void loop()
{
  
 vremyacikla = vremyakonca - vremyanachala; /*рассчитываем время цикла, от цикла к циклу это время не изменяется, оно меняется только, если вносится изменение во время выполнения программы, 
 в таком случае оно будет автоматически рассчитано и точность измерения не будет нарушена. При выполнении самого первого цикла это время будет посчитано, как 0, т.к. переменные еще не вычислены 
 и равны 0, но этим можно принебречь, т.к. речь идет о примерно 10 первых милисекундах после включения.*/
 
 vremyanachala = micros(); /*записываем в переменную время начала цикла - функция micros() возвращает время с момента старта программы в микросекундах*/
 
 susilitelya = analogRead(0) * opornoe / 1023; /*измеряем напряжение с выхода ОУ, переводим значение в вольты*/
 tok = (susilitelya - smeshenie) * koefftoka; /*считаем ток. Из измеренного на выходе ОУ напряжения нужно предварительно вычесть напряжение, соответствующее нулевому току*/
 napryazhenie = analogRead(1) * opornoe / 1023 * koeffnapr; /*измеряем напряжение на А1 и переводим в вольты*/
 moshnost = tok * napryazhenie ;/*считаем мгновенную мощность*/
 energiyacikla = moshnost * vremyacikla / 3600000000; /*упрощенно считаем энергию протекщую за время выполнения цикла программы, приняв что мощность за время цикла не менялась. Переводим из Вт*мкс в Вт*ч */
 energiya = energiyapred + energiyacikla; /*Считаем значение энергии, протекшей через шунт с момента запуска программы, прибавляя энергию за цикл к энергии за все предыдущие циклы*/
 energiyapred = energiya;/*обновляем значение энергии за предыдущие циклы текущим значением. Это значение будет использовано в следующем цикле*/
 
 
 lcd.setCursor(0, 0); /* Устанавливаем курсор в нужный столбец и строку. Нумерация идёт с нуля,первым аргументом идёт номер столбца */
 lcd.print("       A       V");/*выводим на экран единицы измерения*/
 lcd.setCursor(0, 0); 
 lcd.print(tok, 1);/*выводим на экран значение тока с точностью до 1 знака после запятой*/
 
 lcd.setCursor(9, 0);
 lcd.print(napryazhenie, 1);/*выводим на экран значение напряжения с точностью до 1 знака после запятой*/
 
 lcd.setCursor(0, 1);
 lcd.print("       W      Wh");
 lcd.setCursor(0, 1);
 lcd.print(moshnost, 2);/*выводим на экран значение мгновенной мощности с точностью до 2 знаков после запятой*/
 lcd.setCursor(9, 1);
 lcd.print(energiya,1);/*выводим на экран значение потребленной энергии с точностью до 1 знака после запятой*/
 vremyakonca = micros();/*записываем в переменную время окончания цикла*/
/* за такие подробные комментарии нужно молоко бесплатно давать ;) */
}

 

questioner
Offline
Зарегистрирован: 10.06.2016

код для OLED

#include <OLED_I2C.h>

OLED  myOLED(SDA, SCL, 8);

extern uint8_t SmallFont[];

/*Выход ОУ через резистор 1кОм подключаем к A0 Arduino, + измеряемого напряжения, через делитель 10/1 на вход А1*/

float susilitelya ; /*переменная с плавающей запятой (float) для хранения напряжения с операционного усилителя - ОУ)*/
float tok ; /*переменная для посчитанного тока */
float smeshenie = 0.1819 ; /*переменная равная напряжению на выходе ОУ при нулевом токе через шунт. Измеряется мультиметром на собранной схеме*/
float koefftoka = 10 ; /*коэффициент, связывающий значение на выходе ОУ и ток на шунте. Зависит от реального номинала шунта и реального коэффициента усиления ОУ.
                       Если шунт 0,001 Ом, то при токе 1А напряжение м/у его концами будет 1А*0,001Ом=0,001В это напряжение пойдет
                       на вход ОУ, который усилит его во столько раз, какой коэфф. усиления (КУ) мы зададим ему подбором резисторов на делителе в обратной связи. У нас 100кОм и 1кОм,
                       то есть КУ = 100, значи на выходе ОУ будет напряжение усиленное в 100 раз = 0,001В*100 = 0,1В. Получается, что току 1А соответствует напряжение на на выходе ОУ 0,1В, 
                       значит коэффициент = 10. В реальности резисторы не точные, поэтому можно либо использовать потенциометр лоя подстройки, 
                       либо немного изменять значение переменной koefftoka для получения точных результатов измерения тока*/
float koeffnapr = 10.99; /*коэффициент делителя для измерения напряжения на входе А1 (измеряемое напряжение на нагрузке). 
                       При неточных показаниях напряжения, этим коэффициентом можно подогнать значения вместо подстроечного резистора*/                
float napryazhenie; /*напряжение на нагрузке*/
float moshnost; /*переменная для мощности*/
float energiya; /*переменная для суммарной энергии прошедшей через ваттметр с начала запуска*/
float energiyacikla; /*переменная для энергии, прошедшей через шунт за время текущего цикла*/
float energiyapred; /* переменная для энергии, прошедшей через шунт за время предыдущего цикла*/
int vremyacikla; /* переменная для хранения времени цикла (измеряется автоматически при работе программы)*/
int vremyanachala; /*переменная для хранения времени начала цикла*/
int vremyakonca; /*переменная для хранения времени конца цикла*/
float opornoe = 5; /*переменная для хранения точно измеренного опорного напряжения. Это напряжение питания микроконтроллера, его нужно измерить мультиметром на готовом устройстве*/

void setup()
{
  analogReference(DEFAULT); /*устанавливаем напряжение питания в качестве опорного*/

  myOLED.begin(); /* Инициализируем дисплей */
  myOLED.setFont(SmallFont); /*устанавливаем размер шрифта*/
  
}


void loop()
{
  
 vremyacikla = vremyakonca - vremyanachala; /*рассчитываем время цикла, от цикла к циклу это время не изменяется, оно меняется только, если вносится изменение во время выполнения программы, 
 в таком случае оно будет автоматически рассчитано и точность измерения не будет нарушена. При выполнении самого первого цикла это время будет посчитано, как 0, т.к. переменные еще не вычислены 
 и равны 0, но этим можно принебречь, т.к. речь идет о примерно 10 первых милисекундах после включения.*/
 
 vremyanachala = micros(); /*записываем в переменную время начала цикла - функция micros() возвращает время с момента старта программы в микросекундах*/
 
 susilitelya = analogRead(0) * opornoe / 1023; /*измеряем напряжение с выхода ОУ, переводим значение в вольты*/
 tok = (susilitelya - smeshenie) * koefftoka; /*считаем ток. Из измеренного на выходе ОУ напряжения нужно предварительно вычесть напряжение, соответствующее нулевому току*/
 napryazhenie = analogRead(1) * opornoe / 1023 * koeffnapr; /*измеряем напряжение на А1 и переводим в вольты*/
 moshnost = tok * napryazhenie ;/*считаем мгновенную мощность*/
 energiyacikla = moshnost * vremyacikla / 3600000000; /*упрощенно считаем энергию протекщую за время выполнения цикла программы, приняв что мощность за время цикла не менялась. Переводим из Вт*мкс в Вт*ч */
 energiya = energiyapred + energiyacikla; /*Считаем значение энергии, протекшей через шунт с момента запуска программы, прибавляя энергию за цикл к энергии за все предыдущие циклы*/
 energiyapred = energiya;/*обновляем значение энергии за предыдущие циклы текущим значением. Это значение будет использовано в следующем цикле*/

 
 myOLED.clrScr();
 myOLED.print("--Wattmetr--", CENTER, 0); 
 
 myOLED.print("         V        A", LEFT, 16); /*выводим на экран единицы измерения*/
 myOLED.printNumF(napryazhenie, 1, 10,16); /*выводим на экран значение тока с точностью до 1 знака после запятой*/
 myOLED.printNumF(tok, 1, 75, 16); /*выводим на экран значение напряжения с точностью до 1 знака после запятой*/
 
 myOLED.print("         W        Wh", LEFT, 32);
 myOLED.printNumF(moshnost, 1, 10,32); /*выводим на экран значение мгновенной мощности с точностью до 2 знаков после запятой*/
 myOLED.printNumF(energiya, 2, 75, 32); /*выводим на экран значение потребленной энергии с точностью до 1 знака после запятой*/



 myOLED.update();
 
 vremyakonca = micros(); /*записываем в переменную время окончания цикла*/
 
/* за такие подробные комментарии нужно молоко бесплатно давать ;) */
}

 

questioner
Offline
Зарегистрирован: 10.06.2016

Да, такие комменты писал, т.к. планировал поделиться результатом с широкой общественностью. Объяснял так, как хотел бы чтобы объясняли мне. Так что это я на себя ориентировался. если что ;)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

questioner пишет:

 

 myOLED.printNumF(napryazhenie, 1, 10,16); /*выводим на экран значение тока с точностью до 1 знака после запятой*/
 myOLED.printNumF(tok, 1, 75, 16); /*выводим на экран значение напряжения с точностью до 1 знака после запятой*/

Вообще-то комментарии крайне бестолковые. Какой смысл дублировать в них то, что написано в коде? Это написано в самом коде, а комментарии должны содержать информацию зачем это делается.

Впрочем, если называть силу тока "napryazhenie", а напряжение - "tok", то, вероятно, и такие комментарии уместны.

5N62V
Offline
Зарегистрирован: 25.02.2016

questioner пишет:

ока я все выводил на экран 1602А - код работал корректно (сверял по внешним приборам), но когда я решил переделать код под экран OLED I2C 0.96"  - энергия стала рассчитываться неправильно.. Я так понял это из-за i2c и ее прерываний произошло?

 

Расчитываться стало неверно, или выводить значения стала неверно? Это разные вещи.

Прерывания по i2c могут только у слейва случиться, тут это не при чем.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:

Да, такие комменты писал, .... на себя ориентировался. если что ;)

Именно так и надо делать. Писать для себя. Другое дело, писать надо в терминах сутевой задачи "что делается по сути", а не в терминах программы - про программу и по коду всё понятно.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:
когда я решил переделать код под экран OLED I2C 0.96"  - энергия стала рассчитываться неправильно..

Т.е. напряжение и ток - правильно, а их произведение - неправильно. Так?

questioner
Offline
Зарегистрирован: 10.06.2016

andriano , шибко грамотный - а не пойти ли тебе в пешее эротическое путешествие? Бестолковое твое замечание, потому, что только бестолковый может думать, что если информация содержится в его голове, то она должна содержаться и у других. Если мои комменты будет читать человек который только светодиодом на ардуине мигал, то походу чтения комментариев будет узнавать, также, что делает КАЖДАЯ строка. И напряжение током я не называл, умник ты чертов, посмотри комментарии, когда заданы переменные, вконце я поменял местами переменные, так было надо, а комменты не успел поменять. В чем вообще был смысл твоего высера, самоутвердиться, так вот я тебя разочарую - когда есть вся информация 2+2 сложить много ума не надо, а ты научился и тыкаешь свысока тем, кто только в начале пути. Так могут вести себя только крайне низкоинтеллектуальные люди. И да, я готов к бану.

5N62V, ЕвгенийП, спасибо за адекват! 

Мощность, напряжение и ток рассчитываются верно, неверно рассчитывается энергия (сумма энергий всех циклов с момента запуска программы).

ЕвгенийП, Произведение тока и напряжения - это мощность, а энергия это произведение мощности на промежуток времени, который эта мощность действовала. Я измеряю однократно мощность и умножаю ее на время цикла "loop", которое отщитывается отдельно. Приближенно считая. что мощность за время цикла была постоянной, в следующем цикле будет другая мощность (если ток и напряжение изменились) и она опять умножится на время цикла, полученное значение энергии сложится со значением из предыдущего вычисления и т. д. Текущее накопленное значение выводится на экран и постоянно растет (как в электрическом счетчике).

Она получается меньше где-то в 2 раза. Я так понимаю, что время цикла рассчитывается меньше, чем оно есть в реальности. То есть какие-то вычисления происходят, но их время почему-то не учитывается. Явно по коду я этого понять не могу, видимо есть ньюанс о котором я не знаю.

nik182
Offline
Зарегистрирован: 04.05.2015

questioner пишет:

 Произведение тока и напряжения - это мощность...

Это справедливо только для постоянного тока. Такой ток вы измеряете?

questioner
Offline
Зарегистрирован: 10.06.2016

nik182 пишет:

Это справедливо только для постоянного тока. Такой ток вы измеряете?

Постоянный

b707
Offline
Зарегистрирован: 26.05.2017

questioner - что касается расчеты времени, вы уверены, что время исполнения цикла помещается в переменную типа int?

Ну и насчет комментов вы зря на Андриано наехали. Его замечание может и резкое, но по сути верное - если писать комменты для идиотов, только идиотам они и будут полезны. Все-таки мы предполагаем. что если человек дорос до скетчей уровня ваттметра, то комментировать назначение основных операторв языка Си ему уже не нужно - можно сосредоточится на сути программы. а не на пространных пояснениях в стиле "Кэп Очевидность"

questioner
Offline
Зарегистрирован: 10.06.2016

b707 пишет:
questioner - что касается расчеты времени, вы уверены, что время исполнения цикла помещается в переменную типа int?

Воот.. это уже по делу. Конечно не уверен - проверю.

b707 пишет:
Ну и насчет комментов вы зря на Андриано наехали. Его замечание может и резкое, но по сути верное - если писать комменты для идиотов, только идиотам они и будут полезны. Все-таки мы предполагаем. что если человек дорос до скетчей уровня ваттметра, то комментировать назначение основных операторв языка Си ему уже не нужно - можно сосредоточится на сути программы. а не на пространных пояснениях в стиле "Кэп Очевидность"

И вы туда же! Каких идиотов? Если человек не знает, что делает та или иная команда, он идиот? Да он может посмотреть, но нафига людям делать одно и то же по over9000 раз, года можно "один сделал-поделился со всеми" эта схема продуктивней. Ну почему, стоит только человеку подняться на ступеньку повыше - он сразу начинает считать тех, кто пониже недочеловеками, вместо того, чтобы протянуть руку?! Я писал комменты НЕ для тех, кто знает. Вашу позицию по этому вопросу резко осуждаю!

b707
Offline
Зарегистрирован: 26.05.2017

questioner пишет:

Вашу позицию по этому вопросу резко осуждаю!

Взаимно :)

Не страшно, когда человек чего-то не знает. Но если он категорически не хочет учиться - и, главное, еще и настаивает, что ему ничего знать не нужно, так, мол, "продуктивней"! :) - я такую позицию всецело осуждаю. Таким не стоит и помогать.

Да и как им поможешь, если они учиться не хотят? Сделать за них?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:
Да он может посмотреть, но нафига людям делать одно и то же по over9000 раз, года можно "один сделал-поделился со всеми" эта схема продуктивней.

Стеснюсь просить, Вы эффективный менеджер? Или продуктивный?

questioner
Offline
Зарегистрирован: 10.06.2016

b707 пишет:
Не страшно, когда человек чего-то не знает. Но если он категорически не хочет учиться

Это не ваша позиция - вы просто повторяете распространенный шаблон. Понимаю, так проще, не думая пользоватьться чужими готовыми конструкциями, а вы попробуйте проанализировать эту конструкцию... понимаю не охота вникать глубоко... философия, демогогия.. вот это всё... не для серьезных парней занятие ;)

ЕвгенийП пишет:
Стеснюсь просить, Вы эффективный менеджер? Или продуктивный?

Это не я

_________

По сути топика, если кому-то еще это надо: переменная float судя по описанию вмещает 32 бита данных, в десятичных числах это около 4,2 миллиардов. В секундах это 4200, не думаю, что мой цикл столько длится.. Эх, говорили мне - учись сначала на ассемблере ))

b707
Offline
Зарегистрирован: 26.05.2017

questioner пишет:

Это не ваша позиция - вы просто повторяете распространенный шаблон. Понимаю, так проще, не думая пользоватьться чужими готовыми конструкциями

строго по вашим заветам :) Зачем же мне овер9000раз выдумывать новое - я просто повторяю то, что кто-то уже написал за меня, так же "продуктивней", разве нет? :)

Что касается скетчей - я тоже не брезгую брать готовые в инете. Но я всегда досконально разбираюсь. что и как делает каждая строчка, если это сразу непонятно. И не только потому. что люблю учиться - но и хотя бы потому, что в этих скетчах встречается невроятное количество туфты, которую бездумно копируют друг у друга подобные вам "продуктивные" программисты.

b707
Offline
Зарегистрирован: 26.05.2017

questioner пишет:

По сути топика, если кому-то еще это надо: переменная float судя по описанию вмещает 32 бита данных, в десятичных числах это около 4,2 миллиардов. В секундах это 4200, не думаю, что мой цикл столько длится..

длительность цикла у вас выражена переменной типа int (а никак не float) которая"вмещает" всего 32768 микросекунд - то есть чуть менее чем 33 тысячных секунды.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

а вот если использовать датчик тока INA219 всё будет точно не зависимо от дисплея

b707
Offline
Зарегистрирован: 26.05.2017

ua6em пишет:

а вот если использовать датчик тока INA219 всё будет точно не зависимо от дисплея

если путать float и int, то и с сертифицированным по ISO ваттметром за ХХХ тыр ничего работать не будет :)

questioner
Offline
Зарегистрирован: 10.06.2016

b707 пишет:
строго по вашим заветам :) Зачем же мне овер9000раз выдумывать новое - я просто повторяю то, что кто-то уже написал за меня, так же "продуктивней", разве нет? :)

Так продуктивней только в том случае, если за вас написали правильно, не так ли? Строго по вашим заветам:

b707 пишет:
.. я всегда досконально разбираюсь. что и как делает каждая строчка ... потому, что в этих скетчах встречается невроятное количество туфты
Неплохо было бы применить этот подход к жизненной философии. Хотя я забыл, это ведь занятие не для серьезных парней: философия, демогогия... вот это всё..

b707 пишет:
..которую бездумно копируют друг у друга подобные вам "продуктивные" программисты ..
 

И что же я бездумно у кого скопировал, этот скетч писал-таки сам, о чем и сказал сразу? В чем конкретно они подобны мне?

 Насчет на счет моей "продуктивности" в качестве программиста я написал в первой строке ервого поста: "Программист из меня никудышний, учусь так сказать на практике". Вы даже не представляете, насколько низок мой уровень в качестве программиста, до этого я пару раз мигал светодиодом, делал ШИМ по примеру и выводил текст на экран с помощью библиотеки.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

ua6em пишет:

а вот если использовать датчик тока INA219 всё будет точно не зависимо от дисплея

если путать float и int, то и с сертифицированным по ISO ваттметром за ХХХ тыр ничего работать не будет :)

Всё должно быть сделано просто, насколько возможно, но не проще А Эйнштейн
Все сложное – не нужно, все нужное – просто. М. Калашников

а с переменными да )))

questioner
Offline
Зарегистрирован: 10.06.2016

По сути вопроса: Я действительно перепутал int и float, но не при написании программы, а при обсуждении с вами. Там действительно int, я намеренно это сделал. Но я не знал, что так мало бит вмещает этот тип данных. Спасибо, что заметили и сказали! Я попробовал изменить типы всех переменных времени на float - результат тот же - посчитанная энергия примерно в 2 раза меньше той, что должна быть. Это только из-за времени, ток, напряжение и мощность тут не при чем - эти величины вообще постоянны при проверке (я тупо подаю на входы 5В). Также попробовал использовать millis() вместо micros() - цифры те же.

vk007
Offline
Зарегистрирован: 16.06.2015

questioner пишет:

Я действительно перепутал int и float...

Читаю и нихрена не могу понять - какие нахрен float? Для микросов и миллисов - unsigned long!

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:

Я попробовал изменить типы всех переменных времени на float - результат тот же

Открою Вам страшный секрет. float вообще не предназначен для хранения точных значений. Он неточен по своей природе :(

questioner
Offline
Зарегистрирован: 10.06.2016

ЕвгенийП пишет:

Открою Вам страшный секрет. float вообще не предназначен для хранения точных значений. Он неточен по своей природе :(

Спасибо, прочел. Но дело тут не в типе переменных, c unsigned long то же самое. Ладненько, буду искать, пока не найду. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:
дело тут не в типе переменных, c unsigned long то же самое. Ладненько, буду искать, пока не найду.

И в переменных, и много в чём другом тоже.

Ваша беда в том. что Вы качаете права, вместо того, чтобы слушать и учиться.

Вот в ответ на мой пост

ЕвгенийП пишет:

Т.е. напряжение и ток - правильно, а их произведение - неправильно. Так?

Вы решили обратить внимание на неаккуратное использование терминов, по сути на описку. А самого важного в это посте Вы не заметили.

Я повторю вопрос, упростив его для десткого сада. Этот вопрос очень важен - в нём ключ к решению проблемы.

итак, у Вас три параметра - ток, напряжение и время. Какой из них начинает врать? Не могут же все быть одинаковыми, а результат иной. Если Вы их все три напечатаете и поймёте кто из них ломается, Вы втрое сузите пространство поиска проблемы.

Доходит?

questioner
Offline
Зарегистрирован: 10.06.2016

Я же отвечал, что неверно считается только энергия, а т.к. произведение тока и напряжения считается верно, следовательно неверно считается время. Странно, что вы не заметили.

questioner
Offline
Зарегистрирован: 10.06.2016

Вот я вам отвечал:

"Мощность, напряжение и ток рассчитываются верно, неверно рассчитывается энергия "

questioner
Offline
Зарегистрирован: 10.06.2016

Как я и писал с самого начала - неверно считается время. Вот как я это проверил:

Чтобы не писать дополнительных строк в коде, я заменил расчет енергии

вместо

energiyacikla = moshnost * vremyacikla / 3600000000;

сделал

energiyacikla =  vremyacikla / 1000000;

То есть на экране вместо энергии в Wh будет посчитанное программой ,а не взятое из micros() время с начала запуска, сложенное из значений времени каждого цикла. И да, временные переменные пришлось объявить как float.

В результате на эрене вышел счетчик секунд. Как и предполагалось - эти посчитанные секунды бегут медленнее, чем реальные почти в 2 раза - за 2 посчитанные минуты проходит 3,5 реальные.  Именно с такой погрешностью и считалась энергия.

Вопрос изначально был именно в этом, по коду явно я не пойму, вроде все правильно..

questioner
Offline
Зарегистрирован: 10.06.2016

Еще компилятор ругается: 

In function 'void loop()':

warning: deprecated conversion from string constant to 'char*'

nik182
Offline
Зарегистрирован: 04.05.2015

Из идей только одна. Микрос и миллис начинают врать когда либо любое прерывание, либо запрет прерываний длится более 4 мкс. Других причин вроде нет. Искать надо где это происходит. Для начала библиотеку i2c поменять.

questioner
Offline
Зарегистрирован: 10.06.2016

nik182, спасибо! Действительно врет micros() . Вывел на экран отношение посчитанного времени к micros() в начале это отношение больше единицы, но секунд за 20 становится единицей. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

nik182 пишет:

 Микрос и миллис начинают врать когда либо любое прерывание, либо запрет прерываний длится более 4 мкс.

Конечно, начинают.

questioner
Offline
Зарегистрирован: 10.06.2016

Вот все и заработало корректно! Поменял библиотеку дисплея, как посоветовали, спасибо всем, кто помогал.

Чтобы цифры не менялись слишком быстро сделал вывод на экран через 5 циклов. Первый раз в жизни заюзал for()

Если кому нужно: код, хекс и файл для протеуса https://yadi.sk/d/Whd7ZFSY3Upor7

Потенциометры для регулировки напряжения источника и сопротивления нагрузки во время симуляции. Погрешность есть конечно, но небольшая, в пределах 1-2%.

b707
Offline
Зарегистрирован: 26.05.2017

questioner пишет:

Погрешность есть конечно, но небольшая, в пределах 1-2%.

Вы просто время в программе считаете неправильно, вот и все.Вы считаете время промежутка между 47 и 73 строчкой. Однако есть еще промежуток между 73 и 47 строчкой, которые вы не учитываете, отсюда и ошибка.

Вместо двух переменных время_начала и время_конца в двух разных местах цикла нужно оставить одну единственную в каком-то одном месте. Тогда время будет считаться точно.

questioner пишет:

Если кому нужно: код, хекс и файл для протеуса

Кому это может быть нужно - недоделанный глючный код с ошибками? Вы же очевидно нифига не смыслите в программировании.  Так зачем вы свой г...-код выкладываете для других? Чтобы они копались в ваших ошибках? Первый раз в жизни for() использовал....

questioner
Offline
Зарегистрирован: 10.06.2016

Время-таки как раз считается верно - проверял по секундомеру. Погрешность в измерении тока и напряжения из-за особенностей ОУ. Эту погрешность видно при симуляции в протеусе.

В программировании, вы правы, я смыслю крайне мало, ну прямо очень, но код тем не менее работает теперь корректно. И пригодиться он может начинающему, как я, коих тьмы. 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

questioner пишет:

Время-таки как раз считается верно - проверял по секундомеру. 

Точность micros() по секундомеру контролируете? Это сильно!

questioner
Offline
Зарегистрирован: 10.06.2016

Так секундомер-то тоже на micros() :) добавляю его в коде и вывожу на свободую строку экрана. Показания сходятся.

b707
Offline
Зарегистрирован: 26.05.2017

questioner пишет:

Так секундомер-то тоже на micros() :) добавляю его в коде и вывожу на свободую строку экрана. Показания сходятся.

ЭТО ПЯТЬ! :))))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

b707 пишет:

questioner пишет:

Так секундомер-то тоже на micros() :) добавляю его в коде и вывожу на свободую строку экрана. Показания сходятся.

ЭТО ПЯТЬ! :))))

Метрология - наше всё )))