Atmega328 Weather Station with NRF24L01: Hardware and Software Implementation
The base station of the weather station is built on the Atmega328 microcontroller with an external 16 MHz resonator. Power supply is 5 V, with a separate AMS1117 3.3 V regulator for the NRF24L01 module. The circuit includes RGB backlighting with brightness balancing: a 100 Ω resistor on the red channel, 200 Ω on green and blue to compensate for the eye's physiological sensitivity and differences in crystal emission.
Power Supply Optimization
In the initial circuit, one bypass capacitor was used for power and one for AREF. This worked but violated recommendations: each VCC-GND pair requires a separate 100 nF capacitor to suppress microcontroller impulse noise. Optimally, three for power plus one on AREF. On the I²C bus, two pairs of pull-up resistors are excessive; one pair of 4.7 kΩ is sufficient.
PCB Layout and Grounding
The board was handmade using the photoresist method with UV solder mask. The bottom layer is a solid GND polygon, vias implemented by soldering wires. Separating analog and digital ground for the photoresistor proved unnecessary: the sensor is low-frequency, signal 0.5–4.5 V, noise in millivolts. A 0.1 µF filter on the ADC input shunts high-frequency interference and compensates for ground spikes in common mode.
- Photoresistor vs photodiode: Photoresistor (kΩ–MΩ) provides a voltage signal, robust to noise; photodiode (µA) requires clean AGND.
- Recommendation: Common ground + 0.1 µF on ADC for photoresistors.
Ground separation is needed for low-current sensors (thermocouples, piezo).
Software Flicker Filtering
Display and backlight brightness are adjusted via PWM based on the photoresistor. ADC noise and thermal noise (±3–4 units) cause flickering. Power supply didn't solve the issue; a 3rd-order median filter and exponential filter were applied.
int rawValue = analogRead(0);
int filteredValue = med.filter(rawValue);
float smoothValue = expF.filter(filteredValue);
int photoresistor = map(smoothValue, 260, 1023, 0, 255);
photoresistor = constrain(photoresistor, 0, 255);
analogWrite(3, 255 - photoresistor);
The filter combination is better than averaging over 10: eliminates spikes without significant reaction delay.
Precipitation Forecast via Barometer
BMP280 measures pressure every 10 min, averaging over 10 readings. An array of the last 6 values is analyzed using the least squares method for approximation.
if (millis() - lasttime > 600000) {
lasttime = millis();
PP = pressure();
for (byte i = 0; i < 5; i++) {
pres1_array[i] = pres1_array[i + 1];
}
pres1_array[5] = PP;
}
// Least squares
for (byte i = 0; i < 6; i++) {
sumX += time_array[i];
sumY += (long)pres1_array[i];
sumX2 += time_array[i] * time_array[i];
sumXY += (long)time_array[i] * pres1_array[i];
}
a = (long)6 * sumXY - (long)sumX * sumY;
a = (float)a / (6 * sumX2 - sumX * sumX);
delta = a * 6;
rain = map(delta, -250, 250, 100, -100);
Coefficient a is the slope, delta is the change per hour (Pa). rain from -100 (rising, clear) to +100 (falling, rain).
Communication Control and Timeout
When receiving a packet from the outdoor sensor, lastReceiveTime is recorded. If absent >60 min:
if (radio.available()) {
radio.read(&rxData, sizeof(rxData));
lastReceiveTime = millis();
dataIsFresh = true;
}
if (lastReceiveTime > 0 && millis() - lastReceiveTime > 3600000) {
resetWirelessData();
}
resetWirelessData() zeros dataIsFresh, the screen shows dashes.
Atmospheric RGB Backlighting
Color changes over time, mimicking nature: morning — yellow, day — blue, evening — pink, night — purple. Linear interpolation of RGB based on progress within the interval.
float progress = (currentHour - 8 + (float)currentMinute / 60.0) / 3.0;
if (progress < 0.5) {
float subProgress = progress * 2.0;
r = 255;
g = 80 + subProgress * 90;
b = 0 + subProgress * 50;
} else {
float subProgress = (progress - 0.5) * 2.0;
r = 255 - subProgress * 170;
g = 180 - subProgress * 50;
b = 60 + subProgress * 195;
}
void day() {
r = 85; g = 130; b = 255;
}
Phases ensure smoothness without abrupt jumps.
Enclosure and Firmware
Enclosure: ABS + transparent PETG, board sized to the display. Firmware via Arduino as ISP on PLS connectors.
Key Points
- RGB balancing: 100 Ω on red for visual equalization.
- Filters: median + exponential better than averaging against flicker.
- Least squares for pressure: delta ±250 Pa determines rain probability.
- 60 min timeout for NRF24L01 prevents displaying stale data.
- Common ground sufficient for photoresistor with 0.1 µF.
— Editorial Team
No comments yet.