Rotationsgeschwindigkeit mit Hall-Sensor messen

Hallo Zusammen,

ich versuche gerade mit einem Arduino Uno und dem BLDC-Motor Nidec 24H677H010 die Rotationsgeschwindigkeit des Rotors auszulesen. Dazu verwende ich einen externen Interrupt und habe leider das Problem, dass mein Sensorwerte vom Hallsensor nicht im Programm ankommen.
Könnt ihr mir sagen, was ich falsch mache bzw. warum ich keine Werte erhalte?

Nachstehend mein aktueller Code:

#include <MsTimer2.h>       // Internal Timer2 for ISR Routine
#include <PinChangeInterrupt.h> // Create external interrupts
#include <MPU6050.h>      // MPU6050 library
#include <Wire.h>        // IIC communication library
#include <PWM.h>        // Require Timer1 PWM frequency of 20Khz-25Khz for Nidec 24H677 BLDC Motor

//************** Nidec 24H677H010 BLDC Motor Variablen ****************
const int nidecDirection = 8;         // CW/CCW Drehrichtung
const int nidecBrake = 7;             // Bremse
const int nidecPWM = 6;               // Nidec Motor PWM

///////// Anfang der Integrated Service Routine ISR Zahler Variablen ////////
#define nidecHalleffect 4  // Externer Interrupt für Nidec FG  Ausgang 6 Impulse/Umdrehung
volatile long countHall = 0;// Zählt die Pulse des Hall Encoders
////////////////// Ende der Integrated Serivce Routine ISR Zähler Variablen//

void setup() {

  //Nidec Motor Control Pins
  pinMode(nidecDirection,OUTPUT);
  pinMode(nidecPWM,OUTPUT);
  pinMode(nidecBrake, OUTPUT);
  pinMode(nidecHalleffect, INPUT);  //Input für Halleffect
  
  // Initialer Zustand
  digitalWrite(nidecDirection,LOW);
  analogWrite(nidecPWM,0); // No PWM Signal
  digitalWrite(nidecBrake,HIGH); //Bremse an
  
  Serial.begin(9600);
}



void loop() {
  //Externer Interrupt: Für Messung der Motorgeschwindigkeit
  attachPinChangeInterrupt(nidecHalleffect, Code_Hall, CHANGE);  
}



void Code_Hall() 
{
  countHall ++;
  Serial.print("Count Hall ="); 
  Serial.println(countHall);
} 

1) Welche Hardware hast Du?
2) Serial Ausgaben in der Interruptroutine sind tödlich. Die gehören dort nicht hin.
Kontrolliere in loop ob sich der Zähler verändert hat und gib dann die Infos aus.

Prinzipiell gibt es 2 Ansätze um Drehzahl zu messen: Bei langsamer Drehzahl die Zeit zwischen 2 Impulsen messen (Flanke); bei schneller Drehzahl die Impulse in einem gewissen Zeitintervall messen.
Grüße Uwe

Der UNO hat die Interrupteingänge 0 und 1 auf den Pins 2 und 3. Auch andere Pins sind Interrupfähig, müssen aber anders angesprochen werden und die Kontrolle welcher Pin wieso ausgelöst hat mußt Du auch übernehmen.

Bitte lies Dir mal das durch: attachInterrupt() - Arduino Reference

Grüße Uwe

Hallo Uwe,

danke für die Rückmeldung. Ich habe jetz den Code angepasst und den Pin 2 genutzt, Sowie die Serielle Ausgabe in die Loop verschoben

#include <MsTimer2.h>       // Internal Timer2 for ISR Routine
#include <PinChangeInterrupt.h> // Create external interrupts
#include <MPU6050.h>      // MPU6050 library
#include <Wire.h>        // IIC communication library
#include <PWM.h>        // Require Timer1 PWM frequency of 20Khz-25Khz for Nidec 24H677 BLDC Motor

//************** Nidec 24H677H010 BLDC Motor Variablen ****************
const int nidecDirection = 8;         // CW/CCW Drehrichtung
const int nidecBrake = 7;             // Bremse
const int nidecPWM = 6;               // Nidec Motor PWM

