Зависает прерывание?

Ganzer
Offline
Зарегистрирован: 17.12.2015

Сделал индикатор мощности в сети 220В.
Подключил arduino к счетчику, к выводам удаленного мониторинга, там похоже стоит опторозвязка.
Вобщем все работает, мощность показывает какое-то время, сутки или 3 часа, по разному.

Счетчик ненужный используется, поэтому там долгое время бывает не бывает нагрузки, при этом светодиод не моргает и в итоге при подключении нагрузки прерывания не срабатывают.

При этом перестает правильно реагировать на millis(), это только-что заметил, т.к. проект включает в себя управление курятником :) регулирует температуру, управляет освещением, и еще температуру дома и на улице показывает. Вобщем входы-выходы все использованы.

В обработчике прерывания никакних сложных действий не производится, один рас вызывается micros() и пара сравнений инкрементов переменных с ключевым словом volatile.

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

Вобщем. мне надо какие-то мысли по поводу как победить это дело.
Если в нагрузку включена лампа 8Вт светодиодная, то он очень радко, раз в несколько минут помаргивает и и вроде как не зависает, а вот зарядник от телефона такого эффекта не дал - зависло за 3 часа.

Счас примеры кода не могу привести, т.к. все на другом компе. Сделан по такому принципу: int pin = 13;

int state = LOW;



unsigned long time;

unsigned long timenext=0;

unsigned long NewData;

unsigned long NewData2;



void setup()

{

  Serial.begin(115200); 

  pinMode(pin, OUTPUT);

  pinMode(2, INPUT);  

  attachInterrupt(0, reader, RISING);

}



void loop()

{

  time=millis();  

  if (time>=timenext)

  {

  timenext=timenext+1000;

  NewData2=NewData; // для отображения

  NewData=0;

  Serial.println(NewData2);

  state=!state;

  digitalWrite(pin, state);       

  }

}



void reader()

{

  NewData++; 

}

Только в функции reader измеряется интервал по отношению к предыдущему событию.

Araris
Offline
Зарегистрирован: 09.11.2012

1. http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

2. Не вижу слова volatile в приведённом скетче.

Ganzer
Offline
Зарегистрирован: 17.12.2015

Ага, про code понял.

В двух словах если

при объявлении NewData написать volatile в loop вывести NewData на индикатор, то через какое-то время NewData престает изменяться, на вход импульс приходит исправно, если его считывать и выводить на экран в loop то видно.

Я вобще чайник и про voltile узнал позавчера. До этого боролся с "ложными" срабатываниями прерывания при помехе, которая возникала если где-то в сети 220 пощелкать выключателем к которому ничего не подключено, всякие конденсаторно-дроссельные фильтры на входе не помогли. Победил это считывая состояние порта в момент прерывания, ложных срабатываний не стало.

Дело в том что запасной ардуины пока нет и приходится экспериментировать по живому, т.к. куры несуться, а если утром свет не включать вовремя, а я любитель поспать до 11, то не несуться :)

Сегодня причешу код и выложу скетч.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Вешать что-либо на   прерывание без хотя-бы простейшего эр-цэ  фильтра крайне не рекомендуется......
Устанете дребезг обрабатывать.

Возьмите на вооружение правильную схему: http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-dlya-taktovoi-knopki?page=2#comment-152876

Ganzer
Offline
Зарегистрирован: 17.12.2015

Код, даже не буду оправдываться за стиль, все написано на коленке на ходу между делом. Много всякой экспериментально-отладочной каши.

Проблемное место с 320 строки.

//Sample using LiquidCrystal library
#include <LiquidCrystal.h>

/*

Красный пин
Белый минус

*/


/*******************************************************

This program will test the LCD panel and the buttons
Mark Bramwell, July 2010

1.
try connect to pc
if ok - sync date time


********************************************************/

// select the pins used on the LCD panel
// 4 5 6 7 8 9
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int Watts = 0;
int temp_1_int = 0;
double temp_1_old = 0.0;
unsigned long temp_1_millis = 100000;

int temp_2_int = 0;
double temp_2_old = 0.0;
unsigned long temp_2_millis = 100000;

//const int pin_kw = 5;
//const int pin_sound = 5;
const int pin_test = 2;  //
const int pin_heater = 13;  //
const int pin_light = 12; //
const int pin_backlight = 10; //

//const int SoundPin = ;   // белый Пин подключения пьезоизлучателя – ШИМ

