Нужна помощь по калибровке аналогового датчика

AndreiPol
Offline
Зарегистрирован: 02.02.2015

Есть такой вариант калибровки .

/*
  
 Пока нажата кнопка, в программе будет работать только функция калибровки.
 На основе данных от датчика, считанных за это время, будут определены новый максимум и минимум.
 
 Это вариация примера «Калибровка».
 
 Цепь:
 * фоторезистор подключен к 0-ому аналоговому и 5-вольтовому контактам
 * 10000-омовый резистор подключен к «земле» и 0-ому аналоговому контакту
 * светодиод через 220-омовый резистор подключен к 9-ому цифровому контакту, а также к «земле»
 * кнопка подключена ко 2-ому цифровому и 5-вольтовому контактам
 * 10000-омовый резистор подключен ко 2-ому цифровому контакту и «земле»
  
 */
 
 
// это константы, т.е. значения, которые не изменятся:
const int sensorPin = A0;       // контакт, к которому подключен датчик
const int ledPin = 9;           // контакт, к которому подключен светодиод
const int indicatorLedPin = 13; // контакт, к которому подключен встроенный светодиод
const int buttonPin = 2;        // контакт, к которому подключена кнопка
 
 
// это переменные, т.е. значения, которые изменятся:
int sensorMin = 1023;  // минимальное значение от датчика
int sensorMax = 0;     // максимальное значение от датчика
int sensorValue = 0;         // значение, считанное от датчика
 
 
void setup() {
  // задаем контакты светодиодов как выходные,
  // а контакт кнопки – как входной
  pinMode(indicatorLedPin, OUTPUT);
  pinMode (ledPin, OUTPUT);
  pinMode (buttonPin, INPUT);
}
 
void loop() {
  // пока нажата кнопка, берем данные для калибровки:
  while (digitalRead(buttonPin) == HIGH) {
    calibrate();
  }
  // даем сигнал о начале калибровочного периода:
  digitalWrite(indicatorLedPin, LOW);  
 
  // считываем данные от датчика:
  sensorValue = analogRead(sensorPin);
 
  // применяем калибровку к считанным данным:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);
 
  // задаем лимит, если во время калибровки данные от датчика
  // вышли за пределы нужного диапазона:
  sensorValue = constrain(sensorValue, 0, 255);
 
  // меняем яркость светодиода на основе откалиброванных значений:
  analogWrite(ledPin, sensorValue);
}
 
void calibrate() {
  // включаем светодиод, оповещая о том, что калибровка завершена:
  digitalWrite(indicatorLedPin, HIGH);
  // считываем данные от датчика:
  sensorValue = analogRead(sensorPin);
 
  // записываем максимальное значение:
  if (sensorValue > sensorMax) {
    sensorMax = sensorValue;
  }
 
  // записываем минимальное значение:
  if (sensorValue < sensorMin) {
    sensorMin = sensorValue;
  }
}

Но при выключении питания настройки калибровки сбрасываются. Прошу помощи в добавлении таких функций:

 1. При входе в режим калибровки данные из EEPROM стираются и устанавливаются на дефолтные 0,1023. 

2. При выходе из режима калибровки новые данные записываются в EEPROM и далее считываются с EEPROM

пи.си. Я очень начинающий ардуинщик, поэтому прошу не использовать сильно умные слова. :0)

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

п. 1 у Вас явно лишний.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

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

ЗЫ. Вот готовые функции для считывания и записи целочисленного значения в/из EEPROM

/* Read integer value */
int EEPROM_int_read(int addr) {
    byte raw[2];
    for (byte i = 0; i < 2; i++) {
        raw[i] = EEPROM.read(addr + i);
    }
    int &num = (int&)raw;
    return num;
}

/* Write integer value */
void EEPROM_int_write(int addr, int num) {
    byte raw[2];
    (int&)raw = num;
    for (byte i = 0; i < 2; i++) {
        EEPROM.write(addr + i, raw[i]);
    }
}
AndreiPol
Offline
Зарегистрирован: 02.02.2015

мне нужно записать и считать число,например, 1023. Оно займет две ячейки памяти. Как корректно это сделать?

sadman41
Offline
Зарегистрирован: 19.10.2016
AndreiPol
Offline
Зарегистрирован: 02.02.2015

вообщем сейчас работает в таком виде
 



#include <EEPROM.h>
int a = 0; // переменая для вывода в монитор
int value; // переменая для вывода в монитор
bool prevState = LOW;
// это константы, т.е. значения, которые не изменятся:
const int sensorPin = A0;       // контакт, к которому подключен датчик
const int ledPin = 9;           // контакт ШИМ, к которому подключен светодиод
const int indicatorLedPin = 13; // контакт, к которому подключен встроенный светодиод
const int buttonPin = 2;        // контакт, к которому подключена кнопка
// это переменные, т.е. значения, которые изменятся:
int sensorMin = EEPROM.read(0) * 4; //данные с ячейки умножаем на 4
int sensorMax = EEPROM.read(1) * 4; //данные с ячейки умножаем на 4
int sensorValue = 0;         // значение, считанное от датчика
int sensorValue1 = 0; // значение, считанное от датчика для монитора
void setup() {
  Serial.begin (9600);
  pinMode(indicatorLedPin, OUTPUT); //светодиод на борту ардуины
  pinMode (ledPin, OUTPUT); //светодиод на выходе ШИМ
  pinMode (buttonPin, INPUT); //кнопка
 
}
void loop() {
 
  Serial.print(a);//на монитор
  Serial.print("\t");//на монитор
  Serial.print(value);//на монитор
  value = EEPROM.read(a); //на монитор
  a = a + 1;
  if (a == 4)
    a = 0;
  delay (100);//для задержки в мониторе. потом нужно удалить
 
  Serial.print (" /in ");
  Serial.print (sensorValue1);
  Serial.print (" /min ");
  Serial.print (sensorMin);
  Serial.print (" /max ");
  Serial.println (sensorMax);
  // пока нажата кнопка, берем данные для калибровки:
  while (digitalRead(buttonPin) == HIGH) {
    if (prevState == LOW) {
      sensorMax = 0; //сбрасываем переменную
      sensorMin = 1023; //сбрасываем переменную
      prevState = HIGH; //выставляем что бы повторно в цикле не обнулять
    }
    calibrate();
  }
 
  digitalWrite(indicatorLedPin, LOW); // даем сигнал о начале калибровочного периода:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue1 = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// применяем калибровку к считанным данным:
  sensorValue = constrain(sensorValue, 0, 255); // задаем лимит, если во время калибровки данные от датчика вышли за пределы нужного диапазона:
  analogWrite(ledPin, sensorValue);// меняем яркость светодиода на основе откалиброванных значений:
  prevState = LOW;
}
 
void calibrate() {
  Serial.print (" in ");
  Serial.print (sensorValue1);
  Serial.print (" /min ");
  Serial.print (sensorMin);
  Serial.print (" /max ");
  Serial.println (sensorMax);
  digitalWrite(indicatorLedPin, HIGH);// включаем светодиод, оповещая о том, что калибровка завершена:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue1 = analogRead(sensorPin);// считываем данные от датчика:
 
  // записываем максимальное значение:
  if (sensorValue > sensorMax) {
    sensorMax = sensorValue;
  }
  // записываем минимальное значение:
  if (sensorValue < sensorMin) {
    sensorMin = sensorValue;
  }
  if (prevState == HIGH) {
    //тут записываем новые данные калибровки в память
    EEPROM.write(0, (int)(sensorMin / 4)); //делим на 4 чтоб влезло в ячейку
    EEPROM.write(1, (int)(sensorMax / 4)); //делим на 4 чтоб влезло в ячейку
  }
}

покритикуйте, если шо.

OlegK
OlegK аватар
Offline
Зарегистрирован: 26.11.2014

AndreiPol пишет:
покритикуйте, если шо.

