collapse

* Links de Robótica

* Posts Recentes

Recomendação de um opamp para um DAC r2r por jm_araujo
[Hoje às 10:48]


Feira de electricidade e eletrónica por beirao
[Hoje às 00:32]


RN42 e TP-Link MR3020 por doiga
[Ontem às 19:22]


Ajuda Projecto IR / RF por senso
[Ontem às 13:15]


Ideias para construir um quadrúpede simples por dropes
[21 de Novembro de 2017, 22:43]


Ajuda com TRIAC por senso
[17 de Novembro de 2017, 18:00]


TV LG White Screen por almamater
[15 de Novembro de 2017, 08:37]


Pergunta sobre prototipagem ( Pesquisa ) por luisjustin
[14 de Novembro de 2017, 23:22]


Medir Agua que está no Poço por Njay
[14 de Novembro de 2017, 13:28]


Amplificador audio por beirao
[12 de Novembro de 2017, 23:43]

Autor Tópico: Rotary Encoder Com arduino  (Lida 4252 vezes)

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

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Rotary Encoder Com arduino
« em: 06 de Outubro de 2012, 16:10 »
Viva alguém me sabe explicar porque é que neste código abaixo cada vez que rodo o rotary encoder, aumenta 4 valores e não 1? ou seja em vez de ser 1,2,3,4,.. é 0,4,8,12, ... ?
Código: [Seleccione]
//From bildr article: http://bildr.org/2012/08/rotary-encoder-arduino/

//these pins can not be changed 2/3 are special pins
int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
  //Do stuff here

  Serial.println(encoderValue);
  delay(1000); //just here to slow down the output, and show it will work  even during a delay
}

void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}

Obrigado

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #1 em: 06 de Outubro de 2012, 17:24 »
Nunca usei nenhum rotary encoder, então não sei muito bem como funciona, mas penso que o encoder tem 4 fases e quando passa as 4 fases conta 1 step certo?
Se for isso acho que esse código está a ler o número de fases e não o número de steps, daí contar de 4 em 4... Se achares o valor inteiro da divisão do número de fases por 4 dá-te o número de steps.
Assim não precisas de delay. Se só dividires penso que o valor fica arrendondado, assim se por acaso estiver na 3ª fase de um step já vai enviar mais um step que os steps completos. Não sei se me fiz entender...
Penso que para obter o valor inteiro da divisão usa-se a barra de dividir ao contrário (\) ou "div", mas ainda só usei isto em vb.net, não sei se em C é igual.

Assim penso que já vais obter o número de steps correcto.
Experimenta e depois diz alguma coisa, estou curioso para saber  :)

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #2 em: 06 de Outubro de 2012, 17:51 »
Era mesmo isso, bastou dividir o resultado por quatro.
Obrigado pela explicação.

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #3 em: 06 de Outubro de 2012, 18:07 »
Mas atenção que se dividires por 4 só não chega, porque imaginando que o contador tem 6 fases contadas... 6/4 = 1.5. Como o valor é inteiro vai ser arredondado para 2. Como está o código não há problema, visto que só usas o valor dos steps depois do step ser concluído, mas para outras aplicações tens de conseguir o valor inteiro da divisão. Eu estive a ver em arduino.cc e não encontrei lá o comando para obter o valor inteiro da divisão, apenas encontrei para descobrir o resto. Sendo assim, acho que tens que utilizar este pedaço de código para descobrir o valor inteiro:
Código: [Seleccione]
int resto = 0;
if (nrdefases >= 4) {
    resto = nrdefases % 4;
}
int nrdesteps = (nrdefases-resto) / 4;

Penso que é isto, não tenho a certeza, escrevi um bocado à pressa e não tenho aqui forma de testar.

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #4 em: 06 de Outubro de 2012, 22:29 »
Obrigado, mas essa parte acho que não preciso.
Agora surgiu-me outro problema... :/
Se eu usar aquele delay(1000); no void loop(), tenho os valores todos certos como eu quero, se não usar o delay, ao rodar o rotary encoder salta números, porque?

Código: [Seleccione]
int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
 
  if(encoderValue >396){
    encoderValue = 0;}
    if(encoderValue <0){
    encoderValue = 396;}
 
  Serial.print((encoderValue / 4)); //  midiCC(0xC0, 0, (encoderValue / 4));
  delay(1000); 
  }


void updateEncoder(){
 
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}
void midiCC(char command, char value1, char value2){
  Serial.print(command, BYTE);
  Serial.print(value1, BYTE);
  Serial.print(value2, BYTE);
}

Offline senso

  • Global Moderator
  • Mini Robot
  • *****
  • Mensagens: 9.402
  • Helpdesk do sitio
Re: Rotary Encoder Com arduino
« Responder #5 em: 06 de Outubro de 2012, 22:31 »
Falta-te implementar deboucing do encoder, como qualquer botão mecânico, os encoders quando passam de uma posição para a outra, existe um periodo de tempo(2-15ms) em que o estado dos botões não é estavel, pois como são feitos de lamelas metálicas oscilção na transição.

