Bộ ghi dữ liệu Arduino với thẻ SD, cảm biến DS3231 và DHT22
Trong dự án này, chip đồng hồ thời gian thực DS3231 sẽ được sử dụng để duy trì thời gian cũng như ngày, giờ và cảm biến DHT22 để phát hiện độ ẩm và nhiệt độ tương đối. Ngoài ra, trong mạch sẽ có hai nút bấm để thiết lập thời gian và màn hình LCD 20 × 4 để hiển thị tất cả các thông số (thời gian, ngày, nhiệt độ và độ ẩm) như hình dưới đây:
Các linh kiện cần thiết:
- Board Arduino
- Board DS3231
- Cảm biến nhiệt độ và độ ẩm tư DHT22
- Màn hình LCD 20 × 4 (2004)
- thẻ SD
- Ổ cắm thẻ SD (đầu nối)
- 2 x Nút ấn
- 2 x Điện trở 10K ohm
- Điện trở ohm 4,7K
- 3 x Điện trở 3,3K ohm
- 3 x Điện trở 2.2K ohm
- Điện trở 330 ohm
- Breadboard
- Dây dẫn
Sơ đồ mạch:
Mạch đầu tiên bao gồm ba bộ chia điện áp để chuyển 5V thành 3V, các bộ chia điện áp dành cho: tín hiệu SS (chip chọn), MOSI (master in Slave out) và SCK (xung nối tiếp).
(Tất cả các điểm mút nối đất được nối với nhau)
Và mạch thứ hai sử dụng mô-đun thẻ micro SD, mô-đun này được cấp nguồn 5V (đến từ board Arduino), nó có bộ điều chỉnh điện áp AMS1117 và bộ dịch mức (74LVC125A) chuyển đổi 5V thành 3,3V cho các dây: SS, MOSI và SCK:
(Tất cả các điểm mút nối đất được nối với nhau)
Với mô-đun thẻ micro SD, các kết nối đơn giản hơn, mô-đun thẻ sd được cung cấp 5V từ board Arduino.
Mô-đun thẻ SD có 6 chân (từ trái sang phải): GND, VCC, MISO, MOSI, SCK và CS (chọn chip).
Trong mạch có hai nút ấn: B1 và B2 được nối tương ứng với các chân Arduino A1 và A2, các nút này được sử dụng để đặt thời gian và ngày của đồng hồ thời gian thực.
Cảm biến DHT22 có 4 chân: VCC, Dữ liệu, NC (không được kết nối) và GND. Nó được nối nguồn 5V (từ board Arduino).
Code cho dự án:
Code bên dưới đọc nhiệt độ và độ ẩm từ cảm biến DHT22, thời gian và ngày từ chip DS3231, sau đó nó lưu dữ liệu vào thẻ SD trong tệp có tên Logger.txt và cuối cùng nó sẽ gửi cùng một dữ liệu cho PC. Việc đọc và lưu trữ dữ liệu được thực hiện cứ sau 1 giây.
Code arduino đầy đủ là dưới đây.
// Real time clock, calendar, temperature, humidity data logger using Arduino, DS3231 and DHT22 sensor #include <SPI.h> // Include SPI library (needed for the SD card) #include <SD.h> // Include SD library #include <LiquidCrystal.h> // Include LCD library code #include <Wire.h> // Include Wire library code (needed for I2C protocol devices) #include <DHT.h> // Include DHT library code // LCD module connections (RS, E, D4, D5, D6, D7) LiquidCrystal lcd(2, 3, 4, 5, 6, 7); #define B1 A1 // Button B1 is connected to Arduino pin A1 #define B2 A2 // Button B1 is connected to Arduino pin A2 #define DHTPIN A3 // DHT22 data pin is connected to Arduino pin A3 #define DHTTYPE DHT22 // DHT22 sensor is used DHT dht(DHTPIN, DHTTYPE); // Initialize DHT library File dataLog; boolean sd_ok = 0; char temperature[] = " 00.0"; char humidity[] = " 00.0 %"; char Time[] = " : : "; char Calendar[] = " / /20 "; byte i, second, minute, hour, date, month, year, previous_second; int Temp, RH; void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); Serial.print("Initializing SD card..."); if (!SD.begin()) Serial.println("initialization failed!"); else { Serial.println("initialization done."); sd_ok = 1; } pinMode(B1, INPUT_PULLUP); pinMode(B2, INPUT_PULLUP); lcd.begin(20, 4); // Set up the LCD's number of columns and rows Wire.begin(); // Join i2c bus dht.begin(); lcd.setCursor(0, 0); lcd.print("TIME:"); lcd.setCursor(0, 1); lcd.print("DATE:"); lcd.setCursor(0, 2); lcd.print("Temp ="); lcd.setCursor(11, 2); lcd.write(223); // Print degree symbol ( °) lcd.setCursor(12, 2); lcd.write('C'); lcd.setCursor(0, 3); lcd.print("RH ="); Serial.println(" DATE | TIME | TEMPERATURE | HUMIDITY"); if(sd_ok) { // If SD card initialization was OK dataLog = SD.open("Logger.txt", FILE_WRITE); // Open file Logger.txt if(dataLog) { // if the file opened okay, write to it: dataLog.println(" DATE | TIME | TEMPERATURE | HUMIDITY"); dataLog.close(); // Close the file } } } void DS3231_display(){ // Convert BCD to decimal second = (second >> 4) * 10 + (second & 0x0F); minute = (minute >> 4) * 10 + (minute & 0x0F); hour = (hour >> 4) * 10 + (hour & 0x0F); date = (date >> 4) * 10 + (date & 0x0F); month = (month >> 4) * 10 + (month & 0x0F); year = (year >> 4) * 10 + (year & 0x0F); // End conversion Time[7] = second % 10 + 48; Time[6] = second / 10 + 48; Time[4] = minute % 10 + 48; Time[3] = minute / 10 + 48; Time[1] = hour % 10 + 48; Time[0] = hour / 10 + 48; Calendar[9] = year % 10 + 48; Calendar[8] = year / 10 + 48; Calendar[4] = month % 10 + 48; Calendar[3] = month / 10 + 48; Calendar[1] = date % 10 + 48; Calendar[0] = date / 10 + 48; lcd.setCursor(5, 0); lcd.print(Time); // Display time lcd.setCursor(5, 1); lcd.print(Calendar); // Display calendar } void blink_parameter(){ byte j = 0; while(j < 10 && digitalRead(B1) && digitalRead(B2)){ j++; delay(25); } } byte edit(byte x, byte y, byte parameter){ char text[3]; while(!digitalRead(B1)); // Wait until button (pin #8) released while(true){ while(!digitalRead(B2)){ // If button (pin #9) is pressed parameter++; if(i == 0 && parameter > 23) // If hours > 23 ==> hours = 0 parameter = 0; if(i == 1 && parameter > 59) // If minutes > 59 ==> minutes = 0 parameter = 0; if(i == 2 && parameter > 31) // If date > 31 ==> date = 1 parameter = 1; if(i == 3 && parameter > 12) // If month > 12 ==> month = 1 parameter = 1; if(i == 4 && parameter > 99) // If year > 99 ==> year = 0 parameter = 0; sprintf(text,"%02u", parameter); lcd.setCursor(x, y); lcd.print(text); delay(200); // Wait 200ms } lcd.setCursor(x, y); lcd.print(" "); // Display two spaces blink_parameter(); sprintf(text,"%02u", parameter); lcd.setCursor(x, y); lcd.print(text); blink_parameter(); if(!digitalRead(B1)){ // If button (pin #8) is pressed i++; // Increament 'i' for the next parameter return parameter; // Return parameter value and exit } } } void loop() { if(!digitalRead(B1)){ // If button (pin #8) is pressed i = 0; hour = edit(5, 0, hour); minute = edit(8, 0, minute); date = edit(5, 1, date); month = edit(8, 1, month); year = edit(13, 1, year); // Convert decimal to BCD minute = ((minute / 10) << 4) + (minute % 10); hour = ((hour / 10) << 4) + (hour % 10); date = ((date / 10) << 4) + (date % 10); month = ((month / 10) << 4) + (month % 10); year = ((year / 10) << 4) + (year % 10); // End conversion // Write data to DS3231 RTC Wire.beginTransmission(0x68); // Start I2C protocol with DS3231 address Wire.write(0); // Send register address Wire.write(0); // Reset sesonds and start oscillator Wire.write(minute); // Write minute Wire.write(hour); // Write hour Wire.write(1); // Write day (not used) Wire.write(date); // Write date Wire.write(month); // Write month Wire.write(year); // Write year Wire.endTransmission(); // Stop transmission and release the I2C bus delay(200); // Wait 200ms } Wire.beginTransmission(0x68); // Start I2C protocol with DS3231 address Wire.write(0); // Send register address Wire.endTransmission(false); // I2C restart Wire.requestFrom(0x68, 7); // Request 7 bytes from DS3231 and release I2C bus at end of reading second = Wire.read(); // Read seconds from register 0 minute = Wire.read(); // Read minuts from register 1 hour = Wire.read(); // Read hour from register 2 Wire.read(); // Read day from register 3 (not used) date = Wire.read(); // Read date from register 4 month = Wire.read(); // Read month from register 5 year = Wire.read(); // Read year from register 6 DS3231_display(); // Diaplay time & calendar if(previous_second != second){ previous_second = second; // Read humidity RH = dht.readHumidity() * 10; //Read temperature in degree Celsius Temp = dht.readTemperature() * 10; if(Temp < 0){ temperature[0] = '-'; // If temperature < 0 put minus sign Temp = abs(Temp); // Absolute value of 'Temp' } else temperature[0] = ' '; // otherwise (temperature > 0) put space temperature[1] = (Temp / 100) % 10 + 48; temperature[2] = (Temp / 10) % 10 + 48; temperature[4] = Temp % 10 + 48; if(RH >= 1000) humidity[0] = '1'; // If humidity >= 100.0% put '1' of hundreds else humidity[0] = ' '; // otherwise (humidity < 100) put space humidity[1] = (RH / 100) % 10 + 48; humidity[2] = (RH / 10) % 10 + 48; humidity[4] = RH % 10 + 48; lcd.setCursor(6, 2); lcd.print(temperature); lcd.setCursor(6, 3); lcd.print(humidity); // Send data to Arduino IDE serial monitor Serial.print(Calendar); Serial.print(" | "); Serial.print(Time); Serial.print(" | "); Serial.print(temperature); Serial.print("°C | "); Serial.println(humidity); if(sd_ok) { // If SD card initialization was OK dataLog = SD.open("Logger.txt", FILE_WRITE); // Open file Logger.txt if(dataLog) { // if the file opened okay, write to it: dataLog.print(Calendar); dataLog.print(" | "); dataLog.print(Time); dataLog.print(" | "); dataLog.print(temperature); dataLog.print("°C | "); dataLog.println(humidity); dataLog.close(); // Close the file } } } delay(50); // Wait 50ms }
Kết quả ví dụ:
Kết quả trên serial monitor Arduino IDE được hiển thị dưới đây:
Video demo:
Tải xuống:
Thư viện Adafruit cho DHT (sau khi giải nén, hãy đặt thư mục có tên DHT vào thư mục thư viện của Arduino):
Tải xuống
Tệp mô phỏng Proteus:
Tải xuống
Tệp hình ảnh thẻ SD:
Tải xuống