С делением и умножением на 4 - полный бред.
Записывайте сразу полное число (функции выше я давал) -
Пишем значение value по адресу 0
EEPROM_int_write(0, value);
и читайте из адреса 0
value = EEPROM_int_read(0);

или, как предлагали дальше, функции EEPROM.put() и EEPROM.get
EEPROM.put(0, value);
и
value = EEPROM.get(0);

Учитывая, что тип int занимает 2 байта, то следующий адрес будет 2, затем 4 и.т.д.

AndreiPol
Offline
Зарегистрирован: 02.02.2015

можешь скетч выше поправить как надо? А то мне пока это всё как ядерная физика...

AndreiPol
Offline
Зарегистрирован: 02.02.2015

так нормально?
 

#include <EEPROM.h>
int a = 0; // переменая для вывода в монитор
int value; // переменая для вывода в монитор
bool prevState = LOW;
// это константы, т.е. значения, которые не изменятся:
const int sensorPin = A0;       // контакт, к которому подключен датчик
const int ledPin = 9;           // контакт ШИМ, к которому подключен светодиод
const int indicatorLedPin = 13; // контакт, к которому подключен встроенный светодиод
const int buttonPin = 2;        // контакт, к которому подключена кнопка
// это переменные, т.е. значения, которые изменятся:
int sensorMin = 1023;
int sensorMax = 0;
int sensorValue = 0;         // значение, считанное от датчика
int sensorValue1 = 0; // значение, считанное от датчика для монитора


void setup() {
  Serial.begin (9600);
  pinMode(indicatorLedPin, OUTPUT); //светодиод на борту ардуины
  pinMode (ledPin, OUTPUT); //светодиод на выходе ШИМ
  pinMode (buttonPin, INPUT); //кнопка
  EEPROM.get( 0, sensorMin );
  EEPROM.get( 2, sensorMax );

}
void loop() {

  Serial.print(a);//на монитор
  Serial.print("\t");//на монитор
  Serial.print(value);//на монитор
  value = EEPROM.read(a); //на монитор
  a = a + 1;
  if (a == 5)
    a = 0;
  delay (1);//для задержки в мониторе. потом нужно удалить

  Serial.print (" /in ");
  Serial.print (sensorValue1);
  Serial.print (" /min ");
  Serial.print (sensorMin);
  Serial.print (" /max ");
  Serial.println (sensorMax);
  // пока нажата кнопка, берем данные для калибровки:
  while (digitalRead(buttonPin) == HIGH) {
    if (prevState == LOW) {
      sensorMax = 0; //сбрасываем переменную
      sensorMin = 1023; //сбрасываем переменную
      prevState = HIGH; //выставляем что бы повторно в цикле не обнулять
    }
    calibrate();
  }

  digitalWrite(indicatorLedPin, LOW); // даем сигнал о начале калибровочного периода:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue1 = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// применяем калибровку к считанным данным:
  sensorValue = constrain(sensorValue, 0, 255); // задаем лимит, если во время калибровки данные от датчика вышли за пределы нужного диапазона:
  analogWrite(ledPin, sensorValue);// меняем яркость светодиода на основе откалиброванных значений:
  prevState = LOW;
}

