Duvida quanto a loops iniciados por comando via bluetooth

Bom ja havia perguntado sobre loops aqui no fórum e aprendi sobre for, while e do-while. O código que estou usando é o seguinte:

int led = 40;
int led2 = 13;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){
  
  char caracter = Serial.read();
  
  
    if(caracter == 'a'){
      
      while(1) {
      digitalWrite(led, HIGH);
      delay(75);
      digitalWrite(led, LOW);
      delay(75);
    }
      
    
    }
    if(caracter == 'd'){
      
      digitalWrite(led, LOW);
      digitalWrite(led2, LOW);
    }
    if(caracter == 'b'){
     
      digitalWrite(led2, HIGH);
      
    }
    

  delay(1000);
    }

O problema é que quero que se ao receber os caracteres 'a' e 'b' os dois funcionem, ou se só receber um só ele funcione e etc. Mas ao enviar o caracter 'a' que executa o while ele fica somente executando ele, e mesmo que envie outro caracter, como o 'b', se o while foi executado antes ele fica somente executando o while. Espero ter explicado bem.

Aquela linha que diz while(1) e o teu problema...

O outro problema e estares a programar com delays... ve o programa blink without delay na pasta dos exemplos para teres outra maneira de fazer isto.

Entendi, andei procurando, mas não conseguir de forma alguma executar o while somente enquanto não receber outro caracter. Estava a procura de como adaptar o código para que ao receber 'a' ele execute um certo while porem ao receber 'b' pare esse while e execute o while do 'b'. Tem algum método?

Ewler: Entendi, andei procurando, mas não conseguir de forma alguma executar o while somente enquanto não receber outro caracter. Estava a procura de como adaptar o código para que ao receber 'a' ele execute um certo while porem ao receber 'b' pare esse while e execute o while do 'b'. Tem algum método?

Sim, tem. Isso faz-se retirando o while! Explicando um pouco melhor, a própria função loop() já é por si só um "while" se apenas forem escolhidos certos blocos para serem executados em certas ocasiões, como a função já está a ser repetida, isso vai criar o mesmo efeito que criar um ciclo while. Sendo assim, se percebi bem o que é pretendido, apenas teria que fazer:

int led = 40;
int led2 = 13;

char caracter;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){

  if (Serial.available()) {
    caracter = Serial.read();
  }

  if(caracter == 'a'){

    digitalWrite(led, HIGH);
    delay(75);
    digitalWrite(led, LOW);
    delay(75);      

  }
  
  if(caracter == 'd'){

    digitalWrite(led, LOW);
    digitalWrite(led2, LOW);
  }
  
  if(caracter == 'b'){

    digitalWrite(led2, HIGH);

  }

  delay(1000);
}

Neste caso, o que este sketch vai fazer é: - Se for recebido um caracter, lê esse caracter e guarda-o na variável "caracter"; - Se o caracter for 'a', faz piscar muito rapidamente o led1 (eu penso que vai ser muito rápido e nem sequer se vai notar que o led está a piscar e, talvez o que se note é o led com menos brilho); - Se receber o caracter 'd', apaga os 2 led's; - Se receber o caracter 'b', liga o led 2;

Uma nota: quando são necessários vários "is's" é preferível utilizar a estrutura switch/case. Sendo assim, o programa anterior ficaria:

int led = 40;
int led2 = 13;

char caracter;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){

  if (Serial.available()) {
    caracter = Serial.read();
  }

  switch (caracter){
  case 'a':
    digitalWrite(led, HIGH);
    delay(75);
    digitalWrite(led, LOW);
    delay(75);      
    break;
  case 'd':
    digitalWrite(led, LOW);
    digitalWrite(led2, LOW);
    break;
  case 'b':
    digitalWrite(led2, HIGH);
    break;
  }

  delay(1000);
}

Atenção às 2 alterações que fiz no programa original: - defini a variável "caracter" fora da função loop(). Isto é necessário, para manter o valor guardado na variável. Caso não se usasse isto, depois de ler o valor recebido pela série e depois de executar o if correspondente o valor da variável seria destruído e na próxima vez que a função fosse executada (daí a 1 segundo) o mesmo if já não seria executado porque a variável já não conteria nenhum valor. - adicionei um if, para que apenas sejam lidos caracteres quando eles existam.

Muito boa a resposta, só tive problema ao mandar executar dois ao mesmo tempo.

Sim, 2 ao mesmo tempo não dá para fazer com este programa. Repare que só é definida uma variável "caracter", sendo assim é impossível "recordar" 2 caracteres.

Teria algum código ao qual poderia executar os dois ao mesmo tempo? No mesmo esquema.

Para que isso aconteça é necessário definir algumas coisas um pouco melhor, nomeadamente o que significa "ao receber os caracteres 'a' e 'b' os dois funcionem". Ou seja, se receber o caracter 'a' agora e o caracter 'b' daqui por uma hora, o programa deve considerar que recebeu os dois ou não? Nunca, por motivos de hardware e de como as coisas funcionam, poderá alguma vez receber dois caracteres ao mesmo tempo. Por isso das duas uma: - ou define delimitadores para a mensagem (e aí a mesma mensagem pode conter 2 ou mais caracteres); - ou define um tempo limite, para que sejam recebidos caracteres e sejam considerados "da mesma mensagem".

