Devide 12v square wave signal and output 5v squarewave

I have a square wave signal with a range of 2400 - 300000 pules per second coming from a 12v source. I would like to read this signal do some maths (depending on a analogue input) and then output the signal to a 5v square wave. The speed of the output would be in the range of 1000 - 80000 pulses per second. Is this possible with an arduino?

Is the ardunio quick enough todo this, has anything like this been done before? I've had a search but could not find anything. Any advice would be magic.

Thanks

300,000 p/s as the max input frequence? If so yes. Use a voltage divider to drop the 12v to between 4 and 5 volts. (NO MORE than 5V). Connect that to a digital, not analog, input. One of the external interrupt pins is ideal. When the pin changes do the math and output the 5v by setting an output pin high or low as required.

Mark

Thats great news,

So would I read the input as PWM?

Has anyone got an code where they input and output this kind of data?

Thanks

Jimster

So would I read the input as PWM?

If your input signal is PWM, yes. You told us that you have a square wave signal, so you don't have to read anything analog because you have a digital signal (either high or low). That's what the digital inputs are for.

Has anyone got an code where they input and output this kind of data?

Reading square waves? Yes, probably any of use who has done more than the starter blink sketch. Reading a digital input can be done in several ways. Which one to choose depends on what kind of math you wanna do before putting it out again.

Sorry I was getting confused, the input and outputs are not PWM and are sqaure wave.

This is the code which I have come up with so far, the maths should be correct, and give you an idea of what I'm trying todo. What I'm unsure about is how to read in a sqaure wave and save the pulses as a variable, aslo read a variable and output as sqaure wave??

here is my code so far:

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 23890;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1

  square_out = square_in / 2 * ratio2 / idler * FD * pulses;



/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}

What's "square_in" and "square_out" in your code? A frequency? A pulse duration?

If you use this calculation for every pulse you get, the Arduino will not be fast enough. The Arduino cannot handle floating point numbers natively but has to emulate them using integer operations. You're doing 2-4 float divisions and 1-2 float multiplications (after compiler optimizations). At your maximum rate of 300'000 your MCU has about 50 cycles to start your interrupt routine, do all this calculations and output your result. This is probably too much for an Arduino.

In this code

  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses;
  }//end of ratio1

  square_out = square_in / 2 * ratio2 / idler * FD * pulses;

the ratio1 (gear_in == HIGH) will never become active because the next assignment overwrites it with the ratio2 term.

I guess it's a lot easier if you describe what you wanna achieve. My guess is that you can optimize a lot here and change from float to integer calculations. Then it might be possible that the Arduino does it's job.

Thanks for your input, I now see my mistake with the if loop, I've now updated this.
To give you a bit more background information. I am trying to simualte axle speed on a gearbox, and my sqaurewave signal is an igntion pulse from a engine ECU. The output will be connected to a 3rd party data logger for testing.

I made an error when I estitmated the speed of the sqaure wave, it's actually a max of 100 pulses per second, but I would need the output speed to update quicker than every 50ms

Here is my updated code:

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 23890;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1


  if (gear_in == LOW) {        //ratio2 is selected
  square_out = square_in / 2 * ratio2 / idler * FD * pulses;
 }//end of ratio2


/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}

You have given "gear_in " the constant value 3; it is never ever going to be HIGH or LOW.
Are you missing a digitalRead?

Please use tags when posting code

yes I was missing the digitalRead, sorry I'm very new to C

Thanks for the info on the code tags.

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 23890;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (digitalRead(gear_in) == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1


  if (digitalRead(gear_in) == LOW) {        //ratio2 is selected
  square_out = square_in / 2 * ratio2 / idler * FD * pulses;
 }//end of ratio2


/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}

In your calculation, square_in and square_out, are they frequencies or pulse widths?

Square_ and square out is going to be a frequency, but thats the problem I have, I don't know how to input and output this?

