Weather station

hello everyone. Am new in arduino programing but am always want to build a weater station. Am using an Arduino UNO with the SD/RTC shield and also the sensor shield to attach all the sensors. I have like 9 sensor already working and receiving data throughout serial. My problem start when I add a RF 433 MHz module to the project, i get a SD error in the serial monitor. the code can be compile without error. what could i been doing wrong???

You forgot rule 1. Post all your code in code tags, any error or processing logs also in code tags then hand draw your wiring and post a clear photo of it.

1 Like

thanks sonofcy for your quick response. sorry i will do it now. Am also new in this of posting in a forum.
this is the code that actually works. this is without the RF module

#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>
#include <BH1750.h>

// Sensor Pins
#define DHTPIN 7
#define DHTTYPE DHT11
#define UV_PIN A0
#define RAIN_PIN 3 // Reed switch input
#define WIND_PIN 2 // Hall effect sensor input
#define SD_CS_PIN 10
#define MQ135_PIN A1


// Rainfall and Wind Constants
#define RAIN_MM_PER_TICK 0.2
#define WIND_SPEED_FACTOR 2.4 // km/h per rotation/sec

// Sensor Objects
RTC_DS3231 rtc;
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
BH1750 lightMeter;

// Rain & Wind Variables
volatile unsigned int rainTicks = 0;
volatile unsigned int windTicks = 0;
unsigned long lastWindCalc = 0;
float windSpeedKmh = 0.0;
float rainfallMm = 0.0;

File dataFile;

void countRain() {
rainTicks++;
}

void countWind() {
windTicks++;
}

void setup() {
Serial.begin(9600);

// Sensor Setup
dht.begin();
if (!bmp.begin()) {
Serial.println("BMP180 not found!");
//while (1);
}

lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);

// RTC
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
//while (1);
}

//if (rtc.lostPower()) {
//rtc.adjust(DateTime(F(DATE), F(TIME)));
//}

// Rain and Wind
pinMode(RAIN_PIN, INPUT_PULLUP);
pinMode(WIND_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(RAIN_PIN), countRain, FALLING);
attachInterrupt(digitalPinToInterrupt(WIND_PIN), countWind, FALLING);

// SD Card
if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD init failed!");
//while (1);
}

if (!SD.exists("weather.csv")) {
dataFile = SD.open("weather.csv", FILE_WRITE);
dataFile.println("Timestamp,Temp_C_DHT,Humid_%,Temp_C_BMP,Pressure_hPa,UV,Light_lux,Rain_mm,Wind_kmh,MQ135_PPM");
dataFile.close();
}

lastWindCalc = millis();
}

void loop() {
DateTime now = rtc.now();

float tempDHT = dht.readTemperature();
float humid = dht.readHumidity();
float tempBMP = bmp.readTemperature();
float pressure = bmp.readPressure() / 100.0;
float lux = lightMeter.readLightLevel();
float uvRaw = analogRead(UV_PIN);
float uvIndex = (uvRaw / 1023.0) * 15.0;

// Wind Speed Calculation (every 2 seconds)
if (millis() - lastWindCalc >= 2000) {
noInterrupts();
unsigned int ticks = windTicks;
windTicks = 0;
interrupts();
float rps = ticks / 2.0;
windSpeedKmh = rps * WIND_SPEED_FACTOR;
lastWindCalc = millis();
}

// Rain Calculation
noInterrupts();
unsigned int rainCount = rainTicks;
rainTicks = 0;
interrupts();
rainfallMm = rainCount * RAIN_MM_PER_TICK;

// Timestamp
char timestamp[20];
sprintf(timestamp, "%04d-%02d-%02d %02d:%02d:%02d",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second());

//MQ135 calculations
int mq135_raw = analogRead(MQ135_PIN);
// Optional: convert to approximate CO2 PPM using calibration (very approximate)
float mq135_ppm = (mq135_raw / 1023.0) * 1000.0; // simple linear approximation

// Serial Output
Serial.print("Time: "); Serial.println(timestamp);
Serial.print("Temp DHT: "); Serial.println(tempDHT);
Serial.print("Humid: "); Serial.println(humid);
Serial.print("Temp BMP: "); Serial.println(tempBMP);
Serial.print("Pressure: "); Serial.println(pressure);
Serial.print("UV: "); Serial.println(uvIndex);
Serial.print("Light: "); Serial.println(lux);
Serial.print("Rain (mm): "); Serial.println(rainfallMm);
Serial.print("Wind (km/h): "); Serial.println(windSpeedKmh);
Serial.print("Air Quality: "); Serial.println(mq135_ppm);
Serial.println("-----------------------------");

// Write to SD Card
dataFile = SD.open("weather.csv", FILE_WRITE);
if (dataFile) {
dataFile.print(timestamp); dataFile.print(",");
dataFile.print(tempDHT); dataFile.print(",");
dataFile.print(humid); dataFile.print(",");
dataFile.print(tempBMP); dataFile.print(",");
dataFile.print(pressure); dataFile.print(",");
dataFile.print(uvIndex); dataFile.print(",");
dataFile.print(lux); dataFile.print(",");
dataFile.print(rainfallMm); dataFile.print(",");
dataFile.println(windSpeedKmh);
dataFile.print(",");
dataFile.println(mq135_ppm);
dataFile.close();
} else {
Serial.println("SD write failed");
}

delay(10000); // Log every 10 seconds
}

