Помогите объединить два скетча

Савелий
Offline
Зарегистрирован: 26.10.2019

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

Савелий
Offline
Зарегистрирован: 26.10.2019
#include <SPI.h>                              // Подключаем библиотеку SPI
#include <SD.h>                               // Подключаем библиотеку SD
int pulse;
const int auf = 10; //после скольких записей подтверждается запись
// медианный фильтр
int medFilt(int value) {
  const int bufSize = 70; // количество элементов
  // должно быть нечётным
  static int buf[bufSize]; // массив нескольких
  // последних элементов
  static int sortBuf[bufSize]; // массив элементов
  // который сортируется
  static int pos = 0; // текущая позиция в массиве

  buf[pos] = value; // запись нового значения в массив

  // вычисление позиции следующего элемента
  pos++;
  if (pos == bufSize) pos = 0;

  // копирование первого массива во второй
  for (int i = 0; i < bufSize; i++) {
    sortBuf[i] = buf[i];
  }

  // сортировка второго массива
  for (int i = 0; i < bufSize; i++) {
    for (int j = i; j < bufSize; j++) {
      if (sortBuf[i] < sortBuf[j]) {
        int k = sortBuf[i];
        sortBuf[i] = sortBuf[j];
        sortBuf[j] = k;
      }
    }
  }

  // возвращается средний элемент
  // из отсортированного массива
  return sortBuf[(bufSize / 2)];
}
File my;
const int chipSelect = 4;// Указываем к какому выводу подключен CS
unsigned long seed;//случайное имя
String str;//.txt
boolean pz;  //состояние переключателя
void setup()
{
  pinMode (5, INPUT_PULLUP);
  pinMode (3, INPUT_PULLUP);
  pinMode (A6, INPUT);
  pinMode (13,OUTPUT);
  pinMode (A2, INPUT);
  Serial.begin(9600);                // Открытие последовательную связь
  Serial.print("Initializing SD card...");
  if (!SD.begin(4)) {
    Serial.println("Card failed, or not present");
  }
  seed = 1;
  seed *= 4;
  seed += analogRead(A1) & 3;
  randomSeed(seed);
  str = String (random (100000));
  static String xp = ".txt";
  static String asfd = str + xp;
  Serial.println("card initialized.");
  Serial.println("initialization done.");     // Печатаем текст, если инициализация прошла успешно
  my = SD.open(asfd, FILE_WRITE);
  delay (1);
  pz =  !digitalRead (A2);
}
// пересечения порогового уровня сверху вниз
int buf1 [15];
float buf1f [15];
int pos = 0; //позиция буфера
unsigned long prevTime, time;
int ti = 0; // текущее значение
int tm = 0; // прошлое значение
float f = 0.0000; //фильтрованное значение
byte kol; // кол-во записей
int q = 0;
int d = 0;
int por = 0; //нейтральный порог
int por1 = 0; //порог вдоха
int por2 = 0;//порог выдоха
boolean per2; //пересечение низа (выдох)
boolean per1, podt;// пересечение верха (вдох), подтверждение о записи
boolean ed = 0; //еденичная запись
void loop() {
  ti = analogRead (A6);
  f = (ti * 0.75) + (tm * 0.25);
  por = medFilt (f); // вычисление нейтрального порога
  por1 = por + 3; // вычисления остальных прогов - вдоха и выдоха
  por2 = por - 3;
  q++;
  if (q > 70) {
    q = 0;
  }
  if (f > por1 && per1 == 0) {
    per1 = 1;
  }
  if (per1 == 1 && f < por) { // если было пересечение вверх а текущее ниже нижнего порога то происходят вычисления а факт пересечения стирается
    digitalWrite (13,1);
    per1 = 0;
    prevTime = time;
    // текущее время обновляется
    time = millis();
    // вычисляется мгновенное значение пульса
    // (60 секунд) * 1000 / (период в миллисекундах)
    int period = time - prevTime;
    pulse = 60000 / period;
    // компенсация погрешности целочисленного деления
    if ((60000 % period) >= (60000 / 2)) pulse++;
    buf1f [pos] = (float) millis () / 1000.000;
    buf1 [pos] = pulse;
    kol++;
    pos++;
    
    Serial.println (pulse)
   // Serial.println (pos);
;    if (pos > 14) {
      for (int xt = 0; xt < 15; xt++) {
        my.print (buf1f [xt]);
        my.print (" ");
        my.println (buf1 [xt]);
      }
      pos = 0;
      my.flush();
    }
    //Serial.print (kol);
  //  Serial.println ("вдох");

      digitalWrite (13,0);
  }
  Serial.print (f);
  Serial.print (" ");
  Serial.print (por);
   Serial.print (" ");
     Serial.print (por1);
       Serial.print (" ");
        Serial.println (por2);
  ti = tm;z
  delay (50);
}

