07.07.2013Beacon (maják)

K vytvoření tohoto zařízení jsem použil MSP430G2452 (chip dodávaný s Launchpadem jako druhý chip) a transceiver NRF24L01. Obojí je konstruováno pro minimální spotřebu a obojí je schopné jít do hlubokého spánku(deep sleep). Velmi snadno by šlo přidat jakýkoliv senzor (například teploty) a udělat tak bezdrátový modul na měření teploty. Takových modulů může být mnoho a jeden příjmač (sběrač dat) by mohl data ze všech senzorů zpracovávat.

Konstrukce

Test návrhu

Konstrukce je jednoduchá, v podstatě se propojí mikrokontroler, transceiver a základní součástky jako decoupling kondenzátor a pull-up odpor na RST pin. Já navíc přidal ještě informační LED a nastavovací 3-přepínač, který mi umožňuje nastavit parametry majáku bez přeprogramovávání. Deska i s baterií budou v krabičce klíčenkového typu.

Program

Spotřeba pouze 4uA!

Program má dvě různé varianty jak může fungovat v závislosti na nastavení 3-přepínače. Přepínač #1 slouží k zapnutí nebo vypnutí signalizační LED, přepínače #2 a #3 nastavují délku intervalu a jiné chování.

Existují 4 stavy přepínačů:

  • 0 : Interval 1s, bez deep sleep, v naslouchacím režimu, je možné ho požádat o identifikaci, s autoACK
  • 1 : Interval 1s, s deep sleep, bez naslouchacího režimu, nelze ho požádat o identifikaci, bez autoACK
  • 2 : Interval 5s, s deep sleep, bez naslouchacího režimu, nelze ho požádat o identifikaci, bez autoACK
  • 3 : Interval 15s, s deep sleep, bez naslouchacího režimu, nelze ho požádat o identifikaci, bez autoACK


program si po startu načte nastavení 3-přepínače, nastaví transceiver a krom stavu 0 uvede chip i transceiver do deep sleep. Po uběhnutí nastaveného intervalu se chip i transceiver probudí, provedou vysílání a zase se uspí. Díky tomu je celé zařízení většínu času v hlubokém spánku a spotřebovává pouze 4uA! S baterií CR2025 která má 230mAh zhruba 6.5 roku. Vzhledem k tomu, že není celou dobu jen ve spánku, bude to výrazně méně. Určitě ale vzdrží mnoho měsíců až let podle délky intervalu.

Kód

#include "Enrf24.h"
#include "nRF24L01.h"
#include <string.h>
#include <SPI.h>

/* SWITCHER STATES
2 | 3
0 | 0 => enable RX / 1s
1 | 0 => disable RX / 1s
0 | 1 => disable RX / 5s
1 | 1 => disable RX / 15s
*/

Enrf24 radio(P2_0, P2_1, P2_2); // P2.0=CE, P2.1=CSN, P2.2=IRQ

const char IDENTIFY=1;
const int SWITCHER_2=P1_4;
const int SWITCHER_3=P1_3;
const int SWITCHER_POWER=P2_3;
const int INFO_LED=P1_0;

char rxaddr[] = {'d','e','v','-','b'};
char txaddr[] = {'d','e','v','-','0'};

unsigned long mil;
unsigned long prev_time;
boolean rx_enabled=false;
int status=0;
int interval=1000;

void mdelay(uint32_t milliseconds)
{
    WDTCTL = WDT_ADLY_1_9;  // WDT triggered from ACLK after ~6ms, millis() will be skewed BTW
    uint32_t wakeTime = milliseconds/5;
        while(wakeTime>0){
                wakeTime--;
                /* Wait for WDT interrupt in LMP3 */
                __bis_status_register(LPM3_bits+GIE);
        }
   WDTCTL = WDT_MDLY_0_5; // WDT back to original Energia setting, SMCLK 0.5ms/IRQ
}

void setup() {
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(1); // MSB-first
  
  radio.begin();  // Defaults 1Mbps, channel 0, max TX power

  radio.setRXaddress((void*)rxaddr);
  radio.setTXaddress((void*)txaddr);
  
  // LED
  pinMode(INFO_LED, OUTPUT);
  digitalWrite(INFO_LED, LOW);
  // Switcher power
  pinMode(SWITCHER_POWER,OUTPUT);
  digitalWrite(SWITCHER_POWER, LOW);
  // Switcher 2
  pinMode(SWITCHER_2, INPUT);
  // Switcher 3
  pinMode(SWITCHER_3, INPUT);
  //
  
  digitalWrite(INFO_LED, HIGH);
  delay(100);
  digitalWrite(INFO_LED, LOW);
  delay(100);
  digitalWrite(INFO_LED, HIGH);
  delay(100);
  digitalWrite(INFO_LED, LOW);
  delay(100);
  
  digitalWrite(SWITCHER_POWER, HIGH);
  if(digitalRead(SWITCHER_2)==HIGH && digitalRead(SWITCHER_3)==LOW){status=1;}
  if(digitalRead(SWITCHER_2)==LOW && digitalRead(SWITCHER_3)==HIGH){status=2;}
  if(digitalRead(SWITCHER_2)==HIGH && digitalRead(SWITCHER_3)==HIGH){status=3;}
  digitalWrite(SWITCHER_POWER, LOW);
  
  if(status==1 || status==0){interval=1000;}
  if(status==2){interval=5000;}
  if(status==3){interval=15000;}
  
  if(status==0)
  {
    rx_enabled=true;
    radio.enableRX();  // Start listening
    digitalWrite(INFO_LED, HIGH);
    delay(1000);
    digitalWrite(INFO_LED, LOW);
    delta_set();
  }
  
  if(status>0)
  {
    radio.autoAck(false);
    delay(100);
    radio.deepsleep();
  }
}

void loop() {
  if(rx_enabled)
  {
    char inbuf[33];
    while (!radio.available(true)){
      beep(status);
    }
    if (radio.read(inbuf))
    {
      if (inbuf[0]==IDENTIFY)
      {
       radio.lastTXfailed=false;
       radio.print("Beacon #1");
       radio.flush();
       if(radio.lastTXfailed)
       {
         radio.print("Beacon #1");
         radio.flush();
       }
      }
    }
  }
  else
  {
    beep(status);
  }
}

void beep(int status)
{
  if(status>0)
  {
    mdelay(interval);
    radio.begin();
  }
  if(status>0 || delta_get()>interval)
  {
    radio.lastTXfailed=false;
    radio.print("BEACON#1");
    radio.flush();
    if(!radio.lastTXfailed)
    {
      digitalWrite(INFO_LED,HIGH);
      delay(1);
      digitalWrite(INFO_LED,LOW);
    }
    else if(status==0)
    {
      digitalWrite(INFO_LED,HIGH);
      delay(10);
      digitalWrite(INFO_LED,LOW);
      delay(100);
      digitalWrite(INFO_LED,HIGH);
      delay(10);
      digitalWrite(INFO_LED,LOW);
    }
    if(status==0)
    {
      delta_set();
    }
  }
  
  if(status>0)
  {
    radio.deepsleep();
  }
}

unsigned long delta_set() {
      prev_time = millis();
      return prev_time;
}

unsigned long delta_get() {
      unsigned long time;
      unsigned long delta;
      
      time = millis();
      if (time < prev_time) { // Timer overflow
            delta = 0xffffffff - prev_time + time + 1;
      } else {
            delta = time - prev_time;
      }
      return delta;
}


Ke stažení




comments powered by Disqus