///////// Anfang der Integrated Service Routine ISR Zahler Variablen ////////
#define nidecHalleffect 2  // Externer Interrupt für Nidec FG  Ausgang 6 Impulse/Umdrehung
volatile long countHall = 0;// Zählt die Pulse des Hall Encoders
////////////////// Ende der Integrated Serivce Routine ISR Zähler Variablen//

void setup() {

  //Nidec Motor Control Pins
  pinMode(nidecDirection,OUTPUT);
  pinMode(nidecPWM,OUTPUT);
  pinMode(nidecBrake, OUTPUT);
  pinMode(nidecHalleffect, INPUT);  //Input für Halleffect
  
  // Initialer Zustand
  digitalWrite(nidecDirection,LOW);
  analogWrite(nidecPWM,0); // No PWM Signal
  digitalWrite(nidecBrake,HIGH); //Bremse an
  
  Serial.begin(9600);
}



void loop() {
  //Externer Interrupt: Für Messung der Motorgeschwindigkeit
  attachPinChangeInterrupt(nidecHalleffect, Code_Hall, CHANGE);  
  Serial.print("Count Hall ="); 
  Serial.println(countHall);
}



void Code_Hall() 
{
  countHall ++;
  } 

leider noch keine Besserung. Weiterhin gibt der Serielle Monitor "Count Hall = 0" aus

Schmeiß mal alle Bibliotheken raus die es nicht braucht (praktisch alle). Den Motor kannst Du für die Programmierung der Interrupterkennung auch manuell drehen.

 attachPinChangeInterrupt(nidecHalleffect, Code_Hall, CHANGE);  

Ist falsch. Für Pin 2 mußt Du 0 einsetzen. Die Referenz rät folgendes:

attachInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE);  

CHANGE: Brauchst Du bei der steigenden und fallenden Flanke einen Interrupt? praktisch 2 Interrupts pro Impuls?
Grüße Uwe

[EDIT] Fehler bei attachInterrupt ausgebssert. Stand vorher

attachPinChangeInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE); 
``` da.
Uwe

Hallo,
in deinem ersten Sketch, hast Du da eine Serielle Ausgabe bekommen , bzw ist die ISR bearbeitete worden, wurde der Eingang überhaupt erkannt.
Mal ganz normal den Sensor auf einen Eingang legen und damit die TestLED ansteuern , oder eine Serielle Ausgabe machen.

Zur Übergabe der Variablen aus der ISR solltest du noch den Interrupt abschalten , oder das in einem atomic Block umladen.

Heinz

Hallo
gerade gesehen
kenne ich nicht und mein Compiler bockt, muss aber gestehen ich hab die libs oben alle weggelassen.
siehe #3
lesen kannst Du sicher selber

Heinz

Ich habe wie vorgeschlagen jetzt auch die Bibliotheken rausgeworfen und auf "attachInterrupt" geändert.
Leider immer noch die gleiche Ausgabe...

#include <Wire.h>        // IIC communication library
#include <PWM.h>        // Require Timer1 PWM frequency of 20Khz-25Khz for Nidec 24H677 BLDC Motor

//************** Nidec 24H677H010 BLDC Motor Variablen ****************
const int nidecDirection = 8;         // CW/CCW Drehrichtung
const int nidecBrake = 7;             // Bremse
const int nidecPWM = 6;               // Nidec Motor PWM

///////// Anfang der Integrated Service Routine ISR Zahler Variablen ////////
#define nidecHalleffect 0  // Externer Interrupt für Nidec FG  Ausgang 6 Impulse/Umdrehung
volatile long countHall = 0;// Zählt die Pulse des Hall Encoders
////////////////// Ende der Integrated Serivce Routine ISR Zähler Variablen//

void setup() {

  //Nidec Motor Control Pins
  pinMode(nidecDirection,OUTPUT);
  pinMode(nidecPWM,OUTPUT);
  pinMode(nidecBrake, OUTPUT);
  pinMode(nidecHalleffect, INPUT);  //Input für Halleffect
  
  // Initialer Zustand
  digitalWrite(nidecDirection,LOW);
  analogWrite(nidecPWM,500); // No PWM Signal
  digitalWrite(nidecBrake,HIGH); //Bremse an
  
  Serial.begin(9600);
}



void loop() {
  //Externer Interrupt: Für Messung der Motorgeschwindigkeit
  attachInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE);  
  Serial.print("Count Hall ="); 
  Serial.println(countHall);
}



void Code_Hall() 
{
  countHall ++;
  } 

Was soll das bringen den Interrupt 1000Male pro Sekunde neu zuzuweisen?
Ich würde die Anweisung ins Setup schreiben.

Das hab ich jetzt auch mal ausprobiert.... Blinkt wie verrückt :wink:

#include <Wire.h>        // IIC communication library
#include <PWM.h>        // Require Timer1 PWM frequency of 20Khz-25Khz for Nidec 24H677 BLDC Motor

//************** Nidec 24H677H010 BLDC Motor Variablen ****************
const int nidecDirection = 8;         // CW/CCW Drehrichtung
const int nidecBrake = 7;             // Bremse
const int nidecPWM = 6;               // Nidec Motor PWM

///////// Anfang der Integrated Service Routine ISR Zahler Variablen ////////
#define nidecHalleffect 4  // Externer Interrupt für Nidec FG  Ausgang 6 Impulse/Umdrehung
volatile long countHall = 0;// Zählt die Pulse des Hall Encoders
////////////////// Ende der Integrated Serivce Routine ISR Zähler Variablen//

void setup() {

  //Nidec Motor Control Pins
  pinMode(nidecDirection,OUTPUT);
  pinMode(nidecPWM,OUTPUT);
  pinMode(nidecBrake, OUTPUT);
  pinMode(nidecHalleffect, INPUT);  //Input für Halleffect
  
  // Initialer Zustand
  digitalWrite(nidecDirection,LOW);
  analogWrite(nidecPWM,500); // No PWM Signal
  digitalWrite(nidecBrake,HIGH); //Bremse an
  
  Serial.begin(9600);


  pinMode(LED_BUILTIN, OUTPUT);
}



void loop() {
  //Externer Interrupt: Für Messung der Motorgeschwindigkeit

if(digitalRead(nidecHalleffect) == HIGH){
      digitalWrite(LED_BUILTIN, HIGH); 
      delay(10); 
}
  digitalWrite(LED_BUILTIN, LOW); 
}
  
 /* 
  
  attachInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE);  
  Serial.print("Count Hall = "); 
  Serial.println(countHall);
}



void Code_Hall() 
{
  countHall ++;
  } 


*/

Ich hab das ganze jetzt mal mit Pin 3 ausprobiert und plötzlich funktioniert es. Ich weiß zwar noch nicht genau warum aber danke euch trotzdem!

#include <Wire.h>        // IIC communication library
#include <PWM.h>        // Require Timer1 PWM frequency of 20Khz-25Khz for Nidec 24H677 BLDC Motor

//************** Nidec 24H677H010 BLDC Motor Variablen ****************
const int nidecDirection = 8;         // CW/CCW Drehrichtung
const int nidecBrake = 7;             // Bremse
const int nidecPWM = 6;               // Nidec Motor PWM

///////// Anfang der Integrated Service Routine ISR Zahler Variablen ////////
#define nidecHalleffect 3  // Externer Interrupt für Nidec FG  Ausgang 6 Impulse/Umdrehung
volatile long countHall = 0;// Zählt die Pulse des Hall Encoders
////////////////// Ende der Integrated Serivce Routine ISR Zähler Variablen//

void setup() {

  //Nidec Motor Control Pins
  pinMode(nidecDirection,OUTPUT);
  pinMode(nidecPWM,OUTPUT);
  pinMode(nidecBrake, OUTPUT);
  pinMode(nidecHalleffect, INPUT);  //Input für Halleffect
  
  // Initialer Zustand
  digitalWrite(nidecDirection,LOW);
  analogWrite(nidecPWM,500); // No PWM Signal
  digitalWrite(nidecBrake,HIGH); //Bremse an
  
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}



void loop() {
  //Externer Interrupt: Für Messung der Motorgeschwindigkeit

if(digitalRead(nidecHalleffect) == HIGH){
      digitalWrite(LED_BUILTIN, HIGH); 
      delay(5); 
}
  digitalWrite(LED_BUILTIN, LOW); 

  

  
  attachInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE); 
  Serial.print("Count Hall = "); 
  Serial.println(countHall);
}



void Code_Hall() 
{
  countHall ++;
} 


Naja..
"funktioniert"?

analogWrite(nidecPWM,500); // No PWM Signal
Was soll das sein?

Weiterhin wird Atomic missachtet.

attachInterrupt(digitalPinToInterrupt(nidecHalleffect), Code_Hall, CHANGE);
Gibts einen besonderen Grund, dass das über 100 Tausend mal pro Sekunde gemacht werden muss?

00000536 <__vector_2>:
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
 536:	1f 92       	push	r1
 538:	0f 92       	push	r0
 53a:	0f b6       	in	r0, 0x3f	; 63
 53c:	0f 92       	push	r0
 53e:	11 24       	eor	r1, r1
 540:	2f 93       	push	r18
 542:	3f 93       	push	r19
 544:	4f 93       	push	r20
 546:	5f 93       	push	r21
 548:	6f 93       	push	r22
 54a:	7f 93       	push	r23
 54c:	8f 93       	push	r24
 54e:	9f 93       	push	r25
 550:	af 93       	push	r26
 552:	bf 93       	push	r27
 554:	ef 93       	push	r30
 556:	ff 93       	push	r31
 558:	e0 91 02 01 	lds	r30, 0x0102	; 0x800102 <intFunc+0x2>
 55c:	f0 91 03 01 	lds	r31, 0x0103	; 0x800103 <intFunc+0x3>
 560:	09 95       	icall
 562:	ff 91       	pop	r31
 564:	ef 91       	pop	r30
 566:	bf 91       	pop	r27
 568:	af 91       	pop	r26
 56a:	9f 91       	pop	r25
 56c:	8f 91       	pop	r24
 56e:	7f 91       	pop	r23
 570:	6f 91       	pop	r22
 572:	5f 91       	pop	r21
 574:	4f 91       	pop	r20
 576:	3f 91       	pop	r19
 578:	2f 91       	pop	r18
 57a:	0f 90       	pop	r0
 57c:	0f be       	out	0x3f, r0	; 63
 57e:	0f 90       	pop	r0
 580:	1f 90       	pop	r1
 582:	18 95       	reti

Der ISR Prolog und Epilog scheint mir doch, für einen schnellen Interrupt doch arg ausufernd zu sein.

In

#define nidecHalleffect 0 

Mußt Du die Pin Nummer angeben und nicht die Nummer des Interrupts.
Also beim Arduino UNO 2 für Pin 2 und 3 für pin 3.

digitalPinToInterrupt

Rechnet von der PinZahl zur Interruptzahl um.

Wie gesagt attachinterrupt brauchst Du nur ein mal zum Initialisieren der Interruptroutine (Funktion) siehe Beispiel in : attachInterrupt() - Arduino Reference

const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  state = !state;
}

Das Beispiel schaltet eine LED auf Pin 13 gleich ein bze aus wie ein Taster auf pin 2 gedrückt wird.

Grüße Uwe

Danke nochmal! Jetzt hats auch richtig funktioniert

Am Rande und fragmentarisch:
(auch gegen die Winterlangeweile)

#include "util/atomic.h"
#define CriticalSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)



#define nidecHalleffect 3  // Pin
volatile unsigned long countHall = 0;// Zählt die Pulse des Hall Encoders

void setup()
{
  pinMode(nidecHalleffect, INPUT_PULLUP);  //Input für Halleffect
   Serial.begin(9600);

  CriticalSection
  {
    EICRA  = _BV(ISC10); // | _BV(ISC11)
    EIMSK |= _BV(INT1);
    EIFR   = _BV(INTF1);  
  }
}



void loop()
{
  uint32_t temp;
  CriticalSection
  {
    temp = countHall;
    countHall = 0;
  }
  Serial.print("Count Hall = ");
  Serial.println(temp);
  delay(1000);
}


ISR(INT1_vect)
{
  countHall++;
}

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