Скетч датчика дыхания.

Савелий
Offline
Зарегистрирован: 26.10.2019

#include <LiquidCrystal.h>

// используемые пины
const int ledPin=6; // анод инфракрасного светодиода
const int sensorPin=A0; // выход датчика
const int beepPin=7; // анод бипера со встроенным генератором

// размер буфера для вычисления порога
const int bufSize=16; 
// буфер для вычисления порога
int buf[bufSize];
// текущая позиция в буфере
int bufPos=0;
// сумма значений в буфере
long int bufSum=0;
// порог, вычисляемый, как среднее арифметическое 
// значений в буфере 
int  threshold=0;
// расстояние до верхнего и нижнего порогов 
// больше значение - меньше ложных срабатываний
// и меньше чувствительности
const int hyst=45; 

// пропуск некоторого количества замеров 
// после пересечения порога
int skipDetect=0; // количество замеров, 
                  // которые необходимо пропустить
const int crossSkip=7; // пишется в skipDetect
                       // после каждого пересечения порога
                       
// напряжение на датчике при включенном светодиоде
int sensorValueLedOn; 
// при выключенном светодиоде
// фоновая засветка
int sensorValueLedOff;
// значение на датчике с компенсацией фонового освещения
// по формуле sensorValueLedOff - sensorValueLedOn
int sensorValue;

// начало и конец текущего периода
// время записывается при детектировании
// пересечения порогового уровня сверху вниз
unsigned long prevTime, timer;

// находилось ли значение предыдущего отсчёта выше порога
boolean above; 

// мгновенное значение пульса
// количество ударов в минуту
int pulse;
// медианное значение пульса
int pulseMed;
// среднее значение пульса
int pulseAvg;

// медианный фильтр
int medFilt(int value){
  const int bufSize=7; // количество элементов
                       // должно быть нечётным
  static int buf[bufSize]={93,93,93,93,93,93,93}; // массив нескольких 
                           // последних элементов
  static int sortBuf[bufSize]; // массив элементов
                               // который сортируется
  static int pos=0;  // текущая позиция в массиве
  
  buf[pos]=value;  // запись нового значения в массив
  
  // вычисление позиции следующего элемента
  pos++;
  if (pos==bufSize) pos=0;
  
  // копирование первого массива во второй
  for(int i=0; i<bufSize; i++){
    sortBuf[i]=buf[i];
  }
  
  // сортировка второго массива 
  for(int i=0; i<bufSize; i++){
    for(int j=i; j<bufSize; j++){
      if(sortBuf[i]<sortBuf[j]){
        int k=sortBuf[i];
        sortBuf[i]=sortBuf[j];
        sortBuf[j]=k;
      }
    }
  }
  
  // возвращается средний элемент 
  // из отсортированного массива
  return sortBuf[(bufSize/2)];
}

// вычисление среднего значения
int avg(int value){
  const int bufSize=16;  // количество значений
  static int buf[bufSize]; // массив из последних значений 
  static int pos; // текущая позиция
  static long int sum=0; // сумма всех значений
  int avg; // среднее значение
  
  buf[pos] = value; // добавление нового значения
  sum += value; // его добавление в сумму
  avg = sum/bufSize; // вычисление среднего значения
  // компенсация погрешности целочисленного деления
  if ((sum%bufSize)>=(bufSize/2)) avg++;
  
  // вычисление позиции следующего элемента
  pos++;
  if (pos==bufSize) pos=0;
    
  sum -= buf[pos]; // элемент, который будет перезаписан
                   // в следующий раз заранее вычитается
                   // из суммы 
  return avg;
}