Como não sei qual é o objectivo, nem o que se pretende com este projecto, não consigo avaliar qual é a melhor opção.

Ok, o projeto é para iluminação de festa, e criei um aplicativo no android com três checkbox, quando só um ta marcado ele envia somente um caracter, quando 2 ta marcado ele envia os dois caracteres separadamente. Agora, quando dois checkbox estao marcados e é enviado os dois caracteres o arduino está executando um ate o 'break;' ai executa o outro até o 'break;' e assim vai se repetindo, mas queria que os dois executassem simultaneamente. Desde ja agradeço a paciência.

Uma coisa deste género:

int led = 40;
int led2 = 13;

char caracter[2];
int cmax=0;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){

  int cnt=0;

  while (Serial.available()) {
    caracter[cnt++] = Serial.read();
    cmax=cnt;
  }

  for (int i=0; i<cmax; i++) {
    switch (caracter[i]){
    case 'a':
      digitalWrite(led, HIGH);
      delay(75);
      digitalWrite(led, LOW);
      delay(75);      
      break;
    case 'b':
      digitalWrite(led2, HIGH);
      break;
    case 'd':
      digitalWrite(led, LOW);
      digitalWrite(led2, LOW);
      break;
    }
  }
  delay(1000);
}

deve funcionar. Se precisar de ajuda para perceber o código diga.

Bom por ser leigo, não entendi muito, desculpa, mas tentei utilizá-lo:

int led2 = 13;
int led = 40;

char caracter[2];
int cmax=0;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){

  int cnt=0;

  while (Serial.available()) {
    caracter[cnt++] = Serial.read();
    cmax=cnt;
  }

  for (int i=0; i<cmax; i++) {
    switch (caracter[i]){
    case 'a':
      digitalWrite(led2, HIGH);
      delay(75);
      digitalWrite(led2, LOW);
      delay(75);      
      break;
    case 'b':
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(70);
      digitalWrite(led, LOW);
      delay(70);
      digitalWrite(led, HIGH);
      delay(500);
      digitalWrite(led, LOW);
      delay(500);
      digitalWrite(led, HIGH);
      delay(500);
      digitalWrite(led, LOW);
      delay(500);
      digitalWrite(led, HIGH);
      delay(500);
      digitalWrite(led, LOW);
      delay(500);
      digitalWrite(led, HIGH);
      delay(500);
      digitalWrite(led, LOW);
      delay(500);
      break;
    case 'd':
      digitalWrite(led, LOW);
      digitalWrite(led2, LOW);
      break;
    }
  }
  delay(1000);
}

Bom aconteceu o mesmo que antes, ao receber os caracteres ‘a’ e ‘b’ ele executou o do ‘a’ primeiro e depois o do ‘b’ e ficou nesse loop. Nesse programa o caracter ‘a’ teria que executar um pisca pisca e o caracter ‘b’ um outro led piscando com varios delays. Espero que possa me ajuda. Desde ja agradeço

Mas testou os dois ao mesmo tempo? A alteração que eu fiz foi apenas essa. Quanto ao “pisca” o programa original estava a fazê-lo apenas para o ‘a’ (e não para o ‘b’) por isso foi assim que o deixei (pensei que tivesse alguma lógica).

Esta versão:

int led = 40;
int led2 = 13;

char caracter[2];
int cmax=0;
int estado = LOW;

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop(){

  int cnt=0;

  while (Serial.available()) {
    caracter[cnt++] = Serial.read();
    cmax=cnt;
    estado = HIGH;
    digitalWrite(led, LOW);
    digitalWrite(led2, LOW);
  }

  for (int i=0; i<cmax; i++) {
    switch (caracter[i]){
    case 'a':
      digitalWrite(led, estado);
      break;
    case 'b':
      digitalWrite(led2, estado);
      break;
    case 'd':
      digitalWrite(led, LOW);
      digitalWrite(led2, LOW);
      estado = LOW;
      break;
    }
  }
  
  if (estado == HIGH) {
    estado = LOW;
  }
  else {
    estado = HIGH;
  }
  
  delay(1000);
}

faz piscar os dois LED’s, quando é recebida a instrução. O efeito “pisca-pisca” é dado pela variável “estado” que ora faz acender o LED, ora o faz apagar. No final:

  if (estado == HIGH) {

estado = LOW;
  }
  else {
    estado = HIGH;
  }

é feita a troca do estado do LED. Se ele está aceso na próxima vez apaga, caso contrário, na próxima vez acende.
Esta parte:

    estado = HIGH;

digitalWrite(led, LOW);
    digitalWrite(led2, LOW);

foi adicionada para “recomeçar” quando recebe uma nova instrução. Se tinha recebido um ‘a’ e recebe um ‘b’, desliga o ‘a’ e liga o ‘b’. Isto é conseguido desligando os dois LED’s quando recebe uma nova mensagem. A primeira linha deste bloco, serve para começar sempre com o LED ligado. Isto tem que ser feito, porque o bloco que actualiza o estado, é sempre executado, quer seja recebida uma nova mensagem, quer não seja e podia acontecer, que quando fosse recebida uma nova mensagem o LED estivesse apagado e isso podia confundir um pouco o utilizador (e eu, pessoalmente, penso que fica melhor).