Go Down

Topic: Help needed with interrupts (Read 1 time) previous topic - next topic

CrossRoads

I have 4 rotary encoders driving 4 quadrature encoder chips, LS7184, that output some pulses and an up/down direction line.

I bring the pulses into the arduino on D2, D3 (INT0, 1) and D4, D5 (PCINT20, 21).
The up/down lines go in on D6, D7, D14, D15.

I have the ISRs written to set bits in a byte when an interrupt occurs. I want to send the byte out over the serial lines, or at least make an LED flash at the top of loop when I see that an interrupt bit has been set.

I can't seem to get any interrupt created tho. Looking for some help.

There are variables here that read 3 switches and an octal DAC every 5mS and send that out blink without delay style, that works great and is deleted here to meet post length.

Thanks
Code: [Select]

/* Sketch for Remote Control Transmitter board.
Set up to read from 4-channel ADC and send int values to the Receive board over the serial interface every 10mS.
2 INTs & 2 PCINT's used to detect pulses from four Quadrature Encoders and send out over the RS232 as well with direction.
Also send the state of 2 push buttons.
Octal ADC MCP3208
S3  LED on D8
SYNC LED on D9
*/
/*
Revision to use interrupts
Rewired board some:
D0 - RX - no change
D1 - Tx - no change
D2 - INT0, Optical encoder 0 clk via LS7184
D3 - INT1, Optical encoder 1 clk
D4 - PCINT20, mechanical encoder 0 clk
D5 - PCINT21, mechanical encoder 1 clk
D6 - Optical encoder 0 Up/Down
D7 - Optical encoder 1 Up/Down
D8 - S3 status from Rx card - no change
D9 - Sync status from Rx card - no change
D10 - ADC_SS - no change
D11 - MOSI - no change
D12 - MISO - no change
D13 - SCK - no change
D14 - mechanical encoder 0 Up/Down
D15 - mechanical encoder 1 Up/Down
D16 - S0 switch input - no change
D17 - S1 switch input - no change
D18 - S2 switch input - no change
D19 - not used
*/

// call libraries

#include <SPI.h>

// declare the pins used

// Port B
byte ADC_SS = 10; // SPI SS for ADC
// D11,12,13 - SPI for ADC
byte Syncpin = 9; // Sync output
byte S3pin = 8; // Switch2 output, Hi/Lo received from Serial

// Port C
byte D19 = 19; // not used
byte S2pin = 18; // Switch2 input, Hi/Lo
byte S1pin = 17; // Switch1 input, Hi/Lo
byte S0pin = 16; // Switch0 input, Hi/Lo

byte updown3 = 15;
byte updown2 = 14;

// Port D
byte updown1 = 7;
byte updown0 = 6;
byte enc_clk3 = 5;
byte enc_clk2 = 4;
byte enc_clk1 = 3;
byte enc_clk0 = 2;
// D1, D0 used by Serial

// declare variables

byte ADCsyncbyte = 0x33; // b00110011 sync byte when send ADC data
byte Encsyncbyte = 0xAA; // B10101010 sync byte when send quadrature encoder data

int ADCaddress = 0x0600;     // 600, 640, 680, 6C0, 700, 740, 780, 7C0

byte dummyADC = 0;
byte highADC = 0;
byte lowADC = 0;
int x= 0;

byte volatile quadEncoder = 0; // volatile for the interrupts

/* quadEncoder bit assigments:
BIT7 - optical encoder 1 up/down direction
BIT6 - optical encoder 0 up/down direction
BIT5 - mechanical encoder 1 pulse
BIT4 - mechanical encoder 0 pulse
BIT3 - optical encoder 1 pulse
BIT2 - optical encoder 0 pulse
BIT1 - mechanical encoder 1 up/down direction
BIT0 - mechanical encoder 0 up/down direction

Works out well for masking off & mixing in results!
*/

// other variables used in the interrupts
byte volatile dir0;
byte volatile dir1;
byte volatile dir2;
byte volatile dir3;

