2015-04-18 3 views
6

Я написал этот код для отправки SMS, если вход HIGH, как вы можете видеть в нем, но проблема в том, что у меня есть 4 входа и delay() s являются фатальными и очень неправильными, если мне нужно одновременно выполнять несколько отдельных операций (я использую 4 входа).таймер записи без задержки()

Поэтому мне нужно изменить delay() с помощью millis() или что-то еще в void loop(), Send_SMS() и initia().

Может кто-то мне помочь, и спасибо заранее.

const int DI = 2; 
const int DT = 3; 
const int DGP1 = 4; 
const int DGP2 = 5; 

int value1_old = 0; 
int value2_old = 0; 
int value3_old = 0; 
int value4_old = 0; 

unsigned long previousMillis = 0; 
unsigned long interval=100; 

#include<SoftwareSerial.h> 
SoftwareSerial SIM900 (7, 8); 

void setup() { 
pinMode(DI, INPUT); 
pinMode(DT, INPUT); 
pinMode(DGP1, INPUT); 
pinMode(DGP2, INPUT); 

SIM900.begin(19200); 
SIM900power(); 
delay(20000); 

} 

void SIM900power(){ 
    digitalWrite(9 ,HIGH); 
    delay(1000); 
    digitalWrite(9 ,LOW); 
    delay(5000); 
} 

void initia(){ 
    SIM900.print("AT+CMGF=1\r"); 
    delay(100); 
    SIM900.println("AT + CMGS = \"+212xxxxxxx\""); 
    delay(100); 
} 

void Send_SMS(){ 
    SIM900.println((char)26); 
    delay(100); 
    SIM900.println(); 
    delay(100); 
    SIM900power(); 
} 

void loop() { 
    int value1 = digitalRead (DI); 
    int value2 = digitalRead (DT); 
    int value3 = digitalRead (DGP1); 
    int value4 = digitalRead (DGP2); 

    if (value2 != value2_old && value2 == HIGH) { 
    initia(); 
    SIM900.println("Station 85: Defaut electrique"); 
    delay(100); 
    Send_SMS(); 
    value2_old = value2; 
    } 

    if (value3 != value3_old && value3 == HIGH) 
    { 
    initia(); 
    SIM900.println("Station 85: DefautGP1"); 
    delay(100); 
    Send_SMS(); 
    value3_old = value3; 
} 

if (value4 != value4_old && value4 == HIGH) 
{ 
    initia(); 
    SIM900.println("Station 85:DD>1000");  
    delay(100); 
    Send_SMS(); 
    value4_old = value4; 
} 
value2_old = value2; 
value3_old = value3; 
value4_old = value4; 

}

+0

ли вы сказать, что с помощью задержки вы тратите циклов ожидания на вещи, а не делать больше других потенциальных (время критических) задач? Если это так, я думаю, вам нужно посмотреть на использование прерываний (для выполнения критически важной задачи в ISR) или использования аппаратного таймера, присутствующего на самом AVR. – initramfs

+1

Вместо этого используйте функцию millis(). Пример учебника [здесь] (http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay). –

+0

Я думаю, что мне нужно использовать millis() вместо задержки, но я не знаю, как, потому что я новичок:/ –

ответ

-1

Функция millis() потерпит неудачу, когда значение переполнения. Как сказал @CPU_Terminator, используйте прерывания. Для этого существуют полезные библиотеки Arduino, например Timer1.

EDIT. Предполагая, что вы хотите отправить SMS каждые 100 мс, если некоторые из ваших входов изменились, вы можете использовать такой код (я удалил некоторые задержки, которые мне не кажутся необходимыми, добавьте их снова, если я ошибаюсь) :

#include <SoftwareSerial.h> 
#include "TimerOne.h" 

const int DI = 2; 
const int DT = 3; 
const int DGP1 = 4; 
const int DGP2 = 5; 
const long interval = 100000; // in microseconds 

int value1 = 0; 
int value2 = 0; 
int value3 = 0; 
int value4 = 0; 
int value1_old = 0; 
int value2_old = 0; 
int value3_old = 0; 
int value4_old = 0; 
boolean changed1 = false; 
boolean changed2 = false; 
boolean changed3 = false; 
boolean changed4 = false; 

SoftwareSerial SIM900 (7, 8); 

void SIM900power(){ 
    digitalWrite(9, HIGH); 
    delay(1000); 
    digitalWrite(9, LOW); 
    delay(5000); 
} 

void initia(){ 
    SIM900.print("AT+CMGF=1\r"); 
    SIM900.println("AT + CMGS = \"+212xxxxxxx\""); 
} 

void Send_SMS(){ 
    SIM900.println((char)26); 
    SIM900.println(); 
    delay(20); 
    SIM900power(); 
} 

void isr_timer(){ 
    if (changed2) { 
    initia(); 
    SIM900.println("Station 85: Defaut electrique"); 
    Send_SMS(); 
    changed2 = false; 
    } 

    if (changed3) { 
    initia(); 
    SIM900.println("Station 85: DefautGP1"); 
    Send_SMS(); 
    changed3 = false; 
    } 

    if (changed4) { 
    initia(); 
    SIM900.println("Station 85:DD>1000"); 
    Send_SMS(); 
    changed4 = false; 
    } 
} 

void setup() { 
    pinMode(DI, INPUT); 
    pinMode(DT, INPUT); 
    pinMode(DGP1, INPUT); 
    pinMode(DGP2, INPUT); 

    SIM900.begin(19200); 
    SIM900power(); 
    delay(20000); 
    Timer1.initialize(interval); 
    Timer1.attachInterrupt(isr_timer); 
} 

void loop() { 
    value1 = digitalRead (DI); 
    value2 = digitalRead (DT); 
    value3 = digitalRead (DGP1); 
    value4 = digitalRead (DGP2); 

    if (value1 != value1_old && value1 == HIGH) changed1 = true; 
    if (value2 != value2_old && value2 == HIGH) changed2 = true; 
    if (value3 != value3_old && value3 == HIGH) changed3 = true; 
    if (value4 != value4_old && value4 == HIGH) changed4 = true; 

    value1_old = value1; 
    value2_old = value2; 
    value3_old = value3; 
    value4_old = value4; 

    // Here the rest of your code 
} 

Таким образом, функция isr_timer() будет выполняться каждые 0,1 секунды.

+0

Отлично! Я получил -1, и никто не говорит, почему. – mclopez

+0

спасибо, можете ли вы привести пример в моем коде? ^^ –

+0

Там у вас есть, надеюсь, это полезно. Если это ответ, который вы ожидали, примите его и произнесите, пожалуйста, пожалуйста :) – mclopez

0

Вы можете попробовать использовать код в isr_timer функции():

if (changed2) { 
    initia(); 
    SIM900.println("Station 85: Defaut electrique"); 
    delay(100); 
    Send_SMS(); 
    changed2 = false; 
} 

С наилучшими пожеланиями

0

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

По моему мнению, решение ISR не является хорошим выбором, поскольку ISR блокируют нормальное выполнение. Единственной выполнимой реализацией с использованием прерываний является запись изменения смены, а затем отправка SMS-сообщений.

Это, на мой взгляд, не является хорошим решением. Для этой проблемы я бы пошел с автоматом для отправки SMS-сообщений; поскольку у вас есть состояния, вы можете ждать перехода, выполняя другие действия, например, проверять кнопки.

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

Теперь рабочий процесс содержит семь действий, которые вы должны выполнить, каждый из которых следует ожиданию. Я пишу это здесь, так что это проще, чтобы увидеть все действия:

SIM900.print("AT+CMGF=1\r"); 
delay(100); 
SIM900.println("AT + CMGS = \"+212xxxxxxx\""); 
delay(100); 
SIM900.println("Message you want"); 
delay(100); 
SIM900.println((char)26); 
delay(100); 
SIM900.println(); 
delay(100); 
digitalWrite(9 ,HIGH); 
delay(1000); 
digitalWrite(9 ,LOW); 
delay(5000); 

Таким образом, мы имеем восемь состояний: незанятый (когда вы ждете государственной машины, чтобы начать, по имени SIM_IDLE), а затем пять «SEND» (я называю их SIM_SEND1..5) и двумя состояниями для сброса мощности (с именем SIM_POW1 и SIM_POW2). Обычно вы находитесь в режиме ожидания; когда нажата одна или несколько кнопок, вы переключаетесь на первую отправку, проезжаете через них, а затем перезагружаете питание и возвращаетесь в режим ожидания.

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

Теперь, вот код, который реализует этот:

const uint8_t DI = 2; 
const uint8_t DT = 3; 
const uint8_t DGP1 = 4; 
const uint8_t DGP2 = 5; 

const uint8_t SIMPOW = 9; 

uint8_t value1_old = 0; 
uint8_t value2_old = 0; 
uint8_t value3_old = 0; 
uint8_t value4_old = 0; 

boolean value1_changed = false; 
boolean value2_changed = false; 
boolean value3_changed = false; 
boolean value4_changed = false; 

/********************************/ 
//   SIM STATES 
#define SIM_IDLE 0 
//SEND1: SIM900.print("AT+CMGF=1\r");delay(100); 
#define SIM_SEND1 1 
//SEND2: SIM900.println("AT + CMGS = \"+212xxxxxxx\"");delay(100); 
#define SIM_SEND2 2 
//SEND3: SIM900.println("Message you want");delay(100); 
#define SIM_SEND3 3 
//SEND4: SIM900.println((char)26);delay(100); 
#define SIM_SEND4 4 
//SEND5: SIM900.println();delay(100); 
#define SIM_SEND5 5 
//POW1: digitalWrite(SIMPOW,HIGH);delay(1000); 
#define SIM_POW1 6 
//POW2: digitalWrite(SIMPOW,LOW);delay(5000); 
#define SIM_POW2 7 
/********************************/ 

unsigned long previousMillis; 
uint8_t currentSimState; 

#include<SoftwareSerial.h> 
SoftwareSerial SIM900 (7, 8); 

void setup() 
{ 
    pinMode(DI, INPUT); 
    pinMode(DT, INPUT); 
    pinMode(DGP1, INPUT); 
    pinMode(DGP2, INPUT); 
    pinMode(SIMPOW, OUTPUT); 

    SIM900.begin(19200); 

    digitalWrite(SIMPOW,HIGH); 
    delay(1000); 
    digitalWrite(SIMPOW,LOW); 
    delay(25000); 
    currentSimState = -1; // Force a state transition 
} 

