LusoRobótica - Robótica em Português
Sistemas específicos => Arduino / AVR => Tópico iniciado por: r16 em 27 de Dezembro de 2014, 19:49
-
vivas companheiros,
tenho o seguinte codigo:
tenho um sensor dht11, que le a temperatura e humidade, e quero ter no mesmo codigo um outro que me ligue um pin durante 5 segundos que espere 20 e volte a ligar o pin por mais 5 segundos e por ai adiante...
so que eu fiz com um delay... e este delay que fiz interfere com o resto do codigo e eu nao queria isso alguem me ajuda a modificar sff:
#include <DHT11.h>
int motor = 10; // Motor liga no pino 10 do mini pro
int fogger = 11; // fogger liga no pino 11 do mini pro
int sensor=4;
DHT11 dht11(sensor);
void setup()
{
pinMode(fogger, OUTPUT);
pinMode(motor, OUTPUT);
Serial.begin(9600);
while (!Serial) {
;
}
}
void loop()
{
digitalWrite(motor, HIGH); //Motor Liga durate 5 segundos
delay(5000);
digitalWrite(motor, LOW);
delay(20000); //Espera 20 segundos
{
int err;
float temp, humi;
if((err=dht11.read(humi, temp))==0)
{
Serial.print("temperatura:");
Serial.print(temp);
Serial.print(" humidade:");
Serial.print(humi);
Serial.println();
if (humi<=40){
Serial.print(" FOGGER LIGADO");
Serial.println();
digitalWrite(fogger,HIGH);
}
if (humi>=50){
Serial.print(" FOGGER DESLIGADO");
Serial.println();
digitalWrite(fogger,LOW);
}
delay(DHT11_RETRY_DELAY); //delay for reread
}
}
}
-
Podes usar "multitasking cooperativo":
http://troniquices.wordpress.com/2010/05/24/arduino-a-fazer-varias-coisas-ao-mesmo-tempo/ (http://troniquices.wordpress.com/2010/05/24/arduino-a-fazer-varias-coisas-ao-mesmo-tempo/)
Se aprenderes a técnica, que é simples, depois fazes qualquer coisa.
Quando já tiveres "pro" podes aprender mais umas coisas no 2º artigo, mas este só tenho em Inglês:
http://embeddeddreams.com/site/2011/07/23/more-on-doing-several-things-at-the-same-time/ (http://embeddeddreams.com/site/2011/07/23/more-on-doing-several-things-at-the-same-time/)
-
Ou a solução básica, abrir o exemplo blink without delay no IDE do arduino, está lá, comentado e explicado, faz-me confusão como é que tanta gente nem para os exemplos olha ::)
-
senso foi a primeira coisa que fiz,...
no entanto esse exemplo faz com que o led pisque 1 em 1 segundo.
nao entendo como é que a partir dele consigo fazer com que ligue 5 seg e espere 20
obrigado
-
É mudar os tempos no if.
Introduz mais que um if, faz um if para meter on, outro para meter off.
-
ok,,,alterei para:
#include <DHT11.h>
int motor = 13; // Motor liga no pino 10 do mini pro
int fogger = 11; // fogger liga no pino 11 do mini pro
unsigned long time = 0;
int sensor=4;
int aciona = 0;
DHT11 dht11(sensor);
void setup()
{
pinMode(fogger, OUTPUT);
pinMode(motor, OUTPUT);
Serial.begin(9600);
while (!Serial) {
;
}
}
void loop()
{
if(millis() - time < 4999 && aciona ==0)
{
digitalWrite(motor,HIGH);
aciona = 1;
}
if (millis() - time > 5000 && millis() - time < 20000 && aciona ==1)
{
digitalWrite(motor, LOW);
time = millis();
aciona = 0;
}
{
int err;
float temp, humi;
if((err=dht11.read(humi, temp))==0)
{
Serial.print("temperatura:");
Serial.print(temp);
Serial.print(" humidade:");
Serial.print(humi);
Serial.println();
if (humi<=40){
Serial.print(" FOGGER LIGADO");
Serial.println();
digitalWrite(fogger,HIGH);
}
if (humi>=50){
Serial.print(" FOGGER DESLIGADO");
Serial.println();
digitalWrite(fogger,LOW);
}
delay(DHT11_RETRY_DELAY); //delay for reread
}
}
}
no entanto o pino 10 fica ligado por 5 segundos depois desliga mas nao volta a ligar passado os 20 segundos.... onde estou a errar?
-
só fazes o update da variavel time num dos milis, para esse tipo de coisas prefiro usar uma variavel para cada if.
-
nao consigo atinar com isto.... ajuda -me :o
-
Boa noite.
Dá uma olhada a este link...
https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all (https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all)
-
Boa noite.
Dá uma olhada a este link...
https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all (https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all)
obrigado era mesmo isto
-
Eu não percebi bem o que queres
mas se for o que penso teria resolvido assim,
/************************************************************************************
**** Autor: Sérgio Fonseca
**** Data: 28-12-2014
**** Versão: 1.1
****
**** Descrição: Envia para a porta serial a temperatura a cada segundo e ao
**** mesmo tempo executa ciclicamente ligar um LED 5 segundos e desligar 20 segundos
****
**** Observações: Não tem grande precisão no tempo uma vez que cada instrução influencia o tempo
****
***********************************************************************************/
/*____Declarações e variáveis ________________________________*/
int led1=13; //LED Que acende 5 segundos e esta apagado 20segundos (cíclico)
int sensor=4; // Sensor de temperatura ligado no pin 4 (analógico)
int contador; // contador que incrementa aproximadamente a cada 1 segundo
int temperatura; //variável que guarda o valor da temperatura
/*________________Rotina de configuração ao iniciar o Arduíno______________________*/
void setup()
{
Serial.begin(9600);
pinMode(led1,OUTPUT);
contador=0;
}
/*________________Programa____________________________________*/
void loop()
{
if (contador <4)
{ligaled();} // se contador for menor que 4 chama a função ligaled
desligaled(); // se for maior que 4 chama a função desligaled
}
/*_______________Função ligaled_______________________________________*/
void ligaled()
{
digitalWrite(led1, HIGH); // liga o led
incrementa(); // chama a função incrementa
}
/*___________Função desligaled_________________________________________*/
void desligaled()
{
if (contador > 4)
{digitalWrite(led1, LOW);} // se o contador for maior que 4 desliga o led
incrementa(); // caso o contador seja inferior a 4 chama a função incrementa
}
/*___________________Função incrementa____________________________________________*/
void incrementa() // função que demora aproximadamente um segundo a ser executada
{
//____ trata os dados do sensor de temperatura e envia__________
temperatura = analogRead(sensor); //Coloca o valor analógico do pino na variavel
Serial.println("sensor temperatura"); //envia o valor da variável para a porta serie com quebra de linha
Serial.println(temperatura);
Serial.println(contador);
// ________Fim do tratamento de dados a enviar___________
contador = contador + 1; // incrementa o contador
delay(998); // espera aproximadamente um segundo (1s)
if (contador == 25) // 20 segundos + 5 segundos
{contador = 0;} // inicia o contador
}
/*__________________________FIM____________________________________________________*/
Agradecia que comentassem o código, este é apenas um exemplo.
O fórum serve para (ajudar) aprender e ensinar.
-
O link que enviaram acima está muito claro e deve ter sido só fazer copy paste para ter o problema resolvido
O teu código abaixo "não interfere" com o loop de uma forma um bocado relativa. Ou seja, não está na função principal mas quando é chamado utilizas delays e caso leias o link da adafruit vês que essa não é a forma mais "profissional" de fazeres as coisas
Simplesmente estás a dizer ao microcontrolador para durante esses milisegundos ficar em idle e não executar nenhuma tarefa (de forma simplista)
O ideal é usar a função milis e mais algum código para verificar a alteração no tempo em vez de utilizares delays. É claro que nesse exemplo simples e meio de experimentação não vale a pena elaborar muito o código. Em aplicações mais complexas, isso sim elimina o delay por completo (para mim a única função mais razoável que poderia ter seria na inicializacao do programa em que podes querer estabilizar as leituras de alguns sensores ou escrever algum texto via série para debug)
-
Com ifs e milis(ou implementação caseira do mesmo), por exemplo código retirado de um projecto adormecido para exemplo:
if(milis() - lastMilis > 250){
LEDPORT ^= ((1<<LED1));
lastMilis = milis();
//printEncoders();
encoder1Count += encode1_read4();
encoder2Count += encode2_read4();
setDac(0,0,1,encoder1Count);
getPowerData();
debug1();
updateScreen();
}
if(milis() - buttonsMilis > 10){
buttonsMilis = milis();
getBtnStatus();
}
if(milis() - measureMilis > 50){
measureMilis = milis();
}
-
vou só aproveitar um pouco para perguntar uma cena.
Njay tive uma idea e gostava da tua opinião.
Para fazer tipo 2-3 programas a correr em paralelo poderia fazer isto?
Criar um interrupt periódico com um timer de 1 em 1 ms.
Programa1 começa.
Interrupt é chamado - salta para Programa2.
Interrupt é chamado - salta para Programa3.
Interrupt é chamado - salta para Programa1.
Por ai a fora.
A ideia é ter um interrupt handler que tem tipo um variavel que vai de 0-2, ou seja o numero do programa a correr (usando um if), e chama essa função.
O meu problema é que isto teria de ser de forma a que o interrupt chama-se a função mas era mesmo um Jump, não um jump and link para voltar. Não é?
Claro que teria de ter cuidados para os programas não se atropelarem mas isso é trabalho que teria de ser feito e cuidados a ter. Tambem algumas funções criticas podiam desativar o interrupt por momentos.
Isto seria para um ARM-M0 de 48Mhz ou um MCU mais rápido.
Se disser alguma asneira calem-me :p
-
Tens de guardar stack para garantir que não dás cabo das variaveis todas.
Tens tanto RTOS para micros que até doi, o mais comum actualmente é o ChibiOS, permite fazer o que queres, e muito mais.
-
vou só aproveitar um pouco para perguntar uma cena.
Njay tive uma idea e gostava da tua opinião.
Para fazer tipo 2-3 programas a correr em paralelo poderia fazer isto?
Criar um interrupt periódico com um timer de 1 em 1 ms.
Programa1 começa.
Interrupt é chamado - salta para Programa2.
Interrupt é chamado - salta para Programa3.
Interrupt é chamado - salta para Programa1.
Por ai a fora.
A ideia é ter um interrupt handler que tem tipo um variavel que vai de 0-2, ou seja o numero do programa a correr (usando um if), e chama essa função.
O meu problema é que isto teria de ser de forma a que o interrupt chama-se a função mas era mesmo um Jump, não um jump and link para voltar. Não é?
Claro que teria de ter cuidados para os programas não se atropelarem mas isso é trabalho que teria de ser feito e cuidados a ter. Tambem algumas funções criticas podiam desativar o interrupt por momentos.
Isto seria para um ARM-M0 de 48Mhz ou um MCU mais rápido.
Se disser alguma asneira calem-me :p
Boas,
A primeira questão que deves colocar é se realmente necessitas de um verdadeiro multitasking ou
se uma simples state machine pode servir. Em termos de desempenho uma state machine tem
vantagens, um sistema verdadeiramente multitasking é muito mais versátil.
Nos cores ARM uso o Systick (e respectiva interrupção) para implementar um round-robin com uma
fracção de 5us por tarefa. Cada tarefa deve ter uma estrutura associada onde vais guardar o
estado da mesma, e podes até implementar um sistema de prioridades, e cada estrutura deve ter
uma área que sirva de stack. O switching de tarefas é relativamente simples, guardar o code pointer, stack pointer, interrups state, etc, e activar o novo code pointer, stack pointer, etc. Deves também
manter e actualizar (na dita INTR) uma variável com o tickcount que é muito útil para implementar
delays, sendo que para isso deves ter uma função de delay global que seja transversal a todas as
tarefas de forma a que os timings sejam assegurados.
É claro que numa verdadeira multi-tarefa é depois necessário controlar o acesso aos periféricos, e
uma vez que podes aceder aos mesmos dentro de diversas tarefas concorrentes, deves implementar
um sistema de semáforos para evitar que duas tarefas possam aceder por exemplo à UART1 ou usar
a mesma buffer da mesma enquanto a anterior não libertar este periférico. E isto é aplicável a todos
os periféricos, memória partilhada, canais DMA, etc.
Deves ponderar muito bem se necessitas mesmo de multi-tarefa, uma state-machine mesmo que
seja muito rude pode resolver a questão sem estes problemas.
Se realmente pretendes multi-tarefa tens toda a vantagem em recorrer a um RTOS que já tenha
dado provas, não vale a pena queimar neurónios e correr riscos a reinventar a roda, a não ser que
seja por um desafio pessoal.
Geralmente só uso o RTEMS nos cores SPARC (MCUs LEON) e o RTX da ARM/Keil nos cores ARM
mas existem por ai muitos RTOS com licença FOSS que podes usar sem problemas.
Abraços,
PA
-
O já aqui foi dito, sendo que saliento a pergunta: qual é a aplicação?
Se é para pura recreação tua, aprender e tal, fiquei um pouco na dúvida se os teus 3 programas são interrompidos "sem saberem", mas vamos assumir que sim. Em C há um par de funções que pode ajudar a fazer esse tipo de coisa, setjmp e longjmp (http://en.wikipedia.org/wiki/Setjmp.h (http://en.wikipedia.org/wiki/Setjmp.h)) . Precisas de ver a documentação do compilador que estiveres a usar para ficares a par de todos os detalhes. Já usei isto por exemplo para "simular" excepções, em que podes estar algures dentro duma função que chamou outra que chamou outra que chamou outra que ... e voltar "instantaneamente" para a função "de topo". Lembro-me de ter usado na implementação dum parser preditivo.
A decisão que vais tomar na interrupção sobre qual o próximo "programa" a executar é o trabalho do "scheduler", e podes implementar N politicas de atribuição do CPU.
vou só aproveitar um pouco para perguntar uma cena.
Njay tive uma idea e gostava da tua opinião.
Para fazer tipo 2-3 programas a correr em paralelo poderia fazer isto?
Criar um interrupt periódico com um timer de 1 em 1 ms.
(...)
-
A ideia é ter um interrupt handler que tem tipo um variável que vai de 0-2, ou seja o numero do programa a correr (usando um if), e chama essa função.
Boas novamente,
Todo o código que é executado dentro de uma INTR deve ser o mais conciso possível, chamar funções que
tenham loops ou bastante processamento de dentro de uma ISR alem de ser má pratica vai possivelmente
causar stack overflow mesmo em ISR que não sejam reentrantes.
Vais chamar a "função" dentro da ISR e esperar que esta retorne ? Mesmo sendo uma função não blocking
vais ter que dentro dessa mesma função ter um state machine se pretendes executar código mais complexo,
e nunca vais poder ter ciclos infinitos.
Abraços,
PA
-
Obrigado pelo info. Não sabia sobre o setjmp e longjmp.
Para multitasking a sério usaria um RTOS de certeza, isso dá demasiado trabalho.
Eu em todos os programas tenho sempre o SysTick de 1ms em 1ms e uma função delay parecida ao do arduino. Isto para poder contar tempo.
A idea por agora é mesmo por recreação. Isto porque andei a mexer nos legos com programação de blocos - dá para ter 3 linhas de código e fiquei curioso
A ideia é começar a aprender mais sobre como controlar vários actuadores que dependem de varios sensores.
Neste caso é mais uma curiosidade, os programas não precisam de saber se foram interrompidos.
Vou ter de ver mais sobre isto depois :p
-
Boas novamente,
Todo o código que é executado dentro de uma INTR deve ser o mais conciso possível, chamar funções que
tenham loops ou bastante processamento de dentro de uma ISR alem de ser má pratica vai possivelmente
causar stack overflow mesmo em ISR que não sejam reentrantes.
Era isso uma das duvidas que tinha, obrigado!
Então é melhor ir para os RTOS se precisar de tal coisa.
Por agora vou ver melhores praticas simples. Tenho de começar a para de usar delays :p