byte volatile p;
byte volatile oldPortD;

unsigned long previousMillis;

byte address_count;

void setup(){

 // setup the I/O pins

 pinMode (ADC_SS, OUTPUT);
 digitalWrite (ADC_SS, HIGH);

 pinMode(enc_clk0, INPUT);
 digitalWrite (enc_clk0, HIGH); // enable pullup resistor
 pinMode(enc_clk1, INPUT);
 digitalWrite (enc_clk1, HIGH); // enable pullup resistor
 pinMode(enc_clk2, INPUT);
 digitalWrite (enc_clk2, HIGH); // enable pullup resistor
 pinMode(enc_clk3, INPUT);
 digitalWrite (enc_clk3, HIGH); // enable pullup resistor

 pinMode(updown0, INPUT);
 digitalWrite (updown0, HIGH); // enable pullup resistor
 pinMode(updown1, INPUT);
 digitalWrite (updown1, HIGH); // enable pullup resistor
 pinMode(updown2, INPUT);
 digitalWrite (updown2, HIGH); // enable pullup resistor
 pinMode(updown3, INPUT);
 digitalWrite (updown3, HIGH); // enable pullup resistor

 pinMode(S0pin, INPUT);
 digitalWrite (S0pin, HIGH); // enable pullup resistor
 pinMode(S1pin, INPUT);
 digitalWrite (S1pin, HIGH); // enable pullup resistor
 pinMode(S2pin, INPUT);
 digitalWrite (S2pin, HIGH);  // enable pullup resistor
 pinMode(S3pin, OUTPUT);
 digitalWrite (S3pin, LOW);  // add new wiring to drive LED anode High when S3 on receiver is closed
 pinMode(Syncpin, INPUT);
 digitalWrite (Syncpin, LOW);  // add new wiring to drive LED anode High when Sync message from receiver is returned

 // free pin  
 pinMode (D19, INPUT);
 digitalWrite (D19, HIGH);  

 PCMSK2 = _BV (PCINT4) | _BV (PCINT5); // want pins 20, 21  >> PCMSK2 is port D

 PCIFR = _BV (PCIF2) ;  // Clear any existing interrupts

 PCICR |= _BV (PCIE2) ; // enable pin change interrupts for PCINT20,21  on port D

 // Open Serial interface
 Serial.begin (115200);
 // Open SPI interface
 SPI.begin (); // leave blank, we are master

}  // end void setup
/*
>  1  Reset
>  2  External Interrupt Request 0  (pin D2)          (INT0_vect)
>  3  External Interrupt Request 1  (pin D3)          (INT1_vect)
>  6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)
*/

// ISRs for Hardware interrupts

// Hardware interrupt 0

ISR (INT0_vect) //
{
 // optical encoder 0 pulse
 dir0 = PORTD & B01000000;  // 40
 quadEncoder = quadEncoder  | B00000100 | dir0; // 04
}

// Hardware interrupt 1

ISR (INT1_vect) //
{
 // optical encoder 1 pulse
 dir1 = PORTD & B10000000; // 80
 quadEncoder = quadEncoder | B0001000 | dir1; // 08
}

// PCINTs for mechanical encoders 0 & 1
ISR (PCINT2_vect)  // PCINT2 for port D
{
 byte p = PORTD;
 // mechanical encoder 0 pulse
 if ((p & 0x10) != (oldPortD & 0x10))  
 {
   // portD4, PCINT20, has changed
   dir2 = PORTC & B00000001; // 01
   quadEncoder = quadEncoder | B00010000 | dir2; // 10
 }
 // mechanical encoder 0 pulse
 if ((p & 0x20) != (oldPortD & 0x020))
 {
   // portD5, PCINT21, has changed
   dir3 = PORTC & B00000010; // 02
   quadEncoder = quadEncoder | B00100000 | dir3; // 20
 }

 // remember for next time
 oldPortD = p;

} // end of PCINT2_vect

