Hi
I need to take a 12v hall effect sensor and reduce the PWM to an output. I dont know the ratio yet.
I found this one going the other way here
http://forum.arduino.cc/index.php?topic=102250.0
Can i get away with changing the pwminperiod to 1k Hz and the pwmoutperiod to whatever the ratio turns out to be, say 500Hz for arguments sakes.
Andy
// PWM input 1 variables
byte pwmIn1IO = 2; // IO used to measure PWM input 1, IO 2 is also interrupt 0
volatile unsigned long pwmIn1PulseStartTime; // store PWM pulse start time in uS
volatile long pwmIn1PulseElapsedTime; // store PWM pulse length in uS
unsigned long pwmIn1Period = 500ul; // used to calc pwmIn1Duty percentage, 500 uS = 2K Hz
byte pwmIn1Duty; // PWM pulse length converted to duty cycle in percent * 100
volatile boolean pwmIn1Ready; // used to flag the duty cycle calc after a completed PWM pulse measurement
unsigned long pwmIn1Timeout = 50; // uS added to pwmIn1Period for the timeout
volatile boolean pwmIn1Invert = 1; // used to invert input PWM readings
// PWM output 1 variables
byte pwmOut1Pin = 8; // IO for PWM ouput 1
unsigned long pwmOut1Period = 100000ul; // base period in uS for PWM out 1, 10Hz
unsigned long pwmOut1PulseTime = 0ul; // pulse active time in uS
unsigned long pwmOut1PrevEndTime = 0ul; // previous PWM period end time in uS
boolean pwmOut1State = 0; // tracks the current phase of the PWM output, ie active or inactive ("on" or "off")
boolean pwmOut1Invert = 0; // used to invert PWM output, '0' means active is HIGH or 5V
void setup() {
// set IO modes
pinMode(pwmIn1IO, INPUT);
digitalWrite(pwmIn1IO, HIGH); // set internal pullup resistor
attachInterrupt(0, pwmIn1Trigger, CHANGE); // catch interrupt 0 (IO 2) changing state and send to pwmIn1Trigger()
pinMode(pwmOut1Pin, OUTPUT);
digitalWrite(pwmOut1Pin, pwmOut1Invert);
}
void loop(){
// if a pulse has been measured
if (pwmIn1Ready){
pwmIn1Ready = false;
if (pwmIn1PulseElapsedTime <= pwmIn1Period){ // to help deal with 0% or 100% duty cycle conditions, let the timeout code deal with it
pwmIn1Duty = (int)(pwmIn1PulseElapsedTime * 100ul / pwmIn1Period); // calc duty cycle of input pwm
pwmIn1Duty = constrain(pwmIn1Duty,0,100);
pwmOut1PulseTime = pwmIn1Duty * pwmOut1Period / 100ul; // calc output pwm's pulse time in uS
}
}
// timeout code, if input pwm does not finish a measurement due to 0% or 100% duty cycle, ie. there are no pulses to trigger the interrupt
if (micros() > pwmIn1PulseStartTime + pwmIn1Period + pwmIn1Timeout){
if (digitalRead(pwmIn1IO) == pwmIn1Invert){
pwmOut1PulseTime = 0; // set 0 duty cycle
} else {
pwmOut1PulseTime = pwmOut1Period; // set max duty cycle
}
pwmIn1PulseStartTime = micros(); // reset pwm in pulse start time
}
// if output pwm is "active", check for end of pulse time
if (pwmOut1State){
if (micros() >= (pwmOut1PrevEndTime + pwmOut1PulseTime)){
digitalWrite(pwmOut1Pin, pwmOut1Invert); // pulse "active" time has expired, toggle pwm output IO
pwmOut1State = 0; // set state tracking flag
}
}
// if output pwm is "inactive" or "off", check for end of pwm period time
if (!pwmOut1State){
if (micros() >= (pwmOut1PrevEndTime + pwmOut1Period)){
digitalWrite(pwmOut1Pin, !pwmOut1Invert);
pwmOut1PrevEndTime = micros(); // originally I used (pwmOut1PrevEndTime += pwmOut1Period)
// depends which is more important, steady frequency or accurate pwm "active" pulse length
pwmOut1State = 1;
}
}
}
// runs when interrupt is triggered
void pwmIn1Trigger(){
if (digitalRead(pwmIn1IO) != pwmIn1Invert){
pwmIn1PulseStartTime = micros();
} else {
pwmIn1PulseElapsedTime = micros() - pwmIn1PulseStartTime; // may glitch during timer wrap-around
pwmIn1Ready = true;
}
}