Environmental monitoring is a useful application for small embedded systems. A data logger can record temperature, humidity, and light conditions in a workshop, storage room, greenhouse, or laboratory.
Many Arduino projects use a complete development board. This project takes a different approach by placing the ATmega328P-AUR directly on the circuit board. The goal is to demonstrate how a common AVR microcontroller can be used as the core of a standalone data acquisition system.
The ATmega328P-AUR provides enough memory and peripheral interfaces for this application. The TWI interface connects the OLED display and BH1750FVI light sensor, while the SPI interface connects the MicroSD card. The DHT22 sensor uses a single digital data line.
How the System WorksThe microcontroller runs at 16 MHz from an external crystal. A regulated 3.3 V supply powers the ATmega328P-AUR and the peripheral devices.
The DHT22 measures temperature and relative humidity. The BH1750FVI measures ambient light through its I2C interface. The OLED displays the latest sensor readings.
Every 10 seconds, the firmware creates a CSV record containing the current time, temperature, humidity, and light level. The record is appended to a file named ENVLOG.CSV on the MicroSD card.
A push button allows the user to save a measurement immediately. The status LED briefly flashes after a successful write.
Why Use a Standalone ATmega328P-AUR?The ATmega328P is widely used in Arduino-compatible designs, but a custom PCB can reduce unnecessary board-level hardware and make the design easier to integrate into a larger product.
The AUR version uses a TQFP-32 package, which is suitable for compact PCB designs. It provides the same core microcontroller features as the other ATmega328P package variants, with the appropriate pinout for the package.
Data Logging FormatThe project stores data in a simple CSV format:
Time,Temperature_C,Humidity_Percent,Light_Lux
0,24.6,48.2,125
10,24.7,48.1,128
20,24.7,48.0,132The time field is an elapsed time counter in seconds. It is not a real calendar timestamp because the design does not include a real-time clock.
Building the CircuitBegin with the ATmega328P-AUR power supply, crystal oscillator, reset circuit, and ICSP header. Verify the supply voltage and basic programming connection before adding the sensors.
The OLED display and BH1750FVI share the same I2C bus. The MicroSD card uses the SPI interface. The DHT22 connects to a separate digital input.
The circuit should be tested in stages. First verify that the microcontroller can be programmed. Then check the OLED display, sensor readings, and MicroSD card independently.
TestingUse a digital multimeter to verify the 3.3 V supply and check for short circuits before applying power.
Test the DHT22 against a known room temperature and humidity reading. Compare the BH1750FVI reading with a separate light meter if available.
For the MicroSD card, format the card as FAT32 and verify that the firmware can create and append to ENVLOG.CSV.
The recorded values should be checked for plausible changes when the sensor environment changes. The project does not claim laboratory-grade accuracy or calibrated environmental measurements.
Possible ImprovementsThe project can be extended with:
- A DS3231 real-time clock for calendar timestamps.
- A rechargeable battery supply.
- A low-power sleep mode.
- A wireless communication module.
- A larger OLED display.
- Additional analog sensors.
- A web dashboard for viewing the recorded data.
- A custom enclosure for outdoor monitoring.
The circuit uses a 3.3 V regulated supply. The ATmega328P-AUR supports operation from 1.8 V to 5.5 V, and the 3.3 V supply is suitable for this design.
Power Supply- ATmega328P-AUR VCC → 3.3 V.
- ATmega328P-AUR AVCC → 3.3 V.
- ATmega328P-AUR GND → common ground.
- 100 nF capacitor between VCC and GND.
- 100 nF capacitor between AVCC and GND.
- AREF → 100 nF capacitor → GND.
- 10 µF capacitor between 3.3 V and GND.
The MCP1700-3302E/TO provides the regulated 3.3 V supply.
Clock and Reset- XTAL1 → 16 MHz crystal → XTAL2.
- XTAL1 → 22 pF capacitor → GND.
- XTAL2 → 22 pF capacitor → GND.
- RESET → 10 kΩ resistor → 3.3 V.
- RESET → push button → GND.
- DHT22 VCC → 3.3 V.
- DHT22 GND → GND.
- DHT22 DATA → PD2 / Arduino digital pin 2.
- 1 kΩ resistor between DATA and 3.3 V.
- BH1750FVI VCC → 3.3 V.
- BH1750FVI GND → GND.
- BH1750FVI SDA → PC4 / A4.
- BH1750FVI SCL → PC5 / A5.
The I2C bus requires pull-up resistors. Use 4.7 kΩ resistors from SDA to 3.3 V and SCL to 3.3 V if the sensor and OLED modules do not already provide them.
SSD1306 OLED Display- OLED VCC → 3.3 V.
- OLED GND → GND.
- OLED SDA → PC4 / A4.
- OLED SCL → PC5 / A5.
The OLED shares the same I2C bus as the BH1750FVI.
MicroSD Card- MicroSD VCC → 3.3 V.
- MicroSD GND → GND.
- MicroSD MOSI → PB3 / Arduino digital pin 11.
- MicroSD MISO → PB4 / Arduino digital pin 12.
- MicroSD SCK → PB5 / Arduino digital pin 13.
- MicroSD CS → PB2 / Arduino digital pin 10.
Use a MicroSD module that is designed for 3.3 V operation. Do not connect a 5 V-only SD module directly to the 3.3 V ATmega328P supply without checking its interface requirements.
Status LED- PD6 / Arduino digital pin 6 → 330 Ω resistor → LED anode.
- LED cathode → GND.
The LED flashes after a successful data write.
Push Button- PD7 / Arduino digital pin 7 → push button → GND.
- The firmware enables the internal pull-up resistor.
ICSP Signal
ATmega328P-AUR Connection
MISO
PB4
MOSI
PB3
SCK
PB5
RESET
RESET
VCC
3.3 V
GND
GND
The ICSP header is used for programming the microcontroller and can also be used for bootloader installation.
CodeThe following Arduino sketch reads the DHT22 and BH1750FVI sensors, updates the OLED display, and writes CSV data to the MicroSD card.
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <DHT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <BH1750.h>
#define DHTPIN 2
#define DHTTYPE DHT22
#define SD_CS 10
#define STATUS_LED 6
#define BUTTON_PIN 7
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
DHT dht(DHTPIN, DHTTYPE);
BH1750 lightMeter;
Adafruit_SSD1306 display(
SCREEN_WIDTH,
SCREEN_HEIGHT,
&Wire,
-1
);
unsigned long lastLog = 0;
unsigned long elapsedSeconds = 0;
const unsigned long LOG_INTERVAL = 10000;
void showMessage(const char *message)
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(message);
display.display();
}
bool writeLog(float temperature,
float humidity,
float lux)
{
File file = SD.open("ENVLOG.CSV", FILE_WRITE);
if (!file)
{
return false;
}
file.print(elapsedSeconds);
file.print(",");
file.print(temperature, 2);
file.print(",");
file.print(humidity, 2);
file.print(",");
file.println(lux, 2);
file.close();
return true;
}
void displayReadings(float temperature,
float humidity,
float lux)
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Temperature: ");
display.print(temperature, 1);
display.println(" C");
display.setCursor(0, 16);
display.print("Humidity: ");
display.print(humidity, 1);
display.println(" %");
display.setCursor(0, 32);
display.print("Light: ");
display.print(lux, 0);
display.println(" lux");
display.setCursor(0, 48);
display.print("Time: ");
display.print(elapsedSeconds);
display.println(" s");
display.display();
}
void recordMeasurement()
{
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
float lux = lightMeter.readLightLevel();
if (isnan(temperature) || isnan(humidity))
{
showMessage("DHT22 read error");
return;
}
if (lux < 0)
{
showMessage("BH1750 read error");
return;
}
displayReadings(temperature, humidity, lux);
if (writeLog(temperature, humidity, lux))
{
digitalWrite(STATUS_LED, HIGH);
delay(100);
digitalWrite(STATUS_LED, LOW);
}
else
{
showMessage("SD write error");
}
}
void setup()
{
pinMode(STATUS_LED, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
Wire.begin();
dht.begin();
lightMeter.begin();
if (!display.begin(
SSD1306_SWITCHCAPVCC,
0x3C))
{
while (1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("ATmega328P-AUR");
display.println("Environmental");
display.println("Data Logger");
display.display();
delay(2000);
if (!SD.begin(SD_CS))
{
showMessage("SD init failed");
}
else
{
File file = SD.open("ENVLOG.CSV", FILE_WRITE);
if (file)
{
if (file.size() == 0)
{
file.println(
"Time,Temperature_C,Humidity_Percent,Light_Lux"
);
}
file.close();
}
}
recordMeasurement();
lastLog = millis();
}
void loop()
{
if (millis() - lastLog >= LOG_INTERVAL)
{
lastLog = millis();
elapsedSeconds += 10;
recordMeasurement();
}
if (digitalRead(BUTTON_PIN) == LOW)
{
recordMeasurement();
delay(300);
}
}Code NotesThe firmware uses the Arduino AVR platform for ATmega328P development. The 16 MHz clock setting must match the actual crystal and board configuration.
The OLED display address is set to 0x3C. Some SSD1306 modules use a different address, so check the module documentation if the display does not respond.
The DHT22 sensor requires a suitable pull-up resistor on its data line. Some breakout modules already include one.
The MicroSD card should be formatted as FAT32. The firmware creates ENVLOG.CSV if it does not already exist.
The recorded time is an elapsed seconds counter, not a real-time clock. A DS3231 module can be added if calendar timestamps are required.
ConclusionThis project demonstrates how the ATmega328P-AUR can serve as the main controller in a standalone environmental data logger. It uses the microcontroller's I2C, SPI, GPIO, and timer resources to connect several practical peripherals.
The design is suitable for learning, prototyping, and developing a custom PCB-based monitoring system. It can also serve as a starting point for more advanced data logging projects that require low power consumption, wireless communication, or real-time clock support.
The ATmega328P remains a practical choice for small embedded applications where its memory, processing capability, and peripheral interfaces are sufficient. For new designs, engineers should also review Microchip's current recommended products and compare them with the ATmega328P before committing to a long-term production design.



_4YUDWziWQ8.png?auto=compress%2Cformat&w=48&h=48&fit=fill&bg=ffffff)

_Ujn5WoVOOu.png?auto=compress%2Cformat&w=40&h=40&fit=fillmax&bg=fff&dpr=2)



Comments