/*
Watch for an encoder clock pulse, if a pulse occurs then capture that in the ISR with the direction, and at the top of loop set the bits/direction for any of the four that occurred and RS232 message.

On the receive side, set the output bits accordingly & clear.
Change the bias resistor on the LS7184s to shorten up the pulses that create the interrupt, currently around 25uS.

*/

void loop(){

 // send out quad encoder data if any occured
 if ((quadEncoder & B00111100) !=0){

   // serial.println for serial monitor testing
   // serial.write for actual use
   Serial.println (Encsyncbyte, HEX); // syncbyte = B10101010, 0xAA
   Serial.println (quadEncoder, HEX);
   quadEncoder = quadEncoder & B11000011;  // clear the interrupt bits
 }
 /* added to make sure loop was running
 else{
       digitalWrite (Syncpin, HIGH);
   delay (50);
   digitalWrite (Syncpin, LOW);
   delay (50);}
   */

 // Split up for DAC & INT responses?    
 if (Serial.available()>0){                          
   digitalWrite (Syncpin, HIGH);                    // show receive comimg back
 }
 else {
   digitalWrite (Syncpin, LOW);
 }


} // end void loop

Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

bubulindo

#1
Apr 16, 2012, 07:21 am Last Edit: Apr 16, 2012, 07:38 am by bubulindo Reason: 1
I don't see the interrupt configuration for INT0 and INT1. And I think that by default the interrupt is triggered on low level. How fast is the encoder moving?
Try adding
Code: [Select]
EIMSK = 3; to your startup code maybe?

Were those the ones missing? Or you can't get any interrupt going?

This may have to do with the Arduino, but I normally call sei(); to enable interrupts. I think Arduino does that for you, but I am not 100% sure. It does.

Have you tried stripping down the code to the bare minimum to see if this is caused by any object?
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

CrossRoads

I saw this in someone else's code - maybe need to add to top of the sketch:

#include <avr/interrupt.h>
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

CrossRoads

From what I've seen with a scope, the encoder chip (LS7184) (and there are 4 of them) can put out a pair of pulses maybe 1mS apart or so when its spun really fast by hand (like snapping the shaft in your fingers fast). They are intended to have manually controlled wheels on them for steering, controlling a motor, that kind of thing on the far end, so not determining the speed say of a continually rotating shaft.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

CrossRoads

#4
Apr 16, 2012, 09:41 pm Last Edit: Apr 16, 2012, 09:45 pm by CrossRoads Reason: 1
Just found this PCINT library, with testing showing speed of operation, by Michael Schwager/GreyGnome.

http://code.google.com/p/arduino-pinchangeint/

Gonna check it out tonight.

This playground article seems to be based on the same:

http://arduino.cc/playground/Main/PinChangeIntExample
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kf2qd

You would be better off using just a pulse or 2  (depending on shaft speed) to determine speed. You need some time to elapse between pulses to determine speed. You would be better off using multiple AVR chips, 1 for each axis, to do something like this because you have no way of controlling when the interrupts are routed to the program, and thus you might have overlapping interrupts that are not processed properly.  Multiple smaller chips reporting to a larger controller chip - several of the tiny series chip, with a 328 as the master.

You can work out the programming on the arduino - just do it for 1 axis. Then program a slave chip and a 328 (Arduino) to communicate and then add slave devices. I used some ATtiny2313 chips for a project, less than $3.00US and the operation is simplified.

Think of it as distibuted processing. A complex set of operations, broken down into simpler blocks, and combined to do the complex operation.

Typically, in larger systems these types of operations were done by specialized hardware and the results pulled from that hardware as needed. With individula AVR's you can do the same thing, but with much smaller boards.

bubulindo

The avr/interrupt.h is needed on top of the code, but since you had declared the interrupt vectors and compiled I don't think that is the problem.

I'll have another look later on.
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

CrossRoads

Will be sending Pulse & direction to this card via serial link, recreating the pulse on the far end:
IBL2403
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Go Up