Вольтметр + контроль освещенности для автомобиля

Narkus
Offline
Зарегистрирован: 23.05.2017
Доброго времени суток!
Описываю ситуацию: 
имеется автомобильное головное устройство (ГУ) на андроиде, есть идея прикрутить к нему ардуино для регулировки яркости экрана в зависимости от освещения и вывода напряжения бортовой сети на экран, при помощи SerialManager (ссылка).
Для это была взята ардуино нано и подключена следующим образом
залит скетч такого вида

#include <MsTimer2.h>
#include <SimpleTimer.h>


SimpleTimer timer; // таймер измерения освещения
int sens = 0;
int sens_save;
int light = 0;
float vout = 0.0;
float vin = 0.0;
float R1 = 150000.0; // сопротивление R1 (150K)
float R2 = 50500.0; // сопротивление R2 (51K)
int value = 0;

void setup()
{  
  Serial.begin(115200);
  pinMode(3, INPUT);
  MsTimer2::set(5000, timerInterupt); // установка интервала таймера вольтметра 5 сек.  
  MsTimer2::start();  //запуск таймера вольтметра
  timer.setInterval(500, brightcheck); // установка интервала таймера измерения освещения 0,5 сек.
} 

// запуск таймера измерения освещения
void loop() 
  {
    timer.run();
  }

// измерение уровня яркости освещения
void brightcheck()
{ 
  sens = analogRead(1);
  sens = map(sens, 0, 1000, 0, 100); // для упрощения калибровки фоторезистора "map(sens, нижний порог, верхний порог, 0, 100)"
  sens = constrain(sens, 0, 100); // числовые показания ограничены диапазоном от 0 до 100 
  if (abs(sens_save - sens) > 5)
  {
    if (sens<10) light = 0;
    if ((sens > 10) && (sens<20)) light = 2;
    if ((sens > 20) && (sens<30)) light = 5;
    if ((sens > 30) && (sens<40)) light = 10;
    if ((sens > 40) && (sens<50)) light = 20;
    if ((sens > 50) && (sens<60)) light = 35;
    if ((sens > 60) && (sens<70)) light = 50;
    if ((sens > 70) && (sens<80)) light = 70;
    if (sens > 80) light = 100;
    String s = "<brightness:" + String(light) + "%>";
    Serial.print(s);
	sens_save = sens;
  }
}
  
// обработчик прерывания 5 с
void timerInterupt() 
  { 
  value = analogRead(3); // считывание аналогового значения напряжения
  vout = (value * 5.0) / 1024.0;
  vin = vout / (R2/(R1+R2)); 
  String u = "<volt:" + String(vin) + ">"; 
  Serial.print(u); 
  }

 

По таймеру SimpleTimer.h каждые 0,5 сек измеряется освещенность на А1, при изменении на 5 (по шкале от 0 до 100) данные отсылаются в ком-порт. MsTimer2.h каждые 5 сек прерывает для измерения напряжения на А3 и также отсылает значение в ком-порт.
 
Питание ардуины идет через USB, подключенной в активный USB-хаб, который, в свою очередь, подключен к USB входу ГУ.
Теперь собственно проблема: на комп порт данные яркости отправляются как положено (при изменении освещенности > 10), а вот показания вольтметра постоянно скачут (при поданных на А3 честных 12,0 В), при чем при изменении освещенности в меньшую сторону, вольтаж, выводимый в ком-порт соответственно падает (при полной темноте показывает почти 0В, но на входе-то остаются всё те же 12В).
Подскажите, пожалуйста, в чем проблема? Почему вольтметр имеет такую зависимость от фоторезистора?
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Опишите R1, R2, value, vout и vin внутри функции timerInterupt - с какого перепугу им быть глобальными.

Или, если уж так хочется сделать их глобальными, то хотя бы опишите как volatile.

Сделайте, а там посмотрим.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

А зачем использовать 2 разных библиотеки таймера? если все можно сделать на одной?

#include <MsTimer2.h>
#include <SimpleTimer.h> 

 

Narkus
Offline
Зарегистрирован: 23.05.2017

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

Опишите R1, R2, value, vout и vin внутри функции timerInterupt - с какого перепугу им быть глобальными.

Или, если уж так хочется сделать их глобальными, то хотя бы опишите как volatile.

Сделайте, а там посмотрим.

Спасибо, вечером попробую.

Andrey12 пишет:

А зачем использовать 2 разных библиотеки таймера? если все можно сделать на одной?

#include <MsTimer2.h>
#include <SimpleTimer.h> 

Не придумал ничего лучше, чтоб сделать опрос входов с разными интервалами времени. Я в "ардуиностроении" новичёк, если подскажете как запихнуть всё в одну библиотеку, буду благодарен.

Andrey12
Andrey12 аватар
Offline
Зарегистрирован: 26.12.2014

Narkus пишет:

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

Опишите R1, R2, value, vout и vin внутри функции timerInterupt - с какого перепугу им быть глобальными.

Или, если уж так хочется сделать их глобальными, то хотя бы опишите как volatile.

Сделайте, а там посмотрим.

Спасибо, вечером попробую.

Andrey12 пишет:

А зачем использовать 2 разных библиотеки таймера? если все можно сделать на одной?

#include <MsTimer2.h>
#include <SimpleTimer.h> 

Не придумал ничего лучше, чтоб сделать опрос входов с разными интервалами времени. Я в "ардуиностроении" новичёк, если подскажете как запихнуть всё в одну библиотеку, буду благодарен.

Ну типа того, в принципе SimpleTimer может создавать много вызовов как цикличных так и одиночных тут вот подробнее можно прочитать - https://playground.arduino.cc/Code/SimpleTimer

Переделал код на одну библиотеку и с учетом замечаний ЕвгенийП 

Не сказать что код оптимален, но это уж сами. В IDE 1.8.2 компилируется без ошибок.

 

#include <SimpleTimer.h>


SimpleTimer timer; // таймер измерения освещения

void setup()
{
  Serial.begin(115200);
  pinMode(3, INPUT);
  timer.setInterval(500, brightcheck); // установка интервала таймера измерения освещения 0,5 сек.
  timer.setInterval(5000, timerInterupt); // установка интервала таймера вольтметра 5 сек.
}

// запуск таймера измерения освещения
void loop()
{
  timer.run();
}

// измерение уровня яркости освещения
void brightcheck()
{
  int sens = 0;
  static int sens_save = 0;
  int light = 0;

  sens = analogRead(1);
  sens = map(sens, 0, 1000, 0, 100); // для упрощения калибровки фоторезистора "map(sens, нижний порог, верхний порог, 0, 100)"
  sens = constrain(sens, 0, 100); // числовые показания ограничены диапазоном от 0 до 100
  if (abs(sens_save - sens) > 5)
  {
    if (sens < 10) light = 0;
    if ((sens > 10) && (sens < 20)) light = 2;
    if ((sens > 20) && (sens < 30)) light = 5;
    if ((sens > 30) && (sens < 40)) light = 10;
    if ((sens > 40) && (sens < 50)) light = 20;
    if ((sens > 50) && (sens < 60)) light = 35;
    if ((sens > 60) && (sens < 70)) light = 50;
    if ((sens > 70) && (sens < 80)) light = 70;
    if (sens > 80) light = 100;
    String s = "<brightness:" + String(light) + "%>";
    Serial.print(s);
    sens_save = sens;
  }
}

// обработчик прерывания 5 с
void timerInterupt()
{

  float vout = 0.0;
  float vin = 0.0;
  float R1 = 150000.0; // сопротивление R1 (150K)
  float R2 = 50500.0; // сопротивление R2 (51K)
  int value = 0;

  value = analogRead(3); // считывание аналогового значения напряжения
  vout = (value * 5.0) / 1024.0;
  vin = vout / (R2 / (R1 + R2));
  String u = "<volt:" + String(vin) + ">";
  Serial.print(u);
}

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

асинхронный многотаймеров.  

https://github.com/DetSimen/Arduino-

обращайся, помогу, еслишто. 

Narkus
Offline
Зарегистрирован: 23.05.2017

Andrey12 пишет:

Переделал код на одну библиотеку и с учетом замечаний ЕвгенийП 

Опробовал код, ситуция не поменялась, вот кусок вывода данных в ком-порт

<brightness:5%><volt:5.28><volt:5.47><brightness:5%><volt:12.34><brightness:70%><volt:11.91><volt:12.36><volt:11.93><volt:12.48>

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

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

Очень странный результат. Вы правильно пользуетесь таймерами? Дело в том, что brightness должно печататься в 10 раз чаще, чем напряжение.

Давайте сделаем так: 

1. В печать добавляете значение millis()
2. вместо print используете println, чтобы каждое значение было на отдельной строке

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

Narkus
Offline
Зарегистрирован: 23.05.2017

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

Очень странный результат. Вы правильно пользуетесь таймерами? Дело в том, что brightness должно печататься в 10 раз чаще, чем напряжение.

Давайте сделаем так: 

1. В печать добавляете значение millis()
2. вместо print используете println, чтобы каждое значение было на отдельной строке

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

У меня код измерения освещенности выводит новое значение только при изменении освещенности >5, чтоб не засорять ком-порт каждые полсекунды. Схема подключения в первом сообщении.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Narkus, у вас и код и схема с разного рода недочётами. Но примитивность скечта тут вряд ли оказывает влияние, скорее всё таки аппаратные недоработки. В частности 50 кОм со входа на землю -слишком много.  максимум 10k, а лучше меньше. Например делитель из 4к7 и 12к. Либо можно повесить паралельно входу конденсатор 100n, но по последним данным это вредит точности) Так что лучше уменьшать резистор. 

Narkus
Offline
Зарегистрирован: 23.05.2017

dimax пишет:

Narkus, у вас и код и схема с разного рода недочётами. Но примитивность скечта тут вряд ли оказывает влияние, скорее всё таки аппаратные недоработки. В частности 50 кОм со входа на землю -слишком много.  максимум 10k, а лучше меньше. Например делитель из 4к7 и 12к. Либо можно повесить паралельно входу конденсатор 100n, но по последним данным это вредит точности) Так что лучше уменьшать резистор. 

О, спасибо, попробую.