Arduino Nano Using Median Filter to Display DHT22 and RTC
Despike/smooth data from a DHT22 with a median filter and display on a 0.96 inch OLED with the date and time from a DS3231 real-time clock!
Components and supplies
1
DHT22 Temperature Sensor
1
Robojax DS3231 IIC Precision Real time Clock Module
1
Kuman 0.96 Inch Yellow Blue IIC OLED Module I2c
1
Arduino Nano R3
Project description
Code
DHT Median filter with RTC
arduino
Simply upload to your Nano with the Arduini IDE
1/* 2 3 Use an Arduino Nano to display temp/humidy on 0.96 inch Yellow/Blue IIC OLED I2c 4 serial 128x64 Display 5 6 Use an Adafruit DHT22 Temperature and Humidity Sensor (accuracy ±2%) 7 8 These data might bounce around somewhat because the sensor can be a little noisy 9 at times. We use a simple median filter to smooth out the noise 10 11 Arduino Nano <--> OLED = pin A4 to SDA and pin A5 to SLC 12 13 February 2020 14 15 Paul M Dunphy, VE1DX 16 17*/ 18 19 20// This library allows you to communicate with I2C devices, in this 21// case the RTC and OLED display 22#include <Wire.h> 23 24// For the DS3231 Real time Clock Module (AT24C32 Module) 25#include <DS1307RTC.h> 26 27// Include DHT Library from Adafruit 28 29#include "DHT.h"; 30/* DHT22 pin-out: 31 Pin 1 VCC 32 Pin 2 Data out 33 Pin 3 Not connected 34 Pin 4 Ground 35*/ 36 37#include "U8glib.h" // For the OLED - Obtain from: https://github.com/olikraus/u8glib 38 39// Define Constants 40 41#define dhtPin 7 // DHT-22 Output Pin connection 42#define dhtType DHT22 // DHT Type is a DHT 22 (AM2302) 43 44// Initialize OLED 45U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); 46 47// Initialize DHT sensor 48 49DHT dht(dhtPin, dhtType); 50 51tmElements_t tm; // For the RTC 52 53#define buff_size 7 // Must be an odd number. Should be greater than 5. 7 works well. 54 55unsigned long a_second = 1000; 56float h = 0.0; //Stores humidity value 57float t = 0.0; //Stores temperature value 58float h_array[buff_size] = {0.0}; 59float t_array[buff_size] = {0.0}; 60float h_array_sort[buff_size] = {0.0}; 61float t_array_sort[buff_size] = {0.0}; 62String string_Temp, string_Humid, temporary_string, tick_string; 63 64 65char OLED_string_1[50]; // Need a couple of character buffers to hold the two OLED lines 66char OLED_string_2[50]; 67 68 69String str_day, str_month, str_year, str_time; // Lot of conversion to strings required because the 70 // DSD Tech display doesn't like integers and floats 71 72 73void clearOLED() 74 { 75 u8g.firstPage(); 76 do { 77 } while( u8g.nextPage() ); 78 } 79 80 81void Initialize() 82{ 83 float startup_delay; 84 int i; 85 86 clearOLED(); 87 startup_delay = buff_size * (a_second * 5.0 / 1000.0); 88 temporary_string = String(startup_delay,0); 89 temporary_string = " (" + temporary_string + " seconds)"; 90 91 tick_string = "Initializing "; 92 strcpy(OLED_string_1, tick_string.c_str()); 93 strcpy(OLED_string_2, temporary_string.c_str()); 94 95 // Take "buff_size" readings of each parameter, one every 5 seconds, 96 // to get initial arrays of data. Print "status" dots across display. 97 for (i = 0 ; i < buff_size ; i++) 98 { 99 tick_string = tick_string + ". "; 100 strcpy(OLED_string_1, tick_string.c_str()); 101 sendstringstoDisplay(); 102 delay(a_second * 5); 103 h_array[i] = dht.readHumidity(); // Get Humidity value 104 t_array[i] = dht.readTemperature(); // Get Temperature value 105 } 106 } 107 108 109 110void bubble_sort(float sort_array[], int n) 111 { 112 int i, j; 113 float temp; 114 115 for (i = 0 ; i < n - 1; i++) 116 { 117 for (j = 0 ; j < n - i - 1; j++) 118 { 119 if (sort_array[j] > sort_array[j+1]) 120 { 121 // Swap values 122 temp = sort_array[j]; 123 sort_array[j] = sort_array[j+1]; 124 sort_array[j+1] = temp; 125 } 126 } 127 } 128 } 129 130 131 132 133void sendstringstoDisplay() 134 { 135 u8g.firstPage(); // Send them to the dispaly 136 do { 137 138 u8g.setFont(u8g_font_5x7); // This can be adjusted to various fonts. See: https://github.com/olikraus/u8glib/wiki/fontsize 139 u8g.setPrintPos(0,7); // Position of first line 140 u8g.print(OLED_string_1); 141 u8g.setFont(u8g_font_helvB14); // Little biger and bolder font as this is the temperature and humidy 142 u8g.setPrintPos(0, 25); // Position of second line 143 u8g.print(OLED_string_2); 144 145 } while (u8g.nextPage() ); 146 } 147 148 149 150 151void monthStr(tmElements_t tm) 152{ 153 154 int int_month; 155 156 str_month = tm.Month; 157 int_month = str_month.toInt(); 158 159 switch(int_month) 160 { 161 case 1: 162 str_month =("JAN"); 163 break; 164 case 2: 165 str_month =("FEB"); 166 break; 167 case 3: 168 str_month =("MAR"); 169 break; 170 case 4: 171 str_month =("APR"); 172 break; 173 case 5: 174 str_month =("MAY"); 175 break; 176 case 6: 177 str_month =("JUN"); 178 break; 179 case 7: 180 str_month =("JUL"); 181 break; 182 case 8: 183 str_month =("AUG"); 184 break; 185 case 9: 186 str_month =("SEP"); 187 break; 188 case 10: 189 str_month =("OCT"); 190 break; 191 case 11: 192 str_month =("NOV"); 193 break; 194 case 12: 195 str_month =("DEC"); 196 break; 197 default: 198 str_month =("ERR"); 199 break; 200 } 201 202} 203 204 205 206void timeStr(tmElements_t tm) 207{ 208 209 // Add a leading zero when needed so all numbers are two characters 210 211 String hours,seconds,minutes; 212 213 if(tm.Hour<10) 214 { 215 hours = "0"+String(tm.Hour); 216 } 217 else 218 { 219 hours = String(tm.Hour); 220 } 221 222 if(tm.Minute<10) 223 { 224 minutes = "0"+String(tm.Minute); 225 } 226 else 227 { 228 minutes = String(tm.Minute); 229 } 230 231 // We're processing seconds "just in case", but not adding them to the small display 232 233 if(tm.Second<10) 234 { 235 seconds = "0"+String(tm.Second); 236 } 237 else 238 { 239 seconds = String(tm.Second); 240 } 241 242 str_time = hours + ":" + minutes; 243} 244 245 246 247 248void setup() 249 { 250 // Start Wire library for I2C 251 Wire.begin(); 252 clearOLED(); 253 dht.begin(); 254 // initialize digital pin LED_BUILTIN as an output. 255 pinMode(LED_BUILTIN, OUTPUT); 256 Initialize(); 257 } 258 259 260 261 262void loop() 263 { 264 int i, median_index; 265 266 RTC.read(tm); // Get the date and time 267 monthStr(tm); // Convert the month from a number to Jan, Feb, Mar, etc 268 timeStr(tm); // Convert the time to strings 269 270 h = dht.readHumidity(); // Get Humidity value 271 t = dht.readTemperature(); // Get Temperature value 272 273 // Replace the oldest value with the newest just read by moving every element in 274 // the arrays up one and sticking this new value in the bottom. 275 for (i = 0 ; i < buff_size - 1 ; i++) 276 { 277 h_array[i] = h_array[i + 1]; 278 t_array[i] = t_array[i + 1]; 279 } 280 h_array[buff_size-1] = h; 281 t_array[buff_size-1] = t; 282 283 // Move them into the sort arrays 284 for (i = 0 ; i < buff_size ; i++) 285 { 286 h_array_sort[i] = h_array[i]; 287 t_array_sort[i] = t_array[i]; 288 } 289 290 // Sort them. Use quick and dirty bubble sort because it's a small number of data points 291 bubble_sort(h_array_sort, buff_size); 292 bubble_sort(t_array_sort, buff_size); 293 294 // Use the median of the last "buff_zize" readings for the display 295 median_index = buff_size / 2; 296 h = h_array_sort[median_index]; 297 t = t_array_sort[median_index]; 298 string_Temp = String(t,1); // Make temp a character string 299 string_Humid = String(h,1); // Make humid a character string 300 301 // Build first OLED line 302 str_year = tmYearToCalendar(tm.Year); 303 str_day = tm.Day; 304 str_day = str_day + "-"; 305 str_month = str_month + "-"; 306 temporary_string = " " + str_day + str_month + str_year + " " + str_time; 307 strcpy(OLED_string_1, temporary_string.c_str()); // Put date/time string in the first character array 308 309 // Build second OLED line 310 temporary_string = ""; 311 temporary_string = temporary_string + string_Temp + char(176) + "C "; // char(176) is the degree symbol 312 temporary_string = temporary_string + string_Humid + " %"; 313 strcpy(OLED_string_2, temporary_string.c_str()); // Put temperature/humidity string in the second character array 314 315 316 sendstringstoDisplay(); // Display the median temperature and humidity 317 delay(5000); // Updates every 5 seconds 318 319 }
DHT Median filter with RTC
arduino
Simply upload to your Nano with the Arduini IDE
1/* 2 3 Use an Arduino Nano to display temp/humidy on 0.96 inch Yellow/Blue 4 IIC OLED I2c 5 serial 128x64 Display 6 7 Use an Adafruit DHT22 Temperature 8 and Humidity Sensor (accuracy ±2%) 9 10 These data might bounce around somewhat 11 because the sensor can be a little noisy 12 at times. We use a simple median 13 filter to smooth out the noise 14 15 Arduino Nano <--> OLED = pin A4 to SDA 16 and pin A5 to SLC 17 18 February 2020 19 20 Paul M Dunphy, VE1DX 21 22*/ 23 24 25// 26 This library allows you to communicate with I2C devices, in this 27// case the 28 RTC and OLED display 29#include <Wire.h> 30 31// For the DS3231 Real time Clock 32 Module (AT24C32 Module) 33#include <DS1307RTC.h> 34 35// Include DHT Library 36 from Adafruit 37 38#include "DHT.h"; 39/* DHT22 pin-out: 40 Pin 1 VCC 41 42 Pin 2 Data out 43 Pin 3 Not connected 44 Pin 4 Ground 45*/ 46 47#include 48 "U8glib.h" // For the OLED - Obtain from: https://github.com/olikraus/u8glib 49 50// 51 Define Constants 52 53#define dhtPin 7 // DHT-22 Output Pin connection 54#define 55 dhtType DHT22 // DHT Type is a DHT 22 (AM2302) 56 57// Initialize OLED 58U8GLIB_SSD1306_128X32 59 u8g(U8G_I2C_OPT_NONE); 60 61// Initialize DHT sensor 62 63DHT dht(dhtPin, dhtType); 64 65 66tmElements_t tm; // For the RTC 67 68#define buff_size 7 // Must be 69 an odd number. Should be greater than 5. 7 works well. 70 71unsigned long a_second 72 = 1000; 73float h = 0.0; //Stores humidity value 74float t = 0.0; //Stores temperature 75 value 76float h_array[buff_size] = {0.0}; 77float t_array[buff_size] = {0.0}; 78float 79 h_array_sort[buff_size] = {0.0}; 80float t_array_sort[buff_size] = {0.0}; 81String 82 string_Temp, string_Humid, temporary_string, tick_string; 83 84 85char OLED_string_1[50]; 86 // Need a couple of character buffers to hold the two OLED lines 87char OLED_string_2[50]; 88 89 90String 91 str_day, str_month, str_year, str_time; // Lot of conversion to strings required 92 because the 93 // DSD Tech display 94 doesn't like integers and floats 95 96 97void clearOLED() 98 { 99 u8g.firstPage(); 100 101 do { 102 } while( u8g.nextPage() ); 103 } 104 105 106void Initialize() 107{ 108 109 float startup_delay; 110 int i; 111 112 clearOLED(); 113 startup_delay = 114 buff_size * (a_second * 5.0 / 1000.0); 115 temporary_string = String(startup_delay,0); 116 117 temporary_string = " (" + temporary_string + " seconds)"; 118 119 tick_string 120 = "Initializing "; 121 strcpy(OLED_string_1, tick_string.c_str()); 122 strcpy(OLED_string_2, 123 temporary_string.c_str()); 124 125 // Take "buff_size" readings of each parameter, 126 one every 5 seconds, 127 // to get initial arrays of data. Print "status" dots 128 across display. 129 for (i = 0 ; i < buff_size ; i++) 130 { 131 tick_string 132 = tick_string + ". "; 133 strcpy(OLED_string_1, tick_string.c_str()); 134 135 sendstringstoDisplay(); 136 delay(a_second * 5); 137 h_array[i] 138 = dht.readHumidity(); // Get Humidity value 139 t_array[i] = dht.readTemperature(); 140 // Get Temperature value 141 } 142 } 143 144 145 146void bubble_sort(float 147 sort_array[], int n) 148 { 149 int i, j; 150 float temp; 151 152 for (i = 153 0 ; i < n - 1; i++) 154 { 155 for (j = 0 ; j < n - i - 1; j++) 156 { 157 158 if (sort_array[j] > sort_array[j+1]) 159 { 160 // 161 Swap values 162 temp = sort_array[j]; 163 sort_array[j] 164 = sort_array[j+1]; 165 sort_array[j+1] = temp; 166 } 167 168 } 169 } 170 } 171 172 173 174 175void sendstringstoDisplay() 176 177 { 178 u8g.firstPage(); // Send them to the dispaly 179 do { 180 181 u8g.setFont(u8g_font_5x7); 182 // This can be adjusted to various fonts. See: https://github.com/olikraus/u8glib/wiki/fontsize 183 184 u8g.setPrintPos(0,7); // Position of first line 185 u8g.print(OLED_string_1); 186 187 u8g.setFont(u8g_font_helvB14); // Little biger and bolder font as this is 188 the temperature and humidy 189 u8g.setPrintPos(0, 25); // Position 190 of second line 191 u8g.print(OLED_string_2); 192 193 } while (u8g.nextPage() 194 ); 195 } 196 197 198 199 200void monthStr(tmElements_t tm) 201{ 202 203 int int_month; 204 205 206 str_month = tm.Month; 207 int_month = str_month.toInt(); 208 209 switch(int_month) 210 211 { 212 case 1: 213 str_month =("JAN"); 214 break; 215 case 216 2: 217 str_month =("FEB"); 218 break; 219 case 3: 220 str_month 221 =("MAR"); 222 break; 223 case 4: 224 str_month =("APR"); 225 226 break; 227 case 5: 228 str_month =("MAY"); 229 break; 230 231 case 6: 232 str_month =("JUN"); 233 break; 234 case 7: 235 236 str_month =("JUL"); 237 break; 238 case 8: 239 str_month 240 =("AUG"); 241 break; 242 case 9: 243 str_month =("SEP"); 244 245 break; 246 case 10: 247 str_month =("OCT"); 248 break; 249 250 case 11: 251 str_month =("NOV"); 252 break; 253 case 12: 254 255 str_month =("DEC"); 256 break; 257 default: 258 str_month 259 =("ERR"); 260 break; 261 } 262 263} 264 265 266 267void timeStr(tmElements_t 268 tm) 269{ 270 271 // Add a leading zero when needed so all numbers are two characters 272 273 274 String hours,seconds,minutes; 275 276 if(tm.Hour<10) 277 { 278 hours 279 = "0"+String(tm.Hour); 280 } 281 else 282 { 283 hours = String(tm.Hour); 284 285 } 286 287 if(tm.Minute<10) 288 { 289 minutes = "0"+String(tm.Minute); 290 291 } 292 else 293 { 294 minutes = String(tm.Minute); 295 } 296 297 // We're 298 processing seconds "just in case", but not adding them to the small display 299 300 301 if(tm.Second<10) 302 { 303 seconds = "0"+String(tm.Second); 304 } 305 306 else 307 { 308 seconds = String(tm.Second); 309 } 310 311 str_time 312 = hours + ":" + minutes; 313} 314 315 316 317 318void setup() 319 { 320 // 321 Start Wire library for I2C 322 Wire.begin(); 323 clearOLED(); 324 dht.begin(); 325 326 // initialize digital pin LED_BUILTIN as an output. 327 pinMode(LED_BUILTIN, 328 OUTPUT); 329 Initialize(); 330 } 331 332 333 334 335void loop() 336 { 337 338 int i, median_index; 339 340 RTC.read(tm); // Get the date and time 341 342 monthStr(tm); // Convert the month from a number to Jan, Feb, Mar, etc 343 344 timeStr(tm); // Convert the time to strings 345 346 h = dht.readHumidity(); 347 // Get Humidity value 348 t = dht.readTemperature(); // Get Temperature 349 value 350 351 // Replace the oldest value with the newest just read by moving 352 every element in 353 // the arrays up one and sticking this new value in the 354 bottom. 355 for (i = 0 ; i < buff_size - 1 ; i++) 356 { 357 h_array[i] 358 = h_array[i + 1]; 359 t_array[i] = t_array[i + 1]; 360 } 361 h_array[buff_size-1] 362 = h; 363 t_array[buff_size-1] = t; 364 365 // Move them into the sort arrays 366 367 for (i = 0 ; i < buff_size ; i++) 368 { 369 h_array_sort[i] 370 = h_array[i]; 371 t_array_sort[i] = t_array[i]; 372 } 373 374 // 375 Sort them. Use quick and dirty bubble sort because it's a small number of data points 376 377 bubble_sort(h_array_sort, buff_size); 378 bubble_sort(t_array_sort, buff_size); 379 380 381 // Use the median of the last "buff_zize" readings for the display 382 median_index 383 = buff_size / 2; 384 h = h_array_sort[median_index]; 385 t = t_array_sort[median_index]; 386 387 string_Temp = String(t,1); // Make temp a character string 388 string_Humid 389 = String(h,1); // Make humid a character string 390 391 // Build first 392 OLED line 393 str_year = tmYearToCalendar(tm.Year); 394 str_day = tm.Day; 395 396 str_day = str_day + "-"; 397 str_month = str_month + "-"; 398 temporary_string 399 = " " + str_day + str_month + str_year + " " + str_time; 400 strcpy(OLED_string_1, 401 temporary_string.c_str()); // Put date/time string in the first character array 402 403 404 // Build second OLED line 405 temporary_string = ""; 406 temporary_string 407 = temporary_string + string_Temp + char(176) + "C "; // char(176) is the degree 408 symbol 409 temporary_string = temporary_string + string_Humid + " %"; 410 411 strcpy(OLED_string_2, temporary_string.c_str()); // Put temperature/humidity 412 string in the second character array 413 414 415 sendstringstoDisplay(); 416 // Display the median temperature and humidity 417 delay(5000); 418 // Updates every 5 seconds 419 420 }
Downloadable files
Breadboard layout
Breadboard layout

Comments
Only logged in users can leave comments