Author Topic: Unidirectional Transmission system (to remotely activate a buzzer) [Help needed]  (Read 2457 times)

Laeras

  • Newbie
  • *
  • Posts: 5
Hello, 18yr old engineering high school student here (but I digress, demographics are for marketers)


For a school project, I (foolishly, in hindsight.  This is far more difficult than I could have possibly anticipated.  I guess I was disillusioned by my success in getting two PC's to network properly?) decided to try making an object locating device. 


Said device would function by causing a loud buzzing sound to play from a small device when a button on a linked device was held.  I got myself two arduino mini pro's (the 5v version) and 2 RFM12BSP transcievers (and also a programmer so that I could program the arduinos). 

I've wired them up approximately as shown at http://lowpowerlab.com/blog/2012/12/28/rfm12b-arduino-library/ (I need to add some more resistors because I ran out, but I'm resupplying tomorrow, so that shouldn't be a huge issue).  However, I then ran into the daunting task of actually programming this thing. 

I've been reading over https://github.com/LowPowerLab/RFM12B/blob/master/Examples/Send/Send.ino and https://github.com/LowPowerLab/RFM12B/blob/master/Examples/Receive/Receive.ino, but as I was honestly quite confused as to how to use these, I decided to try a forum search, which netted me this topic: https://lowpowerlab.com/forum/index.php/topic,172.msg744.html#msg744 .  To finally get to the proper topic at hand, however, I wanted to know how to use the send/recieve code(I'm treating it like a black-box at the moment, where I don't need to know HOW it does what it does, I just need to know what it does), and whether I could make the payload a boolean value and set a variable on the recieve side equal to the value sent by the transmitting side (I figured I could go with a longer "update" cycle, such as 1 packet every second or so, since the button isn't exactly time-sensitive.)  Sorry about the wall of text, just trying to ensure that whatever I do, I don't screw up the programming and totally break the arduino or the transciever (I'm entirely out of budget at this point, so if I screw this up, my grade is screwed).