// символьный дисплей HD44780 16x2
// RS, EN, D4, D5, D6, D7
LiquidCrystal lcd(10, 8, 5, 4, 3, 2);

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(beepPin, OUTPUT);
  digitalWrite(beepPin, LOW);
  Serial.begin(9600);
  lcd.begin(16, 2);
}


void loop() {
  digitalWrite(ledPin, HIGH); // светодиод включается
  delay(10); // задержка, чтобы фототранзистор успел среагировать
  // замеряется напряжение с датчика со включенным светодиодом
  sensorValueLedOn = analogRead(sensorPin); 
  digitalWrite(ledPin, LOW); // светодиод выключается
  delay(10);
  // замер с выключенным светодиодом
  sensorValueLedOff = analogRead(sensorPin);
  
  // компенсация фоновой засветки
  sensorValue =sensorValueLedOn;
  
  buf[bufPos] = sensorValue;  // запись нового значения в буфер
  bufSum += sensorValue;  // прибавление его к сумме
  
  // вычисление порога
  // (среднее арифметическое всех значений в буфере)
  threshold = bufSum/bufSize+1; 

  // вычисление позиции следующего элемента
  bufPos++; 
  if (bufPos==bufSize) bufPos=0;
  
  // элемент, который будет перезаписан в следующий раз,
  // вычитается из суммы заранее
  bufSum -= buf[bufPos];
  
  // если не нужно пропускать замеры
  if (skipDetect==0){
    // детектирование того, что значение находится выше
    // верхнего порога
    if (sensorValue<(threshold+hyst-10)){
      // при пересечении порога детективрование отключается 
      // на несколько замеров 
      if (!above) skipDetect=crossSkip; 
      // показания с датчика теперь выше порога
      above=true; 
    }
    // детективрование того, что значение находится ниже 
    // нижнего порога
    else if (sensorValue>(threshold+hyst)){
      // при пересечении порога сверху вниз происходят вычисления
      if (above){
        // текущее время становится предыдущим
        prevTime = timer; 
        // текущее время обновляется
        timer = millis();
        // вычисляется мгновенное значение пульса
        // (60 секунд) * 1000 / (период в миллисекундах)
        int period = timer-prevTime;
        pulse = 60000/period;
        // компенсация погрешности целочисленного деления
        if ((60000%period)>=(60000/2)) pulse++;
        
        // если значение пульса реалистично, то оно выводится
        if ((pulse>=40)&&(pulse<=200)){
          // би
          digitalWrite(beepPin, HIGH);
          // вывод данных
          lcd.clear();
          lcd.print("Inst:");
          lcd.print(pulse);
          lcd.setCursor(9,0);
          lcd.print("Med:");
          pulseMed = medFilt(pulse);
          lcd.print(pulseMed);
          lcd.setCursor(4,1);
          lcd.print("Avg: ");
          pulseAvg = avg(pulseMed);
          lcd.print(pulseAvg);   
          //Serial.print("Inst: ");
        //  Serial.print(pulse);
      //    Serial.print("; Med: ");
          Serial.println(pulseMed);
     //     Serial.print("; Avg: ");
       //   Serial.println(pulseAvg);    
          // п
          digitalWrite(beepPin, LOW);
          // последнее значение с датчика ниже порога
          // above = false; на самом деле должно быть не тут
        }
        // при пересечении порога детективрование отключается 
        // на несколько замеров        
        skipDetect=crossSkip;
      }
      // а здесь
      above = false;
    }
  }else{
    skipDetect--; // один замер пропущен, 
                  // поэтому ещё надо пропустить
                  // на один меньше :-)
  } 
}

Скетч AD8232, который, по сути и является шаблонным. Изменены только настройки.

Савелий
Offline
Зарегистрирован: 26.10.2019

Конечно можно сделать проэкт "двухядерным" (с двумя ардуинками). Но, мне кажется, тут можно обойтись и без 2 ядер.

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

Ничего, что в этих скетчах используются одни и те же пины (3 и 5) для разных целей? Интересно, как Вы их подключали для объединённого скетча?

Савелий
Offline
Зарегистрирован: 26.10.2019

3 и 5 объявлены, но не используются (код LCD дисплея закомментировал при объединении)

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

Савелий пишет:

код LCD дисплея закомментировал при объединении

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

Простите, но я расцениваю это как издевательство над собой с Вашей стороны. Поставьте себя на моё место.

До свиданья, удачи Вам с кодом!