byte BB0[8] =
{
  B11111,
  B10001,
  B10001,
  B10001,
  B10001,
  B10001,
  B10001,
  B11111
};

byte BB1[8] =
{
  B00000,
  B00000,
  B00000,
  B00100,
  B01110,
  B10101,
  B00100,
  B00100
};

byte BB2[8] =
{
  B00000,
  B00000,
  B00000,
  B00100,
  B00100,
  B10101,
  B01110,
  B00100
};

byte BB3[8] =
{
  B11111,
  B10001,
  B10001,
  B10001,
  B11111,
  B11111,
  B11111,
  B11111
};

byte BB4[8] =
{
  B11111,
  B10111,
  B10111,
  B10111,
  B10111,
  B10111,
  B10001,
  B11111
};

byte BB5[8] =
{
  B11111,
  B11001,
  B10111,
  B10111,
  B10111,
  B10111,
  B11001,
  B11111
};

byte BB6[8] =
{
  B11111,
  B10001,
  B11011,
  B11011,
  B11011,
  B11011,
  B11011,
  B11111
};

byte BB7[8] =
{
  B11111,
  B11001,
  B10111,
  B11011,
  B11101,
  B11101,
  B10011,
  B11111
};

byte BB8[8] =
{
  B11111,
  B11001,
  B10111,
  B10111,
  B10111,
  B10111,
  B11001,
  B11111
};


int DelaySound = 1000; // Пауза 1 секунда

int cur_pos = 0;

// текущий экран
int cur_scr = 0; // Главный
int max_scr = 3; // Последний экран


// define some values used by the panel and buttons
int lcd_key     = 0;
int lcd_key1     = 0;
int old_lcd_key     = 1;
int adc_key_in  = 0;

int show_points = 0;
unsigned long time;

unsigned long time_total;
unsigned long time_begin;
unsigned long time_end;

unsigned long time_on;
unsigned long cur_time;

unsigned long time_on_1;
int time_flag = 0;
unsigned long time_off;

unsigned long cur_sec = 0;
unsigned long cur_min = 0;
unsigned long cur_hrs = 0;

unsigned long set_sec = 0;
unsigned long set_min = 0;
unsigned long set_hrs = 0;

unsigned long kw_total = 0;
unsigned long kw_1 = 800;
unsigned long kw_2 = 8;


int incomingByte = 0;


char rxstr[30];
char rxcmd[30];
int rxlen = 0;
int i = 0;

#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// Датчики темпреатуры

int TempPin = 2;
int temp_src = 0;
double temp_1 = 0.0;

int TempPin2 = 3;
int temp_src2 = 0;
double temp_2 = 0.0;
double temp_2_on = 7.65;
double temp_2_off = 7.9;
int temp_2_switch = 0;
int TempPin3 = 4;
int temp_src3 = 0;
double temp_3 = 0.0;

int LuxPin = 5;
int lux_src = 0;
int lux_day = 200;
int lux_on = 0;


char str0[16];
char str1[16];

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor
  // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 195)  return btnUP;
  if (adc_key_in < 380)  return btnDOWN;
  if (adc_key_in < 555)  return btnLEFT;
  if (adc_key_in < 790)  return btnSELECT;
  return btnNONE;  // when all others fail, return this...
}
// создаем метод для перевода показаний сенсора в градусы Цельсия

double analog_pin(int pin)
{
  int i;
  int max = 20;
  unsigned long term = 0;
  // Измеряем 10 раз
  for (i = 0; i < max; i++)
  {
    term = term + analogRead(pin);
  }
  term = term / max;
  return term;
}

double Getterm(int RawADC) {
  double temp;
  temp = log(((10240000 / RawADC) - 10000));
  temp = 1 / (0.001129148 + (0.000234125 * temp) + (0.0000000876741 * temp * temp * temp));
  temp = temp - 273.15;
  return temp;
}


void testfade()
{

  //С помощью функции analogWrite подаем на порт напряжение от 0 до 5в.
  //В качестве первого аргумента номер пина, в качестве второго число от 0 до 255
  //В качестве примера будем подавать значение от 0 до 255 и наблюдать плавное увеличение яркости
  for (int i = 0; i <= 255; i++) {
    analogWrite(pin_light, i);
    lcd.setCursor(0, 0);
    lcd.print(i);
    lcd.print("   ");
    //Задержка для более плавного эффекта свечения
    delay(30);
  }
  //затухания светодиода
  for (int i = 255; i >= 0; i--) {
    analogWrite(pin_light, i);
    lcd.setCursor(0, 0);
    lcd.print(i);
    lcd.print("   ");
    //Задержка для более плавного эффекта потухания
    delay(30);
  }

  //Выставляем паузу 0.5с
  delay(500);
}

