Jump to content
DeepBlueSky

Air humidity alarm

Recommended Posts

I decided to build an air humidity alarm so I know when to air (you can also attach a piezo buzzer, which is more recognizable in some situations). I found/use this lib.

Chip: MSP430G2452 (this I had left, I think it's overkill for this task)

--

Problem solved.

Thanks to all who helped.

To solve the problem I decided to comment out

if (millis() < _lastMillis) {
    return _lastResult; // return last correct measurement
  }
_lastMillis = millis() + 1;

in DHT22_430.cpp because I think the millis() doesn't run below LPM1. I also don't need the millis() because I already wait in interrupts (3-10 seconds, enough for this sensor which needs at least 1-2 seconds time).

I also commented out "delay(250);" and changed "delay(20);" to "delay(10);" to reduce unnecessary power consuming cycles. Tested and works.

BTW: don't forget to comment out "#define DEBUG" in DHT22_430.h (but it will give you a compile error anyway when using timer ("multiple definition of `__isr_9'")).

That's it, no further changes (if I would have made many small changes to the lib, I'd have attached the two lib files in an archive file).

--

Power consumption:

  • In LPM3: 10

    post-39290-0-95126400-1421358874_thumb.jpg

    post-39290-0-15095600-1421358907_thumb.jpg

    post-39290-0-90228900-1421358922_thumb.jpg

Share this post


Link to post
Share on other sites

I don't know the DHT22 library, so I can't be really sure. But as far as I see, you should be able to drop into LPM3, since you're only using the ACLK in the down time. Maybe the DHT22 needs a few milliseconds between wakeup and .get()?

Also, delaying inside an interrupt service routine is deemed bad practice. Instead, set a flag and return with clear on exit (__bic_status_register_on_exit(LPM3_bits))

void loop() {
 _BIS_SR(LPM1_bits); 
  flag = mySensor.get();
  h = mySensor.humidityX10();
  //t = mySensor.temperatureX10();

  if (flag) {
    if(h>=485) {
      digitalWrite(LED,HIGH); //on
      delay(5); //this maybe could be optimized without using delay() but since this is only a few ms, I think it's ok for now
      digitalWrite(LED,LOW); //off
      frequency=3;
    } else
      frequency=10;
  }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0 (void) {
  if(wakeupCounter % frequency == 0) { //check every 10 seconds and sleep deep meanwhile
    __bic_status_register_in_exit(LPM3_bits);
    wakeupCounter=0;
  }
  wakeupCounter++;
}

Share this post


Link to post
Share on other sites

Your code gave this error:

error: '__bic_status_register_in_exit' was not declared in this scope

 

In the msp430g2452.h header file I found

...
#define LPM3      _BIS_SR(LPM3_bits)     /* Enter Low Power Mode 3 */
#define LPM3_EXIT _BIC_SR_IRQ(LPM3_bits) /* Exit Low Power Mode 3 */
...

and replaced the line with LPM3_EXIT. Is this the same as your line?

It compiles but unfortunately does not improve power consumption (700

Share this post


Link to post
Share on other sites

Yes, that's why it is set to every 3 seconds. The delay(100)s come after this time has passed. But there's a problem which I tracked down:

Using e.g. TACCR0 = 12000 and the if(wakeupCounter % frequency == 0) and setting any frequency doesn't work at all, even 10s.

What also doesn't work at all is setting TACCR0 = 60000 and removing the if(...), so it only checks every 5s (which should be more than enough). By "at all" I mean that the sensor just doesn't return a valid value.

It seems that the sensor needs a busy wait of approx 1 second (it's like only this delay(1000) starts the time of the sensor, which is, as already mentioned, "every second or two", which is no problem for me, I don't need a super fast sensor) which of course defies the purpose of sleep.

So although this works, it is not a solution (edited my prior reply code too so it is more correct):

void loop() {
 _BIS_SR(LPM3_bits);
}
...
    delay(1000);
    flag = mySensor.get();
    h = mySensor.humidityX10();
    //t = mySensor.temperatureX10();
    if (flag) {

Any suggestions?

Share this post


Link to post
Share on other sites

I made a typo: use __bic_status_register_on_exit instead of __bic_status_register_in_exit'

 

I think your sensor may be dependent on SMCLK, which is turned off during LPM3. Maybe it's dependent on time deltas from Energia.

Does the system work when dropping to LPM1 instead of LPM3?

If it does not work in LPM1, but does work when adding the 1 second delay after waking from LPM1, then it's the library/driver. There could be some dependency on the Energia framework throwing you off.

Share this post


Link to post
Share on other sites

I tried your version again and it compiles with __bic_status_register_on_exit, but has the same problem as mentioned earlier.

 

Yes, it does work in LPM1, no delay(1000) needed (it's the version in my first post). But when using LPM3 it only works with delay(1000) (as in my post #5). Without the delay in LPM3 I can wait as long as I want, the sensor still doesn't return any valid value.

Share this post


Link to post
Share on other sites

It looks like you are using rei_veilo's DHT22 library. Did you edit the header file and disable the DEBUG ?

 

The reason I ask, by default his library uses the serial port to output debugging information. Because the 2452 lacks hardware serial, it uses timer_serial, and the 2452 only has 1 timer.  If you are trying to use the timer to manage your wake times, it will clash with the timer that timer_serial uses, and hence you'll see funny behaviour like what you are seeing.

 

I haven't actually used your code to see if this is the problem, but it is what jumps out at me from reading the thread.

 

--------------

Edit

--------------

Had another look, and I'm almost certain that the serial debug code in the library is the source of your frustrations. You are using P1_2 for your sensor, which is the TX pin for the 2452's timerserial library.  I'd say that what's happening is the serial code in the debug is sending data on P1_2, which is messing up the DHT22. The reason you need the 1 second delay in LPM3, is to give the timerserial library time to clear the serial queue.

Share this post


Link to post
Share on other sites

Touching the sensor it seems rather cold, no warming.

 

The thing is it needs this delay(1000) only in LPM3, not LPM1. Maybe clock related? In LPM3 SMCLK is, as roadrunner84 also mentioned, turned off, but I don't know. It's strange. LPM2 BTW is same as LPM3.

 

From msp430g2452.pdf:

Share this post


Link to post
Share on other sites

I've had a bit of a play, and the following code (a mash up of yours and roadrunner's)  is working fine, going into LPM3 with about 50uA according to my meter.  Note that I have edited the header for the DHT22 library to comment out the #define DEBUG, and that my data pin for the DHT22 is on P1.4.  

// Include application, user and local libraries
#include "DHT22_430.h"


///
/// @brief	Pin for DHT22 signal
/// @n 		Connect 
/// *		pin 1 (on the left) of the sensor to +5V
/// *		pin 2 of the sensor to DHTPIN 
/// *		pin 4 (on the right) of the sensor to GROUND
/// @n		Place a 10k resistor between pin 2 (data) to pin 1 (power) of the sensor
///
#define DHTPIN P1_4

DHT22 mySensor(DHTPIN);
int wakeupCounter;
int frequency;
#define LED P1_0

void setup() {
    TACCTL0 = CCIE;                     
  TACCR0 = 12000; //1 second
  TACTL = MC_1 | TASSEL_1;
  
  for (int i=0;i<16;i++) //put all pins in INPUT, helps cut power consumption
    pinMode(i,INPUT);
    
  mySensor.begin();
  pinMode(LED,OUTPUT);
  digitalWrite(LED,0);
}


void loop() {
 _BIS_SR(LPM3_bits); 
  int flag = mySensor.get();
  int h = mySensor.humidityX10();
  //t = mySensor.temperatureX10();

  if (flag) {
    if(h>=485) {
      digitalWrite(LED,HIGH); //on
      delay(5); //this maybe could be optimized without using delay() but since this is only a few ms, I think it's ok for now
      digitalWrite(LED,LOW); //off
      frequency=3;
    } else
      frequency=10;
  }
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer0_A0 (void) {
  if(wakeupCounter % frequency == 0) { //check every 10 seconds and sleep deep meanwhile
    __bic_status_register_on_exit(LPM3_bits);
    wakeupCounter=0;
  }
  wakeupCounter++;
}

Share this post


Link to post
Share on other sites

I tried your code and also switched to your ports but it's the same without adding delay: LED does not blink if I breathe at the sensor. ("#define DEBUG" is commented out too).

The sensor gets its data when restarting the chip but doesn't get its data when it's running/waking up when in LPM3 and without delay(1000). Maybe you should test again.

 

What seems to work is when I comment out

  if (millis() < _lastMillis) {
    return _lastResult; // return last correct measurement
  }
  _lastMillis = millis() + 1;

Because in my case I do a "millis()"/waiting by entering the interrupt routine every 10s.

Share this post


Link to post
Share on other sites

I think I've solved it. Mine is working, even when I changed to P1_2. But then I noticed that it was blinking about once every second, not once every 3 seconds as it should. That indicated to me that the clock it was using for the timer was about 3x faster than VLOCLOCK should be. What is 3x faster than VLOCLOCK? The 32768 crystal, and it just so happens my launchpad has the crystal. Grabbed a launchpad without the crystal and I got the failure.

 

Then I realised, nowhere in the above code is the clock source for ACLK configured, so it is probably defaulting to the crystal. I added BCSCTL3=LFXT1S_2; to the setup() just before the lines to configure TimerA, and now it is running with approx 3 seconds between blips as expected on a board without the crystal.

 

 

Sent from my iPad using Tapatalk

Share this post


Link to post
Share on other sites
Had another look, and I'm almost certain that the serial debug code in the library is the source of your frustrations. You are using P1_2 for your sensor, which is the TX pin for the 2452's timerserial library.  I'd say that what's happening is the serial code in the debug is sending data on P1_2, which is messing up the DHT22. The reason you need the 1 second delay in LPM3, is to give the timerserial library time to clear the serial queue.

I'm not sure / I don't think so: Before I decided to ask I already commented out the debug code because it gave me a compile error right away "multiple definition of `__isr_9'". Using different ports also works (DHTPIN P1_3, LED P1_2) when millis() (see below) is commented out.

 

grahamf72, you indeed solved it for yourself :) As already said your code doesn't work for me. However, when I comment out

  if (millis() < _lastMillis) {
    return _lastResult; // return last correct measurement
  }
  _lastMillis = millis() + 1;

in DHT22_430.cpp it seems to work :) It looks like the millis() can't run in LPM2 / LMP3.

I also commented out "delay(250);" and changed "delay(20);" to "delay(10);" to reduce unnecessary power consuming cycles.

And what also works now is the code pattern suggested by roadrunner84.

 

I think the problem is hereby solved :)First post edited.

Can this be moved back to projects?

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...