Why my arduino fails to work after some time

HI,
below i have given my code for arduino uno the algorithum is simple read the encoder output and switch on two pins on and off as fast as possible . the problem is the uno was working properly suddenly the uno fails to work at proper timing , what may be the reason?
this code was built with help of @cattledog @StefanL38

const char  encTable[16] = {0, 1, -1, 0, -1, 0, -0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; //gives -1, 0 or 1 depending on encoder movement
volatile long encoderCount;
long copyEncoderCount; // add new transfer variable
volatile long errorCount;
volatile byte encState;

const byte zAxisPin = 2;
volatile boolean zTrigger = false;
volatile long cycleCount = 0;
int led1 = A0;//sol 1-intake
int led2 = A1;//sol 2-exhaust



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

  pinMode(9, INPUT_PULLUP ); //output A
  pinMode(8, INPUT_PULLUP ); //output B
  pinMode(2, INPUT_PULLUP ); //z axis
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);


  attachInterrupt(digitalPinToInterrupt(zAxisPin), cycleStart, FALLING);//maybe RISING
  //Enable pin change interrupts on pins 8 and 9 PB 0 and 1
  PCICR |= (1 << PCIE0); //enable group interrupts on PORTB PCINT[7:0]
  PCMSK0 |= (1 << PCINT0); //enable interrupt pin 8
  PCMSK0 |= (1 << PCINT1); //enable interrupt pin 9
}

