trying to do function at certain count

i got a code to start with off youtube about reading encoder inputs x2
it works nice and i am trying to add some millis functions at a certain count

volatile unsigned int  temp;                               //not sure how this works? maybe rename to better understand?
volatile unsigned int  counter = 0;
byte ledPin = 13;                                          // visual of what is happening
unsigned int previousMillis = 0;
const byte IndexDIPin   = 1;

void setup() {
  Serial.begin (9600);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(0, encoder1, RISING);
  attachInterrupt(1, encoder2, RISING);
  pinMode(ledPin, OUTPUT);
  pinMode(IndexDIPin, INPUT_PULLUP);

}
void loop() {

  
 /* unsigned int currentMillis = millis();

  while ( counter >= 500)                               // when to do some work
    digitalWrite(ledPin, HIGH);
  if (currentMillis - previousMillis >= 1000) {         // how long to do this work
    previousMillis = currentMillis;
    digitalWrite(ledPin, LOW);}
                                                    // need some way to do this work once through the cycle?  END
  } */

    if ( counter != temp ) {                          // would like to display counter only if changed and not contueniously running
    Serial.println (counter);
    Serial.print (" count ");
    temp = counter;
  }
  
}
void encoder1() {                                   // reading encoder 1                  WORKS
  if (digitalRead(3) == LOW) {
    counter++;
  } else {
    counter--;
  }
}
void encoder2() {                                   // reading encoder 2                 WORKS
  if (digitalRead(2) == LOW) {
    counter--;
  } else {
    counter++;
  }

  if (counter >= 1440)                             // end of cycle start the count over    WORKS
    counter = 0;
}

What does the code do? How is that different than what you want?

trying to run a IGBT, off a digital output, for a certain amount of time, at a certain count of the encoder
right now i am having trouble understanding when or how i can insert a millis function without effecting the encoder counting

You don’t use ‘temp’ in your interrupt routines so it doesn’t have to be ‘volatile’. prevCounter is a better name and since it is only used in loop(), making it a static local is better than a global. The ‘static’ makes it keep its value between calls to loop().

You should not use Pin 1 (the Serial receive pin) for your index input.

You should briefly turn off interrupts and make a local copy of ‘counter’ in loop() so the interrupt can’t change it while you try to do math on it.

Your commented-out code contains a ‘while’ loop that will get stuck if the counter reaches 500.

When turning on the LED at 500, start a timer so you can tell if it has been on for one second.

volatile unsigned Counter = 0;


const byte IndexDIPin  = 2;


void setup()
{
  Serial.begin (9600);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(0, encoder1, RISING);
  attachInterrupt(1, encoder2, RISING);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(IndexDIPin, INPUT_PULLUP);
}


void loop()
{
  static unsigned prevCounter = 0;
  static unsigned long previousMillis = 0;


  unsigned int l_counter;
  noInterrupts();
  l_counter = Counter;
  interrupts();


  // Turn on the LED if the counter is just going from below 500 to 500 or higher
  if (prevCounter < 500 && l_counter >= 500)                               // when to do some work
  {
    digitalWrite(LED_BUILTIN, HIGH);
    previousMillis = millis();  // Start the led timer
  }


  if (digitalRead(LED_BUILTIN) == HIGH && millis() - previousMillis > 1000)
  {
    // The LED has been on for one second
    digitalWrite(LED_BUILTIN, LOW);
  }


  if (l_counter != prevCounter)                            // would like to display counter only if changed and not contueniously running
  {
    Serial.print ("counter=");
    Serial.println (l_counter);


    prevCounter = l_counter;
  }
}


void encoder1()                                     // reading encoder 1                  WORKS
{
  if (digitalRead(3) == LOW)
  {
    Counter++;
  }
  else
  {
    Counter--;
  }
}


void encoder2()                                     // reading encoder 2                 WORKS
{
  if (digitalRead(2) == LOW)
  {
    Counter--;
  }
  else
  {
    Counter++;
  }


  if (Counter >= 1440)                             // end of cycle start the count over    WORKS
    Counter = 0;
}

i was thinking the encoder A/B inputs can only go to pin 2/3?
so Z pin2, A pin3, B pin4 will run fine?

i will crunch on your edit and see what i can learn
thanks!

i was thinking the encoder A/B inputs can only go to pin 2/3?
so Z pin2, A pin3, B pin4 will run fine?

If you want to run a half resolution (what you call encoder 2X) with one interrupt pin and a standard I/O pin, you need to interrupt on CHANGE.

#define outputA 3
#define outputB 4
volatile int counter = 0;
int copy_counter;
int last_copy_counter;
volatile byte aState;
volatile byte bState;

void setup() {
  pinMode (outputA, INPUT);
  pinMode (outputB, INPUT);

  Serial.begin (115200);
  Serial.println("Starting Encoder Counts");

  attachInterrupt(digitalPinToInterrupt(3), readEncoder, CHANGE);
}
void loop() {
  noInterrupts();
  copy_counter = counter;
  interrupts();
  
  if (copy_counter != last_copy_counter)
  {
    Serial.print("Position: ");
    Serial.println(copy_counter);
  }
  last_copy_counter = copy_counter;
}

void readEncoder()
{
  aState = digitalRead(outputA);
  bState = digitalRead(outputB);
  // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
  if (bState != aState)
  {
    counter ++;
  }
  else
  {
    counter --;
  }
}

dam i think i forgot to mention to start the count only after the index is found!

does the serial monitor not show a close accuracy to what the UNO is doing.
i doubled the outputs and added in some print function to show where the action is taking place and i think there is some gap?

volatile unsigned Counter = 0;
const byte IndexDIPin  = 4;
int COP1 = 5;
int COP2 = 6;
int COP3 = 7;
int COP4 = 8;
int COP5 = 9;
int COP6 = 10;

