Hall sensor input, read RPM, then PWM output

Can you please provide a link to the hall sensor.

If it were my project, I would read the digital output with the interrupt.

it cant do anything past just reading rpm
i add in the bare minimum to map both outputs and it start reading 10,000 rpm. with out any outputs it reads pretty true

The interaction of the solenoid outputs (VVT1, VVT2) on 9 and 10 with the interrupt input sound like a hardware issue to me. EMI can certainly generate a false interrupt signal. Depending on how fast the interrupts occur at max rpm, it might be possible to use a RC filter on the input.

Defeating interrupt noise by switching to analog input is not dealing with the root cause, but if all else fails, it may be a way to go. I would certainly try and work out the digital issues before going down that route.

Please provide some documentation on the solenoids.

Are the solenoids connected through opto isolators?
Can they work at analogWrite frequencies?
Are they configured with flyback diodes?
Are the solenoid output and signal input wires in one bundle?

No opto isolators
No idea on the frequency. Just throwing some science at it to see what happens.
Yes on diodes. Measured about 70 volt flyback
Not really in a bundle. Loose at the moment

Is there a bad ass rpm reading library available?

I am using a tach output off the megasquirt. PT4
Not using the hall sensor off the toothed cam wheel at this time. It is a nice even signal.

I wonder if the mega might have some advantage to run this project?

There are definitely libraries to use, but you say your rpm reading is solid without any output. Counting the number of interrupts, or pulses sensed by analog or digital read in a period of time is one of the standard methods.

There are other methods which look at the time gap between two pulses.

I do not think that your issue is measuring the rpm generated by the PT4 tach output of the megasquirt. As you say, it is a very good signal. Have you configured PT4 to activate based on rpm? How many pulses per rotation.

The main issue that I see is that the output is interactive with the input. That is not a software issue, but rather hardware. You maybe able to filter some of the noise in software with lockout or debounce techniques, but it is better to get to the root cause.

An automotive environment is very difficult.

the mega might have some advantage to run this project?

I don't see how it would be different. The advantage of the Mega is lots of I/O pins and additional hardware serial ports. I don't think that either of these features is useful for your application.

EDIT:

It is a nice even signal.

What does the signal look like when you turn on the outputs?

i will hit it with the scope in the morning to see if it gets bad with some outputs
not much in tach output options....

first thing i going to do after coffee is test for rpm levels to make sure it looks clean while driving

const byte analogPin = A5;     // Analog pin connected to the Hall sensor
const float threshold = 4.5;   // Voltage threshold for detection
const int numCycles = 4;       // Number of cycles to count for RPM calculation

unsigned long cycleStartTimes[numCycles]; // Store start times for each cycle
unsigned long cycleEndTimes[numCycles];   // Store end times for each cycle
int cycleCount = 0;
bool aboveThreshold = false;

void setup() {
  Serial.begin(115200);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop() {
  float voltage = analogRead(analogPin) * (5.0 / 1023.0);  // Read and convert the voltage

  // Detect voltage threshold crossing
  if (!aboveThreshold && voltage > threshold) {
    aboveThreshold = true;
  } else if (aboveThreshold && voltage < threshold) {
    aboveThreshold = false;
    cycleEndTimes[cycleCount] = millis();  // Record end time
    cycleCount++;

    if (cycleCount >= numCycles) {
      // Calculate average cycle time and RPM
      unsigned long totalTime = 0;
      for (int i = 0; i < numCycles; i++) {
        totalTime += (cycleEndTimes[i] - cycleStartTimes[i]);
      }
      float averageTime = totalTime / (float)numCycles;
      float rpm = 60000.0 / averageTime;  // Convert time to RPM

      // Reset for next reading
      cycleCount = 0;
      cycleStartTimes[0] = millis();

      // Output to Serial for debugging
      Serial.print("RPM: ");
      Serial.println(rpm);

      // Set output pins based on RPM thresholds
      digitalWrite(3, rpm > 500 ? HIGH : LOW);
      digitalWrite(5, rpm > 1200 ? HIGH : LOW);
      digitalWrite(6, rpm > 2000 ? HIGH : LOW);
      digitalWrite(9, rpm > 3000 ? HIGH : LOW);
      digitalWrite(10, rpm > 4000 ? HIGH : LOW);
      digitalWrite(11, rpm > 5000 ? HIGH : LOW);
    } else {
      cycleStartTimes[cycleCount] = millis();  // Start time for next cycle
    }
  }
}

i can easily see the led lights while driving

nope, that code above reads like 14,000 rpm at idle now

when it cools down a little outside i am going to try out the new code my dad helped with. he suggested a Schmitt trigger. i never heard of it but like the strategy. so far it reads accurate with the /3 added in for the rpm and smooth

const byte analogPin = A5;  // Analog pin connected to the Hall sensor
float highThreshold = 4.0;  // High voltage threshold
float lowThreshold =  2.0;   // Low voltage threshold
const int numCycles =   4;    // Number of cycles to count for RPM calculation

unsigned long totalTime;  // Total ms from first cycle start to last start
unsigned long cycleStartTimes[numCycles];  // Store start times for each cycle

int cycleCount = 0;
bool aboveThreshold = false;
float currentThreshold = highThreshold;  // Start with high threshold

const int fadeStartRPM = 2600;  // RPM threshold to start the fade
const int fadeStopRPM = 1600;   // RPM threshold to stop the fade and turn off

// Adjustable RPM thresholds and PWM map values
// Idle Range
const int idleRangeRPMMin =  1300;  // Minimum RPM for the idle range
const int idleRangeRPMMax =  1800;  // Maximum RPM for the idle range
const int idleRangeStartPWM = 100;  // Start PWM percentage for the idle range
const int idleRangeEndPWM =   255;  // End PWM percentage for the idle range

// Torque Range
const int torqueRangeRPMMin =  2001;   // Minimum RPM for the torque range
const int torqueRangeRPMMax =  4000;   // Maximum RPM for the torque range
const int torqueRangeStartPWM = 255;  // Start PWM percentage for the torque range
const int torqueRangeEndPWM =   150;    // End PWM percentage for the torque range

// Peak Range
const int peakRangeRPMMin = 4001;   // Minimum RPM for the peak range
const int peakRangeRPMMax = 5500;   // Maximum RPM for the peak range
const int peakRangeStartPWM = 150;  // Start PWM percentage for the peak range
const int peakRangeEndPWM = 0;      // End PWM percentage for the peak range

bool TCCEnabled = false;  // Track the state of TCC

// Define pins
const int TCC = 3;
const byte VVT1 = 9;
const byte VVT2 = 10;
const int controlPin = 4;  // Digital input pin for controlling TCC

void setup() {
  Serial.begin(115200);
  // Initialize the PWM output pins
  pinMode(VVT1, OUTPUT);
  pinMode(VVT2, OUTPUT);
  pinMode(TCC, OUTPUT);

  // Initialize the control pin as an input
  pinMode(controlPin, INPUT);
}

void loop() {

  // Check TCC control state
  int controlState = digitalRead(controlPin);
  if (controlState == LOW) {
    stopTCC(); // If pin is LOW, stop TCC
  } else if (controlState == HIGH) {
    startTCC(); // If pin is HIGH, start TCC
  }

  float voltage = analogRead(analogPin) * (5.0 / 1023.0);  // Read and convert the voltage

  if (aboveThreshold && voltage < lowThreshold) {  // Just reset threshold flag
    aboveThreshold = false;                        // When it goes low
  }

  // Detect voltage threshold crossing, save time, increment cycle count
  if (!aboveThreshold && voltage > highThreshold) {
    aboveThreshold = true;                   // Set upper threshold flag
    cycleStartTimes[cycleCount] = millis();  // Record start time of high threshold
    cycleCount++;                            // Increment Cycle Count
  }

  if (cycleCount >= numCycles) {  // Calculate average cycle time and RPM

    // Total Time is time from cyclesStartTimes[0] to cyclesStartTimes[numCycles-1]
    // That is, one cycle is start time to start time
    // Just like a day is midnight to midnight

    totalTime = cycleStartTimes[numCycles - 1] - cycleStartTimes[0];
    float averageTime = totalTime / (float)(numCycles - 1);  // Average for one cycle
                                                             // Four start times is three full cycles
    float rpm = 60000.0 / averageTime / 3;                       // Convert time to RPM

    // Reset for next reading
    cycleCount = 0;

    // Output to Serial for debugging
    Serial.print("RPM: ");
    Serial.println(rpm);

    // Variable to store PWM value
    int pwmValue = 0;

    // Map the RPM value to the desired PWM range based on the idle range
    if (rpm >= idleRangeRPMMin && rpm <= idleRangeRPMMax) {
      pwmValue = map(rpm, idleRangeRPMMin, idleRangeRPMMax, idleRangeStartPWM, idleRangeEndPWM);
    }
    // Map the RPM value to the desired PWM range based on the torque range
    else if (rpm >= torqueRangeRPMMin && rpm <= torqueRangeRPMMax) {
      pwmValue = map(rpm, torqueRangeRPMMin, torqueRangeRPMMax, torqueRangeStartPWM, torqueRangeEndPWM);
    }
    // Map the RPM value to the desired PWM range based on the peak range
    else if (rpm >= peakRangeRPMMin && rpm <= peakRangeRPMMax) {
      pwmValue = map(rpm, peakRangeRPMMin, peakRangeRPMMax, peakRangeStartPWM, peakRangeEndPWM);
    }

    // Set the PWM output
    analogWrite(VVT1, pwmValue);
    analogWrite(VVT2, pwmValue);

    // Check if the RPM is greater than the fade start threshold and TCC is enabled
    if (TCCEnabled && rpm > fadeStartRPM) {
      fadeTCC(0, 255, 500);             // start, end, time
    }

    // Check if the RPM is below the fade stop threshold
    if (rpm < fadeStopRPM) {
      analogWrite(TCC, 0);             // Turn off the PSI output
    }

    // Reset for next measurement
    cycleStartTimes[0] = millis(); // Record the new initial start time
  } else {
    // Record the start time for the next cycle
    cycleStartTimes[cycleCount] = millis();
  }
}

// Handles stopping TCC by setting it to 0 and disabling TCC control
void stopTCC() {
  analogWrite(TCC, 0); // Immediately set TCC value to 0
  TCCEnabled = false;  // Disable TCC
}

// Handles starting TCC by enabling TCC control
void startTCC() {
  TCCEnabled = true;   // Enable TCC
}

// Non-blocking fade function for TCC, with a final set to 255 after fade completes
void fadeTCC(int startValue, int endValue, int duration) {
  static int currentStep = 0;
  static unsigned long previousMillis = 0;
  static int steps = 255;  // Number of steps for the fade
  static int delayTime = duration / steps;
  static float stepValue = (endValue - startValue) / float(steps);
  static bool fading = false;

  // Start the fading process if it's not already started
  if (!fading) {
    currentStep = 0;
    previousMillis = millis();
    fading = true;
  }

  // Continue the fading process
  if (fading) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= delayTime) {
      previousMillis = currentMillis;  // Reset the timer
      int value = startValue + (stepValue * currentStep);
      analogWrite(TCC, value);
      currentStep++;

      // Check if fade is complete
      if (currentStep > steps) {
        fading = false;  // Stop the fading
        analogWrite(TCC, 255); // Ensure TCC is set to 255 after fade completes
      }
    }
  }
}

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