An screenshot of the serial showing the data

this is the code with the RF module code already included.

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>
#include <BH1750.h>
#include <RH_ASK.h>
//#include <avr/wdt.h> // Optional: watchdog
//#include <EEPROM.h>

// Set custom RX pin (IO27)
#define RF_TRASMITTER_PIN 6

// Create the RF driver instance using custom RX pin
RH_ASK rf_driver(2000, -1, RF_TRASMITTER_PIN, -1); 
// Parameters: speed, rxPin, txPin, pttPin


//RH_ASK rf_driver;

// Sensor Pins
#define DHTPIN 7
#define DHTTYPE DHT11
#define UV_PIN A0
#define RAIN_PIN 3
#define WIND_PIN 2
#define SD_CS_PIN 10
#define MQ135_PIN A1

// Rain and Wind Constants
#define RAIN_MM_PER_TICK 0.2
#define WIND_SPEED_FACTOR 2.4

// Sensor Objects
RTC_DS3231 rtc;
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
BH1750 lightMeter;

// Rain & Wind Variables
volatile unsigned int rainTicks = 0;
volatile unsigned int windTicks = 0;
volatile unsigned long lastRainTime = 0;
volatile unsigned long lastWindTime = 0;

unsigned long lastWindCalc = 0;
float windSpeedKmh = 0.0;
float rainfallMm = 0.0;

File dataFile;

void countRain() {
  if (millis() - lastRainTime > 10) {
    rainTicks++;
    lastRainTime = millis();
  }
}

void countWind() {
  if (millis() - lastWindTime > 10) {
    windTicks++;
    lastWindTime = millis();
  }
}

void setup() {
  Serial.begin(9600);
  rf_driver.init();

  dht.begin();
  if (!bmp.begin()) Serial.println("BMP180 not found!");
 
  lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);

  if (!rtc.begin()) Serial.println("Couldn't find RTC");

  pinMode(RAIN_PIN, INPUT_PULLUP);
  pinMode(WIND_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RAIN_PIN), countRain, FALLING);
  attachInterrupt(digitalPinToInterrupt(WIND_PIN), countWind, FALLING);

  if (!SD.begin(SD_CS_PIN)) {
Serial.println("SD init failed!");
//while (1);
}


  if (!SD.exists("weather.csv")) {
    dataFile = SD.open("weather.csv", FILE_WRITE);
    dataFile.println("Timestamp,Temp_C_DHT,Humid_%,Temp_C_BMP,Pressure_hPa,UV,Light_lux,Rain_mm,Wind_kmh,MQ135_PPM");
    dataFile.close();
  }

  lastWindCalc = millis();
}

void loop() {
  DateTime now = rtc.now();

  float tempDHT = dht.readTemperature();
  float humid = dht.readHumidity();
  float tempBMP = bmp.readTemperature();
  float pressure = bmp.readPressure() / 100.0;
  float lux = lightMeter.readLightLevel();
  float uvRaw = analogRead(UV_PIN);
  float uvIndex = (uvRaw / 1023.0) * 15.0;

  if (millis() - lastWindCalc >= 2000) {
    noInterrupts();
    unsigned int ticks = windTicks;
    windTicks = 0;
    interrupts();
    float rps = ticks / 2.0;
    windSpeedKmh = rps * WIND_SPEED_FACTOR;
    lastWindCalc = millis();
  }

  noInterrupts();
  unsigned int rainCount = rainTicks;
  rainTicks = 0;
  interrupts();
  rainfallMm = rainCount * RAIN_MM_PER_TICK;

  char timestamp[20];
  sprintf(timestamp, "%04d-%02d-%02d %02d:%02d:%02d",
    now.year(), now.month(), now.day(),
    now.hour(), now.minute(), now.second());

  int mq135_raw = analogRead(MQ135_PIN);
  float mq135_ppm = (mq135_raw / 1023.0) * 1000.0;

  // Serial Output
  Serial.println("Timestamp: " + String(timestamp));
  Serial.println("Temp DHT: " + String(tempDHT) + " °C");
  Serial.println("Humidity: " + String(humid) + " %");
  Serial.println("Temp BMP: " + String(tempBMP) + " °C");
  Serial.println("Pressure: " + String(pressure) + " hPa");
  Serial.println("UV Index: " + String(uvIndex));
  Serial.println("Light: " + String(lux) + " lux");
  Serial.println("Rainfall: " + String(rainfallMm) + " mm");
  Serial.println("Wind: " + String(windSpeedKmh) + " km/h");
  Serial.println("Air Quality (approx): " + String(mq135_ppm) + " ppm");
  Serial.println("-----------------------------");

  // Write to SD card
  dataFile = SD.open("weather.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.print(timestamp); dataFile.print(",");
    dataFile.print(tempDHT); dataFile.print(",");
    dataFile.print(humid); dataFile.print(",");
    dataFile.print(tempBMP); dataFile.print(",");
    dataFile.print(pressure); dataFile.print(",");
    dataFile.print(uvIndex); dataFile.print(",");
    dataFile.print(lux); dataFile.print(",");
    dataFile.print(rainfallMm); dataFile.print(",");
    dataFile.print(windSpeedKmh); 
    dataFile.print(",");
    dataFile.println(mq135_ppm);
    dataFile.close();
  } else {
    Serial.println("SD write failed");
  }

  // Create CSV packet and send via RF
  String packet = String(timestamp) + "," +
                  String(tempDHT, 1) + "," +
                  String(humid, 1) + "," +
                  String(tempBMP, 1) + "," +
                  String(pressure, 1) + "," +
                  String(uvIndex, 1) + "," +
                  String(lux, 1) + "," +
                  String(rainfallMm, 2) + "," +
                  String(windSpeedKmh, 2) + "," +
                  String(mq135_ppm, 1);

  char msg[128];
  packet.toCharArray(msg, sizeof(msg));
  rf_driver.send((uint8_t *)msg, strlen(msg));
  rf_driver.waitPacketSent();

  delay(10000); // Send every 10 seconds
}

This the serial output for this code

In the future, copy/paste the Serial log and put in code tags like the source. I am 83 and can't see this kind of screen grab easily.

What is the RF? Lora, Bluetooth, WiFi, something else?

oh sorry.

serial output that works:

Time: 2000-00-09 15:13:24
Temp DHT: 22.40
Humid: 49.60
Temp BMP: 22.20
Pressure: 1020.85
UV: 0.04
Light: 25.00
Rain (mm): 0.00
Wind (km/h): 0.00
Air Quality: 597.26

serial output that do not work:

SDSD

just the common one FS1000A with his receiver

That means nothing to me. If you can't tell me what the RF thing is, I will bid you adieu.

this is the module

Global variables use 1944 bytes (94%) of dynamic memory, leaving 104 bytes for local variables. Maximum is 2048 bytes.

