Датчик света. Замеры
- Войдите на сайт для отправки комментариев
Ср, 07/12/2016 - 15:01
Понадобилось посмотреть значения света на улице в разное время суток. Если вдруг кому пригодится.
Записывает значения света в 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);
}

Тоже выложу пример измерения освещенности в больших пределах без использования АЦП. Проверено на 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");// время заряда конденсатора больше установленного }Можно таким образом измерять сопротивление или емкость конденсаторов. Из опастностей: разряд конденсатора идет через пин, т.е. установка большой емкости недопустима!