I would change this to a pulse length. First, this is easier to acquire and second, you may get rid of the float and use integer calculations (the pulse length is the reciprocal value of the frequency).

If you connect your input to pin 2, you could use this code to get the pulse length:

volatile uint32_t lastPulseTime = 0;
volatile uint32_t lastPulseWidth = 0;

void setup() {
  attachInterrupt(0, registerPulse, RISING);
}

void loop() {
  Serial.print("Current frequency: ");
  Serial.print(1000000UL / lastPulseWidth);
  Serial.println(" Hz");
}

void registerPulse() {
  uint32_t cur = micros();
  lastPulseWidth = cur - lastPulseTime;
  lastPulseTime = cur;
}

To put out a square wave signal, the way to go depends a lot on the update frequency (how fast does the pulse length/frequency change) and the precision you have to achieve. You then either use a PWM pin to generate the signal (good precision) or encode it into your loop() (fast adaption to pulse length changes).

the pulse length is the reciprocal value of the frequency).

Only if the duty cycle is 50%.

I measure the time from a rising edge to the next rising edge. How is that called in English? Wave length? Pulse length? Then the duty cycle is not relevant (or am I missing something?).

A pulse, in my book, is leading edge to trailing edge.
Wave length possibly is what you're referring to.

Thanks for your input,

I'd like to update the output sqaurewave as quick as possible, accuracy wise, an error margin of around 5% would be acceptable.

I've merged your code into mine, have I understood your code correctly?

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */

volatile uint32_t lastPulseTime = 0;
volatile uint32_t lastPulseWidth = 0;


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 1000000UL / lastPulseWidth;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1

  square_out = square_in / 2 * ratio2 / idler * FD * pulses;



/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}
void registerPulse() {
  uint32_t cur = micros();
  lastPulseWidth = cur - lastPulseTime;
  lastPulseTime = cur;
}
if (gear_in == HIGH) {

Ahem!

oops sorry :roll_eyes: forgot about that (again!)

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */

volatile uint32_t lastPulseTime = 0;
volatile uint32_t lastPulseWidth = 0;


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 1000000UL / lastPulseWidth;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1


if (gear_in == LOW) {        //ratio1 is selected
  square_out = square_in / 2 * ratio2 / idler * FD * pulses;
  }//end of ratio2


/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}
void registerPulse() {
  uint32_t cur = micros();
  lastPulseWidth = cur - lastPulseTime;
  lastPulseTime = cur;
}

Where do you have the attachInterrupt()?

oops sorry missed that out too. You can tell I'm a newbee :roll_eyes:

/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */

volatile uint32_t lastPulseTime = 0;
volatile uint32_t lastPulseWidth = 0;


const int speed_in = 2; //sqaure wave input from speed source 
const int gear_in = 3;     //gear select input 
const int speed_out = 4; //sqaure wave output

// variables for calculation
const float ratio1 = 1/ 2.315;
const float ratio2 = 1/ 1.731;
const float FD = 1 / 4.7;
const float idler = 1.04;
const float pulses = 4; //pulses per simultated revolution
float square_in; //speed received
float square_out; //speed to send

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_in, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_in, INPUT);

attachInterrupt(0, registerPulse, RISING);
}

// the loop routine runs over and over again forever:
void loop() {
  //Sample data to test
  square_in = 1000000UL / lastPulseWidth;


/*
 read the square wave speed input from "speed_in" into variable "sqaure_in"
*/



  if (gear_in == HIGH) {        //ratio1 is selected
    square_out = square_in / 2 * ratio1 / idler * FD * pulses; 
  }//end of ratio1


if (gear_in == LOW) {        //ratio1 is selected
  square_out = square_in / 2 * ratio2 / idler * FD * pulses;
  }//end of ratio2


/*
  //output the variable "sqaure_out" as square wave to "Speed_out"
*/
}
void registerPulse() {
  uint32_t cur = micros();
  lastPulseWidth = cur - lastPulseTime;
  lastPulseTime = cur;
}