Pages: [1] 2   Go Down
Author Topic: Sensor that gives PWM reading in pulse train  (Read 491 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi every1!

I'm having a problem, already posted in Italian section, but I'm posting here so maybe the solution can be helpful to people around there.
I have a sensor which makes 3 readings in a pulse train (inverted PWM signal). Here's an image that maybe explains better:



As you can see, it is inverted PWM output. That's why I need to take the time of the LOW signal states.
Then, I need to calculate the three different values with this simple formulas:

PWM1 = T1/T
PWM2 = T2/T
PWM3 = T3/T

the period of T should be 1.2 sec = 1200 milliseconds.

I would like to do this with pulseIn() or interrupt, but maybe pulseIn() is much more easier. I don't have any idea on how to do this. Any ideas? Thanks!
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I would use an interrupt, with mode CHANGE so that you get an interrupt on both edges. In the interrupt service routine, get the current time by calling micros(). If the pin is low, then you are at the start of T1, T2 or T3, so just store the value you read (in an 'unsigned long' variable). If the pin is high, subtract the value you stored earlier, that gives you the T1, t2 or T3 value in microseconds. Use micros() rather than millis(), because millies() is less accurate and is subject to jitter - it sometimes advances by 2 instead of 1.

Something like this (warning: untested code!):

Code:
unsigned long lastFallingTime;
volatile unsigned long lettura[3];
byte index = 0;

void setup()
{
  attachInterrupt(2, isr, CHANGE);
  Serial.begin(19200);
}

void isr()
{
  unsigned long now = micros();
  if (digitalRead(2) == LOW)
  {
    // falling edge seen
    if (now - lastFallingTime > 2000000UL)
    {
       index = 0;   // we've seen the pause, so reset the counter
    }
    lastFallingTime = now;
  }
  else
  {
    // rising edge seen
    if (index < 3)
    {
      lettura[index] = now - lastFallingTime;
      ++index;
    }
  }
}

void loop()
{
  delay(5000);
  for (int i = 0; i < 3; ++i)
  {
    noInterrupts();
    unsigned long t = lettura[i];
    interrupts();
    Serial.print("Lettura ");
    Serial.print(i);
    Serial.print('=');
    Serial.println(t);
  }
}

[EDIT: corrected code so that it at least compiles without warnings]
« Last Edit: October 25, 2013, 01:52:13 pm by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanx dc42, that's a nice idea.
If I'm not doing something wrong... and if I understood correctly, 100% duty cycle (in this case LOW signal) should be 1.200 milliseconds.
If I have to do the following calculation I need:

Code:
PWM1 = T1/T
PWM2 = T2/T
PWM3 = T3/T

should be
Code:
PWM1 = lettura[0] / T (T, taking a look at the wave graph above, should be 1.200 milliseconds, is that correct?)
PWM2 = lettura[1]
PWM3 = lettura[2]

What do you think?
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

From the diagram in your original post, it looks like 20% of T is the minimum, and 80% is the maximum. It's been done this way so that you always see a pulse, otherwise it would be difficult to work out what is going on when some pulses were at 0% or 100%. So your calculation will give values in the range 20% to 80%.

Do you know how accurate the 1.2 seconds is supposed to be? If it is not very accurate, or if you are looking for accuracy better than 0.5% (the accuracy of the Arduino's ceramic resonator), then it would be best to measure the time between falling edges as well, and use that as the reference. Like this:

Code:
unsigned long lastFallingTime, lastRisingTime;
volatile unsigned int pwm[3];
byte index = 3;    // to avoid storing readings until we are synchronized

void setup()
{
  attachInterrupt(2, isr, CHANGE);
  Serial.begin(19200);
}

void isr()
{
  unsigned long now = micros();
  if (digitalRead(2) == LOW)
  {
    // falling edge seen
    unsigned long interval = now - lastFallingTime;
    if (interval > 2000000UL)
    {
       index = 0;   // we've seen the pause, so reset the counter
    }
    else if (index < 3 && interval >= 0x1000000UL && interval <= 0x1400000UL)   // if between 1000 and 1400ms
    {
      pwm[index] = (unsigned int)(((lastRisingTime - lastFallingTime) * 100)/interval);   // store the PWM value as a percentage
      ++index;
    }
    lastFallingTime = now;
  }
  else
  {
    // rising edge seen
    lastRisingTime = now;
  }
}

void loop()
{
  delay(5000);
  for (int i = 0; i < 3; ++i)
  {
    noInterrupts();
    unsigned int t = pwm[i];
    interrupts();
    Serial.print("PWM ");
    Serial.print(i);
    Serial.print('=');
    Serial.println(t);
  }
}
« Last Edit: October 26, 2013, 04:02:12 am by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

dc42, thanks for the reply.

Using that code i get these results from the serial monitor:

Code:

PWM 0=0
PWM 1=0
PWM 2=0


what's wrong?
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks like no input is being received. The code I suggested assumes that you are running on an Arduino Uno and you feed the input to digital pin 2 (because that is the pin that triggers interrupt 0). Is that what you have done? Do you have a common ground between the sensor and the Arduino?
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Looks like no input is being received. The code I suggested assumes that you are running on an Arduino Uno and you feed the input to digital pin 2 (because that is the pin that triggers interrupt 0). Is that what you have done? Do you have a common ground between the sensor and the Arduino?

Sure yes! Output from the sensor goes to Arduino digital pin 2 and there is ground in common. Maybe there's something with timing in the code? I don't think...
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Are you sure the sensor is generating the pulses? If you do a digitalRead of pin 2 in a loop, do you read both highs and lows?

Also, are you certain that T is 1200ms? It doesn't say that in the diagram that you posted.
« Last Edit: October 28, 2013, 03:17:55 am by dc42 » Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you take a look on the first line just below "PAUSA" in the diagram, you will see that it says

1 sec + 200 msec

oh wait - 1 sec + 200 msec maybe it's not 1.2 secs?
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It's not clear what the 1 sec + 200 msec is, because it doesn't indicate where that time starts from. I think it is the length of the pause. This might not be the same as the time T.

Try this code:

Code:
void loop()
{
  while (digitalRead(2) == HIGH) {}
  unsigned long fall =micros();
  while (digitalRead(2) == LOW) {}
  unsigned long rise = micros();
  Serial.print("Low="); Serial.print(rise - fall);
  while (digitalRead(2) == HIGH) {}
  fall =micros();
  Serial.print(" High="); Serial.println(fall - rise);
}
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That's what I get:

Code:
Low=44724 High=71020
Low=43992 High=71156
Low=22616 High=1249748
Low=44004 High=71020
Low=43992 High=71156
Low=22628 High=1249764
Low=44000 High=71020
Low=44000 High=71164
Low=22624 High=1249824
Low=44004 High=71012
Low=43992 High=71156
Low=22620 High=1249804
Low=44004 High=71024
Low=43992 High=71156
Low=22776 High=1249636
Low=44004 High=71020
Low=44136 High=71016
Low=22624 High=1249764
Low=44004 High=71024
Low=43996 High=71156
Low=22624 High=1249780
Low=43996 High=71016
Low=43992 High=71156
Low=22640 High=1249764
Low=44000 High=71020
Low=44124 High=71020
Low=22636 High=1249740
Low=43996 High=71016
Low=43984 High=71160
Low=22640 High=1249744
Low=44004 High=71012
Low=43992 High=71156
Low=22624 High=1249784
Low=44004 High=71016
Low=43992 High=71160
Low=22784 High=1249652
Low=43996 High=71020
Low=43992 High=71156
Low=22796
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, so T looks like 1.15sec for the first 2 pulses, and 1.27sec for the one that includes the pause. Try the code I suggested in my first reply, but change the constant 2000000UL to 1200000UL.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Done, but i get this:

Code:

Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Lettura 0=0
Lettura 1=0
Lettura 2=0
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 220
Posts: 6587
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry, I got the attachInterrupt call wrong. It should be attachInterrupt(0, isr, CHANGE).
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 46
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice, this is what I get:

Code:

Lettura 0=45196
Lettura 1=44724
Lettura 2=23212
Lettura 0=45196
Lettura 1=44584
Lettura 2=23232
Lettura 0=45196
Lettura 1=44748
Lettura 2=23208
Lettura 0=45200
Lettura 1=44584
Lettura 2=23212
Lettura 0=45200
Lettura 1=44724
Lettura 2=23232

Good! We get results. Now I need to calculate PWM1, PWM2 and PWM3. That is simply done by this:

PWM1 = T1 / T
PWM2 = T2 /T
PWM3 = T3/T

That way we designed PWM signal definition. Then, T1 is the total time subtracted the time that signal stays LOW. Am I correct? I think this is already done in the code. Right?
Logged

Pages: [1] 2   Go Up
Jump to: