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;
}
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
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.
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.
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
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.
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 .
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?
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.