Прерывания, му

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

Добрый день! Пилю девайс, который должен каждые полчаса включать реле на 10 минут. При этом он ещё и пишет в лог данные с датчиков каждые 5 минут.

Вопрос вот какой - как правильно реализовать регулярное включение каждые полчаса на 10 минут? Есть RTC подключенное, может через него как-то ещё можно? Прочитал ряд статей с использованием millis(), но одну потерял, там использовалась библиотека Thread, может кто видел - поделится линком? Там похожее организовывалось.

Спасибо!

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Здесь на форуме dimax предложил очень хороший код часов. Так вот на его основе можно реализовать посуточное Вк/Вык чего завгодно и в любое время. В Вшем случае это будет вот так

volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

byte op_dat;//Переменная для опроса датчиков
byte rele;// Переменная ВК/Вык реле

void setup(){
Serial.begin(9600);
TCCR1A=(1<<WGM11); //режим14 FAST PWM 
TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
TIMSK1=(1<<TOIE1); //разрешить прерывание
}

ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду
if (sec>59){
sec=0; 
minut++; 
op_dat++; 
rele++;
}
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop(){
if (op_dat>=5)
{
 op_dat=0;
 // Здесь опрашуем датчики каждые 5 минут 
}
if (rele>=30)
{
  rele = 0;
  //Здесь включаем РЕЛЕ на 10 минут
}
if (rele==10)
{
  // Здесь выключаем Реле через 10 минут
}

}

 

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

Добрый день! запустил скетч, но честно говоря не работает. 

volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

byte op_dat;//Переменная для опроса датчиков
byte rele;// Переменная ВК/Вык реле

void setup(){
Serial.begin(9600);
TCCR1A=(1<<WGM11); //режим14 FAST PWM 
TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
TIMSK1=(1<<TOIE1); //разрешить прерывание
}

ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду
if (sec>59){
sec=0; 
minut++; 
op_dat++; 
rele++;
}
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop(){
if (op_dat>=5)
{
 op_dat=0;
 // Здесь опрашуем датчики каждые 5 минут 
}
if (rele>=5)
{
  rele = 0;
 digitalWrite(3, 0);
 Serial.println("rele on");
}
if (rele==1)
{
 digitalWrite(3, 1);
 Serial.println("rele run and off");
}

}

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

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014

Проверил в симуляторе все работает, только задержки выставил на секунды через 5 вк. через 1 вык. для проверки а Вы себе поставте как надо 

volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

byte op_dat;//Переменная для опроса датчиков
byte rele;// Переменная ВК/Вык реле
bool f_rele = 0;
#define LEDpin  3 

void setup(){
pinMode(LEDpin, OUTPUT);
Serial.begin(9600);
TCCR1A=(1<<WGM11); //режим14 FAST PWM 
TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
TIMSK1=(1<<TOIE1); //разрешить прерывание
}

ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду

rele++;
if (sec>59){
sec=0; 
minut++; 
op_dat++; 
}
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop(){
if (op_dat>=5)
{
 op_dat=0;
 // Здесь опрашуем датчики каждые 5 минут 
}
if (rele>=5)
{
  rele = 0;
  f_rele = 1;
  digitalWrite(LEDpin, 1);
  Serial.println("rele on");

  //Здесь включаем РЕЛЕ на 10 минут
}
if (rele==1 && f_rele==1)
{
    f_rele = 0;
   digitalWrite(LEDpin, 0);
    Serial.println("rele run and off");
  // Здесь выключаем Реле через 10 минут
}

}

 

Logik
Offline
Зарегистрирован: 05.08.2014

Зачем Вы в преравания полезли? Это вещи не того масштаба, как Ваша задача. Про RTC - забыть, у Вас же нет требования произвести действие в заданное время. Про Thread тоже забыть, если вспомните где читали - напишите сюда шоб другие туда случайно не зашли. 

Читать стати про millis() до просветления, чередовать с чтением тем про применение millis() для отсчета промежутков с этого форума. Их тут легион.

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

