collapse

* Posts Recentes

Amplificador - Rockboard HA 1 In-Ear por almamater
[27 de Março de 2024, 19:13]


O que é isto ? por KammutierSpule
[26 de Março de 2024, 19:35]


Bateria - Portátil por almamater
[25 de Março de 2024, 22:14]


Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]

Autor Tópico: Threads no arduino?  (Lida 13232 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline msr

  • Mini Robot
  • *
  • Mensagens: 798
Threads no arduino?
« em: 30 de Setembro de 2009, 00:33 »
Threads no arduino: é possível? Ou alguma espécie de "threads virtuais"?

Por exemplo, imaginem esta situação:

Têm varios botoes de pressao ligados aos digital pins e querem detectar quando cada um deles é pressionado.
Se cada um dos botoes tiver um efeito secundario associado, enquanto estiver a correr o código desse "efeito secundário" é impossivel detectar um novo botão.

Não sei se me faço entender, mas como contornariam esta situação?
« Última modificação: 30 de Setembro de 2009, 00:35 por msr »

Offline Tyran

  • Mini Robot
  • *
  • Mensagens: 293
Re: Threads no arduino?
« Responder #1 em: 30 de Setembro de 2009, 01:07 »
É possível sim, se usares interrupções.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Threads no arduino?
« Responder #2 em: 30 de Setembro de 2009, 01:39 »
Depende de quanto tempo demora a fazer o efeito secundário.

Offline TigPT

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 5.372
    • Tiago Rodrigues
Re: Threads no arduino?
« Responder #3 em: 30 de Setembro de 2009, 06:56 »
No fundo podes fazer sempre uma programação "semi-paralela" mas sempre controlada pelo programador e não "threads" visto que vais correr código nativo em vez de código um sistema operativo que possa fazer esse controlo.

Podes no entanto inscrever as tarefas numa pilha, e ter interrupções a serem geradas a cada X milisegundos que em vez de a interrupção em si ser lançada por essa "thread", ser a interrupção que vai verificar se existem mais processos concorrentes aos quais ela necessite de dar tempo de execução até que na nova interrupção ele volta ao processo anterior, ou a outro que tb tenha sido entretanto lançado.

O início dessa interrupção verificava tb o lançamento de novos processos, por exemplo testando o teclado a cada x milisegundos (já que os humanos são mt lentos a carregar nos botões).

Offline Tyran

  • Mini Robot
  • *
  • Mensagens: 293
Re: Threads no arduino?
« Responder #4 em: 30 de Setembro de 2009, 13:55 »
Isso já seria uma boa dor de cabeça, em assembly talvez não tanto mas em c nem estou a ver como fazer isso lol mas tem de dar, é preciso é saber como aceder ao program counter etc... (já começa a dar saudades do 8051 xD)

Offline TigPT

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 5.372
    • Tiago Rodrigues
Re: Threads no arduino?
« Responder #5 em: 30 de Setembro de 2009, 14:09 »
Não é necessário complicar muito, pode-se fazer "semi-threads" e gerir com switch case com simples interrupções.

Se quiseres mais complexo podemos falar depois em privado que creio que seja mais simples.

Offline msr

  • Mini Robot
  • *
  • Mensagens: 798
Re: Threads no arduino?
« Responder #6 em: 30 de Setembro de 2009, 16:48 »
Ou seja, no fundo o que dava jeito era uma library,  em que usando as interrupções disponiveis no AVR escalonasse as "threads" por exemplo usando o algoritmo Round Robin, ou outro. Certo?

Não estou a ver bem como se faz a coisa (pro ex, como criar a thread em si) porque nunca trabalhei com interrupções de um microcontrolador...
A unica coisa que encontrei foi isto: http://code.google.com/p/arduino-threads/
Mas parece que se esqueceram de uploadar o source code :-\

Mas era uma cena porreira de se fazer. Ninguem com tempo a mais e com vontade de fazer uma coisa destas?  ;D


Edit: estava eu a googlar e encontrei isto: http://lusorobotica.com/index.php?topic=442.0%3Bwap2 + http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts

Edit2: http://gonium.net/md/2006/12/20/handling-external-interrupts-with-arduino/   com isto acho que já resolvia o problema que descrevi ali em cima
« Última modificação: 30 de Setembro de 2009, 16:57 por msr »

Offline TigPT

  • Administrator
  • Mini Robot
  • *****
  • Mensagens: 5.372
    • Tiago Rodrigues
Re: Threads no arduino?
« Responder #7 em: 30 de Setembro de 2009, 20:12 »
Resolve o problema mas tem que a segunda acção terminar por completo para voltar à primeira e continuar onde estava. Não sei se era isso que pretendias se era multi-thread paralelos (ou semi).

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Threads no arduino?
« Responder #8 em: 01 de Outubro de 2009, 00:02 »
Não é fácil trabalhar com threads. Só o recomendo a quem souber programar muito bem e conheça a fundo arquitectura de processadores e em particular a arquitectura do AVR. E interrupções também não são muito mais simples.

Há um modelo mais simples de trabalhar, que é o modelo "orientado a eventos". Isto implica dividir o trabalho em pedaços pequenos que não bloqueiam o processamento. No fundo a forma de programação do Arduino implicitamente recomenda este modelo. Por exemplo, um tipico pedaço de código para ler um byte da porta série e fazer qualquer coisa dependendo o byte recebido, enquanto faz piscar o LED:

void loop()
{
    if (Serial.available())
    {
        switch (Serial.read())
        {
            case 'f' :
                AndaEmFrente();
                break;

            case 't' :
                AndaParaTras();
                break;
        }
    }

    static int  led_ctr = 0;
    led_ctr = (led_ctr < 10? led_ctr + 1 : 0);
    digitalWrite(13, (led_ctr < 5? HIGH : LOW));

    delay(100);    // em milisegundos
}


Como vocês devem saber, a função loop() é invocada repetidamente tão depressa quanto possível. A pausa de 100 milisegundos (ms) no final obriga a que tenhamos uma cadência conhecida, neste caso, 100ms; o código na função é executado agora de 100 em 100ms. Aqui já estamos a fazer 2 coisas "em simultaneo": ler da porta série e piscar o LED do Arduino.

Queres fazer coisas mais complexas e que demoram mais tempo? Divides a tarefa que queres fazer transformando-a numa máquina de estados. Por exemplo, imagina que queres fazer a luminosidade do LED variar devagar desde apagado até totalmente aceso, havendo 10 níveis de luminosidade e ficando 1 segundo em cada nível. A solução óbvia e simples seria

void loop()
{
    int  nivel;
    for (nivel = 1; nivel < 10; nivel++)
    {
        analogWrite(pin, nivel);   // pin é o pino de PWM onde estaria ligado o LED
        delay(1000);   // 1 segundo
    }
}


O problema óbvio disto é não poderes fazer mais nada enquanto o LED acede devagar. Para integrar esta funcionalidade no código anterior que já lê da porta série e pisca um LED, vamos arranjar uma variável que guarda o estado da máquina de estados, "estado". Esta variável será incrementada 1 vez no loop(), o que quer dizer que será incrementada a cada 100ms; depois fazemos uma determinada acção conforme o seu valor. Para fazer 1 segundo, a variável estado tem que ser incrementada 10 vezes; então podemos dizer que de 1 a 10 o LED acende no nível 1, de 11 a 20 o LED acende no nível 2, e assim sucessivamente. Quando chegarmos ao final, estado será igual a 10 niveis x 10 incrementos ou seja 100, e então voltamos a colocá-la a 0:

void loop()
{
    // ... o código para ler da porta série e piscar o LED ficaria aqui ...

    // acender um LED progressivamente
    static int  estado = 0;
    estado++;
    if (estado < 10)  analogWrite(pin, 1);
    else if (estado < 20)  analogWrite(pin, 2);
    else if (estado < 30)  analogWrite(pin, 3);
    ...
    else if (estado < 100)  analogWrite(pin, 10);
    else
        estado = 0;

    delay(100);    // em milisegundos
}


Claro que neste caso seria mais fácil, em vez da carrada de ifs, fazer simplesmente

analogWrite(pin, estado / 10);

mas é só para dar exemplificar, pois a acção que pretendias fazer em cada ponto poderia ser completamente diferente das acções nos outros pontos. Com este método podes sempre arranjar uma forma de fazeres coisas complexas "em simultaneo" e que demorem o tempo que quiseres. O valor da variável estado controla o estado em que está a operação.

Nos exemplos omiti a configuração inicial dos pinos, pois não é relevante para o que queria mostrar. Também não garanto que eles compilem tal como estão, são apenas exemplos ilustrativos.

Offline msr

  • Mini Robot
  • *
  • Mensagens: 798
Re: Threads no arduino?
« Responder #9 em: 01 de Outubro de 2009, 21:17 »
Tenho que voltar a pegar nisto mais tarde. Obrigado pelas respostas!

A ideia basica do que queria era: dois botoes de pressao, em que um funciona como start e outro como stop. Carrego no start e um piezo (bezouro) começa a "cantarolar" (em loop), carrego no stop e para de "cantarolar".
Assim, acho que as interrupções serviam para isto, mas hei-de experimentar mais tarde.

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Threads no arduino?
« Responder #10 em: 01 de Outubro de 2009, 23:11 »
Facílimo. Assumindo que usas o PWM para fazer a musiquinha, aqui tens o esqueleto:

const int cPinoBotaoOn = ... ;
const int cPinoBotaoOff = ... ;
const int cPinoBuzzer = ... ;

void loop()
{
    static bool  bLigado = false;    // "static" quer dizer que é variável global

    if (digitalRead(cPinoBotaoOn))
    {
        bLigado = true;
    }
    else if (digitalRead(cPinoBotaoOff))
    {
        bLigado = false;
    }
    if (bLigado)
    {
        analogWrite(cPinoBuzzer, 127);  // gerar onda com 50% de ciclo activo
    }
    else
    {
        analogWrite(cPinoBuzzer, 0);   // desligar o pino
    }

    delay(100);
}


Não é preciso ir para as interrupções e respectivas dores de cabeça. Depois para controlar a frequência, para dar diferentes notas musicais, há lá pelo site do Arduino uma página que diz como alterar a frequência da função writePWM.

Isto é só para tocar 1 nota, mas para tocar uma música toda é só aplicar o método que descrevi na outra mensagem.

Offline msr

  • Mini Robot
  • *
  • Mensagens: 798
Re: Threads no arduino?
« Responder #11 em: 01 de Outubro de 2009, 23:38 »
Exactamente, eu fiz uma coisa desse género, só que para o "digitalRead(cPinoBotaoOn)" sacar o valor pretendido eu tinha que carregar no botao de pressao no preciso momento em que essa linha de código estivesse a correr. Se não houvesse muitos delays pelo código não fazia mal, mas quando os há, dá barraca.

Alem dos dois botoes e do piezo (bezouro) liguei tambem um potenciometro que controlava a frequencia com que o bezouro apitava (ao invés do exemplo que deste, que são sempre os 100ms). Ou seja, o potenciometro definia o valor do delay, o que, se para valores pequenos nao havia problema, para valores maiores havia. Ou tentava adivinhar a altura em que o programa ia ler o valor do botão, ou então, não o detectava.

Depois disto, apareceu-me a ideia das threads, ou seja: o codigo que faz o piezo "cantarolar" (e que controla a frequencia, atraves do pot.) corria numa thread independente e o loop principal do programa limitava-se a ver se algum dos botoes foi pressionado (start: cria thread, stop: fecha thread).

Mas com as interrupções parece-me que vai dar ao mesmo.
Por exemplo: tenho o codigo que faz cantarolar o piezo todo no loop, depois tenho uma variavel global que é alterada consoante as interrupções (interrupção originada pelo botao1 -> start, interrupção originada pelo botao2 -> stop).

Mas como nunca "handlei" interrupções não tenho muita certeza do que estou a dizer. Que te parece?


Edit: é capaz de dar para fazer isto da forma que colocaste em cima: por exemplo ter sempre um delay baixo e fixo, depois o potenciometro apenas influencia as vezes que esse delay tem que se repetir antes que o piezo volte a apitar. e enquanto isto está sempre a ver se algum botao foi pressionado. mas...
« Última modificação: 01 de Outubro de 2009, 23:42 por msr »

Offline Tyran

  • Mini Robot
  • *
  • Mensagens: 293
Re: Threads no arduino?
« Responder #12 em: 01 de Outubro de 2009, 23:43 »
Se os delays forem um problema não uses a função normal de delay, usas um timer que te vai correr a função Y passado Y segundos e enquanto isso podes ir fazendo outras coisas no código...

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Threads no arduino?
« Responder #13 em: 02 de Outubro de 2009, 00:23 »
Estás a complicar o que é simples, msr :). Se usares o PWM, é o AVR que faz o som. Ao fazeres analogWrite(pino, 127), o próprio chip gera uma onda quadrada que podes ouvir de ligares o besouro ao pino "pino" (que tem que ser um pino "PWM"). Tu depois só tens que controlar quando é que o "som" está ligado ou desligado. Se escreveres 0 em vez de 127 ele fica desligado.

Agora falta é controlar a frequência da nota tocada. Por omissão o ambiente do Arduino configura o periférico de PWM do AVR para uma frequência de poucas centenas de Hz (não me lembro do valor, mas está tudo lá no site do Arduino). Tens que re-configurar essa frequência para obteres outras notas musicais.

Depois só tens que controlar a música, por exemplo, se tiveres a tal variável estado a ser incrementada no loop() e escolheres que de 1 a 4 é um dó, de 5 a 6 é 0Hz e 7 a 8 é um si, ele dá um dó durante 4 x 100ms = 400ms depois uma pausa de 2 x 100ms = 200ms e depois um si durante 2 x 100ms = 200ms. Voltando a variável "estado" a 1 a música repete-se. A qualquer momento podes fazer re-iniciar a música dando a "estado" o valor 0, ou fazer a melodia ir para qualquer ponto.

Numa segunda fase, em vez de uma carrada de if's, fazes uma tabela (array) com as notas e durações, e assim ficas com uma forma muito fácil de introduzir lá uma música. Podes até fazer um editor de melodias.

Tudo isto dá perfeitamente para fazer sem interrupções nem threads. Há pequenos detalhes nestes 2 métodos que vos vão fazer andar a bater com a cabeça nas paredes, e por isso não recomendo mesmo nada que se metam nisso até que sejam mais pros em programação. Tenho quase a certeza que ias esbarrar com um desses detalhes manhosos logo à 1ª...
« Última modificação: 02 de Outubro de 2009, 00:25 por Njay »