void setup()
{
  Serial.begin (9600);
  pinMode(IndexDIPin, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  attachInterrupt(0, encoder1, RISING);
  attachInterrupt(1, encoder2, RISING);
}

void loop()
{
  static unsigned prevCounter = 0;
  static unsigned long previousMillis = 0;

  unsigned int l_counter;
  noInterrupts();
  l_counter = Counter;

  interrupts();

  if (prevCounter < 500 && l_counter >= 500)                                 // Turn on the LED if the counter is just going from below 500 to 500 or higher
  {
    digitalWrite(COP1, HIGH);
    Serial.print (" fire 1 ");
    previousMillis = millis();                                             // Start the led timer
  }
  if (digitalRead(COP1) == HIGH && millis() - previousMillis > 3)
  {
    digitalWrite(COP1, LOW);
    
  }

  if (prevCounter < 1000 && l_counter >= 1000)                                 // Turn on the LED if the counter is just going from below 500 to 500 or higher
  {
    digitalWrite(COP2, HIGH);
    Serial.print (" fire 2 ");
    previousMillis = millis();                                             // Start the led timer
  }
  if (digitalRead(COP2) == HIGH && millis() - previousMillis > 3)
  {
    digitalWrite(COP2, LOW);
    
  }


  if (l_counter != prevCounter)                                          //  display counter   WORKS
  {
    Serial.print ("counter=");
    Serial.println (l_counter);

    prevCounter = l_counter;
  }
}

void encoder1()                                                            // reading encoder 1                  WORKS
{
  if (digitalRead(3) == LOW)
  {
    Counter++;
  }
  else
  {
    Counter--;
  }
}

void encoder2()                                            // reading encoder 2                 WORKS
{
  if (digitalRead(2) == LOW)
  {
    Counter--;
  }
  else
  {
    Counter++;
  }

  if (Counter >= 1440)                             // end of cycle, start the count over    WORKS
    Counter = 0;
}

shows this when i spin the encoder as fast as my little fingers can

counter=72
counter=82
counter=105
counter=146
counter=204
counter=288
counter=396
 fire 1 counter=527
counter=732
counter=818
counter=943
 fire 2 counter=1088
counter=1392

Which encoder are you using? Do you have a datasheet for it?

yup
E6B2-CWZ6C

turbothis:
yup
E6B2-CWZ6C

https://www.ia.omron.com/data_pdf/cat/e6b2-c_ds_e_6_1_csm491.pdf?id=487

  1. Where do you get 1440 ticks indicating a full revolution?

  2. Seeing that you're firing COPs, you're running this on an engine. At 1440 ticks/rev 5000RPM is 120kHz per phase. Quadrature frequency will be 240kHz (that is, 120kHz for each phase, 90-degrees from one another.) That's 8.3uS between rising edges on A and the same for B; time between interrupts will be half that or 4.16uS.

120kHz is above the rated frequency of the the ecnoder but I don't think an Uno will keep up anyway.

i just spun it roughly one revolution and that was very close to what it showed on the monitor
i would be running this camshaft speed or even half that

What's the entire part number? It should be something like "E6B2-CWZ6C 1500P/R 0.5M".

So if you spin the engine to 6000RPM, the cam is turning 3000. Assuming you have the 1500 pulse/rev encoder, that's still 75kHz per channel (13.3uS/interrupt/channel) at max RPM.

I still think it's going to be too high a speed for an Uno using pin change interrupts and manual counting, even at much lower RPM.

Do you need that sort of resolution?

I haven't thought this through fully (so I could be full of shit) but perhaps you could repurpose TC1:

  • set up TC1 to be a counter with its source as T1 (pin 5); feed PHA of your encoder to this pin

In your program,

  • initially wait until you see the index/Z pulse; zero the counter and set your first COP output compare
  • on each OC, (a)energize the desired COP (record its time and any flags you need) and set the OC count of the next COP
  • in the mainline, look for flags set indicating COP active and have a statemachine that times the dwell using the standard millis() logic (timer 0)
  • when the index/Z interrupt occurs, reset TC1 and start all over

it is a 720 p/r encoder
just E6B2-CWZ6C

i did get one of these too. absolute encoder with binary. should do away with counting and just do something in a position???? lol
E6F-AB3C-C

ultimately i wanted 1 degree of crankshaft control. more would be alright, hence the 720 count on the camshaft.

you lost me in the bottom there.

  1. Where do you get 1440 ticks indicating a full revolution?

It appears that you are using a 720 ppr encoder with a 2 of the 4 available quadrature pulses being read. 1440/350 is .25 degree resolution.

What resolution does your firing cycles require? 1 degree, .5 degree, .25 degree?

If this is for a 6 cylinder Coil on Plug (COP) ignition system? Where is the encoder attached, and why are you reading an encoder instead of flywheel or gear sensor on the engine?

Your engine is only rotating in one direction, and there is no need to use directional encoder algorithms. You can optimize the speed by using a timer/counter in external clock source mode instead of an external interrupt based routine. You want to optimize the reading algorithm for the needs of the program.

You may also find it easier to work with time measurements from the z axis pulse instead of counts from the AB outputs. Instead of external interrupts, you may want to be working with timer interrupts.

But first, you need to describe what you are trying to achieve, what signals you have available, and the requirements of the cycle timing.

EDIT: I see that Blackfin has raised some of these same considerations.

the encoder now only have output A, B and Z. 3 wires and then power/ground
1-0.5 degrees on the crank would be nice
i have a couple CNC machines that i built and all have servo motors with encoders. i like there function
on the motor it already has an external portion of the exhaust cam to run the water pump. easy access to adapt on a little encoder
it is nice to have the encoder count backwards in case, while cranking/starting the crank stops spinning and the crank counter rotates due to compression. then the ignition position is not lost
i will read about timer interrupts. never run across this yet

with an binary input the UNO would just fire on a commanded position right?

What are the counts where you want the six COPs to turn on and in what order to the COPs turn on?

In your earlier code you had 500 and 1000 which don't seem right to me...

For example if #1 is at TDC when the index pulse occurs (so assume encoder count zeros at this point), you'd want #1 have fired at count 720 - 10 or 710 (10 is a guess at the spark advance you want...). If firing intervals are 120-degrees, then:

1 710
2 110
3 230
4 350
5 470
6 590

1 710 etc...

(not index number 1-6 are not COP numbers; that will depend on the firing order.) Also note that if your engine does not have evenly-spaced firing intervals) you'll need to account for that in the degrees...

Does the above sound about right?

on the motor it already has an external portion of the exhaust cam to run the water pump. easy access to adapt on a little encoder

How are you going to determine TDC?

cattledog:
How are you going to determine TDC?

My hope would be that he'd set the crank to TDC on #1 (compression) and then index his encoder body until the index/Z output went high (with the direction of rotation carefully considered...)

ya even 120 degree engine
i just had some random numbers to bench test it
i am trying to learn the how this works and then i can hash out the final details
i can set TDC and the first count pretty easy and adjust from there
base advance would be 10 and about 20 added to that