Go Down

Topic: Missing pulses in fast speeds although using interrupts (Read 639 times) previous topic - next topic

gclu

Hi all,

this is my project ( arduino uno, gear dc motor and encoder feedback, position control, display on LCD );

http://g1303.hizliresim.com/17/n/l8pjc.jpg
http://g1303.hizliresim.com/17/n/l8ppf.jpg
http://g1303.hizliresim.com/17/n/l8pqw.jpg

and this is entire code;

Code: [Select]

#include <LiquidCrystal.h>


const int analogInPin = A0;  //speed control with pot
const int analogOutPin = 9;
const int analogInPin1 = A1; //diection control with pot
const int in1 = 4;
const int in2 = 5;

#define encoder0PinA  2
#define encoder0PinB  3

int encoder0Pos = 0;


int analog = 0;
int analog1 = 0;       
int cikis = 0;
int yon = 0;
int buton = 0;
int in1d=0;
int in2d=0;
int ekran=0;
char ekr[4];
int a=0;

LiquidCrystal lcd(12, 11, 7, 6, 10, 8);

void setup() {
 
  Serial.begin(9600);
   lcd.begin(16,2);
  pinMode(in1,OUTPUT);
  pinMode(in2,OUTPUT);

pinMode(encoder0PinA, INPUT);
       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
       // turn on pullup resistor

  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2

  Serial.println("start");                // a personal quirk



}




void loop() {
 

 
  in1d=digitalRead(in1);
  in2d=digitalRead(in2);
 
  analog1=analogRead(analogInPin1);
  yon = map(analog1, 0,1023,0,255);
  analog=analogRead(analogInPin);
  cikis = map(analog, 0, 1023, 0, 255); 

  analogWrite(analogOutPin, cikis);
 

 

if (analog1 < 300 )
{
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
}

if (analog1 > 600 )
{
  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
}

if (analog1 > 300 && analog1 <600 && in1d==LOW && in2d==HIGH )
{
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
  delay(100);
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);
}

if (analog1 > 300 && analog1 <600 && in1d==HIGH && in2d==LOW )
{
  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
  delay(100);
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);
}


if (buton == HIGH )
{
if (in1d==LOW && in2d==HIGH )
{
  digitalWrite(in1,HIGH);
  digitalWrite(in2,LOW);
  delay(100);
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);


}

if (in1d==HIGH && in2d==LOW )
{
  digitalWrite(in1,LOW);
  digitalWrite(in2,HIGH);
  delay(100);
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);



 
}

lcd.setCursor(0,0);
lcd.print(encoder0Pos);
delay(1);



}


void doEncoder() {

  if (digitalRead(encoder0PinB) == HIGH ) {
    if (in1d==LOW && in2d==HIGH) {
    encoder0Pos++;
    }
    else
    {
    encoder0Pos--;
    }
   
  }
   
  Serial.println (encoder0Pos);


}



Problem is when I feed the motor about 5V I have 180 pulse per revolation and lover voltages too. But when I feed the motor 12V I see only 18-19 pulse on the lcd and serialmonitor and than it stops the counting.

I see healty pulses on the oscilloscope. It is about 300khz 12V feeding

I don't have any knowledge about clock cycle or perscale. But I think don't need any changing cause it have to enough speed with interrupts to count correct.

But I haven't try any feeding between 12..5 yet.

Please help If you have any idea immediately.

Thanks


PaulS

Serial.print() inside an ISR is a bad idea.

Variables shared between ISR and other functions need to be volatile.

gclu

Thank you very much I moved serial.print void loop and now I have about 140 pulse per revolation but it have to be 180. If I use volatile int I can't write it LCD and what can I do else ?

holmes4

Quote
If I use volatile int I can't write it LCD and what can I do else ?


What?

Mark

PeterH

Obviously you will take the Serial.println() out of the interrupt and make encoderPos, in1d and in2d volatile.

You seem to be combining an interrupt with two digital reads that are done in loop().

I don't if that makes sense at all, but it makes me wonder how often you expect in1 and in2 to change state and what would happen if an interrupt occurred while they were changing.
I only provide help via the forum - please do not contact me for private consultancy.

gclu

Holmes4 and PeterH firstly thanks for your interest,


My older problem was type of my encoder.

http://robotus.net/wp-content/uploads/2012/07/manyetik-encoder-forceup.jpg

This is not usual rotary encoder. So, I tried a lot of example in Arduino Rotary Encoder Library. One of them was this code below.


Code: [Select]


/* read a rotary encoder with interrupts
   Encoder hooked up with common to GROUND,
   encoder0PinA to pin 2, encoder0PinB to pin 4 (or pin 3 see below)
   it doesn't matter which encoder pin you use for A or B 

   uses Arduino pullups on A & B channel outputs
   turning on the pullups saves having to hook up resistors
   to the A & B channel outputs

*/