/*
void alarm()
{
  int i;
  for (i = 0; i < 200; i++)
  {
    tone(pin_sound, 4000);  // Воспроизводим сигнал с частотой 1915 Гц
    delay(10);  // Пауза 1 секунда (1000 миллисекунд – значение переменной DelaySound ) – длительность воспроизведения сигнала
    noTone(pin_sound); // Выключаем звук
    delay(100);  // Пауза 1 секунда (1000 миллисекунд – значение переменной DelaySound ) – длительность воспроизведения сигнала
  }
}

*/


// Измеряем частоту по прерыванию

volatile int hz_count = 0;
volatile long int cur_micros = 0;
volatile long int cur_micros_1 = 0;
volatile long int micros_prev = 0;
volatile double Hz_new = 0.0;
volatile double Hz = 0.0;
void MAP () {

  if (digitalRead(pin_test) == LOW)
  {
    cur_micros_1 = micros();

    if (((cur_micros_1 - micros_prev) > 100000) && ((cur_micros_1 - micros_prev) < 1000000000))
    {
      cur_micros = cur_micros_1;

      Hz = (1000000000.0 / (cur_micros - micros_prev));
      Hz = Hz / 1.33333333333;

      Hz_new = Hz;
      hz_count++;
      micros_prev = cur_micros;
    }
  }
}


void setup()
{
  pinMode(pin_test, INPUT_PULLUP);
  //  digitalWrite(pin_test, LOW);

  attachInterrupt(0, MAP, FALLING);


  lcd.begin(16, 2);              // start the library
  pinMode(pin_heater, OUTPUT);
  pinMode(pin_light, OUTPUT);
  digitalWrite(pin_heater, LOW);
  //  digitalWrite(pin_light, LOW);
  Serial.begin(9600);

  lcd.createChar(1, BB0);
  lcd.createChar(2, BB1);
  lcd.createChar(3, BB2);
  lcd.createChar(4, BB3);
  lcd.createChar(5, BB4);
  lcd.createChar(6, BB5);
  lcd.createChar(7, BB6);
  lcd.createChar(8, BB7);

  lcd.clear();
  cur_scr = 0;

}

void loop()
{
  
    cur_micros_1 = micros();
    if ((cur_micros_1 - micros_prev) > 10000000)
    {
      Hz_new=0;
    }

   Watts=Hz_new;

  lcd_key = read_LCD_buttons();  // read the buttons


  if (cur_scr > max_scr) cur_scr = 0;
  /*
    while (Serial.available() > 0)
    {
      incomingByte = Serial.read();
      if ((incomingByte == 10) && (rxlen > 2))
      {
        rxstr[rxlen] = incomingByte;
        Serial.print("RX: ");
        for (i = 0; i <= rxlen; i++) Serial.print(rxstr[i]);
        if (rxstr[0] == 35)
        {
          if (rxstr[1] == 84) // T
          {
            if (rxstr[4] == 58)
            { set_hrs = rxstr[3] - 48;
              i = 4;
            }
            else
            { set_hrs = (rxstr[3] - 48) * 10 + (rxstr[4] - 48);
              i = 5;
            }
            set_min = (rxstr[i + 1] - 48) * 10 + (rxstr[i + 2] - 48);
            set_sec = (rxstr[i + 4] - 48) * 10 + (rxstr[i + 5] - 48);
          }
        }

        rxlen = 0;
      }
      else
      {
        rxstr[rxlen] = incomingByte;
        rxlen++;
      }
    }
  */


  time_on = 20600; // 6:00
  time_off = 79200; // 22:00

  cur_time = set_hrs * 60 * 60 + set_min * 60 + set_sec;

  time = millis() / 1008; // 1009 - корректировка того что часики убегают

  time = time % 86400;
  time = cur_time + time;

  cur_hrs = ((time / 60 / 60) % 24);
  cur_min = ((time / 60) % 60);

  temp_src = analog_pin(TempPin);
  temp_src2 = analog_pin(TempPin2);
  temp_src3 = analog_pin(TempPin3);

  temp_1 = Getterm(temp_src);
  temp_2 = Getterm(temp_src2);
  temp_3 = Getterm(temp_src3);

  if (temp_2 < temp_2_on)
  {
    temp_2_switch = 1;
    if (time_flag == 0)
    {
      time_on_1 = millis() / 1009; // 1009 - корректировка того что часики убегают
      time_begin = millis() / 1009; // 1009 - корректировка того что часики убегают
      time_flag = 1;
    }
  }
  if (temp_2 >= temp_2_off)
  {
    if (time_flag == 1)
    {
      time_end = millis() / 1009; // 1009 - корректировка того что часики убегают
      time_total = time_total + (time_end - time_begin);
      time_flag = 0;
    }
    temp_2_switch = 0;
  }


  lux_src = analog_pin(LuxPin);    // Датчик освещенности
  if (lux_src > lux_day)
  {
    analogWrite(pin_backlight, 255);
  }
  else
  {
    analogWrite(pin_backlight, 30);
  }


  if ((time >= time_on) && (time < time_off) && (lux_src < lux_day))
  {
    // Если в промежутке времени и недостаточно света - включить свет
    lux_on = 1;
    digitalWrite(pin_light, HIGH);
  } else
  {
    lux_on = 0;
    digitalWrite(pin_light, LOW);
  }

  if (temp_2_switch == 1)
  {
    digitalWrite(pin_heater, HIGH);
  } else
  {
    digitalWrite(pin_heater, LOW);
  }

  // Вывод датчиков в COM-порт

  while (Serial.available() > 0)
  {
    incomingByte = Serial.read();
    if ((incomingByte == 10) && (rxlen > 2))
    {
      rxstr[rxlen] = incomingByte;
      Serial.print(cur_hrs, DEC);
      Serial.print(":");
      Serial.print(cur_min, DEC);
      Serial.write(9);
      Serial.print(temp_1, DEC);
      Serial.write(9);
      Serial.print(temp_2, DEC);
      Serial.write(9);
      Serial.print(temp_3, DEC);
      Serial.write(9);
      Serial.print(temp_2_switch, DEC);
      Serial.write(9);
      Serial.println("");

      rxlen = 0;
    }
    else
    {
      rxstr[rxlen] = incomingByte;
      rxlen++;
    }
  }

  Serial.print(Hz_new, DEC);
  Serial.println("");


  /*
        Serial.print(cur_hrs,DEC);
        Serial.print(":");
        Serial.print(cur_min,DEC);
        Serial.write(9);
        Serial.print(temp_1,DEC);
        Serial.write(9);
        Serial.print(temp_2,DEC);
        Serial.write(9);
        Serial.print(temp_3,DEC);
        Serial.write(9);
        Serial.print(temp_2_switch,DEC);
        Serial.write(9);
        Serial.println("");
  */

  lcd.clear();

  if (cur_scr == 0)
  {
    lcd.setCursor(0, 0);
    if (cur_hrs < 10) lcd.print("0");
    lcd.print(cur_hrs);

    if (show_points == 0)
    {
      lcd.print(" ");
      show_points = 1;
    }
    else
    {
      lcd.print(":");
      show_points = 0;
    }

    if (cur_min < 10) lcd.print("0");
    lcd.print(cur_min);

    lcd.print(" ");

    if ((time >= time_on) && (time < time_off))
    {
      lcd.write(6);
    }
    else
    {
      lcd.write(1);
    }

    if (lux_src >= lux_day)
    {
      lcd.write(8);
    }
    else
    {
      lcd.write(1);
    }

    if (lux_on == 1)
    {
      lcd.write(5);
    }
    else
    {
      lcd.write(1);
    }

    lcd.write(1);

    if (temp_2_switch == 1)
    {
      lcd.write(7);
    }
    else
    {
      lcd.write(1);
    }


    // Время работы обогревателя в минутах
    lcd.print(" ");
//    lcd.print(time_total / 60); //
    lcd.print(Watts);

    lcd.setCursor(0, 1);
    temp_1_int = temp_1 * 10;
    //    if(temp_1_int>0) lcd.print(" ");
    lcd.print(temp_1_int / 10);

    if (temp_1 > temp_1_old + 0.1)
    {
      temp_1_millis = millis();
      temp_1_old = temp_1;
      lcd.write(2);
    }
    else if (temp_1 < temp_1_old - 0.1)
    {
      temp_1_millis = millis();
      temp_1_old = temp_1;
      lcd.write(3);
    }
    else
    {
      lcd.print(".");
    }
    if (temp_1_millis + 10000 > millis())
    {
      temp_1_millis = millis();
      temp_1_old = temp_1;
    }
    lcd.print(temp_1_int % 10);

    //lcd.print(temp_1, 1);

    lcd.setCursor(6, 1);
    if (temp_1 > 0) lcd.print(" ");
    lcd.print(temp_2, 1);

    lcd.setCursor(11, 1);
    if (temp_1 > 0) lcd.print(" ");
    lcd.print(temp_3, 1);

    //  lcd.setCursor(13, 1);
    //  lcd.print(lux_src,DEC);
    switch (lcd_key)               // depending on which button was pushed, we perform an action
    {
      case btnRIGHT:
        {
          if (cur_scr == 0)
          {
            cur_scr++;
            if (cur_scr > max_scr) cur_scr = 0;
          }
          break;
        }
      case btnLEFT:
        {
          if (cur_scr == 0)
          {
            cur_scr--;
            if (cur_scr < 0) cur_scr = max_scr;
          }
          break;
        }
      case btnUP:
        {
          break;
        }
      case btnDOWN:
        {
          break;
        }
      case btnSELECT:
        {
          //testfade();
          cur_scr++;
          break;
        }
      case btnNONE:
        {
          break;
        }
    }

  }


  // Настройка часов

  else if (cur_scr == 1)
  {
    lcd.setCursor(0, 0);
    if (cur_hrs < 10) lcd.print("0");
    lcd.print(cur_hrs);

    if (show_points == 0)
    {
      lcd.print(" ");
      show_points = 1;
    }
    else
    {
      lcd.print(":");
      show_points = 0;
    }

    if (cur_min < 10) lcd.print("0");
    lcd.print(cur_min);

    if (cur_pos == 0) lcd.setCursor(0, 1);
    if (cur_pos == 1) lcd.setCursor(1, 1);
    if (cur_pos == 2) lcd.setCursor(3, 1);
    if (cur_pos == 3) lcd.setCursor(4, 1);

    lcd.print("-");

    switch (lcd_key)               // depending on which button was pushed, we perform an action
    {
      case btnRIGHT:
        {
          cur_pos++;
          if (cur_pos > 3) cur_pos = 0;
          break;
        }
      case btnLEFT:
        {
          cur_pos--;
          if (cur_pos < 0) cur_pos = 3;
          break;
        }
      case btnUP:
        {
          if (cur_pos == 0)
          {
            if (set_hrs < 14) set_hrs = set_hrs + 10;
          }
          if (cur_pos == 1)
          {
            if (set_hrs < 23) set_hrs = set_hrs + 1;
          }
          if (cur_pos == 2)
          {
            if (set_min < 50) set_min = set_min + 10;
          }
          if (cur_pos == 3)
          {
            if (set_min < 59) set_min = set_min + 1;
          }
          break;
        }
      case btnDOWN:
        {
          if (cur_pos == 0)
          {
            if (set_hrs > 9) set_hrs = set_hrs - 10;
          }
          if (cur_pos == 1)
          {
            if (set_hrs > 0) set_hrs = set_hrs - 1;
          }
          if (cur_pos == 2)
          {
            if (set_min > 9) set_min = set_min - 10;
          }
          if (cur_pos == 3)
          {
            if (set_min > 0) set_min = set_min - 1;
          }
          break;
        }
      case btnSELECT:
        {
          cur_scr++;
          break;
        }
      case btnNONE:
        {
          break;
        }
    }
  }

  // Порог освещенности

  else if (cur_scr == 2)
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(lux_src, DEC);
    lcd.setCursor(0, 1);
    lcd.print(lux_day, DEC);
    lcd.setCursor(10, 0);
    lcd.print(Watts, DEC);
    lcd.setCursor(10, 1);
    lcd.print(hz_count);


    switch (lcd_key)               // depending on which button was pushed, we perform an action
    {
      case btnUP:
        {
          if (lux_day < 1000) lux_day++;
          break;
        }
      case btnDOWN:
        {
          if (lux_day > 0) lux_day--;
          break;
        }
      case btnSELECT:
        {
          cur_scr++;
          break;
        }
    }
  }


  else if (cur_scr == 3)
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(time_total, DEC);

    switch (lcd_key)               // depending on which button was pushed, we perform an action
    {
      case btnSELECT:
        {
          cur_scr = 0;
          break;
        }
    }
  }
  delay(500);

}