В общем всё равно не получается :(

#include <DHT.h>

#include <BH1750.h>

#include <DallasTemperature.h>

#include <OneWire.h>

#include <RTC.h>
#include <SD.h>
#include <SPI.h>
#include <Wire.h>

DHT    sensor;
int    result;

BH1750 lightMeter;

RTC    time;
//relay section
#define RELAY_ON 0
#define RELAY_OFF 1
//
#define PUMP_1 3 // Arduino Digital I/O pin number
#define PUMP_2 4
#define LIGHT 5
#define Relay_4 6
//Thread logThread = Thread(); // создаём поток управления логом
//Thread pumpThread = Thread(); // создаём поток управления поливом
#define ONE_WIRE_BUS 10 // номер пина к которому подключен DS18B20
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

volatile uint8_t minut=0;
volatile uint8_t chas=0;
volatile uint8_t sec=0;

byte op_dat;//Переменная для опроса датчиков
byte rele;// Переменная ВК/Вык реле
bool f_rele = 0;

void setup(){
pinMode(53, OUTPUT);
  lightMeter.begin();
Serial.begin(9600);
SD.begin(53);
    delay(1000);

time.begin(RTC_DS1307);
Serial.println("pump checking start");
    pinMode(PUMP_1, OUTPUT); 
delay(1000);
pinMode(PUMP_2, OUTPUT); 
delay(1000);
pinMode(LIGHT, OUTPUT); 
delay(1000);
pinMode(Relay_4, OUTPUT); 
delay(1000);

digitalWrite(PUMP_1, RELAY_OFF);
delay(1000);
digitalWrite(PUMP_2, RELAY_OFF);
delay(1000);
digitalWrite(LIGHT, RELAY_OFF);
delay(1000);
digitalWrite(Relay_4, RELAY_OFF);
//
////---( THEN set pins as outputs )---- 
Serial.println("pump checking complete");
//pinMode(Relay_4, OUTPUT); 
delay(4000); //Check that all relays are inactive at Reset



//    logThread.onRun(logging);  // назначаем потоку задачу
//    logThread.setInterval(1000); // задаём интервал срабатывания, мсек
//    
//    pumpThread.onRun(pump);     // назначаем потоку задачу
//    pumpThread.setInterval(20); // задаём интервал срабатывания, м
Serial.println("timer setup start");
sensors.begin();
TCCR1A=(1<<WGM11); //режим14 FAST PWM 
TCCR1B=(1<<CS12)|(1<<WGM13)|(1<<WGM12); //делить частоту CPU на 256
ICR1=62499;  // (16000000MHz /div256) -1 = 1 раз в секунду
TIMSK1=(1<<TOIE1); //разрешить прерывание
Serial.println("timer setup complete");
}

ISR (TIMER1_OVF_vect) { 
sec++ ; //инкремент переменной каждую секунду
Serial.println(sec);
rele++;
if (sec>59){
sec=0; 
minut++; 
op_dat++; 
}
if (minut>59){minut=0; chas++; }
if (chas>23){chas=0;}
}

void loop(){

if (op_dat>=3)
{
  Serial.println("sensor read start");
 
   sensors.requestTemperatures();
  Serial.println(String(sensors.getTempCByIndex(0) , 1));
  String dataString = "";
    result = sensor.read(2); // нужно указать № вывода (сейчас 2pin)
    
    uint16_t lux = lightMeter.readLightLevel();
dataString = ";"+String(sensor.tem)+";"+String(sensor.hum)+";"+String(lux);
Serial.print(time.gettime("d-m-Y, H:i:s"));

File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  } // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
  op_dat=0;
  
}
if (rele>=24)
{
  rele = 0;
  f_rele = 1;
  Serial.println("rele on");
digitalWrite(PUMP_1, RELAY_ON);

}
if (rele==1 && f_rele==1)
{
    f_rele = 0;
   digitalWrite(PUMP_1, RELAY_OFF);
    Serial.println("rele runned and off");
  // Здесь выключаем Реле через 10 минут
}
//if (lux <= 150 && time.Hours > 9 && time.Hours < 22 ) 
//{ digitalWrite(LIGHT, RELAY_ON);} 
//else {digitalWrite(LIGHT, RELAY_OFF);}
}

Срабатывает каждые 24 секунды и через секунду отключается...

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

Вроде с реле разобрадся, а вот опрос датчиков не срабатывает...

vosara
vosara аватар
Offline
Зарегистрирован: 08.02.2014
Я Вам писал что поставил ускореный вариант для проверки, а Вы поставте так как вам нужно, но Вы все так и оставили поэтому и срабатует не через 24 минуты а через 24 сек.
Для отработки минут переместите строчку 092 - rele++;
между строчками 094 и 095
А также строчку 138 - if (rele==1 && f_rele==1) замените на if (rele==10 && f_rele==1)
 

 

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

Да-да-да, разобрался, в том числе и с опросом датчиков, спасибо!

Pahom-ka
Offline
Зарегистрирован: 01.12.2014

Апну тему (( переделал под RTC, но блин, оно не включается в нужное время ((( почему так? Модуль рабочий, батарейку поменял, после вкл-выкл не сбрасывает время тоже. Но не срабатывает(( Вот листинг (что-то закоментировано, это под дальнейшее развитие):


#include <DallasTemperature.h>

#include <OneWire.h>

#include <BH1750.h>
#include <RTC.h>
#include <SD.h>
#include <SPI.h>
#include <DHT.h>
#include <Wire.h>

DHT    sensor;
int    result;

BH1750 lightMeter;

RTC    time;
//relay section
#define RELAY_ON 0
#define RELAY_OFF 1
//
#define PUMP_1 3 // Arduino Digital I/O pin number
#define PUMP_2 4
#define LIGHT 5
#define Relay_4 6

#define ONE_WIRE_BUS 10 // номер пина к которому подключен DS18B20
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
volatile uint8_t minut = 0;
volatile uint8_t sec = 0;
byte op_dat;//Переменная для опроса датчиков
void setup() {
  pinMode(53, OUTPUT);
  lightMeter.begin();
  Serial.begin(9600);
  SD.begin(53);
  delay(1000);

  time.begin(RTC_DS1307);
  //time.settime(0,49,16,18,06,16,5);  // 0  сек, 17 мин, 15 час, 1, октября, 2015 года, четверг
  Serial.println(time.gettime("d.m.Y H:i"));
  pinMode(PUMP_1, OUTPUT);
  delay(1000);
  pinMode(PUMP_2, OUTPUT);
  delay(1000);
  pinMode(LIGHT, OUTPUT);
  delay(1000);
  pinMode(Relay_4, OUTPUT);
  delay(1000);

  digitalWrite(PUMP_1, RELAY_OFF);
  delay(1000);
  digitalWrite(PUMP_2, RELAY_OFF);
  delay(1000);
  digitalWrite(LIGHT, RELAY_OFF);
  delay(1000);
  digitalWrite(Relay_4, RELAY_OFF);
  //
  ////---( THEN set pins as outputs )----

  //pinMode(Relay_4, OUTPUT);
  delay(4000); //Check that all relays are inactive at Reset
  TCCR1A = (1 << WGM11); //режим14 FAST PWM
  TCCR1B = (1 << CS12) | (1 << WGM13) | (1 << WGM12); //делить частоту CPU на 256
  ICR1 = 62499; // (16000000MHz /div256) -1 = 1 раз в секунду
  TIMSK1 = (1 << TOIE1); //разрешить прерывание
  Serial.println("timer setup complete");
}

ISR (TIMER1_OVF_vect) {
  sec++ ; //инкремент переменной каждую секунду


  if (sec > 59) {
    sec = 0;
    minut++;
    op_dat++;
  }
  if (minut > 59) {
    minut = 0;
  }
}

void loop() {

  if (op_dat >= 5)
  {
    Serial.println("sensor read start");

    //sensors.requestTemperatures();
    // Serial.println(String(sensors.getTempCByIndex(0) , 1));
    String dataString = "";
    // result = sensor.read(2); // нужно указать № вывода (сейчас 2pin)

    uint16_t lux = lightMeter.readLightLevel();
    dataString = String(time.gettime("d.m.Y H:i")) + ";" + String(sensor.tem) + ";" + String(sensor.hum) + ";" + String(lux);


    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    if (dataFile) {
      dataFile.println(dataString);
      dataFile.close();
      // print to the serial port too:
      Serial.println(dataString);
    } // if the file isn't open, pop up an error:
    else {
      Serial.println("error opening datalog.txt");
    }
    op_dat = 0;

  }
  //  if (sensor.tem >= 25) { digitalWrite(PUMP_1, RELAY_ON);} else if (sensor.tem < 23) {digitalWrite(PUMP_1, RELAY_OFF);} //тест реле на температуру
  // // if (lux >= 150) { digitalWrite(LIGHT, RELAY_ON);} else {digitalWrite(LIGHT, RELAY_OFF);}
  //  //включение света в нужное время при отсутствии достаточной освещённости и при времени с 8 до 20 (работает)!
  //   if (lux <= 150 && time.Hours > 9 && time.Hours < 22 )

  if (time.Hours == 9 && time.minutes == 00 || time.Hours == 12 && time.minutes == 45 || time.Hours == 17 && time.minutes == 25 || time.Hours == 20 && time.minutes == 00) {
    digitalWrite(PUMP_1, RELAY_ON);
    Serial.println("rele on");

  }
  if (time.Hours == 9 && time.minutes == 15 || time.Hours == 13 && time.minutes == 00 || time.Hours == 17 && time.minutes == 40 || time.Hours == 20 && time.minutes == 15) {
    digitalWrite(PUMP_1, RELAY_OFF);
    Serial.println("rele off");
  }
  //Serial.println(time.gettime("d-m-Y, H:i:s, D"));
}