Dá uma vista de olhos nisto:
http://arduino.cc/playground/Main/RotaryEncoders
Avr fanboy

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #6 em: 06 de Outubro de 2012, 22:34 »
Para além disso não chega dividires por 4, tens que obter o quociente inteiro da divisão por 4... Assim os steps vão ser errados. Dá uma vista de olhos no código que meti em cima.

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #7 em: 06 de Outubro de 2012, 22:57 »
Já dei uma vista de olhos em toda a página mas não encontro nada sobre "deboucing do encoder".
Podem ser mais especificos, eu sou mesmo novato nisto?

obrigado pela atenção

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #8 em: 06 de Outubro de 2012, 23:11 »
Vê aqui:
http://hifiduino.wordpress.com/2010/10/20/rotaryencoder-hw-sw-no-debounce/

Podes fazer por hardware ou software. Por hardware é simples, resistências e condensadores.
« Última modificação: 06 de Outubro de 2012, 23:18 por rglove »

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #9 em: 07 de Outubro de 2012, 01:13 »
Agradeço as respostas, mas já estou farto de ler e não consigo construir o meu Software Debounce através daquele código :/
E também reparei que preciso para um botão que tenho.

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #10 em: 07 de Outubro de 2012, 01:48 »
Não sei se vai funcionar... Se não funcionar experimenta fazer o debouncing por hardware...

Código: [Seleccione]
int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
 
  if(encoderValue >396){
    encoderValue = 0;}
    if(encoderValue <0){
    encoderValue = 396;}
    int resto = 0;
    if (encoderValue>4) {
        resto = encoderValue % 4;
    }
  Serial.print(((encoderValue-resto) / 4)); //  midiCC(0xC0, 0, (encoderValue / 4));
  }


void updateEncoder(){
 
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;
  if(sum == 0b1101 || sum == 0b0010 || sum == 0b1011 || sum == 0b1110 || sum == 0b0111 || sum == 0b0001) delay(2);

  lastEncoded = encoded; //store this value for next time
}
« Última modificação: 07 de Outubro de 2012, 01:54 por rglove »

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #11 em: 07 de Outubro de 2012, 01:54 »
Já agora, que valores é que dá?

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #12 em: 07 de Outubro de 2012, 09:58 »
O objectivo é fazer 0 a 99, superior a 99 volta para zero e inferior a zero volta para 99.
O que acontece é que se eu colcoar um delay grande (1000) no codigo, os valores dão todos certos e esse erro não acontece.
assim sá sempre esse erro, e além disso está sempre a enviar sinal e eu só quero enviar sinal quando o estado do rotary alterar.

Offline joaobernardino

  • Mini Robot
  • *
  • Mensagens: 59
Re: Rotary Encoder Com arduino
« Responder #13 em: 07 de Outubro de 2012, 16:26 »
Hey finalmente ao fim de muito insistrir começo a ter progressos.
Já tenho o código para o botão com o debounce, e o do rotary encoder agora um bocadinho alterado também acho que está bom. Resta um problema, com a aleração que fiz o serial print está a ler-me as fases, ou seja, o que você tinha mencionado, cada passo do rotary encoder apresenta-me quatro valor os seja:
1ª rotação  1,2,3,4     2ª rotação 5,6,7,8  menos uma rotação 8, 7, 6,5....   por aí.

Queria só agora que cada rotação aumentasse só um valor, 1,2,3,4,5,....

Não consegui fazer com o que me foi dado por vocês anteriormente...

Código: [Seleccione]
int encoderPin1 = 2;
int encoderPin2 = 3;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

long previousMillis = 0;
long interval = 100;    // update a cada "X" ms para não ocorrer erros de leitura   

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
}

void updateEncoder(){
 
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  if(lastEncoded != encoded){
  Serial.println(encoderValue);
   lastEncoded = encoded;
}
}

obrigado

Offline rglove

  • Mini Robot
  • *
  • Mensagens: 526
Re: Rotary Encoder Com arduino
« Responder #14 em: 07 de Outubro de 2012, 16:56 »
Experimenta assim:

Código: [Seleccione]
int encoderPin1 = 2;
int encoderPin2 = 3;

int oldsteps = 0;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;

long previousMillis = 0;
long interval = 100;    // update a cada "X" ms para não ocorrer erros de leitura   

void setup() {
  Serial.begin (9600);

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //turn pullup resistor on
  digitalWrite(encoderPin2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop(){
    int resto = 0;
    int steps = 0;
    if (encoderValue >= 4) {
        resto = encoderValue % 4;
        steps = (encoderValue-resto)/4;       
    }
    if (steps != oldsteps) {
        Serial.println(steps);
    }
    oldsteps = steps;
}

void updateEncoder(){
 
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  if(lastEncoded != encoded){
   lastEncoded = encoded;
}
}