void loop ()
{

  if (zTrigger)
  {
    zTrigger = false;
    Serial.println(cycleCount);
  }

  noInterrupts();
  copyEncoderCount = encoderCount;
  interrupts();

  /*if (copyEncoderCount == 0)
    {
    //digitalWrite(led1, 0);
    // digitalWrite(led2, 0);
    PORTC = B00000000;



    }*/
  if ((copyEncoderCount >= 700 ) && (copyEncoderCount <= 1000 ))
  {
    //digitalWrite(led1, 200);
    PORTC = B00000001;


  }
  else if ((copyEncoderCount >= 1200 ) && (copyEncoderCount <= 5000 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;
  }
  else if ((copyEncoderCount >= 0 ) && (copyEncoderCount <= 600 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;



  }/*
   else if  ((copyEncoderCount >= 1100  ) && (copyEncoderCount < 5000 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;



  }*/
  else
  {
    //digitalWrite(led1, 0);
    //digitalWrite(led2, 0);
    PORTC = B00000000;
    PORTC = B00000000;


  }

}
ISR (PCINT0_vect)
{
  encState = ((encState << 2) | ((PINB) & B00000011)) & B00001111; //use encoder bits and last state to form index
  encoderCount += encTable[encState];//update actual position on encoder movement
  if (encTable[encState] == 0)
    errorCount++;
}

void cycleStart() //isr for z axis pulse
{
  cycleCount = encoderCount;
  encoderCount = 0;
  zTrigger = true;
}

Whenever I use encoders I use this library

I never had any problems with using this library.

But I can't tell in your case how you would have to adapt your code. Because you haven't described the overall functionality and the main purpose of your code

best regards Stefan

What do you mean by "timing", and and how do you know the timing is not correct? Have you used an oscilloscope to look at certain signals?

If the code has been working reliably and you have not changed it, then the problem is typically in the hardware supplying the inputs or receiving the outputs. Or the connections of that hardware to the uno. Failure of the uno itself is possible but less likely.

Have you changed anything?

Posting schematics, not toy Fritzings, would help.
No properly powered is often the reason for failures like that.

thank you @Railroader @StefanL38 @cattledog let me check the hard ware and power completely ,
and i have a new simple algorithum for same process i will write the code to my best and reach you
please help me in improving it.

improved algorithm:

virtualised virtually code    

this is how i want my code to work

the program will start working only when you get low/ high signal in digital pin 2

it will start count in milli seconds till it get another low signal in dig pin two

as soon as when it gets second pulse it will reset the milli second counts and stores the value
(simply calculating rpm )

using value from millisecond count ( eg 100 ms)

100 ms / 100 (constant value never changes)
= 1 (ans )

ans (1)* diff(10) ( value given by user in a variable in program eg int diff = 10; )
= 10 (off ans)

take another variable eg int start time = 4.15 (pre determined changed if need by programer for testing diff values or timing )

start time - off ans = delay

10 - 4.15 = 5.85(delay )

this calculation and milli reset will happen for every z pulse and delay will be up dated and the analog pin 0 will go high after 5.85 ms(value of delay ) from zpulse

and the analog pin will be high for certain timing that will be caculated by

ans (from mills / 100) * on time (prederemined valvue from variable eg int ontime = 15)
= timing for A0 on period (after this period anolog pin 0 go low )

1 * 15 = 15 ms (time period for analog pin to stay high )

so using a single pulse i am calculating on delay and of timing of my output
i say analog pin because for using port on / of insted of analogwrite for fast response

const char  encTable[16] = {0, 1, -1, 0, -1, 0, -0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; //gives -1, 0 or 1 depending on encoder movement
volatile long encoderCount;
long copyEncoderCount; // add new transfer variable
volatile long errorCount;
volatile byte encState;


const byte zAxisPin = 2;
volatile boolean zTrigger = false;
volatile long cycleCount = 0;
int led1 = A0;//sol 1-intake
int led2 = A1;//sol 2-exhaust



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

  pinMode(9, INPUT_PULLUP ); //output A
  pinMode(8, INPUT_PULLUP ); //output B
  pinMode(2, INPUT_PULLUP ); //z axis
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);


  attachInterrupt(digitalPinToInterrupt(zAxisPin), cycleStart, FALLING);//maybe RISING
  //Enable pin change interrupts on pins 8 and 9 PB 0 and 1
  PCICR |= (1 << PCIE0); //enable group interrupts on PORTB PCINT[7:0]
  PCMSK0 |= (1 << PCINT0); //enable interrupt pin 8
  PCMSK0 |= (1 << PCINT1); //enable interrupt pin 9
}

void loop ()
{

  if (zTrigger)
  {

    zTrigger = false;
    Serial.println(cycleCount);


  }

  noInterrupts();
  copyEncoderCount = encoderCount;
  interrupts();

  /*if (copyEncoderCount == 0)
    {
    //digitalWrite(led1, 0);
    // digitalWrite(led2, 0);
    PORTC = B00000000;



    }*/
  if ((copyEncoderCount >= 700 ) && (copyEncoderCount <= 1500 ))
  {
    //digitalWrite(led1, 200);
    PORTC = B00000001;


  }
  else if ((copyEncoderCount >= 1600 ) && (copyEncoderCount <= 5000 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;
  }
  else if ((copyEncoderCount >= 0 ) && (copyEncoderCount <= 600 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;



  }/*
   else if  ((copyEncoderCount >= 1100  ) && (copyEncoderCount < 5000 ))
  {
    // digitalWrite(led2, 255);
    PORTC = B00000010;



  }*/
  else
  {
    //digitalWrite(led1, 0);
    //digitalWrite(led2, 0);
    PORTC = B00000000;
    PORTC = B00000000;


  }

}
ISR (PCINT0_vect)
{
  encState = ((encState << 2) | ((PINB) & B00000011)) & B00001111; //use encoder bits and last state to form index
  encoderCount += encTable[encState];//update actual position on encoder movement
  if (encTable[encState] == 0)
    errorCount++;
}

void cycleStart() //isr for z axis pulse
{
  cycleCount = encoderCount;
  encoderCount = 0;
  zTrigger = true;
}

THIS IS THE CODE NOW I am playing with,this code is two rean a incremental rotary encoder and reply switch on off two pins based on the value

in this i like to calculate the rpm using z pulse , by using micros() to count time inbetween two z pule and i will switch on and off pins as per the rpm values

User-Manual-Orange-3806-OPTI-600-AB-OC-Rotary-Encoder-ROBU.IN_ (1).pdf (672.6 KB)

Hi Chitra,

OK you wrote some explanation. But I don't undestand it yet

What is "ans"?

What does ans(1) * diff(10) mean??

What does "= 10 (off ans)" mean???

No idea what you want to tell with

"and the analog pin will be high for certain timing that will be caculated by

ans (from mills / 100) * on time (prederemined valvue from variable eg int ontime = 15)

you tried to be fast in explaining. And all that happened is slowing everything down because
now you have to explain in more detail again.

If you enjoy a ping-pong game of 20 rounds of short answers and new questions you can have this.
If you are really interested in proceeding forward effectively take time to describe in detail and in an easy to understand way what you want.

write down a full example with example numbers.
Best way to understand would be a timing diagramm that shows how all involved IO-pins change their state.

Second best way would be to describe with more than just shortnames like "ans", "diff"
what each number means.
And yes I'm very aware of that this will take 30 to 60 minutes extra time to think it through what is an easy to understand name for each variable that describe down to the point what the purpose of the variable is.

best regards Stefan

the problem is the uno was working properly suddenly the uno fails to work at proper timing

Is this statement no longer correct? Have you resolved what issues there were, and now want to proceed with determining rpm?

This is fairly straightforward. From your previous posting I understand that you are a student. Writing code for you without seeing any attempt at a solution from you is not what happens on this forum. What have you tried?

Is your issue with determining the rpm, or do you not know how to code the outputs once you know the rpm?

Sorry for the inconvenience , let me make it simple , leave all the extra calculations

there is z phase in my encder which gives one pulse for each rotation .

so, now i like to calculate the time for each rotation using time between two z pulse

lets assume it takes 100 milliseconds(time between two z pulse ) for each rotation , so 100/360=0.28 ms, time taken to rotate one degree = 0.28 ms

now i have a valve which takes 5ms seconds to switch on, i need the valve to switch on at 30 degrees of crank position
( crank a circular wheel )
and my z pulse happens at 0 degrees of crank position

thus the angle difference between the zpulse and valve on position is 30 degree

now 30 (angle difference ) * 0.28(time taken to travel one degree) = 8.4 ms time taken to reach valve on position from zpulse position

8.4 (time taken to reach valve on position from zpulse ) - 5(time taken to switch on valve )= 3.4 ms

so the output pin must go high after 3.4 ms from z pulse so that my valve will switch on properly at 30 degrees based on the rotation speed of the crank

if rpm increase or decrease program will calibrte itself to switch on valve at proper time

and i want the valve to switch on for 10 degrees , 10 *0.28=2.8 ms
so the ouput pin should go low after 2.8 ms from from valve on position .

You can add three new global variables like this

volatile unsigned long triggerTime;
volatile unsigned long lastTriggerTime;
unsigned long pulseInterval;

Then the zAxis pulse isr could look like this

void cycleStart() //isr for z axis pulse
{
  //keep track of triggerTime
  lastTriggerTime = triggerTime;
  triggerTime = micros();
  //cycleCount = encoderCount;//not necessary,debug check, always 4096
  encoderCount = 0;
  zTrigger = true;
}

and the zTrigger conditional in loop

if (zTrigger)
  {
    zTrigger = false;
    noInterrupts();
    pulseInterval = triggerTime - lastTriggerTime;
    interrupts();
  }

Then use pulseInterval to calculate your offsets. It is in microseconds.

In my opinion, your tracking of cycleCount is not necessary. If you haven't debugged the encoder and the encoderCount to the point where you know that you count 4096 for every z axis pulse, then you need to get past this point and not keep checking that something has gone wrong with the hardware. It will just slow down and complicate time sensitive code.

thank you for the help ,and the problem here is crank will not run at same speed every time
even though i know it is 4096 pulse per revolution , i will not be able to switch on the valve at proper time , the reason is the valve that i use takes 5ms to switch on completely, for eg if i want the valve to switch on at count of 700 i should switch on the valve 5ms before reaching 700 this 5ms should be calibrated based on the rpm of the crank,otherwise if i program the valve to switch on at count of 500 it will switch on at count of 700 at particular speed if the speed increses or decrecse then the valve will not switch on at count of 700 so i need the the valve to to switch on properly based on the rpm of the the previous rotation

I completely understand. You asked for help with code which measured the period between zAxiz pulses. I have given you that in reply #12. Does it not give you enough to patch into your code? What more do you need?

volatile unsigned long triggerTime;
volatile unsigned long lastTriggerTime;
unsigned long pulseInterval;
unsigned long perdegree;
unsigned long offset;
unsigned long ontime;
const byte zAxisPin = 2;
volatile boolean zTrigger = false;
volatile long encoderCount;
void setup()
{
  Serial.begin(115200);


  pinMode(A0, OUTPUT);
  pinMode(2, INPUT_PULLUP ); //z axis


  attachInterrupt(digitalPinToInterrupt(zAxisPin), cycleStart, FALLING);//maybe RISING
  //Enable pin change interrupts on pins 8 and 9 PB 0 and 1
  PCICR |= (1 << PCIE0); //enable group interrupts on PORTB PCINT[7:0]

}

void loop ()
{
  if (zTrigger)
  {
    zTrigger = false;
    noInterrupts();
    pulseInterval = triggerTime - lastTriggerTime;
    interrupts();
    perdegree = pulseInterval / 360;
    offset = perdegree * 30 ;//"30" angle between zpulse and valve on position
    ontime = 10 * perdegree; // 10 - valv on time in degree
    delay(offset);
    PORTC = B00000001;
    delay(ontime);
    PORTC = B00000000;



  }
}
void cycleStart() //isr for z axis pulse
{
  //keep track of triggerTime
  lastTriggerTime = triggerTime;
  triggerTime = micros();
  //cycleCount = encoderCount;//not necessary,debug check, always 4096
  encoderCount = 0;
  zTrigger = true;
}

THIS the code edited , it will take some time for me to test with hard ware.

 perdegree = pulseInterval / 360;
    offset = perdegree * 30 ;//"30" angle between zpulse and valve on position
    ontime = 10 * perdegree; // 10 - valv on time in degree
    delay(offset);
    PORTC = B00000001;
    delay(ontime);
    PORTC = B00000000;

I previously told you that pulseInterval was in microseconds. You appear to be trying to use it to create a millisecond delay times. You will need to divide by 1000 or else work in microseconds.

ok understood i thought even it is micro seconds the arduino can make delay

perdegree = (pulseInterval/1000) / 360;
offset = perdegree * 30 ;//"30" angle between zpulse and valve on position
ontime = 10 * perdegree; // 10 - valv on time in degree
delay(offset);
PORTC = B00000001;
delay(ontime);
PORTC = B00000000;

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.