Parts List for the Receiver
I sometimes find that the recommended parts are occasionally out of stock at the companies mentioned below. If this is the case they are often in stock at Digikey or Mouser or other electronics supply companies that stock Sparkfun or Adafruit products. Take a look if you are having trouble finding parts.
Quantity 1
Microprocessor and Transmitter / Receiver that supports the I2C (Qwiic) Interface
SparkFun Pro RF – LoRa, 915MHz (SAMD21)
Sparkfun Part: WRL-15836
Quantity 1
SD Card Reader / Writer that uses the I2C (Qwiic) Interface
Qwiic OpenLog Hookup Guide
Sparkfun Part: DEV-15164
Quantity 1
OLED Display that uses the I2C (Qwiic) Interface
Zio Qwiic OLED Display (1.5inch, 128×128)
Sparkfun Part: LCD-15890
Quantity 1
3-Element Directional Antenna on 915 Mhz
Apogee Components 915 MHZ YAGI ANTENNA
Model: 09221
Quantity 1
SMA Connector Female to RP-SMA Female Connector
Amazon
Quantity 1
Battery
Lithium Ion Polymer Battery – 3.7v 1200mAh
Adafruit Product ID: Product ID: 258
Quantity 2
Cable to Connect Electronic Components Together
STEMMA QT / Qwiic JST SH 4-pin Cable – 100mm Long
Adafruit Product ID: 4210
Quantity 1
SMA to IPX SMA Male to UFL/U.FL/IPEX Coaxial Cable IPX to SMA Male Plug WiFi Antenna Pigtail Extension Cable RG178 5pcs 6inch(15cm)
Amazon
Load code using the Arduino IDE (Code Below)
Test
Receiver Code:
There is part of the program that comes before the code below. Unfortunately WordPress has a bug that will not let me list it below. Please email me at JOE(PUT A DOT HERE)BURBAGE(PUT AN AT SIGN HERE)GMAIL(PUT A DOT HERE)COM and I will be very happy to send it to you.
Sorry for the cryptic email but it is an attempt to avoid spam. The rest of the code below if fine.
void setup()
{
pinMode(LED, OUTPUT);
Wire.begin();
// Open a file on the SD card and go to the end of the file
balloonLog.begin(); //Open connection to OpenLog
// Open a file on the SD card for writing balloon date
rtn = balloonLog.append("Flight00.txt");
if (EnableSerialUSB == true){
if (rtn == true){
SerialUSB.println("append to SD card Successful");
}
else {
SerialUSB.println("append to SD card Failed");
}
}
// lcd.begin(Wire); //Set up the LCD for I2C communication
// lcd.setBacklight(0, 0, 255); //Set backlight to bright white
// lcd.setContrast(5); //Set contrast. Lower to 0 for higher contrast
//By default .begin() will set I2C SCL to Standard Speed mode of 100kHz
Wire.setClock(400000); //Optional - set I2C SCL to High Speed Mode of 400kHz
// lcd.clear(); //Clear the display - this moves the cursor to home position as well
// // Turn off the cursor:
// lcd.noCursor();
// // Turn on the display:
// lcd.display();
//Start the OLED Display
u8g2.begin();
u8g2.setBusClock(400000);
// Use a fixed size font that will overwrite well without leaving traces of
// the old characters
u8g2.setFont(u8g2_font_t0_17_mf);
if (EnableSerialUSB == true){
// Start up the Serial connection on USB
SerialUSB.begin(9600);
// It may be difficult to read serial messages on startup. The following line
// will wait for serial to be ready before continuing. Comment out if not needed.
while(!SerialUSB);
//Identify the program
SerialUSB.println("RFM Client!");
}
//Initialize the Radio.
if (rf95.init() == false){
if (EnableSerialUSB == true){SerialUSB.println("Radio Init Failed - Freezing");};
while (1);
}
else{
//An LED inidicator to let us know radio initialization has completed.
if (EnableSerialUSB == true){SerialUSB.println("Transmitter up!");};
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
delay(500);
}
// Set frequency
rf95.setFrequency(frequency);
// The default transmitter power is 13dBm, using PA_BOOST.
// If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
// you can set transmitter powers from 5 to 23 dBm:
// Transmitter power can range from 14-20dbm.
//rf95.setTxPower(14, false);
rf95.setTxPower(20, false); //false - uses the PA_BOOST Pin
rf95.setSignalBandwidth(125000);
rf95.setSpreadingFactor(12);
rf95.setCodingRate4(8);
rf95.setPayloadCRC(true);
delay(1000);
// Write to SD card indicating a new data set is starting
printlnSD("Starting New Data", balloonLog, writedelay);
}
void loop()
{
// You should be sure to call the function below frequently enough
// to not miss any messages It is called in the main loop.
if (rf95.recv(buf, &len)) {
// We have received a string and it is put into "received_str" for use
received_str = String((char*)buf);
// This will print every string that is received to SerialUSB
if (EnableSerialUSB == true){SerialUSB.println(received_str);}
// This will save every string of every reception to the SD Card
printlnSD(received_str, balloonLog, writedelay);
//For every reception find the RSSI (Receive Signal Strength Indicator)
// then output it and save it to the SD Card
RSSI_Received_Signal_Strength_str = String(rf95.lastRssi(), DEC);
received_RSSI_str = "Rec_SSI: " + RSSI_Received_Signal_Strength_str;
if (EnableSerialUSB == true){SerialUSB.println(received_RSSI_str);}
printlnSD(received_RSSI_str, balloonLog, writedelay);
// Calculate time inbetween reception of each message
if (EnableSerialUSB == true){
time_received_XMission_1 = millis();
SerialUSB.print("Time between receptions: ");
SerialUSB.println(time_received_XMission_1 - time_received_XMission_2);
Time_Between_Receptions_ms_str = String((time_received_XMission_1 - time_received_XMission_2), DEC);
time_received_XMission_2 = time_received_XMission_1;
}
//Prepare the OLED Display for the Received Signal Strength Indicator (RSSI) of Data Transmissions
// NOTE: The String RSSI_Received_Signal_Strength_str is filled in by code above
// for every recption
if (EnableSerialUSB == true){SerialUSB.println("*** RSSI " + RSSI_Received_Signal_Strength_str);}
// Prepare the OLED Display for the Time Between Receptions of Data Transmissions
if (EnableSerialUSB == true){SerialUSB.println("*** Time Between Receptions of Data Transmissions " + Time_Between_Receptions_ms_str);}
//Fill GPS_Nmber_of_Satellites_str with the number of received satellites fron the GPS
if ( received_str.startsWith("GPS_Sat:") ){
GPS_Nmber_of_Satellites_str = received_str.substring(9, 11);
if (EnableSerialUSB == true){SerialUSB.println("*** number of received satellites fron the GPS " + GPS_Nmber_of_Satellites_str);}
}
// LCD Display the RSSI data, the Time_Between_Receptions and the # of received satellites
// PrintLCD( RSSI_Received_Signal_Strength_str + " " +
// Time_Between_Receptions_ms_str + " " +
// GPS_Nmber_of_Satellites_str, 0 , 0);
//Fill GPS_Altitde_Feet_str with the Altitude from the GPS
if ( received_str.startsWith("GPS_Alt:") ){
GPS_Altitde_Feet_str = received_str.substring(9, 15);
if (EnableSerialUSB == true){SerialUSB.println("*** Altitude from the GPS " + GPS_Altitde_Feet_str);}
//PrintLCD( GPS_Altitde_Feet_str + " feet", 0 , 1);
}
//Fill String DPS_Pressure_hPa_str with the Athmospheric Pressure from the DPS
if ( received_str.startsWith("DPS_Prs:") ){
DPS_Pressure_hPa_str = received_str.substring(9, 16);
if (EnableSerialUSB == true){SerialUSB.println("*** Pressure from the DPS " + DPS_Pressure_hPa_str);}
//PrintLCD( DPS_Pressure_hPa_str + " hPa", 0 , 2);
}
//Fill String DPS_Temperature_degC_str with the Temperature from the DPS
if ( received_str.startsWith("DPS_Tmp:") ){
DPS_Temperature_degC_str = received_str.substring(9, 15);
if (EnableSerialUSB == true){SerialUSB.println("*** Temperature from the DPS " + DPS_Temperature_degC_str);}
//PrintLCD( DPS_Temperature_degC_str + " deg C", 0 , 3);
}
//Fill String GPS_Latutude_str with the Latutude from the GPS
if ( received_str.startsWith("GPS_Lat:") ){
GPS_Latutude_str = received_str.substring(9, 19);
if (EnableSerialUSB == true){SerialUSB.println("*** Latutude from the GPS " + GPS_Latutude_str);}
//PrintLCD( DPS_Temperature_degC_str + " deg C", 0 , 3);
}
//Fill String GPS_Longitude_str with the Longitude from the GPS
if ( received_str.startsWith("GPS_Lon:") ){
GPS_Longitude_str = received_str.substring(9, 20);
if (EnableSerialUSB == true){SerialUSB.println("*** Longitude from the GPS " + GPS_Longitude_str);}
//PrintLCD( DPS_Temperature_degC_str + " deg C", 0 , 3);
}
// Fill buffer Display_RSSI_Sat_buf for 1st line of the display
sprintf(Temporary_buf_1, "%s", "0");
sprintf(Temporary_buf_2, "%s", "0");
RSSI_Received_Signal_Strength_str.toCharArray(Temporary_buf_1, RSSI_Received_Signal_Strength_str.length()+1);
GPS_Nmber_of_Satellites_str.toCharArray(Temporary_buf_2, GPS_Nmber_of_Satellites_str.length()+1);
sprintf(Display_RSSI_Sat_buf, "SI %s Sat %s", Temporary_buf_1, Temporary_buf_2);
// Fill buffer Display_Alt_buf for 2nd line of the display
sprintf(Temporary_buf_1, "%s", "0");
GPS_Altitde_Feet_str.toCharArray(Temporary_buf_1, GPS_Altitde_Feet_str.length()+1);
sprintf(Display_Alt_buf, "Alt %s", Temporary_buf_1);
// Fill buffer Display_Pressure_buf for 3nd line of the display
sprintf(Temporary_buf_1, "%s", "0");
DPS_Pressure_hPa_str.toCharArray(Temporary_buf_1, DPS_Pressure_hPa_str.length()+1);
sprintf(Display_Pressure_buf, "Prs %s", Temporary_buf_1);
// Fill buffer Display_Temperature_buf for 4th line of the display
sprintf(Temporary_buf_1, "%s", "0");
DPS_Temperature_degC_str.toCharArray(Temporary_buf_1, DPS_Temperature_degC_str.length()+1);
sprintf(Display_Temperature_buf, "Tmp %s", Temporary_buf_1);
// Fill buffer Display_Lat_buf for 5th line of the display
sprintf(Temporary_buf_1, "%s", "0");
GPS_Latutude_str.toCharArray(Temporary_buf_1, GPS_Latutude_str.length()+1);
sprintf(Display_Lat_buf, "Lat %s", Temporary_buf_1);
// Fill buffer Display_Lon_buf for 6th line of the display
sprintf(Temporary_buf_1, "%s", "0");
GPS_Longitude_str.toCharArray(Temporary_buf_1, GPS_Longitude_str.length()+1);
sprintf(Display_Lon_buf, "Lon %s", Temporary_buf_1);
//Quickly write all buffers with lines of data to the ZIO OLED display
// The display has 6 lines of data all starting at the left edge (x = 0)
// and spaced 16 pixels apart in the y diredtion.
u8g2.firstPage();
do {
u8g2.drawStr(0,12, Display_RSSI_Sat_buf);
u8g2.drawStr(0,28, Display_Alt_buf);
u8g2.drawStr(0,44, Display_Pressure_buf);
u8g2.drawStr(0,60, Display_Temperature_buf);
u8g2.drawStr(0,76, Display_Lat_buf);
u8g2.drawStr(0, 92, Display_Lon_buf);
} while ( u8g2.nextPage() );
}
}