Sorry to bother you, and sorry in advance if this is a stupid question (and also sorry for the wall of text.  I tried to break it up some for yo

Laeras

  • Newbie
  • *
  • Posts: 5
Have the resistors plugged in now, and am still looking at the code. (this may or may not be a shameless bump)

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6403
  • Country: us
    • LowPowerLab
Hey, well let's try to help your grade here.
You should have gotten the 3.3V version, or just get Moteinos which just work :P (not meaning to self advertise but it really pays off tons in time saved and exchanges in the forum). Also RFM69 should have been a better choice when you start to realize RFm12B range is kind of limited. But you're budget starved so forget my day dreaming.
You will have to give the RFM12Bs 3.3V and also buffer the data lines going INTO the RFM12B side so they are not more than 3.5V. You can do that with resistors (forming a voltage divider). Many threads in the forum on that topic.
Also Illustrated in this photo below.
After that you should be able to load the Send and Receive examples, adjust settings to match frequency etc, and you should see messages going across. Once you are at that point we can take this further.




Laeras

  • Newbie
  • *
  • Posts: 5
I've done that (put the resistors in the proper place, etc)

I also took the send and recieve example codes and tried getting them working(after modifying them slightly).  Mixed results.  My guess is I screwed something up or didn't understand something somewhere, but I figured that radio.Data[] would be the payload[] send in the transmit side if everything goes well.  I tried using the 8th index of payload[] (so payload[8]) to carry a boolean value by setting it equal to '1' or '0' based off it a button is pressed.  If that's not how it works, my bad, but so far radio.Data[8] is equal to null.  Gonna try figuring out how to progress from here when I get up, but it's 4am so I'm done working for tonight.

TomWS

  • Hero Member
  • *****
  • Posts: 1925
At this point, posting your code would help us help you.

Tom

Laeras

  • Newbie
  • *
  • Posts: 5
Ah, my bad.


Couldn't find the spoiler button, so I'm just putting it in quotes

Code: [Select]
// Simple RFM12B sender program, with ACK and optional encryption
// It initializes the RFM12B radio with optional encryption and passes through any valid messages to the serial port
// felix@lowpowerlab.com


#include <RFM12B.h>
#include <avr/sleep.h>


// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID        2  //network ID used for this unit
#define NETWORKID    99  //the network ID we are on
#define GATEWAYID     1  //the node ID we're sending to
#define ACK_TIME     50  // # of ms to wait for an ack
#define SERIAL_BAUD  115200


//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";


int interPacketDelay = 1000; //wait this many ms between sending packets


// Need an instance of the Radio Module
RFM12B radio;
byte sendSize=0;
char payload[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~!@#$%^&*(){}[]`|<>?+=:;,.";
bool requestACK=false;


void setup()
{
  pinMode(13, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, INPUT);
  pinMode(3, OUTPUT);
  digitalWrite(4, HIGH);//this is the high voltage pin for the button.
  digitalWrite(3, HIGH);//should power up the transciever  (I have it powering the transciever)
  radio.Initialize(NODEID, RF12_915MHZ, NETWORKID);
  //radio.Encrypt(NULL);
  radio.Sleep(); //sleep right away to save power
}


void loop()
{
  if(digitalRead(5))//this is my button, I've tested it and it seems to work fine
  {
    payload[8] = '1';//set 8th character to a 1 to tell the recieving end to buzz
  }
  else
  {
    payload[8] = '0';//set the 8th character to a 0 to tell the recieving end to stop buzzing
  }
  requestACK = !(sendSize % 3); //request ACK every 3rd xmission
  radio.Wakeup();
  radio.Send(GATEWAYID, payload, sendSize+1, requestACK);
  radio.Sleep();
  sendSize = (sendSize + 1) % 88;
  delay(interPacketDelay);
  digitalWrite(13, !digitalRead(5)); //turns the LED to tell me if the button is pushed, but doesn't seem to work right :/
}


// wait a few milliseconds for proper ACK, return true if received
static bool waitForAck() {
  long now = millis();
  while (millis() - now <= ACK_TIME)
    if (radio.ACKReceived(GATEWAYID))
      return true;
  return false;
}]




Recieving end
Code: [Select]
// Simple serial pass through program
// It initializes the RFM12B radio with optional encryption and passes through any valid messages to the serial port
// felix@lowpowerlab.com

#include <RFM12B.h>

// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID           1  //network ID used for this unit
#define NETWORKID       99  //the network ID we are on
#define SERIAL_BAUD 115200

//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";

// Need an instance of the Radio Module
RFM12B radio;
void setup()
{
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(3, HIGH);
 
  radio.Initialize(NODEID, RF12_915MHZ, NETWORKID);
  //radio.Encrypt(NULL);      //comment this out to disable encryption
  Serial.begin(SERIAL_BAUD);
  Serial.println("Listening...");
}

void loop()
{
 
  radio.ReceiveComplete();
 
    radio.CRCPass();
   
      radio.GetSender();
      for (byte i = 0; i < *radio.DataLen; i++) //can also use radio.GetDataLen() if you don't like pointers
       Serial.print((char)radio.Data);
      if(radio.Data[8] == '1')
        {digitalWrite(4, HIGH);} //this part activates a  buzzer (I've tested the buzzer, it works fine
      else
        {digitalWrite(4, LOW);}
         

      if (radio.ACKRequested())
      {
        radio.SendACK();
      }
 
}
I removed a lot of the serial stuff, which in hindsight may have been a bad idea, but it doesn't seem to work with the setup I'm using to program it (I have a very weird setup involving a https://www.sparkfun.com/products/12924 and a breadboard)

Laeras

  • Newbie
  • *
  • Posts: 5
Made some modifications
transmit
Code: [Select]
// Simple RFM12B sender program, with ACK and optional encryption
// It initializes the RFM12B radio with optional encryption and passes through any valid messages to the serial port
// felix@lowpowerlab.com

#include <RFM12B.h>
#include <avr/sleep.h>

// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID        2  //network ID used for this unit
#define NETWORKID    99  //the network ID we are on
#define GATEWAYID     1  //the node ID we're sending to
#define ACK_TIME     50  // # of ms to wait for an ack
#define SERIAL_BAUD  115200

//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";

int interPacketDelay = 1000; //wait this many ms between sending packets

// Need an instance of the Radio Module
RFM12B radio;
byte sendSize=0;
char payload[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~!@#$%^&*(){}[]`|<>?+=:;,.";
bool requestACK=false;
bool buttonPressed = false;
void setup()
{
  pinMode(13, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, INPUT);
  pinMode(3, OUTPUT);
  digitalWrite(4, HIGH);
  digitalWrite(3, HIGH);//should power up the transciever
  radio.Initialize(NODEID, RF12_915MHZ, NETWORKID);
  //radio.Encrypt(NULL);
 radio.Sleep(); //sleep right away to save power
}

void loop()
{
  interPacketDelay = 500;
  buttonPressed = digitalRead(5);
  if(buttonPressed == HIGH)
  {
    payload[8] = '1';
    digitalWrite(13, HIGH);
  }
  else
  {
    digitalWrite(13, LOW);
    payload[8] = '0';
  }
  requestACK = !(sendSize % 3); //request ACK every 3rd xmission
  radio.Wakeup();
  radio.Send(GATEWAYID, payload, sendSize+1, requestACK);
  if(requestACK)
    waitForAck();
  radio.Sleep();
  sendSize = (sendSize + 1) % 88;
  delay(interPacketDelay);
}
// wait a few milliseconds for proper ACK, return true if received
static bool waitForAck() {
  long now = millis();
  while (millis() - now <= ACK_TIME)
    if (radio.ACKReceived(GATEWAYID))
      return true;
  return false;
}


recieve

Code: [Select]
// Simple serial pass through program
// It initializes the RFM12B radio with optional encryption and passes through any valid messages to the serial port
// felix@lowpowerlab.com

#include <RFM12B.h>

// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID           1  //network ID used for this unit
#define NETWORKID       99  //the network ID we are on
#define SERIAL_BAUD 115200

//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";

// Need an instance of the Radio Module
RFM12B radio;

void setup()
{
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(3, HIGH);
 
  radio.Initialize(NODEID, RF12_915MHZ, NETWORKID);
  //radio.Encrypt(NULL);      //comment this out to disable encryption
  Serial.begin(SERIAL_BAUD);
  Serial.println("Listening...");
}

void loop()
{
 
  radio.ReceiveComplete();
 
    radio.CRCPass();
   
      radio.GetSender();
      for (byte i = 0; i < *radio.DataLen; i++) //can also use radio.GetDataLen() if you don't like pointers
       Serial.print((char)radio.Data[i]);
      if(radio.Data[8] != NULL)
        {digitalWrite(4, HIGH);}
      else
        {digitalWrite(4, LOW);}
         

      if (radio.ACKRequested())
      {
        radio.SendACK();
      }
 
}

TomWS

  • Hero Member
  • *****
  • Posts: 1925
I'm not familiar with the RFM12 library so I just have a couple of observations:
1. Does the library really support packets as long as 88 bytes?
2. In the receiving code, where you're trying to print the data, you have:
Code: [Select]
       Serial.print((char)radio.Data);

which should be:
Code: [Select]
       Serial.print((char)radio.Data[i]);
3.  The sender is sending varying lengths of packets from 1 to 88 bytes of data.  Obviously you will not receive payload[8] until the data length is at least 9.
4. The Moteino LED is on pin 9, not 13.
5. Request Ack will not do much good for two reasons: 1. You're sleeping the radio as soon as you send so you're going to miss an Ack when it's sent. 2. The Ack will be send AFTER all the serial output takes place, delaying when the Ack is actually sent.

That's all I see at the moment with admittedly quick scan.

Tom

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 6403
  • Country: us
    • LowPowerLab
Yeah the lib supports up to 128bytes length. The RFm12B only has 2 bytes of buffer but they can be streamed so long messages can be achieved.
More details here: https://github.com/lowpowerlab/rfm12b