Detection Magnetic Field / MLX90393 [closed]

5 days ago 8
ARTICLE AD BOX

I am currently working on an educational project involving magnetic field detection. I designed a PCB using an ATtiny85 microcontroller and an MLX90393 magnetic sensor.

The issue I am facing is that I am having trouble detecting the magnetic field with a satisfactory distance precision. I suspect one specific hardware issue: the CR123A battery is located directly underneath my PCB.

However, I would like to know if it is possible to change some calculations or configurations in my code to improve the detection range and compensate for this, as I have already tried many different approaches without success.

You can find the link for the documentation register of MLX90393 at : https://www.melexis.com/-/media/files/documents/application-notes/mlx90393-application-note-melexis.pdf

I am sharing the schematic of the project and the code below."
Shematicenter image description here

routing enter image description here

/** Capteur : MLX90393 / Microcontrôleur : ATtiny85 */ #include <TinyWireM.h> // ============ CONFIGURATION MATERIEL ============ const int bornierPin = 1; const int ledPin = 3; uint8_t sensorAddr = 0x0C; // ============ BASELINE MAGNÉTIQUE ============ long offX = 0, offY = 0, offZ = 0; // ============ SEUILS DE DÉTECTION ============ unsigned long seuilDeclenchement = 0; unsigned long seuilRearmement = 0; const int FACTEUR_SECURITE = 4; // Baisse massive du seuil plancher grâce au filtre matériel ! const unsigned long SEUIL_MINIMUM = 1500UL; // ============ ÉTATS DE DÉTECTION ============ bool mouvementDetecte = false; unsigned long tempsDebutDetection = 0; bool timeoutActif = false; const unsigned long TIMEOUT_BLOCAGE = 10000UL; // ============ PÉRIODE DE GRÂCE (après init) ============ const unsigned long DUREE_GRACE = 3000UL; unsigned long tempsFinGrace = 0; bool periodeGraceActive = true; // ============ PÉRIODE DE STABILISATION (après grâce) ============ const unsigned long DUREE_STABILISATION = 1000UL; unsigned long tempsFinStabilisation = 0; bool periodeStabilisationActive = false; bool detectionActive = false; // ============ FONCTION : Lire les données brutes du capteur ============ bool lireCapteur(long &rX, long &rY, long &rZ) { TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0x4E); // Commande RM (Read Measurement) TinyWireM.endTransmission(); TinyWireM.requestFrom(sensorAddr, (uint8_t)7); if (TinyWireM.available() >= 7) { TinyWireM.read(); // Ignorer le status byte rX = (int16_t)((TinyWireM.read() << 8) | TinyWireM.read()); rY = (int16_t)((TinyWireM.read() << 8) | TinyWireM.read()); rZ = (int16_t)((TinyWireM.read() << 8) | TinyWireM.read()); return true; } return false; } // ============ FONCTION : Clignoter la LED ============ void clignoter(int nombreFois, int dureeHaut, int dureeBas) { for (int i = 0; i < nombreFois; i++) { digitalWrite(ledPin, HIGH); delay(dureeHaut); digitalWrite(ledPin, LOW); delay(dureeBas); } } // ============ SETUP : INITIALISATION ET CALIBRATION ============ void setup() { pinMode(bornierPin, OUTPUT); pinMode(ledPin, OUTPUT); digitalWrite(bornierPin, LOW); digitalWrite(ledPin, LOW); TinyWireM.begin(); delay(100); // --- ÉTAPE 1 : RESET DU CAPTEUR --- TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0xF0); TinyWireM.endTransmission(); delay(100); // --- ÉTAPE 2 : CONFIGURATION DU GAIN (Registre 0x60) --- TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0x60); TinyWireM.write(0xC7); // HALLCONF=0xC + GAIN_SEL=0x7 TinyWireM.write(0x0C); TinyWireM.write(0x00); TinyWireM.endTransmission(); delay(10); // --- ÉTAPE 2 Bis : ACTIVATION DU FILTRE (Registre 0x02) --- // C'est ce qui permet de ne pas suractiver ! (DIG_FILT = 5) TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0x60); TinyWireM.write(0x14); TinyWireM.write(0x00); TinyWireM.write(0x08); TinyWireM.endTransmission(); delay(10); // --- ÉTAPE 3 : ACTIVATION DU MODE LECTURE --- TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0x1E); TinyWireM.endTransmission(); // --- ÉTAPE 4 : TEMPS DE FUITE --- clignoter(20, 100, 100); delay(2000); // --- ÉTAPE 5 : NETTOYAGE DU TAMPON --- for (int i = 0; i < 5; i++) { TinyWireM.beginTransmission(sensorAddr); TinyWireM.write(0x4E); TinyWireM.endTransmission(); TinyWireM.requestFrom(sensorAddr, (uint8_t)7); if (TinyWireM.available() >= 7) { for (int j = 0; j < 7; j++) TinyWireM.read(); } delay(40); // Délai ajusté pour le filtre } // --- ÉTAPE 6 : PHOTO ABSOLUE --- long rX, rY, rZ; if (lireCapteur(rX, rY, rZ)) { offX = rX; offY = rY; offZ = rZ; } // --- ÉTAPE 7 : CALIBRATION --- unsigned long sommeBruit = 0; const int NB_SAMPLES = 40; for (int i = 0; i < NB_SAMPLES; i++) { if (lireCapteur(rX, rY, rZ)) { long dX = rX - offX; long dY = rY - offY; long dZ = rZ - offZ; sommeBruit += (unsigned long)(dX * dX + dY * dY + dZ * dZ); } delay(40); } unsigned long moyenneBruit = sommeBruit / NB_SAMPLES; seuilDeclenchement = moyenneBruit * FACTEUR_SECURITE; if (seuilDeclenchement < SEUIL_MINIMUM) { seuilDeclenchement = SEUIL_MINIMUM; } seuilRearmement = seuilDeclenchement / 2; // --- ÉTAPE 8 : CONFIRMATION --- clignoter(3, 300, 300); digitalWrite(ledPin, LOW); // --- ÉTAPE 9 : DÉMARRER LA GRÂCE --- tempsFinGrace = millis() + DUREE_GRACE; periodeGraceActive = true; periodeStabilisationActive = false; detectionActive = false; } void loop() { // ========== PHASE 1 : PÉRIODE DE GRÂCE ========== if (periodeGraceActive) { if (millis() < tempsFinGrace) { long rX, rY, rZ; if (lireCapteur(rX, rY, rZ)) { offX = (offX * 7 + rX) / 8; offY = (offY * 7 + rY) / 8; offZ = (offZ * 7 + rZ) / 8; } delay(40); return; } else { long rX, rY, rZ; if (lireCapteur(rX, rY, rZ)) { offX = rX; offY = rY; offZ = rZ; } periodeGraceActive = false; tempsFinStabilisation = millis() + DUREE_STABILISATION; periodeStabilisationActive = true; detectionActive = false; } } // ========== PHASE 2 : PÉRIODE DE STABILISATION ========== if (periodeStabilisationActive && !periodeGraceActive) { if (millis() < tempsFinStabilisation) { long rX, rY, rZ; lireCapteur(rX, rY, rZ); delay(40); return; } else { periodeStabilisationActive = false; detectionActive = true; mouvementDetecte = false; timeoutActif = false; } } // ========== PHASE 3 : DÉTECTION NORMALE ========== if (detectionActive) { long rawX, rawY, rawZ; if (lireCapteur(rawX, rawY, rawZ)) { long dx = rawX - offX; long dy = rawY - offY; long dz = rawZ - offZ; unsigned long d2 = (unsigned long)(dx * dx + dy * dy + dz * dz); // --- SEUIL DE DÉCLENCHEMENT --- if (d2 > seuilDeclenchement) { if (!mouvementDetecte) { digitalWrite(ledPin, HIGH); digitalWrite(bornierPin, HIGH); delay(3000); digitalWrite(ledPin, LOW); digitalWrite(bornierPin, LOW); mouvementDetecte = true; timeoutActif = true; tempsDebutDetection = millis(); } } // --- HYSTÉRÉSIS --- else if (d2 < seuilRearmement) { mouvementDetecte = false; timeoutActif = false; } // --- TIMEOUT --- if (timeoutActif && (millis() - tempsDebutDetection > TIMEOUT_BLOCAGE)) { offX = rawX; offY = rawY; offZ = rawZ; mouvementDetecte = false; timeoutActif = false; clignoter(3, 100, 100); } } } delay(40); // Synchronisé avec le filtre }
Read Entire Article