void calibrate() {
  Serial.print (" in ");
  Serial.print (sensorValue1);
  Serial.print (" /min ");
  Serial.print (sensorMin);
  Serial.print (" /max ");
  Serial.println (sensorMax);
  digitalWrite(indicatorLedPin, HIGH);// включаем светодиод, оповещая о том, что калибровка завершена:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue1 = analogRead(sensorPin);// считываем данные от датчика:

  // записываем максимальное значение:
  if (sensorValue > sensorMax) {
    sensorMax = sensorValue;
  }
  // записываем минимальное значение:
  if (sensorValue < sensorMin) {
    sensorMin = sensorValue;
  }
  if (prevState == HIGH) {
    //тут записываем новые данные калибровки в память
    // теперь одна простая функция, где первый аргумент – это адрес, а второй – объект:
    EEPROM.put(0, sensorMin);
    EEPROM.put(2, sensorMax);
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

AndreiPol. Похоже надо начинать сначала. А вначале у нас было СЛОВО описание как правильно должно работать ваше устройство.

AndreiPol
Offline
Зарегистрирован: 02.02.2015

а что сейчас не так? В железе проверил, работает корректно.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Мда. Попробуйте еще. Похоже я отвлекся , когда вы проверяли. Может сейчас замечу.

ПС: А пока вы это повторяете опишите, какие действия вы делаете для калибровки. 

AndreiPol
Offline
Зарегистрирован: 02.02.2015

это сокращённая версия без вывода на монитор
 

#include <EEPROM.h>

bool prevState = LOW;
// это константы, т.е. значения, которые не изменятся:
const int sensorPin = A0;       // контакт, к которому подключен датчик
const int ledPin = 9;           // контакт ШИМ, к которому подключен светодиод
const int indicatorLedPin = 13; // контакт, к которому подключен встроенный светодиод
const int buttonPin = 2;        // контакт, к которому подключена кнопка
// это переменные, т.е. значения, которые изменятся:
int sensorMin = 0;
int sensorMax = 0;
int sensorValue = 0;         // значение, считанное от датчика

void setup() {
  pinMode(indicatorLedPin, OUTPUT); //светодиод на борту ардуины
  pinMode (ledPin, OUTPUT); //светодиод на выходе ШИМ
  pinMode (buttonPin, INPUT); //кнопка
  EEPROM.get( 0, sensorMin );
  EEPROM.get( 2, sensorMax );

}
void loop() {

  // пока нажата кнопка, берем данные для калибровки:
  while (digitalRead(buttonPin) == HIGH) {
    if (prevState == LOW) {
      sensorMax = 0; //сбрасываем переменную
      sensorMin = 1023; //сбрасываем переменную
      prevState = HIGH; //выставляем что бы повторно в цикле не обнулять
    }
    calibrate();
  }

  digitalWrite(indicatorLedPin, LOW); // даем сигнал о начале калибровочного периода:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:
  sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// применяем калибровку к считанным данным:
  sensorValue = constrain(sensorValue, 0, 255); // задаем лимит, если во время калибровки данные от датчика вышли за пределы нужного диапазона:
  analogWrite(ledPin, sensorValue);// меняем яркость светодиода на основе откалиброванных значений:
  prevState = LOW;
}

void calibrate() {
  digitalWrite(indicatorLedPin, HIGH);// включаем светодиод, оповещая о том, что калибровка завершена:
  sensorValue = analogRead(sensorPin);// считываем данные от датчика:

  // записываем максимальное значение:
  if (sensorValue > sensorMax) {
    sensorMax = sensorValue;
  }
  // записываем минимальное значение:
  if (sensorValue < sensorMin) {
    sensorMin = sensorValue;
  }
  if (prevState == HIGH) {
    // тут записываем новые данные калибровки в память
    // теперь одна простая функция, где первый аргумент – это адрес, а второй – объект:
    EEPROM.put(0, sensorMin);
    EEPROM.put(2, sensorMax);
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Объсняю ... Берем устройство . Подключаем к эталону на котором максимум и нажимаем кнопку максимум.  Потом подключаем к эталону на котором минимум и нажимаем кнопку минимум. Все устройство откалибровано. И нефиг всяким шаманам стручать в барабаны и бегать по кругу. Это не калибровка.

AndreiPol
Offline
Зарегистрирован: 02.02.2015

ну можно и так...

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

нужно так. Но у вас ошибка уже на уровне описания технического задания. Так что переписывайте все .

AndreiPol
Offline
Зарегистрирован: 02.02.2015

не я ж эту калибровку придумал. Взял готовое из примеров и чуток допилил...

 

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

AndreiPol пишет:

не я ж эту калибровку придумал. Взял готовое из примеров и чуток допилил...

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