#define encoder0PinA  2
#define encoder0PinB  4

volatile unsigned int encoder0Pos = 0;

void setup() {


  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor

  attachInterrupt(0, doEncoder, CHANGE);  // encoder pin on interrupt 0 - pin 2
  Serial.begin (9600);
  Serial.println("start");                // a personal quirk

}

void loop(){
// do some stuff here - the joy of interrupts is that they take care of themselves
}

void doEncoder() {
  /* If pinA and pinB are both high or both low, it is spinning
   * forward. If they're different, it's going backward.
   *
   * For more information on speeding up this process, see
   * [Reference/PortManipulation], specifically the PIND register.
   */
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
    encoder0Pos++;
  } else {
    encoder0Pos--;
  }

  Serial.println (encoder0Pos, DEC);
}




When I use this code, I had confused but a kind of order numeric results like that;

-1
0
1
0
-1
0
1
0
-1
...

It seems like logical step like,
http://upload.wikimedia.org/wikipedia/en/6/68/Quadrature_Diagram.svg

I couldn't find anything to solve the problem, so I decieded to use only one channel.

And It works! But,

And than, new problem was I couldn't write the "encoder0Pos" to LCD 16x2 if I identify like "volatile unsigned int encoder0Pos = 0;".

Altough, I try a few type of conversation such as "itoa(x,encoder0Pos,10)" "itoa(x,encoder0Pos,16)" , it was not work.
So, I use only "int encoder0Pos = 0;". This is why I don't use volatile.

I hope I explained problems understandable.

Now I got only about %20 missing pulses per revolation, thanks to Paul. But it isn't acceptable mistake.

Thank a lot again.
Yours faithfully

gclu

In addition for PeterH,

In1 and In2 is driver carriers pins.

http://thumbnails.inkfrog.com/pix/noodlehed/l298_module3.jpg/596/0

ena--->pwm

and

If in1 high and in2 low motor turning clockwise rotation and if else else..

So, I don't compare two channel to relize rotation of the turning. I read In1 and In2 outputs value to understand rotation.

PaulS

Quote
And than, new problem was I couldn't write the "encoder0Pos" to LCD 16x2 if I identify like "volatile unsigned int encoder0Pos = 0;".

Why not? That is the question that you didn't answer. Fancy footwork, though.

What happens when you call lcd.print(encoder0Pos); when encoder0Pos is properly declared volatile? Does nothing print? Or, do you get some kind of compiler error?

gclu


Quote
And than, new problem was I couldn't write the "encoder0Pos" to LCD 16x2 if I identify like "volatile unsigned int encoder0Pos = 0;".

Why not? That is the question that you didn't answer. Fancy footwork, though.

What happens when you call lcd.print(encoder0Pos); when encoder0Pos is properly declared volatile? Does nothing print? Or, do you get some kind of compiler error?


I saw on the LCD confused characters like chinese alfabet. But I saw changes as the same time pulses. Moreover, although I write codes like "lcd.setCursor(0,0);" it shows that confused characters at (0,8) and (0,9).

PaulS

Quote
I saw on the LCD confused characters like chinese alfabet. But I saw changes as the same time pulses. Moreover, although I write codes like "lcd.setCursor(0,0);" it shows that confused characters at (0,8) and (0,9).

I know it's hard to type with your hands in your pockets, but just waving your hands is not productive.

"When I used this code:
Code: [Select]
some code goes here
I see this on the LCD:
<an image goes here>
Does anyone have any idea why?"
is a much more useful thing to do.

michinyon

The lcd function might not like the "volatile" variable.

The suggested solution would be to have the "volatile" variable which the interrupt scheme requires,   and
to capture the value of that variable into another, non-volatile, variable just before calling the LCD function.

gclu

PaulS I will add photos and codes in a few day.

Michinyon, I try that you say, but as I said, if I able to write volatile unsigned int it is not enough also there is a problem that I couldn't compare two channel with rotary encoder libraries cides

Grumpy_Mike

Quote
The lcd function might not like the "volatile" variable.

No there is nothing wrong with declaring a variable volatile, it will not affect how it is used in any other call.

PeterH


I saw on the LCD confused characters like chinese alfabet.


This probably indicates either that your method of formatting the unsigned int to a string was incorrect, or that the volatile int was being updated by the ISR while you were using it - or perhaps both. The safe way to use the volatile variable from your main code would be to disable interrupts long enough to copy it to a local variable, and then use that.

In order to get more practical advice about the problem, you'd need to post your actual code and say what it did wrong.
I only provide help via the forum - please do not contact me for private consultancy.

afremont

Sounds like EMI to me, as the motor speed increases it becomes a problem.  Do you have any noise suppression on the motor?  Are you trying to run the motor off of the arduino board's 5V supply?
Experience, it's what you get when you were expecting something else.

Go Up