You do not have enough dynamic memory (ram) left on an UNO.

You can reduce the dynamic memory usage by using the F() macro for printing string literals, such as:

  if (!bmp.begin()) Serial.println(F("BMP180 not found!"));

This stores the text in program memory instead of dynamic memory.

Use of String also uses a considerable amount of dynamic memory.

thanks david_2018. i will re code all the serial print. still i don't think that its the actual cause wish its not working

think it maybe worth your while moving to a Arduino Mega and a HC-12 433Mhz wireless module
the Mega gives you more memory, more IO pins and 3 hardware serial ports for the HC-12 and any other serial devices

Based on your extensive experience of Arduino programming mentioned in the first post? Or just a wish?

@david_2018 is correct. This may not be your only problem but it certainly is a problem. Any code using over 80% of the dynamic (RAM) memory of the Uno may not run correctly. Closer to 100%, very little chance at all

So get all those F() macros in, re-post the code and the compile statistics. Let's see if we can help you get under that 80% level.

thanks all you guys. I definitely going to make the changes here suggested. And also i already figure out what is the problem. Result that RH_ASK library uses pin 10, 11 and 12 for tx and rx also fora other function, so this pins are the same used by the SD module ans his SPI interface. Sure i could change the pin for ASK but somehow still not work so i gonna use another approach, maybe using virtualwire. i will keep you posted. for now thank you all very much, i appreciate your suggestions

It can use those pins, if you have a "transceiver" which is a piece of RF hardware that can both transmit and receive. But you are using simple RF hardware where one module is only a transmitter and the other is only a receiver. So only one pin is required for each module. And I suspect it can be any pin you choose.

The forum can't help if you don't share all the details.

hello folks again. I spend this afternoon trying another approach. This time i use manchester encoder to transmit the data over RF. below i gonna post the transmitter and the receiver code.

Transmitter:

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>
#include <BH1750.h>
#include <Manchester.h> // https://github.com/mchr3k/arduino-libs-manchester

// Sensor Pins
#define DHTPIN 7
#define DHTTYPE DHT11
#define UV_PIN A0
#define RAIN_PIN 3
#define WIND_PIN 2
#define SD_CS_PIN 10
#define MQ135_PIN A1
#define TX_PIN 4 // RF transmitter

// Constants
#define RAIN_MM_PER_TICK 0.2
#define WIND_SPEED_FACTOR 2.4 // km/h per rotation/sec

// Sensor objects
RTC_DS3231 rtc;
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
BH1750 lightMeter;

// Variables
volatile unsigned int rainTicks = 0;
volatile unsigned int windTicks = 0;
unsigned long lastWindCalc = 0;
float windSpeedKmh = 0.0;
float rainfallMm = 0.0;

File dataFile;

void countRain() { rainTicks++; }
void countWind() { windTicks++; }

void setup() {
  Serial.begin(9600);
  man.setupTransmit(TX_PIN);

  dht.begin();
  bmp.begin();
  lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
  rtc.begin();

  pinMode(RAIN_PIN, INPUT_PULLUP);
  pinMode(WIND_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RAIN_PIN), countRain, FALLING);
  attachInterrupt(digitalPinToInterrupt(WIND_PIN), countWind, FALLING);

  if (SD.begin(SD_CS_PIN)) {
    if (!SD.exists("weather.csv")) {
      dataFile = SD.open("weather.csv", FILE_WRITE);
      dataFile.println("Timestamp,Temp_C_DHT,Humid_%,Temp_C_BMP,Pressure_hPa,UV,Light_lux,Rain_mm,Wind_kmh,MQ135_PPM");
      dataFile.close();
    }
  } else {
    Serial.println("SD init failed!");
  }

  lastWindCalc = millis();
}

void loop() {
  DateTime now = rtc.now();

  float tempDHT = dht.readTemperature();
  float humid = dht.readHumidity();
  float tempBMP = bmp.readTemperature();
  float pressure = bmp.readPressure() / 100.0;
  float lux = lightMeter.readLightLevel();
  float uvRaw = analogRead(UV_PIN);
  float uvIndex = (uvRaw / 1023.0) * 15.0;

  // Wind Speed
  if (millis() - lastWindCalc >= 2000) {
    noInterrupts();
    unsigned int ticks = windTicks;
    windTicks = 0;
    interrupts();
    float rps = ticks / 2.0;
    windSpeedKmh = rps * WIND_SPEED_FACTOR;
    lastWindCalc = millis();
  }

  // Rainfall
  noInterrupts();
  unsigned int rainCount = rainTicks;
  rainTicks = 0;
  interrupts();
  rainfallMm = rainCount * RAIN_MM_PER_TICK;

  // Air Quality
  int mq135_raw = analogRead(MQ135_PIN);
  float mq135_ppm = (mq135_raw / 1023.0) * 1000.0;

  // Timestamp
  char timestamp[20];
  sprintf(timestamp, "%04d-%02d-%02d %02d:%02d:%02d",
          now.year(), now.month(), now.day(),
          now.hour(), now.minute(), now.second());

  // Format message to send
  char rfMessage[80];
  snprintf(rfMessage, sizeof(rfMessage),
           "T:%.1fH:%.1fP:%.1fU:%.1fL:%.0fW:%.1fR:%.1fA:%.0f",
           tempDHT, humid, pressure, uvIndex, lux, windSpeedKmh, rainfallMm, mq135_ppm);

  Serial.print("Sending: ");
  Serial.println(rfMessage);

  // Transmit message using Manchester (char-by-char)
  for (int i = 0; i < strlen(rfMessage); i++) {
    man.transmit((uint16_t)rfMessage[i]);
    delay(5); // small delay between characters
  }

  // Save to SD
  dataFile = SD.open("weather.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.print(timestamp); dataFile.print(",");
    dataFile.print(tempDHT); dataFile.print(",");
    dataFile.print(humid); dataFile.print(",");
    dataFile.print(tempBMP); dataFile.print(",");
    dataFile.print(pressure); dataFile.print(",");
    dataFile.print(uvIndex); dataFile.print(",");
    dataFile.print(lux); dataFile.print(",");
    dataFile.print(rainfallMm); dataFile.print(",");
    dataFile.print(windSpeedKmh); dataFile.print(",");
    dataFile.println(mq135_ppm);
    dataFile.close();
  }

  delay(10000); // Wait 10s
}

this is the receiver code:

#include <Manchester.h> // https://github.com/mchr3k/arduino-libs-manchester

#define RX_PIN 7          // RF receiver data pin
#define START_CHAR 'T'    // Start of message (you can adjust this if needed)
#define MAX_MESSAGE_LEN 80

char message[MAX_MESSAGE_LEN];
byte index = 0;

void setup() {
  Serial.begin(9600);
  man.setupReceive(RX_PIN);
  man.beginReceive();
  Serial.println("Manchester Receiver Started...");
}

void loop() {
  if (man.receiveComplete()) {
    uint16_t data = man.getMessage();
    man.beginReceive();

    // Only accept printable ASCII (safety filter)
    if (data >= 32 && data <= 126) {
      char c = (char)data;

      // Optional: reset message on new transmission
      if (c == START_CHAR) {
        index = 0;
      }

      if (index < MAX_MESSAGE_LEN - 1) {
        message[index++] = c;
        message[index] = '\0'; // Null-terminate
      }

      // Optionally detect end of message (e.g., message length or character)
      if (index > 5 && c == 'A') { // crude heuristic, "A:" is end (Air Quality)
        Serial.print("Received: ");
        Serial.println(message);
        index = 0;
      }
    } else {
      // Non-printable character — ignore or reset
      index = 0;
    }
  }
}

then i get this result in the serial of both arduinos

and my question is, why i only get an question mark and not the actual data????

sprintf / snprintf on an UNO does not support float.
You can use the dtostrf() function to convert a float to text.

thanks david_18 i appreciate your response . i will check this and post back the result.

avoid posting images of text screen output
it wastes space, difficult to read one cannot copy code for testing
copy and upload the text using < CODE > tags