Go Down

Topic: D flip flop not working properly (Read 896 times) previous topic - next topic

TheAxe

Hi,
I'm trying to read 10 Rotary Encoders (EC11) with an Arduino DUE.

I searched for an hardware solution to achieve that and i found this.

I replicated the circuit showed in that page using this IC which i bought online:
M74HC74B1 (check the datasheet by clicking on the part name)

The circuit is not working. The outputs from the IC are flickering without criteria.

Is the IC suitable for my purpose?

Thank you

larryd

Show us a picture of your wiring.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

dlloyd

Quote
I replicated the circuit showed in that page using this IC which i bought online:
M74HC74B1 (check the datasheet by clicking on the part name)
Since you're using the Due, the M74HC74B1 pin 14 (VCC) would be connected to 3.3V.

The circuit shown in the link provided has pins 4 and 10 (PRE) disconnected ... they should be connected to 3.3V (tied HIGH).

Grumpy_Mike

#3
Nov 21, 2014, 07:03 pm Last Edit: Nov 21, 2014, 07:04 pm by Grumpy_Mike
Yes while LS TTL chips are happy (ish) to have unconnected inputs "float high" HC chips are not.

This is my take on it.

http://www.thebox.myzen.co.uk/Workshop/Rotary_Max.html

Paul__B

I searched for an hardware solution to achieve that and i found this.
Very bad move for starters!  That would only be applicable to optical encoders - and then not necessarily reliable.  The "EC11" is a mechanical encoder.

The circuit is not working. The outputs from the IC are flickering without criteria.
Precisely as one would expect.

Is the IC suitable for my purpose?
Totally unsuitable.

You already have the correct solution.  Sitting in front (presumably) of you.  It is called a "microcontroller" and its elegance is in its ability to perform relatively complex functions extremely quickly.

The problem you are facing is called "contact bounce" and it is particularly relevant to these mechanical rotary encoders.  The solution is to employ a software routine that monitors each decoder output (which can easily be done eight at a time as long as you anticipate no more than say, two encoders to be manipulated at a time) and determines a change in state only when that change persists every time it is polled over a period of a number of milliseconds.

Here is example code to perform such a check on one input:
Code: [Select]
// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
// const int led2Pin =  10;
// const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
// int led2State = LOW;
// int led3State = LOW;
char bstate1 = 0;
// unsigned long count1 = 0;   // will store last time LED was updated
// unsigned long count2 = 0;
// unsigned long count3 = 0;
unsigned long bcount1 = 0;

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) {
    *marker += interval;    // move on ready for next interval
    return true;      
  }
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far,
    if (button == HIGH) return false; // Nothing happening!
    else {
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far,
    if (button == LOW) return false; // Nothing happening!
    else {
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else {
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else {
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
//   pinMode(led2Pin, OUTPUT);      
//   pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW;
    }
    digitalWrite(led1Pin, led1State);
  }

/*  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW;
    }
    digitalWrite(led2Pin, led2State);
  }

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW;
    }
    digitalWrite(led3Pin, led3State);
  } */
}

This code of course, only selects one state change, the button being pressed but can be adjusted to observe change in each direction.  The logic to determine the direction of rotation from these changes is fairly trivial.

JimboZA

This thread might help: code and schematics from some messing around I did with an EC11, also 'scope output.
Johannesburg hams call me: ZS6JMB on Highveld rep 145.7875 (-600 & 88.5 tone)
Dr Perry Cox: "Help me to help you, help me to help you...."
Your answer may already be here: https://forum.arduino.cc/index.php?topic=384198.0

TheAxe

Thank you all for the help!!!

I solved this problem thanks to the fact that the DUE has interrupts on every single pin.
I was able to connect A and B of every encoder directly to the Arduino.

Then I used this code in order to read them in a very reliable way.
(this also send a MIDI signal with velocity proportional to the encoder val)

Code: [Select]
void updateEncoder_01() {
  int MSB_01 = digitalRead(encoder_01A);
  int LSB_01 = digitalRead(encoder_01B);

  int encoded_01 = (MSB_01 << 1) | LSB_01;
  int sum_01 = (lastEncoded_01 << 2) | encoded_01;
 
  if(sum_01 == 0b1101 || sum_01 == 0b0100 || sum_01 == 0b0010 || sum_01 == 0b1011) {
    if(EncAltVal_01 == false) {
      if(encoderVal_01 <= encRes) {
        //EncLimit_01 = false;
        encoderVal_01 ++;
        int encMidiVal_01 = map(encoderVal_01, 0, encRes, 0, 127);
        Serial.print("Enc 01  ");     
        Serial.print(encMidiVal_01);
        Serial.println("standard");
        MIDI.sendControlChange(10, encMidiVal_01, AxeCh);
      }
      else {
        //EncLimit_01 = true;
      }
    }
    else if(EncAltVal_01 == true) {
      if(encoderVal_01alt <= encRes) {
        encoderVal_01alt ++;
        int encMidiVal_01alt = map(encoderVal_01alt, 0, encRes, 0, 127);     
        Serial.print("Enc 01  ");
        Serial.print(encMidiVal_01alt);
        Serial.println("alt");
        MIDI.sendControlChange(20, encMidiVal_01alt, AxeCh);
      }
    }   
    else {
      //EncLimit_01alt = true;
    }
  }
 
  if(sum_01 == 0b1110 || sum_01 == 0b0111 || sum_01 == 0b0001 || sum_01 == 0b1000) {
    if(EncAltVal_01 == false) {
      if(encoderVal_01 >= 0) {
        encoderVal_01 --;
        int encMidiVal_01 = map(encoderVal_01, 0, encRes, 0, 127);
        Serial.print("Enc 01  ");     
        Serial.print(encMidiVal_01);
        Serial.println("standard");
        MIDI.sendControlChange(10, encMidiVal_01, AxeCh);
      }
      else {
        //EncLimit_01 = true;
      }
    }
    else if(EncAltVal_01 == true) {
      if(encoderVal_01alt >= 0) {
        encoderVal_01alt --;
        int encMidiVal_01alt = map(encoderVal_01alt, 0, encRes, 0, 127);     
        Serial.print("Enc 01  ");
        Serial.print(encMidiVal_01alt);
        Serial.println("alt");
        MIDI.sendControlChange(20, encMidiVal_01alt, AxeCh);
      }
    }   
    else {
      //EncLimit_01alt = true;
    }
  }
  lastEncoded_01 = encoded_01;
}


I posted only the interrupt function, if you need the full code for any reason just ask!!!

Thank you again to everybody!!!


Paul__B

Using  MIDI.sendControlChange() inside an interrupt routine, eh?

Fascinating!

Go Up