Pages: 1 2 [3]   Go Down
Author Topic: Devide 12v square wave signal and output 5v squarewave  (Read 2474 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've just googled optocoupler and it looks that it could be a good idea, I assume these a fast enough?

That depends on the one you select. Most I have looked at would be fast enough. Just translate your PPS to BPS in the datasheets.
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pylon, thanks for all your input.

The following formula moves your floats to integers (better uint32_t, precision: 3 digits behind the point):

Code:
square_out = square_in * 201UL / 1138UL ; // case ratio1
square_out = square_in * 420 / 1777; // case ratio2


Where would I add this code, in the main void loop?
so by adding that code, I could set all my variables to integers? What role does the "UL" have?

Is this the correct implimentation?

Code:
/*
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_pin = 2; //sqaure wave input from speed source
const int gear_pin = 3;     //gear select input
const int speed_out = 4; //sqaure wave output

// variables for calculation
const int ratio1 = 1/ 2.315;
const int ratio2 = 1/ 1.731;
const int FD = 1 / 4.7;
const int idler = 1.04;
const int pulses = 4; //pulses per simultated revolution
int square_in; //speed received
int square_out; //speed to send
int gear; // current gear selected
// the setup routine runs once when you press reset:
uint32_t lastEdge = 0;
byte state = 0;

void setup() {                
  // initialize the digital pin as an output.

  pinMode(speed_pin, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_pin, 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"
   */


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


  else{        //ratio2 is selected
    square_out = square_in / 2 * ratio2 / idler * FD * pulses;
  }//end of ratio2


  /*
  //output the variable "square_out" as square wave to "Speed_out"
     */
    
     uint32_t outPulse = 500000UL / square_out; // get pulse length (not wave length)
  uint32_t m = micros();
  if (m - lastEdge >= outPulse) {
    state = ! state;
    digitalWrite(speed_out, state);
    lastEdge = m;
  }
    
    
}
void registerPulse() {
  uint32_t cur = micros();
  lastPulseWidth = cur - lastPulseTime;
  lastPulseTime = cur;
}
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have just found out some more info on the sqaurewave speed output from the ECU. The signal is 50% duty so the pulse length is determined by the frequency.The ECU updates the tachometer output every 50mS.

I'm hoping to read the signal in quicker than every 50ms to make sure that I'm not losing data.

I understand that the UNO is 16MHz, but how fast does that mean it could read and ouput data using my code?
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5152
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Where would I add this code, in the main void loop?

That code has to go into your ratio selector if statement like this:

Code:
  if (gear == HIGH) {        //ratio1 is selected
    square_out = square_in * 201UL / 1138UL;
  }//end of ratio1
  else{        //ratio2 is selected
    square_out = square_in * 420UL / 1777UL;
  }//end of ratio2

Quote
so by adding that code, I could set all my variables to integers? What role does the "UL" have?

Yes, you now have to define your variables this way:
Code:
uint32_t square_in = 0;
uint32_t square_out = 0;

The UL hints the compiler that it should recognize the given integer constants as "unsigned long", meaning 32bit positive integers.
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ahh right,

So in this line of code
 
Code:
square_out = square_in * 201UL / 1138UL;

where did the numbers 201 abd 1138 come from?
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5152
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your calculation

Code:
square_out = square_in / 2 * ratio1 / idler * FD * pulses;

is the same as (constants replaced)

Code:
square_out = square_in / 2 / 2.315 / 1.04 / 4.7 * 4;

which is the same as (constants pre-calculated)

Code:
square_out = square_in * 0.176745271;

and 201 / 1138 = 0.176625659, which is the same factor with a precision of 3 digits after the point.
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Very clever, mathimatically, how did you get to those numbers?

It's not just electronics and c I need to learn
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5152
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
how did you get to those numbers?

Take an estimate and approximate till you have the desired precision.
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

very clever
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've updated the code:
Code:
/*
Read square wave speed signal in on pin2 and output squarewave speed on pin4
 */

volatile uint32_t lastPulseTime = 0;
volatile uint32_t lastPulseWidth = 0;
uint32_t square_in = 0; //speed received
uint32_t square_out = 0; //speed to send

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

// variables for calculation

int gear; // current gear selected
// the setup routine runs once when you press reset:
uint32_t lastEdge = 0;
byte state = 0;

void setup() {               
  // initialize the digital pin as an output.

  pinMode(speed_pin, INPUT);
  pinMode(speed_out, OUTPUT);
  pinMode(gear_pin, 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"
   */


  gear = digitalRead(gear_pin);
  if (gear == HIGH) {        //ratio1 is selected
    square_out = square_in * 201UL / 1138UL;
  }//end of ratio1


  else{        //ratio2 is selected
    square_out = square_in * 420UL / 1777UL;
  }//end of ratio2


  /*
  //output the variable "square_out" as square wave to "Speed_out"
   */

  uint32_t outPulse = 500000UL / square_out; // get pulse length (not wave length)
  uint32_t m = micros();
  if (m - lastEdge >= outPulse) {
    state = ! state;
    digitalWrite(speed_out, state);
    lastEdge = m;
  }


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


Does this look right? is there anything which could be done more affectively?
Logged

Switzerland
Offline Offline
Faraday Member
**
Karma: 108
Posts: 5152
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can eliminate the change from wave length to frequencies and back:

Code:
void loop() {
  uint32_t outPulse;

  gear = digitalRead(gear_pin);
  if (gear == HIGH) {        //ratio1 is selected
    outPulse = lastPulseWidth * 1138UL / 201UL;
  } else {        //ratio2 is selected
    outPulse = lastPulseWidth * 1777UL / 420UL;
  }

  uint32_t m = micros();
  if (m - lastEdge >= outPulse) {
    state = ! state;
    digitalWrite(speed_out, state);
    lastEdge = m;
  }
}

The next step is to do the calculation only if one of the input values have changed:

Code:
uint32_t savedPulseWidth = 0;
byte savedGear = LOW;
void loop() {
  uint32_t outPulse;

  gear = digitalRead(gear_pin);
  if (gear != savedGear || lastPulseWidth != savedPulseWidth) {
    savedGear = gear;
    savedPulseWidth = lastPulseWidth;
    if (gear == HIGH) {        //ratio1 is selected
      outPulse = lastPulseWidth * 1138UL / 201UL;
    } else {        //ratio2 is selected
      outPulse = lastPulseWidth * 1777UL / 420UL;
    }
  }

  uint32_t m = micros();
  if (m - lastEdge >= outPulse) {
    state = ! state;
    digitalWrite(speed_out, state);
    lastEdge = m;
  }
}
Logged

UK
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for that, I plan to have my test rig compleated this week to test this on, thanks again for your massive help  smiley-grin smiley-lol
Logged

Pages: 1 2 [3]   Go Up
Jump to: