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 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 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čů:
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.
Konstrukce
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
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í
- Celý balíček pro Energia: beacon.zip
- Schéma zapojení: beacon_sch.jpg
comments powered by Disqus