void loop() 
{ 
    uint8_t value1 = digitalRead (DI); 
    uint8_t value2 = digitalRead (DT); 
    uint8_t value3 = digitalRead (DGP1); 
    uint8_t value4 = digitalRead (DGP2); 

    unsigned long currentMillis = millis(); 

    if (value2 != value2_old && value2 == HIGH) 
     value2_changed = true; 
    if (value3 != value3_old && value3 == HIGH) 
     value3_changed = true; 
    if (value4 != value4_old && value4 == HIGH) 
     value4_changed = true; 

    value1_old = value1; 
    value2_old = value2; 
    value3_old = value3; 
    value4_old = value4; 

    // Check if a state transition is needed 
    uint8_t newSimState = currentSimState; 
    switch (currentSimState) 
    { 
    case SIM_IDLE: // Start sending if a value changed 
     if ((value2_changed) || (value3_changed) || (value4_changed)) 
      newSimState = SIM_SEND1; 
     break; 
    case SIM_SEND1: // Wait 100 ms 
     if ((currentMillis - previousMillis) >= 100) 
      newSimState = SIM_SEND2; 
     break; 
    case SIM_SEND2: // Wait 100 ms 
     if ((currentMillis - previousMillis) >= 100) 
      newSimState = SIM_SEND3; 
     break; 
    case SIM_SEND3: // Wait 100 ms 
     if ((currentMillis - previousMillis) >= 100) 
      newSimState = SIM_SEND4; 
     break; 
    case SIM_SEND4: // Wait 100 ms 
     if ((currentMillis - previousMillis) >= 100) 
      newSimState = SIM_SEND5; 
     break; 
    case SIM_SEND5: // Wait 100 ms 
     if ((currentMillis - previousMillis) >= 100) 
      newSimState = SIM_POW1; 
     break; 
    case SIM_POW1: // Wait 1000 ms 
     if ((currentMillis - previousMillis) >= 1000) 
      newSimState = SIM_POW2; 
     break; 
    case SIM_POW2: // Wait 1000 ms 
     if ((currentMillis - previousMillis) >= 1000) 
      newSimState = SIM_IDLE; 
     break; 
    default: 
     newSimState = SIM_IDLE; 
     break; 
    } 

    // If there was a transition, do the appropriate action 
    if (newSimState != currentSimState) 
    { 
     case SIM_IDLE: 
      // Do nothing 
      break; 
     case SIM_SEND1: 
      SIM900.print("AT+CMGF=1\r"); 
      previousMillis = millis(); 
      break; 
     case SIM_SEND2: 
      SIM900.println("AT + CMGS = \"+212xxxxxxx\""); 
      previousMillis = millis(); 
      break; 
     case SIM_SEND3: 
      if (value2_changed) 
      { 
       SIM900.println("Station 85: Defaut electrique"); 
       value2_changed = false; 
      } 
      else if (value3_changed) 
      { 
       SIM900.println("Station 85: DefautGP1"); 
       value2_changed = false; 
      } 
      else if (value4_changed) 
      { 
       SIM900.println("Station 85:DD>1000"); 
       value2_changed = false; 
      } 
      else 
      { 
       // Should never arrive here. Just in case, you 
       // can either abort the SMS sending if you can 
       // or send another message 
      } 
      previousMillis = millis(); 
      break; 
     case SIM_SEND4: 
      SIM900.println((char)26); 
      previousMillis = millis(); 
      break; 
     case SIM_SEND5: 
      SIM900.println(); 
      previousMillis = millis(); 
      break; 
     case SIM_POW1: 
      digitalWrite(SIMPOW,HIGH); 
      previousMillis = millis(); 
      break; 
     case SIM_POW2: 
      digitalWrite(SIMPOW,LOW); 
      previousMillis = millis(); 
      break; 
     } 
    } 

    // Advance state 
    currentSimState = newSimState; 
} 

Это может показаться сложным, но это действительно очень просто. Цикл выполнен тремя «блоками».

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

Вторая часть - это проверка перехода государства. В этом операторе switch программа определяет, нужно ли изменять состояние конечного автомата. Это происходит, когда кнопка была нажата, если состояние неактивное, или если указанное количество времени прошло, если в процессе отправки SMS.

Третья часть - действие, которое должно выполняться при изменении состояния. Поэтому, если состояние изменилось, выполните действие состояния, что ничего не значит для состояния ожидания, отправьте что-то для состояний SIM_SENDx и измените контакт для состояний SIM_POWx.

Просто примечание: в настройке вы добавили задержку в 20 секунд, не присутствующую в обычном рабочем процессе. Если вы хотите удалить это, вы можете просто удалить четыре строки из настройки, выполняющей сброс, и изменить корпус default в первом коммутаторе, чтобы установить newSimState = SIM_POW1; вместо SIM_IDLE.

Там могут быть небольшие ошибки в этом коде, так как я не проверял, но он должен делать то, что вы хотели

Смежные вопросы