Датчик света. Замеры

32bit
Offline
Зарегистрирован: 16.02.2016

Понадобилось посмотреть значения света на улице в разное время суток. Если вдруг кому пригодится.

Записывает значения света в EEPROM в течении суток через 15мин. Время берется с GPS приемника по Rx.

 

#include <EEPROM.h>

#include <SoftwareSerial.h>

#include <TinyGPS.h>

TinyGPS gps;
SoftwareSerial ss(2, 3);                                  // К D2 подключается Tx GPS приемника    
int timeoffset = 3;                                       // Часовой пояс
int pinAn = 2;                                            // К A2 подключается вход с фоторезистора
unsigned long pauseL = 0;
int arrayL[5] = {0, 0, 0, 0, 0};
byte s = 0;
int currentL = 0;
boolean l = false;
int addr = 0;

void EEPROMWriteInt(int p_address, int p_value)                   // Запись в EEPROM значений типа int
        {
         byte lowByte = ((p_value >> 0) & 0xFF);
         byte highByte = ((p_value >> 8) & 0xFF);
         EEPROM.update(p_address, lowByte);
         EEPROM.update(p_address + 1, highByte);
        }


void setup()
{
  Serial.begin(9600);
  ss.begin(9600);
  //pinMode(pinAn, INPUT);
  Serial.print("Simple TinyGPS library v. ");
  Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    int year;
    byte month, day, hour, minute, second, hundredths;
    gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths);
    hour = hour + timeoffset;
    Serial.print(hour);
    Serial.print(":");
    Serial.print(minute);
    Serial.print(":");
    Serial.println(second);
    if (l && (minute == 0 || minute == 15 || minute == 30 || minute == 45))
    {
      addr = hour*8+(minute/15)*2;                    // Высчитывается адрес ячейки EEPROM в зависимости от времени
      EEPROMWriteInt(addr, currentL);
      Serial.print("Eeprom write ");
      Serial.print(addr);
      Serial.print(" ");
      Serial.println(currentL);
    }
  }


  //Здесь значения со света считываюся 5 раз через 1 сек и высчитывается среднее, если значения отличается более чем на 10 то изменить значение переменной currentL
  
  if (pauseL == 0) {pauseL = millis();}
  else
  {
    if ((millis()-pauseL) > 1000)                     //Если прошло более 1сек между опросами
    {
      if (s < 5)
      {
        arrayL[s] = analogRead(pinAn);
        s++;
      }
      else                                            // Если выполнено 5 опросов
      {
        // Ищем максимальное значение
        int maxL = arrayL[0];
        int imaxL = 0;
        for (int x = 1; x < 5; x++)
        {
         if (maxL < arrayL[x])
         {
           maxL = arrayL[x];
           imaxL = x;
         }
        } 

        //Ищем минимальное значение
        int minL = arrayL[0];
        int iminL = 0;
        for (int x = 1; x < 5; x++)
        {
         if (minL > arrayL[x])
         {
          minL = arrayL[x];
          iminL = x;
         }
        }

        // Вычисляем среднее значение отбрасывая макс и мин
        int sr = 0;
        for (int x = 0; x < 5; x++) {if (!(imaxL == x) && !(iminL == x)) {sr = sr + arrayL[x];}}

        // Если все значения одинаковы, то imaxP = iminP и делить надо на четыре
        int temp1 = 0;
        int st = 0;
        if (imaxL == iminL) {temp1 = sr / 4;}
        else {temp1 = sr / 3;}
        st = currentL - temp1;
        st = abs(st);
        if (st > 10) {currentL = temp1;}
        s = 0;
        l = true;
      }
      pauseL = 0;
    }
  }

  

}

Дальнейшее чтение EEPROM

 

#include <EEPROM.h>

unsigned int value = 0;
int hour[24] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
int minute[4] = {0, 15, 30, 45};
int addr = 0;

unsigned int EEPROMReadInt(int p_address)
        {
         byte lowByte = EEPROM.read(p_address);
         byte highByte = EEPROM.read(p_address + 1);
         return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
        }
   
void setup()
{
 Serial.begin(9600);
 pinMode(13, OUTPUT);
 Serial.println("EEPROM read...");
 for (int i = 0; i < 24; i++)
 {
  for (int m = 0; m < 4; m++)
  {
    addr = hour[i]*8 + (minute[m]/15)*2;
    value = EEPROMReadInt(addr);
    Serial.print(hour[i]);
    Serial.print(":");
    Serial.print(minute[m]);
    Serial.print(" = ");
    Serial.println(value);
  }
 }
}

void loop()
{
 digitalWrite(13, HIGH);
 delay(300);
 digitalWrite(13, LOW);
 delay(300);

}

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

Тоже выложу пример измерения освещенности в больших пределах без использования АЦП. Проверено на ESP8266.

Суть в измерении времени RC цепи. Схема как у вас, только вместо резистора конденсатор на 2,2 мкФ. Фоторезистор к +, конденсатор к минусу, их соединение к пину, имеющему прерывания. Перед замером разряжаем конденсатор пином в 0, потом отсчитываем время до прерывания. Время зарядки конденсатора и берем как попугаи освещенности. Значение времени получаются от 15 мкс при ярком свете до 5000000 мкс при почти полной темноте. Эти попугаи можно приводить к каким либо единицам. Пробовал брать кубический корень из полученной цифры, тогда логарифмичность шкалы уменьшается и более приятно глазу.

//На GPIO 2 конденсатор 2,2мкФ и фоторезистор. Конденсатор на землю, фоторезистор на +. В сериале получаем время заряда конденсатора, меняющееся от освещенности.
void ICACHE_RAM_ATTR InterruptMeasurePin();//ставим функцию прерываний InterruptMeasurePin() в RAM память для стабильной работы
#define measurePin 2// пин измерений
uint32_t RCtime1;// тут хранится начальное время RC цепи
volatile uint32_t RCtime2;// тут хранится конечное время RC цепи
void setup() {
  Serial.begin(115200);
}
void InterruptMeasurePin() {// по прерыванию в момент заряда конденсатора запоминаем время
  RCtime2 = micros();
}

void loop() {
  pinMode(measurePin, OUTPUT);//разряжаем конденсатор
  delay(1);
  attachInterrupt (digitalPinToInterrupt (measurePin), InterruptMeasurePin, CHANGE);// включаем прерывание которое сработает при заряде конденсатора до логической единицы
  pinMode(measurePin, INPUT);// начало заряда
  RCtime1 = micros();// запоминаем время начала заряда конденсатора
  delay(5000);// время необходимое на измерение можно уменьшить до 100мс
  detachInterrupt (digitalPinToInterrupt(measurePin));// в случае превышения времени заряда, прерывание не сработает. отключаем прерывание
  if (RCtime2) { // Если измерение произошло т.е. время окончания заряда не равно нулю
    Serial.println("RCtime=" + String(RCtime2-RCtime1)+" micros1=" + String(RCtime1) + " micros2=" + String(RCtime2));
    RCtime2=0;// обнуляем значение времени конца измерений чтоб потом его использовать как флаг выполнения измерений
  } else Serial.println("timeout");// время заряда конденсатора больше установленного
}

Можно таким образом измерять сопротивление или емкость конденсаторов. Из опастностей: разряд конденсатора идет через пин, т.е. установка большой емкости недопустима!