// RFM69HCW Example Sketch
// Send serial input characters from one RFM69 node to another
// Based on RFM69 library sample code by Felix Rusu
// http://LowPowerLab.com/contact
// Modified for RFM69HCW by Mike Grusin, 4/16
// This sketch will show you the basics of using an
// RFM69HCW radio module. SparkFun's part numbers are:
// 915MHz: https://www.sparkfun.com/products/12775
// 434MHz: https://www.sparkfun.com/products/12823
// See the hook-up guide for wiring instructions:
// https://learn.sparkfun.com/tutorials/rfm69hcw-hookup-guide
// Uses the RFM69 library by Felix Rusu, LowPowerLab.com
// Original library: https://www.github.com/lowpowerlab/rfm69
// SparkFun repository: https://github.com/sparkfun/RFM69HCW_Breakout
// Include the RFM69 and SPI libraries:
#include <Wire.h>
#include <LSM303.h>
#include <avr/wdt.h>
#include <RFM69.h>
#include <SPI.h>
#include <avr/sleep.h>
LSM303 compass;
// Addresses for this node. CHANGE THESE FOR EACH NODE!
#define NETWORKID 0 // Must be the same for all nodes
#define MYNODEID 2 // My node ID
#define TONODEID 1 // Destination node ID
// RFM69 frequency, uncomment the frequency of your module:
//#define FREQUENCY RF69_433MHZ
#define FREQUENCY RF69_915MHZ
// AES encryption (or not):
#define ENCRYPTKEY "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes
// Use ACKnowledge when sending messages (or not):
#define USEACK true // Request ACKs or not
// Packet sent/received indicator LED (optional):
#define LED 14 // LED positive pin
#define PGOOD 4 // PGOOD
#define VTEST 8 // VTEST MOSFET
// Create a library object for our RFM69HCW module:
int level = 0;
RFM69 radio;
void setup()
{
// Open a serial port so we can send keystrokes to the module:
Wire.begin();
compass.init();
compass.enableDefault();
compass.m_min = (LSM303::vector<int16_t>){-32767, -32767, -32767};
compass.m_max = (LSM303::vector<int16_t>){+32767, +32767, +32767};
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
pinMode(7,OUTPUT); //mosfet
pinMode(PGOOD, INPUT); // PGOOD
pinMode(A1, INPUT);
pinMode(LED,OUTPUT);
pinMode(VTEST,OUTPUT);
wdt_enable(WDTO_8S);
}
void loop()
{
digitalWrite(VTEST, HIGH); //turn on MOSFET to read voltage
digitalWrite(7, LOW); // turn off MOSFET
level = digitalRead(PGOOD);
if(level == HIGH)
{
digitalWrite(VTEST, HIGH); //turn on MOSFET to read voltage
digitalWrite(7, HIGH); // turn on MOSFET
radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
radio.setHighPower(); // Always use this for RFM69HCW
// Turn on encryption if desired:
radio.encrypt(ENCRYPTKEY);
compass.read();
double H = compass.heading();
char Pstr[10];
char Hstr[10];
char buffer[50];
double P = (analogRead(A1)*0.006451); // analog read out of 1023 (based on .975V as highest value), multiply this ratio by 3.33333 to get the actual.
dtostrf(H, 3,3, Hstr);
dtostrf(P, 3,3, Pstr);
static int sendlength = strlen(buffer);
sprintf(buffer, "BAT: Power:%sV Heading:%s", Pstr, Hstr);
radio.sendWithRetry(TONODEID, buffer, sendlength);
Blink(LED,1000);
level = LOW;
sleep();
}
else
{
digitalWrite(7, LOW); // turn off MOSFET
sleep();
}
}
void Blink(byte PIN, int DELAY_MS)
// Blink an LED for a given number of ms
{
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}
void sleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select PWR DOWN, the most power savings
sleep_enable(); //set SE bit
sei(); // enable global interrupts
sleep_cpu(); //actually sleep
sleep_disable(); //code reaches this point after interrupt
}
Errata:
-I used SDA and SCL for motor driving but they should have been kept for I2C sensor reading.
-can’t use XTAL in arduino software environment (PB6 and PB7)
-I should have picked up a LUX sensor which already has readily available libraries AND is in stock, such as the VEML7700
-Because soldering tiny components is difficult and not fun I am considering eliminating the compass from the project. If the user sets the device to point north on start up it can track itself knowing the rotation of the motors.
And this code uses both the compass and the lux sensor, sharing the same lines.
This is the Lux sensor I’m using:
https://www.adafruit.com/product/1980
And I’m getting the temperature (and received transmission power reading) from inside the RF69.
I’m also reading two photodiodes and turning two motors. The photodiodes are set up like so: https://electronics.stackexchange.com/questions/73732/how-to-use-sfh235-ir-photodiode-correctly
// RFM69HCW Example Sketch
// Send serial input characters from one RFM69 node to another
// Based on RFM69 library sample code by Felix Rusu
// http://LowPowerLab.com/contact
// Modified for RFM69HCW by Mike Grusin, 4/16
// This sketch will show you the basics of using an
// RFM69HCW radio module. SparkFun's part numbers are:
// 915MHz: https://www.sparkfun.com/products/12775
// 434MHz: https://www.sparkfun.com/products/12823
// See the hook-up guide for wiring instructions:
// https://learn.sparkfun.com/tutorials/rfm69hcw-hookup-guide
// Uses the RFM69 library by Felix Rusu, LowPowerLab.com
// Original library: https://www.github.com/lowpowerlab/rfm69
// SparkFun repository: https://github.com/sparkfun/RFM69HCW_Breakout
// Include the RFM69 and SPI libraries:
#include "Adafruit_TCS34725.h"
#include <Wire.h>
#include <LSM303.h>
#include <avr/wdt.h>
#include <RFM69.h>
#include <SPI.h>
#include <avr/sleep.h>
LSM303 compass;
// Addresses for this node. CHANGE THESE FOR EACH NODE!
#define NETWORKID 0 // Must be the same for all nodes
#define MYNODEID 2 // My node ID
#define TONODEID 1 // Destination node ID
// RFM69 frequency, uncomment the frequency of your module:
//#define FREQUENCY RF69_433MHZ
#define FREQUENCY RF69_915MHZ
// AES encryption (or not):
#define ENCRYPTKEY "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes
// Use ACKnowledge when sending messages (or not):
#define USEACK true // Request ACKs or not
// Packet sent/received indicator LED (optional):
#define LED 14 // LED positive pin
#define PGOOD 4 // PGOOD
#define VTEST 8 // VTEST MOSFET
// Create a library object for our RFM69HCW module:
int level = 0;
RFM69 radio;
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X);
void setup()
{
// Open a serial port so we can send keystrokes to the module:
Wire.begin();
compass.init();
compass.enableDefault();
compass.m_min = (LSM303::vector<int16_t>){-32767, -32767, -32767};
compass.m_max = (LSM303::vector<int16_t>){+32767, +32767, +32767};
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
pinMode(7,OUTPUT); //mosfet
pinMode(PGOOD, INPUT); // PGOOD
pinMode(A1, INPUT);
pinMode(LED,OUTPUT);
pinMode(VTEST,OUTPUT);
pinMode(0, OUTPUT); //motors
pinMode(1, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
wdt_enable(WDTO_8S);
tcs.begin();
}
void loop()
{
uint16_t r, g, b, c, colorTemp, L;
digitalWrite(VTEST, HIGH); //turn on MOSFET to read voltage
digitalWrite(7, LOW); // turn off MOSFET
level = digitalRead(PGOOD);
if(level == HIGH)
{
digitalWrite(VTEST, HIGH); //turn on MOSFET to read voltage
digitalWrite(7, HIGH); // turn on MOSFET
radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
radio.setHighPower(); // Always use this for RFM69HCW
// Turn on encryption if desired:
radio.encrypt(ENCRYPTKEY);
compass.read();
double H = compass.heading();
double T = radio.readTemperature();
char Leftstr[10];
char Rightstr[10];
char Tstr[10];
char Pstr[10];
char Hstr[10];
char Lstr[10];
char buffer[50];
double P = (analogRead(A1)*0.006451); // analog read out of 1023 (based on .975V as highest value), multiply this ratio by 3.33333 to get the actual.
tcs.getRawData(&r, &g, &b, &c);
// colorTemp = tcs.calculateColorTemperature(r, g, b);
colorTemp = tcs.calculateColorTemperature_dn40(r, g, b, c);
L = tcs.calculateLux(r, g, b);
double left = analogRead(A3);
double right = analogRead(A2);
dtostrf(left, 3,3, Leftstr);
dtostrf(right, 3,3, Rightstr);
dtostrf(T, 3,3, Tstr);
dtostrf(H, 3,3, Hstr);
dtostrf(P, 3,3, Pstr);
dtostrf(L, 3,3, Lstr);
static int sendlength = strlen(buffer);
sprintf(buffer, "B:%sV H:%s Lx:%s T:%s L:%s R:%s", Pstr, Hstr, Lstr, Tstr, Leftstr, Rightstr);
radio.sendWithRetry(TONODEID, buffer, sendlength);
if(left>right)
{
digitalWrite(0, HIGH);
digitalWrite(1, LOW);
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
delay(1000);
}
else
{
digitalWrite(0, LOW);
digitalWrite(1, HIGH);
digitalWrite(5, LOW);
digitalWrite(6, HIGH);
delay(1000);
}
Blink(LED,1000);
level = LOW;
sleep();
}
else
{
digitalWrite(7, LOW); // turn off MOSFET
sleep();
}
}
void Blink(byte PIN, int DELAY_MS)
// Blink an LED for a given number of ms
{
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}
void sleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select PWR DOWN, the most power savings
sleep_enable(); //set SE bit
sei(); // enable global interrupts
sleep_cpu(); //actually sleep
sleep_disable(); //code reaches this point after interrupt
}
I am making the BOM list now for the conference. Here is the list of components so far (all in 1206 and hand-solderable packages):
Solar Cell SCC3733 3.3V FTDI Cable MOMENTARY-SWITCH-SPST-SMD-6.2MM-TALL Atmega328P TQFP RFM69HCW Wireless Transceiver – 915MHz solid core wire for antenna Single + double row detachable male headers jumpers of various types (male to female, female to female, male to male) DRV8833 Motor Driver HTSSOP LTC3105 MSOP VEML7700 Lux Sensor Short female double row headers RED LED 1206 GREEN LED 1206 N-CHANNEL POWER MOSFET 2.7V 1F Supercapacitor 647-JUWT1105MCD 10uH Inductor 994-MSS5131-103MLC Photodiode BPW34 Micro Gearmotor – 175 RPM (6-12V) Atmel ICE programmer Gear Motor 23 – 1:192 Offset Shaft GM23 Gear Motor 24 – 1:192 90 Degree Shaft GM24
0.1uF 33pF 10uF 1uF 4.7uF 500K 2.2K 1M 240K 150K 499K 1M 20K 0K 10K 500K 2.2K 1M 240K 150K 499K 1M 20K 0K
And here is a 3D print of how gearmotors could be used to make a two axis panel tilt set up.
And here is the newest version of the board:
Errata: SDA and SCL switched on LTC3105 board. Also, the lux sensor I bought VEML6030 doesn’t work. -break out PGOOD to a pin for testing purposes
Other idea for a minimal version of this circuit with attiny84.
Same thing with Atmega328p (getting things to work software side with Attiny + RF69 is tough…)
I’m calling it the wasp (a 10F cap has some sting!). I like that it fits on one board, this solves the most challenging aspect of the last design – connecting a bunch of pins between two boards and dealing with the cubersome thickness that it has in the end. It has less functionality but it has the essential stuff and maybe the rest was not necessary in the end. It’s ready to be embed in resin and strapped to a tree outdoors!
Here is the mould ready to go for resin test:
I’m using this resin: https://www.boutique-resine-epoxy.fr/resine-biosourcee/352-resine-epoxy-sr-greenpoxy-56-durcisseur-sd-surf-clear.html
SR greenPoxy 56 SD GreenPox 505 V2 (catalizer)
The ratio is 1:2, thanks to Remy Ducros for his documentation: http://fabacademy.org/2019/labs/digiscope/students/remy-ducros/assignement/week18/
My plan is to wrap the capacitor in foam so that it can expand if necessary and to keep all the pins accessible (outside the resin) then to put it outside for a while and see if it still works later!
Had an issue where the device needed to be restarted everytime the microchip lost power (overnight for instance). Came up with a fix, here is the new code:
// RFM69HCW Example Sketch
// Send serial input characters from one RFM69 node to another
// Based on RFM69 library sample code by Felix Rusu
// http://LowPowerLab.com/contact
// Modified for RFM69HCW by Mike Grusin, 4/16
// This sketch will show you the basics of using an
// RFM69HCW radio module. SparkFun's part numbers are:
// 915MHz: https://www.sparkfun.com/products/12775
// 434MHz: https://www.sparkfun.com/products/12823
// See the hook-up guide for wiring instructions:
// https://learn.sparkfun.com/tutorials/rfm69hcw-hookup-guide
// Uses the RFM69 library by Felix Rusu, LowPowerLab.com
// Original library: https://www.github.com/lowpowerlab/rfm69
// SparkFun repository: https://github.com/sparkfun/RFM69HCW_Breakout
// Include the RFM69 and SPI libraries:
#include <SPI.h>
#include <avr/wdt.h>
#include <RFM69.h>
#include <avr/sleep.h>
// Addresses for this node. CHANGE THESE FOR EACH NODE!
#define NETWORKID 0 // Must be the same for all nodes
#define MYNODEID 2 // My node ID
#define TONODEID 1 // Destination node ID
// RFM69 frequency, uncomment the frequency of your module:
//#define FREQUENCY RF69_433MHZ
#define FREQUENCY RF69_915MHZ
// AES encryption (or not):
#define ENCRYPTKEY "TOPSECRETPASSWRD" // Use the same 16-byte key on all nodes
// Use ACKnowledge when sending messages (or not):
#define USEACK true // Request ACKs or not
// Packet sent/received indicator LED (optional):
#define LED A3 // LED positive pin
#define PGOOD 3 // PGOOD
#define MOSFET 9//
// Create a library object for our RFM69HCW module:
int level;
RFM69 radio;
void setup()
{
// Open a serial port so we can send keystrokes to the module:
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
pinMode(MOSFET,OUTPUT); //mosfet
pinMode(PGOOD, INPUT); // PGOOD
}
void loop()
{
wdt_enable(WDTO_8S);
level = digitalRead(PGOOD);
if(level == HIGH)
{
char Tstr[10];
digitalWrite(MOSFET, HIGH); // turn on MOSFET
delay(100);
radio.initialize(FREQUENCY, MYNODEID, NETWORKID);
radio.setHighPower(); // Always use this for RFM69HCW
// Turn on encryption if desired:
radio.encrypt(ENCRYPTKEY);
double T = radio.readTemperature();
char buffer[50];
dtostrf(T, 3,3, Tstr);
static int sendlength = strlen(buffer);
sprintf(buffer, " T:%s", Tstr);
radio.sendWithRetry(TONODEID, buffer, sendlength);
Blink(LED,100);
}
else
{
sleep();
}
}
void Blink(byte PIN, int DELAY_MS)
// Blink an LED for a given number of ms
{
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
}
void sleep(void)
{
digitalWrite(MOSFET, LOW); // turn on MOSFET
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //select PWR DOWN, the most power savings
sleep_enable(); //set SE bit
sei(); // enable global interrupts
sleep_cpu(); //actually sleep
sleep_disable(); //code reaches this point after interrupt
}
I have a new scheme to maintain the flatness of the circuit board but “pop-up” from it. I like the idiosyncratic form it gives:
Here are some of the slides from the workshop itself:
For the TX module A-side:
And for the RX module: