Go Down

### Topic: Devide 12v square wave signal and output 5v squarewave (Read 9953 times)previous topic - next topic

#### Retroplayer

#30
##### Feb 07, 2013, 03:15 pm

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.

#### Jimster

#31
##### Feb 07, 2013, 03:28 pm
Pylon, thanks for all your input.

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

Code: [Select]
`square_out = square_in * 201UL / 1138UL ; // case ratio1square_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: [Select]
`/*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 calculationconst 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 revolutionint square_in; //speed receivedint square_out; //speed to sendint 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;}`

#### Jimster

#32
##### Feb 07, 2013, 05:49 pm
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?

#### pylon

#33
##### Feb 07, 2013, 05:56 pm
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: [Select]
`  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: [Select]
`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.

#### Jimster

#34
##### Feb 07, 2013, 06:03 pm
Ahh right,

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

where did the numbers 201 abd 1138 come from?

#### pylon

#35
##### Feb 07, 2013, 06:46 pm

Code: [Select]
`square_out = square_in / 2 * ratio1 / idler * FD * pulses;`

is the same as (constants replaced)

Code: [Select]
`square_out = square_in / 2 / 2.315 / 1.04 / 4.7 * 4;`

which is the same as (constants pre-calculated)

Code: [Select]
`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.

#### Jimster

#36
##### Feb 07, 2013, 07:49 pm
Very clever, mathimatically, how did you get to those numbers?

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

#### pylon

#37
##### Feb 08, 2013, 11:43 am
Quote
how did you get to those numbers?

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

#38
very clever

#### Jimster

#39
##### Feb 08, 2013, 05:37 pm
I've updated the code:
Code: [Select]
`/*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 receiveduint32_t square_out = 0; //speed to sendconst 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 calculationint 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?

#### pylon

#40
##### Feb 08, 2013, 06:00 pm
You can eliminate the change from wave length to frequencies and back:

Code: [Select]
`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: [Select]
`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;  }}`

#### Jimster

#41
##### Feb 12, 2013, 02:18 pm
Thanks for that, I plan to have my test rig compleated this week to test this on, thanks again for your massive help  XD

Go Up