how to send 1 PWM cycle

Hello all,

I am using an Arduino nano for this project, and I am trying to imitate some old RPM sensors for my electric motor that are no longer produced.

The motor controller, which needs motor RPM via a signal wire (this is a 12V system of a car) this signal line must be pulled low four times per revolution with approximately a 50% duty cycle. On my motor shaft, there is a small ring which has 4 magnets around it, which will give me my four pulses per revolution. (motor will exceed 5000 RPM in some cases)

I have got the hall effect sensor to work with my arduino, and this sensor pulls low when triggered via a magnet, and I have a simple setup where an n channel mosfet controls an led.

My main problem is that when this hall effect sensor detects the magnet, I need it to send out exactly one cycle at 50% duty cycle of that makes sense.

So what do you all recommend I do? Do i have it wrong by trying to even use pwm to begin with? These magnets on the motor shaft are evenly spaced, so should I just set my arduino to trigger the mosfet only when it detects the magnet?

Should I only tell the arduino to signal the mosfet when it detects the magnet then immediately following on the next line turn the mosfet off? Or add a delay of a few milliseconds?

Please let me know of your thoughts and suggestions! I am sorry if this all sounds confusing, I am still working my way around arduino.

Thanks!

If a 1 is a pulse and a 0 is no pulse, then using the phrase "duty cycle" Is meaningless for a single pulse. To have a 50% duty cycle a pulse would have to be a "1" and then a "0" for exactly the same amount of time. You description is of a single "1" with unknown length of time.

Paul

I don't think the concept of 1 PWM cycle makes any sense - it is just a LOW-HIGH-LOW pulse.

...R

Yeah you are both right...that doesn't make any sense. I just didn't know of the best way to phrase it.

thanks for the replies. Would it be best to just send the mosfet LOW HIGH LOW as Robin2 said? Or should I add in a couple milliseconds of delay in each as well? Or is that not really necessary?

Thanks so much!

The length of time the hall effect will be "on" depends on the size of the spinning magnets and the speed they pass the hall effect. Hall effects are normally open collector arrangement so when the magnet is present the signal will be low. So rather than low-high-low, expect to see high-low-high. Of course this depends on how your circuit is arranged.

Thanks for the help!

Oh alright that would make sense with some of the testing I have done, and found the HIGH LOW HIGH.

Is there a way to rearrange my physical circuit so that it becomes LOW HIGH LOW because then I can use that to directly power the mosfet? Then I could bypass having to use an arduino to drive the mosfet and the time between pulses is directly changed by simply the time passed between the magnets.

YoungestEVer:
Yeah you are both right…that doesn’t make any sense. I just didn’t know of the best way to phrase it.

thanks for the replies. Would it be best to just send the mosfet LOW HIGH LOW as Robin2 said? Or should I add in a couple milliseconds of delay in each as well? Or is that not really necessary?

Thanks so much!

You don’t want a delay(). That will stop you from adding concurrent actions like blinking led13 to show running status.

delay(1) stops the sketch for 16000 cpu cycles, a sketch that may run responsive (watch a button and blink a led) in 200 or 300 cycles will be glitchy at best when bogged with process-blocking functions like delay().

We time with millis() or micros(). I use both below, micros() for the blip time as millis() differences can be off by 1.

End time - start time = difference in time <<---- this always works when using unsigned integers even across rollover

// not shown, the pin # and state variables 
...
unsigned long blipStart, blipOver, blipTime = 1000;  // blip time is micros, should be >= 20
unsigned long blinkStart;
unsigned long blinkOver = 500; // blink time is millis
...

void loop()
{
  // some process code that decides when to blip the blip pin
  if ( whatever )  // that does not run as or more often than blipTime 
  {
    .....
    //  turn the blip pin on
    blipOver = blipTime;  // unlocks the timed 1-shot
    blipStart = micros(); // mark the start
  }

  if ( blipOver > 0 )  // this is a 1-shot that some other routine loads
  {
    if ( micros() - blipStart >= blipOver ) // when close counts, use micros
    {
      // turn the blip pin off
      blipOver = 0; // shutdown
    {
  }

  if ( millis() - blinkStart >= blinkOver )  // blink led13 for status
  {
    blinkStart += blinkOver; 
    // flip led13 state
  }
}

YoungestEVer: Thanks for the help!

Oh alright that would make sense with some of the testing I have done, and found the HIGH LOW HIGH.

Is there a way to rearrange my physical circuit so that it becomes LOW HIGH LOW because then I can use that to directly power the mosfet? Then I could bypass having to use an arduino to drive the mosfet and the time between pulses is directly changed by simply the time passed between the magnets.

If you must, then a transistor inverter. Can you not allow for the signal "as-is" in the code?

Simple.

Connect input to interrupt.

In the ISR set the desired output pin high, and set a timer interrupt at the desired pulse length.

Then in the timer ISR set the pin low.

Change duty cycle by varying the pulse length - which is just a variable set elsewhere in the sketch. Phase control of AC signals is doing the exact same thing:

Something like this (adapted from the ACPhaseControl playground tutorial):

#define SENSOR_PIN 2  // hall sensor.
#define OUTPUT_PIN 5  // pin that produces the pulse
unsigned int pulseLength;

void setup(){

  // set up pins
  pinMode(SENSOR_PIN, INPUT); 
  pinMode(OUTPUT_PIN, OUTPUT);
  digitalWrite(OUTPUT_PIN, LOW);

  // set up Timer1 
  TIMSK1 = 0x01;    // enable overflow interrupts
  TCCR1A = 0x00;    // timer control registers set for
  TCCR1B = 0x00;    // normal operation, timer disabled

  // set up zero crossing interrupt
  attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), sensorInterrupt, FALLING);    


  // This variable sets the time the pin remains high. Change this value to something that is useful for you.
  pulseLength = 100; // in timer counts - at clk/256 16µs per count.
}  

//Interrupt Service Routines
void sensorInterrupt(){
  digitalWrite(OUTPUT_PIN, HIGH);
  TCCR1B=0x04; // start timer with divide by 256 input
  TCNT1 = 65536 - pulseLength;      // trigger pulse width
}

ISR(TIMER1_OVF_vect){ //timer1 overflow
  TCCR1B = 0x00;          // disable timer to stop unintended triggers
  digitalWrite(OUTPUT_PIN, LOW);
}

void loop(){

}

Please note: untested; uncompiled; expect typos.

I am trying to imitate some old RPM sensors for my electric motor that are no longer produced.

The motor controller, which needs motor RPM via a signal wire (this is a 12V system of a car) this signal line must be pulled low four times per revolution

Would it be best to just send the mosfet LOW HIGH LOW as Robin2 said? Or should I add in a couple milliseconds of delay in each as well? Or is that not really necessary?

set a timer interrupt at the desired pulse length.

The OP has never specified what pulse length is required by the rpm sensor. For all we know, the several microsecond time period of the simple digitalWrite() HIGH/LOW in the magnet sense ISR will be adequate.

YoungestEVer: Thanks for the help!

Oh alright that would make sense with some of the testing I have done, and found the HIGH LOW HIGH.

Is there a way to rearrange my physical circuit so that it becomes LOW HIGH LOW because then I can use that to directly power the mosfet? Then I could bypass having to use an arduino to drive the mosfet and the time between pulses is directly changed by simply the time passed between the magnets.

Or you could code a pin moded OUTPUT to be LOW HIGH LOW and connect that through a resistor to a TTL level FET. A 220R that would go with a led will do.

cattledog: The OP has never specified what pulse length is required by the rpm sensor. For all we know, the several microsecond time period of the simple digitalWrite() HIGH/LOW in the magnet sense ISR will be adequate.

OP said in #0 they want 50% duty cycle, at a max rpm of 5,000, and four pulses per rotation.

If done with delays, that'd mean that 50% of the time the Arduino is twiddling its thumbs sitting out delays.

5,000 rpm means 20,000 pulses per minute or 333 per second; each pulse is then 3 ms apart, and the pulses would have to be 1.5 ms.

At lower speeds - say 500 rpm - the pulse length would have to increase to 15 ms.

One of the problems is that the pulse length has to depend on the rpms, my code doesn't address that, but some modifications can: use the OCR interrupt, so the timer can continue, and at each pulse you can check how long ago the previous pulse was, and set the output duration to half that. That ought to be very close to 50%, unless the speed changes very fast (and then all bets are off).

The relative speed between the magnet and sensor should affect the strength sensed, could change how long the field is detected.

So you have to trigger on change - falling if I understand OP correctly - but indeed if the point of the rotation where the pulse starts changes with rotation speed it's getting a lot more complex at best.

We're assuming the old sensor is Obsolete and no longer manufactured I would assume it was done in Hardware and not software. I would assume you could have two Hall sensors 22 and a half degrees 1 senses the passing of the magnet turns on II since it's the passing of that exact same magnet and turns off a 50% duty cycle should be resulted