├── .gitattributes ├── .gitignore ├── Arduino ├── NeededLibraries │ ├── Adafruit_GFX │ │ ├── Adafruit_GFX.cpp │ │ ├── Adafruit_GFX.h │ │ ├── README.txt │ │ ├── glcdfont.c │ │ └── license.txt │ ├── Adafruit_MAX31855 │ │ ├── Adafruit_MAX31855.cpp │ │ ├── Adafruit_MAX31855.h │ │ ├── README.txt │ │ ├── examples │ │ │ ├── lcdthermocouple │ │ │ │ └── LCDthermocouple.pde │ │ │ └── serialthermocouple │ │ │ │ └── serialthermocouple.pde │ │ ├── keywords.txt │ │ └── license.txt │ ├── Adafruit_SSD1306 │ │ ├── Adafruit_SSD1306.cpp │ │ ├── Adafruit_SSD1306.h │ │ ├── README.txt │ │ ├── examples │ │ │ ├── ssd1306_128x32_i2c │ │ │ │ └── ssd1306_128x32_i2c.ino │ │ │ ├── ssd1306_128x32_spi │ │ │ │ └── ssd1306_128x32_spi.ino │ │ │ ├── ssd1306_128x64_i2c │ │ │ │ └── ssd1306_128x64_i2c.ino │ │ │ └── ssd1306_128x64_spi │ │ │ │ └── ssd1306_128x64_spi.ino │ │ └── license.txt │ ├── EEPROMEx │ │ ├── EEPROMEx.cpp │ │ ├── EEPROMEx.h │ │ ├── Examples │ │ │ ├── EEPROMBackup │ │ │ │ └── EEPROMBackup.pde │ │ │ ├── EEPROMEx │ │ │ │ └── EEPROMEx.pde │ │ │ └── EEPROMVar │ │ │ │ └── EEPROMVar.pde │ │ └── keywords.txt │ └── PID_v1 │ │ ├── Examples │ │ ├── PID_AdaptiveTunings │ │ │ └── PID_AdaptiveTunings.ino │ │ ├── PID_Basic │ │ │ └── PID_Basic.ino │ │ └── PID_RelayOutput │ │ │ └── PID_RelayOutput.ino │ │ ├── PID_v1.cpp │ │ ├── PID_v1.h │ │ └── keywords.txt ├── ReflowOvenFFLilyMenuOverWrite │ └── ReflowOvenFFLilyMenuOverWrite.ino └── ReflowOvenFLilyMenu │ └── ReflowOvenFLilyMenu.ino ├── Operation ├── Images │ ├── 0_Logo.JPG │ ├── 10_ReflowCyclePeak.JPG │ ├── 11_CoolCycle.JPG │ ├── 1_TempMenu.JPG │ ├── 2_PreheatMenu.JPG │ ├── 3_SoakMenu.JPG │ ├── 4_ReflowMenu.JPG │ ├── 5_SettingsStored.JPG │ ├── 7_PreheatCycle.JPG │ ├── 8_SoakCycle.JPG │ └── 9_ReflowCycle.JPG └── README.md ├── PcbDesignFiles ├── PanelLayout.jpg ├── PanelReal.jpg ├── README.md ├── ReflowControllerC.PDF ├── ReflowControllerC.jpg ├── ReflowControllerC_Bom.pdf ├── ReflowPanelC - CADCAM.ZIP ├── ReflowPanelC.pdsprj ├── ReflowPowerC.PDF ├── ReflowPowerC.jpg └── ReflowPowerC_Bom.pdf └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_GFX/Adafruit_GFX.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This is the core graphics library for all our displays, providing a common 3 | set of graphics primitives (points, lines, circles, etc.). It needs to be 4 | paired with a hardware-specific library for each display device we carry 5 | (to handle the lower-level functions). 6 | 7 | Adafruit invests time and resources providing this open source code, please 8 | support Adafruit & open-source hardware by purchasing products from Adafruit! 9 | 10 | Copyright (c) 2013 Adafruit Industries. All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | - Redistributions of source code must retain the above copyright notice, 16 | this list of conditions and the following disclaimer. 17 | - Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #include "Adafruit_GFX.h" 35 | #include "glcdfont.c" 36 | #ifdef __AVR__ 37 | #include 38 | #else 39 | #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) 40 | #endif 41 | 42 | Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): 43 | WIDTH(w), HEIGHT(h) 44 | { 45 | _width = WIDTH; 46 | _height = HEIGHT; 47 | rotation = 0; 48 | cursor_y = cursor_x = 0; 49 | textsize = 1; 50 | textcolor = textbgcolor = 0xFFFF; 51 | wrap = true; 52 | } 53 | 54 | // Draw a circle outline 55 | void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, 56 | uint16_t color) { 57 | int16_t f = 1 - r; 58 | int16_t ddF_x = 1; 59 | int16_t ddF_y = -2 * r; 60 | int16_t x = 0; 61 | int16_t y = r; 62 | 63 | drawPixel(x0 , y0+r, color); 64 | drawPixel(x0 , y0-r, color); 65 | drawPixel(x0+r, y0 , color); 66 | drawPixel(x0-r, y0 , color); 67 | 68 | while (x= 0) { 70 | y--; 71 | ddF_y += 2; 72 | f += ddF_y; 73 | } 74 | x++; 75 | ddF_x += 2; 76 | f += ddF_x; 77 | 78 | drawPixel(x0 + x, y0 + y, color); 79 | drawPixel(x0 - x, y0 + y, color); 80 | drawPixel(x0 + x, y0 - y, color); 81 | drawPixel(x0 - x, y0 - y, color); 82 | drawPixel(x0 + y, y0 + x, color); 83 | drawPixel(x0 - y, y0 + x, color); 84 | drawPixel(x0 + y, y0 - x, color); 85 | drawPixel(x0 - y, y0 - x, color); 86 | } 87 | } 88 | 89 | void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, 90 | int16_t r, uint8_t cornername, uint16_t color) { 91 | int16_t f = 1 - r; 92 | int16_t ddF_x = 1; 93 | int16_t ddF_y = -2 * r; 94 | int16_t x = 0; 95 | int16_t y = r; 96 | 97 | while (x= 0) { 99 | y--; 100 | ddF_y += 2; 101 | f += ddF_y; 102 | } 103 | x++; 104 | ddF_x += 2; 105 | f += ddF_x; 106 | if (cornername & 0x4) { 107 | drawPixel(x0 + x, y0 + y, color); 108 | drawPixel(x0 + y, y0 + x, color); 109 | } 110 | if (cornername & 0x2) { 111 | drawPixel(x0 + x, y0 - y, color); 112 | drawPixel(x0 + y, y0 - x, color); 113 | } 114 | if (cornername & 0x8) { 115 | drawPixel(x0 - y, y0 + x, color); 116 | drawPixel(x0 - x, y0 + y, color); 117 | } 118 | if (cornername & 0x1) { 119 | drawPixel(x0 - y, y0 - x, color); 120 | drawPixel(x0 - x, y0 - y, color); 121 | } 122 | } 123 | } 124 | 125 | void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, 126 | uint16_t color) { 127 | drawFastVLine(x0, y0-r, 2*r+1, color); 128 | fillCircleHelper(x0, y0, r, 3, 0, color); 129 | } 130 | 131 | // Used to do circles and roundrects 132 | void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, 133 | uint8_t cornername, int16_t delta, uint16_t color) { 134 | 135 | int16_t f = 1 - r; 136 | int16_t ddF_x = 1; 137 | int16_t ddF_y = -2 * r; 138 | int16_t x = 0; 139 | int16_t y = r; 140 | 141 | while (x= 0) { 143 | y--; 144 | ddF_y += 2; 145 | f += ddF_y; 146 | } 147 | x++; 148 | ddF_x += 2; 149 | f += ddF_x; 150 | 151 | if (cornername & 0x1) { 152 | drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); 153 | drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); 154 | } 155 | if (cornername & 0x2) { 156 | drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); 157 | drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); 158 | } 159 | } 160 | } 161 | 162 | // Bresenham's algorithm - thx wikpedia 163 | void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, 164 | int16_t x1, int16_t y1, 165 | uint16_t color) { 166 | int16_t steep = abs(y1 - y0) > abs(x1 - x0); 167 | if (steep) { 168 | swap(x0, y0); 169 | swap(x1, y1); 170 | } 171 | 172 | if (x0 > x1) { 173 | swap(x0, x1); 174 | swap(y0, y1); 175 | } 176 | 177 | int16_t dx, dy; 178 | dx = x1 - x0; 179 | dy = abs(y1 - y0); 180 | 181 | int16_t err = dx / 2; 182 | int16_t ystep; 183 | 184 | if (y0 < y1) { 185 | ystep = 1; 186 | } else { 187 | ystep = -1; 188 | } 189 | 190 | for (; x0<=x1; x0++) { 191 | if (steep) { 192 | drawPixel(y0, x0, color); 193 | } else { 194 | drawPixel(x0, y0, color); 195 | } 196 | err -= dy; 197 | if (err < 0) { 198 | y0 += ystep; 199 | err += dx; 200 | } 201 | } 202 | } 203 | 204 | // Draw a rectangle 205 | void Adafruit_GFX::drawRect(int16_t x, int16_t y, 206 | int16_t w, int16_t h, 207 | uint16_t color) { 208 | drawFastHLine(x, y, w, color); 209 | drawFastHLine(x, y+h-1, w, color); 210 | drawFastVLine(x, y, h, color); 211 | drawFastVLine(x+w-1, y, h, color); 212 | } 213 | 214 | void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, 215 | int16_t h, uint16_t color) { 216 | // Update in subclasses if desired! 217 | drawLine(x, y, x, y+h-1, color); 218 | } 219 | 220 | void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, 221 | int16_t w, uint16_t color) { 222 | // Update in subclasses if desired! 223 | drawLine(x, y, x+w-1, y, color); 224 | } 225 | 226 | void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 227 | uint16_t color) { 228 | // Update in subclasses if desired! 229 | for (int16_t i=x; i= y1 >= y0) 281 | if (y0 > y1) { 282 | swap(y0, y1); swap(x0, x1); 283 | } 284 | if (y1 > y2) { 285 | swap(y2, y1); swap(x2, x1); 286 | } 287 | if (y0 > y1) { 288 | swap(y0, y1); swap(x0, x1); 289 | } 290 | 291 | if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing 292 | a = b = x0; 293 | if(x1 < a) a = x1; 294 | else if(x1 > b) b = x1; 295 | if(x2 < a) a = x2; 296 | else if(x2 > b) b = x2; 297 | drawFastHLine(a, y0, b-a+1, color); 298 | return; 299 | } 300 | 301 | int16_t 302 | dx01 = x1 - x0, 303 | dy01 = y1 - y0, 304 | dx02 = x2 - x0, 305 | dy02 = y2 - y0, 306 | dx12 = x2 - x1, 307 | dy12 = y2 - y1, 308 | sa = 0, 309 | sb = 0; 310 | 311 | // For upper part of triangle, find scanline crossings for segments 312 | // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 313 | // is included here (and second loop will be skipped, avoiding a /0 314 | // error there), otherwise scanline y1 is skipped here and handled 315 | // in the second loop...which also avoids a /0 error here if y0=y1 316 | // (flat-topped triangle). 317 | if(y1 == y2) last = y1; // Include y1 scanline 318 | else last = y1-1; // Skip it 319 | 320 | for(y=y0; y<=last; y++) { 321 | a = x0 + sa / dy01; 322 | b = x0 + sb / dy02; 323 | sa += dx01; 324 | sb += dx02; 325 | /* longhand: 326 | a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); 327 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 328 | */ 329 | if(a > b) swap(a,b); 330 | drawFastHLine(a, y, b-a+1, color); 331 | } 332 | 333 | // For lower part of triangle, find scanline crossings for segments 334 | // 0-2 and 1-2. This loop is skipped if y1=y2. 335 | sa = dx12 * (y - y1); 336 | sb = dx02 * (y - y0); 337 | for(; y<=y2; y++) { 338 | a = x1 + sa / dy12; 339 | b = x0 + sb / dy02; 340 | sa += dx12; 341 | sb += dx02; 342 | /* longhand: 343 | a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); 344 | b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 345 | */ 346 | if(a > b) swap(a,b); 347 | drawFastHLine(a, y, b-a+1, color); 348 | } 349 | } 350 | 351 | void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 352 | const uint8_t *bitmap, int16_t w, int16_t h, 353 | uint16_t color) { 354 | 355 | int16_t i, j, byteWidth = (w + 7) / 8; 356 | 357 | for(j=0; j> (i & 7))) { 360 | drawPixel(x+i, y+j, color); 361 | } 362 | } 363 | } 364 | } 365 | 366 | #if ARDUINO >= 100 367 | size_t Adafruit_GFX::write(uint8_t c) { 368 | #else 369 | void Adafruit_GFX::write(uint8_t c) { 370 | #endif 371 | if (c == '\n') { 372 | cursor_y += textsize*8; 373 | cursor_x = 0; 374 | } else if (c == '\r') { 375 | // skip em 376 | } else { 377 | drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); 378 | cursor_x += textsize*6; 379 | if (wrap && (cursor_x > (_width - textsize*6))) { 380 | cursor_y += textsize*8; 381 | cursor_x = 0; 382 | } 383 | } 384 | #if ARDUINO >= 100 385 | return 1; 386 | #endif 387 | } 388 | 389 | // Draw a character 390 | void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, 391 | uint16_t color, uint16_t bg, uint8_t size) { 392 | 393 | if((x >= _width) || // Clip right 394 | (y >= _height) || // Clip bottom 395 | ((x + 6 * size - 1) < 0) || // Clip left 396 | ((y + 8 * size - 1) < 0)) // Clip top 397 | return; 398 | 399 | for (int8_t i=0; i<6; i++ ) { 400 | uint8_t line; 401 | if (i == 5) 402 | line = 0x0; 403 | else 404 | line = pgm_read_byte(font+(c*5)+i); 405 | for (int8_t j = 0; j<8; j++) { 406 | if (line & 0x1) { 407 | if (size == 1) // default size 408 | drawPixel(x+i, y+j, color); 409 | else { // big size 410 | fillRect(x+(i*size), y+(j*size), size, size, color); 411 | } 412 | } else if (bg != color) { 413 | if (size == 1) // default size 414 | drawPixel(x+i, y+j, bg); 415 | else { // big size 416 | fillRect(x+i*size, y+j*size, size, size, bg); 417 | } 418 | } 419 | line >>= 1; 420 | } 421 | } 422 | } 423 | 424 | void Adafruit_GFX::setCursor(int16_t x, int16_t y) { 425 | cursor_x = x; 426 | cursor_y = y; 427 | } 428 | 429 | void Adafruit_GFX::setTextSize(uint8_t s) { 430 | textsize = (s > 0) ? s : 1; 431 | } 432 | 433 | void Adafruit_GFX::setTextColor(uint16_t c) { 434 | // For 'transparent' background, we'll set the bg 435 | // to the same as fg instead of using a flag 436 | textcolor = textbgcolor = c; 437 | } 438 | 439 | void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { 440 | textcolor = c; 441 | textbgcolor = b; 442 | } 443 | 444 | void Adafruit_GFX::setTextWrap(boolean w) { 445 | wrap = w; 446 | } 447 | 448 | uint8_t Adafruit_GFX::getRotation(void) { 449 | return rotation; 450 | } 451 | 452 | void Adafruit_GFX::setRotation(uint8_t x) { 453 | rotation = (x & 3); 454 | switch(rotation) { 455 | case 0: 456 | case 2: 457 | _width = WIDTH; 458 | _height = HEIGHT; 459 | break; 460 | case 1: 461 | case 3: 462 | _width = HEIGHT; 463 | _height = WIDTH; 464 | break; 465 | } 466 | } 467 | 468 | // Return the size of the display (per current rotation) 469 | int16_t Adafruit_GFX::width(void) { 470 | return _width; 471 | } 472 | 473 | int16_t Adafruit_GFX::height(void) { 474 | return _height; 475 | } 476 | 477 | void Adafruit_GFX::invertDisplay(boolean i) { 478 | // Do nothing, must be subclassed if supported 479 | } 480 | 481 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_GFX/Adafruit_GFX.h: -------------------------------------------------------------------------------- 1 | #ifndef _ADAFRUIT_GFX_H 2 | #define _ADAFRUIT_GFX_H 3 | 4 | #if ARDUINO >= 100 5 | #include "Arduino.h" 6 | #include "Print.h" 7 | #else 8 | #include "WProgram.h" 9 | #endif 10 | 11 | #define swap(a, b) { int16_t t = a; a = b; b = t; } 12 | 13 | class Adafruit_GFX : public Print { 14 | 15 | public: 16 | 17 | Adafruit_GFX(int16_t w, int16_t h); // Constructor 18 | 19 | // This MUST be defined by the subclass: 20 | virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; 21 | 22 | // These MAY be overridden by the subclass to provide device-specific 23 | // optimized code. Otherwise 'generic' versions are used. 24 | virtual void 25 | drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), 26 | drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), 27 | drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), 28 | drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), 29 | fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), 30 | fillScreen(uint16_t color), 31 | invertDisplay(boolean i); 32 | 33 | // These exist only with Adafruit_GFX (no subclass overrides) 34 | void 35 | drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), 36 | drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, 37 | uint16_t color), 38 | fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), 39 | fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, 40 | int16_t delta, uint16_t color), 41 | drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 42 | int16_t x2, int16_t y2, uint16_t color), 43 | fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 44 | int16_t x2, int16_t y2, uint16_t color), 45 | drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, 46 | int16_t radius, uint16_t color), 47 | fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, 48 | int16_t radius, uint16_t color), 49 | drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, 50 | int16_t w, int16_t h, uint16_t color), 51 | drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, 52 | uint16_t bg, uint8_t size), 53 | setCursor(int16_t x, int16_t y), 54 | setTextColor(uint16_t c), 55 | setTextColor(uint16_t c, uint16_t bg), 56 | setTextSize(uint8_t s), 57 | setTextWrap(boolean w), 58 | setRotation(uint8_t r); 59 | 60 | #if ARDUINO >= 100 61 | virtual size_t write(uint8_t); 62 | #else 63 | virtual void write(uint8_t); 64 | #endif 65 | 66 | int16_t 67 | height(void), 68 | width(void); 69 | 70 | uint8_t getRotation(void); 71 | 72 | protected: 73 | const int16_t 74 | WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes 75 | int16_t 76 | _width, _height, // Display w/h as modified by current rotation 77 | cursor_x, cursor_y; 78 | uint16_t 79 | textcolor, textbgcolor; 80 | uint8_t 81 | textsize, 82 | rotation; 83 | boolean 84 | wrap; // If set, 'wrap' text at right edge of display 85 | }; 86 | 87 | #endif // _ADAFRUIT_GFX_H 88 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_GFX/README.txt: -------------------------------------------------------------------------------- 1 | This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). 2 | 3 | Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! 4 | 5 | Written by Limor Fried/Ladyada for Adafruit Industries. 6 | BSD license, check license.txt for more information. 7 | All text above must be included in any redistribution. 8 | 9 | To download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h 10 | 11 | Place the Adafruit_GFX library folder your /Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. 12 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_GFX/glcdfont.c: -------------------------------------------------------------------------------- 1 | #ifndef FONT5X7_H 2 | #define FONT5X7_H 3 | 4 | #ifdef __AVR__ 5 | #include 6 | #include 7 | #else 8 | #define PROGMEM 9 | #endif 10 | 11 | // Standard ASCII 5x7 font 12 | 13 | static const unsigned char font[] PROGMEM = { 14 | 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 16 | 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 17 | 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 18 | 0x18, 0x3C, 0x7E, 0x3C, 0x18, 19 | 0x1C, 0x57, 0x7D, 0x57, 0x1C, 20 | 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 21 | 0x00, 0x18, 0x3C, 0x18, 0x00, 22 | 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 23 | 0x00, 0x18, 0x24, 0x18, 0x00, 24 | 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 25 | 0x30, 0x48, 0x3A, 0x06, 0x0E, 26 | 0x26, 0x29, 0x79, 0x29, 0x26, 27 | 0x40, 0x7F, 0x05, 0x05, 0x07, 28 | 0x40, 0x7F, 0x05, 0x25, 0x3F, 29 | 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 30 | 0x7F, 0x3E, 0x1C, 0x1C, 0x08, 31 | 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 32 | 0x14, 0x22, 0x7F, 0x22, 0x14, 33 | 0x5F, 0x5F, 0x00, 0x5F, 0x5F, 34 | 0x06, 0x09, 0x7F, 0x01, 0x7F, 35 | 0x00, 0x66, 0x89, 0x95, 0x6A, 36 | 0x60, 0x60, 0x60, 0x60, 0x60, 37 | 0x94, 0xA2, 0xFF, 0xA2, 0x94, 38 | 0x08, 0x04, 0x7E, 0x04, 0x08, 39 | 0x10, 0x20, 0x7E, 0x20, 0x10, 40 | 0x08, 0x08, 0x2A, 0x1C, 0x08, 41 | 0x08, 0x1C, 0x2A, 0x08, 0x08, 42 | 0x1E, 0x10, 0x10, 0x10, 0x10, 43 | 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 44 | 0x30, 0x38, 0x3E, 0x38, 0x30, 45 | 0x06, 0x0E, 0x3E, 0x0E, 0x06, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 0x5F, 0x00, 0x00, 48 | 0x00, 0x07, 0x00, 0x07, 0x00, 49 | 0x14, 0x7F, 0x14, 0x7F, 0x14, 50 | 0x24, 0x2A, 0x7F, 0x2A, 0x12, 51 | 0x23, 0x13, 0x08, 0x64, 0x62, 52 | 0x36, 0x49, 0x56, 0x20, 0x50, 53 | 0x00, 0x08, 0x07, 0x03, 0x00, 54 | 0x00, 0x1C, 0x22, 0x41, 0x00, 55 | 0x00, 0x41, 0x22, 0x1C, 0x00, 56 | 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 57 | 0x08, 0x08, 0x3E, 0x08, 0x08, 58 | 0x00, 0x80, 0x70, 0x30, 0x00, 59 | 0x08, 0x08, 0x08, 0x08, 0x08, 60 | 0x00, 0x00, 0x60, 0x60, 0x00, 61 | 0x20, 0x10, 0x08, 0x04, 0x02, 62 | 0x3E, 0x51, 0x49, 0x45, 0x3E, 63 | 0x00, 0x42, 0x7F, 0x40, 0x00, 64 | 0x72, 0x49, 0x49, 0x49, 0x46, 65 | 0x21, 0x41, 0x49, 0x4D, 0x33, 66 | 0x18, 0x14, 0x12, 0x7F, 0x10, 67 | 0x27, 0x45, 0x45, 0x45, 0x39, 68 | 0x3C, 0x4A, 0x49, 0x49, 0x31, 69 | 0x41, 0x21, 0x11, 0x09, 0x07, 70 | 0x36, 0x49, 0x49, 0x49, 0x36, 71 | 0x46, 0x49, 0x49, 0x29, 0x1E, 72 | 0x00, 0x00, 0x14, 0x00, 0x00, 73 | 0x00, 0x40, 0x34, 0x00, 0x00, 74 | 0x00, 0x08, 0x14, 0x22, 0x41, 75 | 0x14, 0x14, 0x14, 0x14, 0x14, 76 | 0x00, 0x41, 0x22, 0x14, 0x08, 77 | 0x02, 0x01, 0x59, 0x09, 0x06, 78 | 0x3E, 0x41, 0x5D, 0x59, 0x4E, 79 | 0x7C, 0x12, 0x11, 0x12, 0x7C, 80 | 0x7F, 0x49, 0x49, 0x49, 0x36, 81 | 0x3E, 0x41, 0x41, 0x41, 0x22, 82 | 0x7F, 0x41, 0x41, 0x41, 0x3E, 83 | 0x7F, 0x49, 0x49, 0x49, 0x41, 84 | 0x7F, 0x09, 0x09, 0x09, 0x01, 85 | 0x3E, 0x41, 0x41, 0x51, 0x73, 86 | 0x7F, 0x08, 0x08, 0x08, 0x7F, 87 | 0x00, 0x41, 0x7F, 0x41, 0x00, 88 | 0x20, 0x40, 0x41, 0x3F, 0x01, 89 | 0x7F, 0x08, 0x14, 0x22, 0x41, 90 | 0x7F, 0x40, 0x40, 0x40, 0x40, 91 | 0x7F, 0x02, 0x1C, 0x02, 0x7F, 92 | 0x7F, 0x04, 0x08, 0x10, 0x7F, 93 | 0x3E, 0x41, 0x41, 0x41, 0x3E, 94 | 0x7F, 0x09, 0x09, 0x09, 0x06, 95 | 0x3E, 0x41, 0x51, 0x21, 0x5E, 96 | 0x7F, 0x09, 0x19, 0x29, 0x46, 97 | 0x26, 0x49, 0x49, 0x49, 0x32, 98 | 0x03, 0x01, 0x7F, 0x01, 0x03, 99 | 0x3F, 0x40, 0x40, 0x40, 0x3F, 100 | 0x1F, 0x20, 0x40, 0x20, 0x1F, 101 | 0x3F, 0x40, 0x38, 0x40, 0x3F, 102 | 0x63, 0x14, 0x08, 0x14, 0x63, 103 | 0x03, 0x04, 0x78, 0x04, 0x03, 104 | 0x61, 0x59, 0x49, 0x4D, 0x43, 105 | 0x00, 0x7F, 0x41, 0x41, 0x41, 106 | 0x02, 0x04, 0x08, 0x10, 0x20, 107 | 0x00, 0x41, 0x41, 0x41, 0x7F, 108 | 0x04, 0x02, 0x01, 0x02, 0x04, 109 | 0x40, 0x40, 0x40, 0x40, 0x40, 110 | 0x00, 0x03, 0x07, 0x08, 0x00, 111 | 0x20, 0x54, 0x54, 0x78, 0x40, 112 | 0x7F, 0x28, 0x44, 0x44, 0x38, 113 | 0x38, 0x44, 0x44, 0x44, 0x28, 114 | 0x38, 0x44, 0x44, 0x28, 0x7F, 115 | 0x38, 0x54, 0x54, 0x54, 0x18, 116 | 0x00, 0x08, 0x7E, 0x09, 0x02, 117 | 0x18, 0xA4, 0xA4, 0x9C, 0x78, 118 | 0x7F, 0x08, 0x04, 0x04, 0x78, 119 | 0x00, 0x44, 0x7D, 0x40, 0x00, 120 | 0x20, 0x40, 0x40, 0x3D, 0x00, 121 | 0x7F, 0x10, 0x28, 0x44, 0x00, 122 | 0x00, 0x41, 0x7F, 0x40, 0x00, 123 | 0x7C, 0x04, 0x78, 0x04, 0x78, 124 | 0x7C, 0x08, 0x04, 0x04, 0x78, 125 | 0x38, 0x44, 0x44, 0x44, 0x38, 126 | 0xFC, 0x18, 0x24, 0x24, 0x18, 127 | 0x18, 0x24, 0x24, 0x18, 0xFC, 128 | 0x7C, 0x08, 0x04, 0x04, 0x08, 129 | 0x48, 0x54, 0x54, 0x54, 0x24, 130 | 0x04, 0x04, 0x3F, 0x44, 0x24, 131 | 0x3C, 0x40, 0x40, 0x20, 0x7C, 132 | 0x1C, 0x20, 0x40, 0x20, 0x1C, 133 | 0x3C, 0x40, 0x30, 0x40, 0x3C, 134 | 0x44, 0x28, 0x10, 0x28, 0x44, 135 | 0x4C, 0x90, 0x90, 0x90, 0x7C, 136 | 0x44, 0x64, 0x54, 0x4C, 0x44, 137 | 0x00, 0x08, 0x36, 0x41, 0x00, 138 | 0x00, 0x00, 0x77, 0x00, 0x00, 139 | 0x00, 0x41, 0x36, 0x08, 0x00, 140 | 0x02, 0x01, 0x02, 0x04, 0x02, 141 | 0x3C, 0x26, 0x23, 0x26, 0x3C, 142 | 0x1E, 0xA1, 0xA1, 0x61, 0x12, 143 | 0x3A, 0x40, 0x40, 0x20, 0x7A, 144 | 0x38, 0x54, 0x54, 0x55, 0x59, 145 | 0x21, 0x55, 0x55, 0x79, 0x41, 146 | 0x21, 0x54, 0x54, 0x78, 0x41, 147 | 0x21, 0x55, 0x54, 0x78, 0x40, 148 | 0x20, 0x54, 0x55, 0x79, 0x40, 149 | 0x0C, 0x1E, 0x52, 0x72, 0x12, 150 | 0x39, 0x55, 0x55, 0x55, 0x59, 151 | 0x39, 0x54, 0x54, 0x54, 0x59, 152 | 0x39, 0x55, 0x54, 0x54, 0x58, 153 | 0x00, 0x00, 0x45, 0x7C, 0x41, 154 | 0x00, 0x02, 0x45, 0x7D, 0x42, 155 | 0x00, 0x01, 0x45, 0x7C, 0x40, 156 | 0xF0, 0x29, 0x24, 0x29, 0xF0, 157 | 0xF0, 0x28, 0x25, 0x28, 0xF0, 158 | 0x7C, 0x54, 0x55, 0x45, 0x00, 159 | 0x20, 0x54, 0x54, 0x7C, 0x54, 160 | 0x7C, 0x0A, 0x09, 0x7F, 0x49, 161 | 0x32, 0x49, 0x49, 0x49, 0x32, 162 | 0x32, 0x48, 0x48, 0x48, 0x32, 163 | 0x32, 0x4A, 0x48, 0x48, 0x30, 164 | 0x3A, 0x41, 0x41, 0x21, 0x7A, 165 | 0x3A, 0x42, 0x40, 0x20, 0x78, 166 | 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 167 | 0x39, 0x44, 0x44, 0x44, 0x39, 168 | 0x3D, 0x40, 0x40, 0x40, 0x3D, 169 | 0x3C, 0x24, 0xFF, 0x24, 0x24, 170 | 0x48, 0x7E, 0x49, 0x43, 0x66, 171 | 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 172 | 0xFF, 0x09, 0x29, 0xF6, 0x20, 173 | 0xC0, 0x88, 0x7E, 0x09, 0x03, 174 | 0x20, 0x54, 0x54, 0x79, 0x41, 175 | 0x00, 0x00, 0x44, 0x7D, 0x41, 176 | 0x30, 0x48, 0x48, 0x4A, 0x32, 177 | 0x38, 0x40, 0x40, 0x22, 0x7A, 178 | 0x00, 0x7A, 0x0A, 0x0A, 0x72, 179 | 0x7D, 0x0D, 0x19, 0x31, 0x7D, 180 | 0x26, 0x29, 0x29, 0x2F, 0x28, 181 | 0x26, 0x29, 0x29, 0x29, 0x26, 182 | 0x30, 0x48, 0x4D, 0x40, 0x20, 183 | 0x38, 0x08, 0x08, 0x08, 0x08, 184 | 0x08, 0x08, 0x08, 0x08, 0x38, 185 | 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 186 | 0x2F, 0x10, 0x28, 0x34, 0xFA, 187 | 0x00, 0x00, 0x7B, 0x00, 0x00, 188 | 0x08, 0x14, 0x2A, 0x14, 0x22, 189 | 0x22, 0x14, 0x2A, 0x14, 0x08, 190 | 0xAA, 0x00, 0x55, 0x00, 0xAA, 191 | 0xAA, 0x55, 0xAA, 0x55, 0xAA, 192 | 0x00, 0x00, 0x00, 0xFF, 0x00, 193 | 0x10, 0x10, 0x10, 0xFF, 0x00, 194 | 0x14, 0x14, 0x14, 0xFF, 0x00, 195 | 0x10, 0x10, 0xFF, 0x00, 0xFF, 196 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 197 | 0x14, 0x14, 0x14, 0xFC, 0x00, 198 | 0x14, 0x14, 0xF7, 0x00, 0xFF, 199 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 200 | 0x14, 0x14, 0xF4, 0x04, 0xFC, 201 | 0x14, 0x14, 0x17, 0x10, 0x1F, 202 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 203 | 0x14, 0x14, 0x14, 0x1F, 0x00, 204 | 0x10, 0x10, 0x10, 0xF0, 0x00, 205 | 0x00, 0x00, 0x00, 0x1F, 0x10, 206 | 0x10, 0x10, 0x10, 0x1F, 0x10, 207 | 0x10, 0x10, 0x10, 0xF0, 0x10, 208 | 0x00, 0x00, 0x00, 0xFF, 0x10, 209 | 0x10, 0x10, 0x10, 0x10, 0x10, 210 | 0x10, 0x10, 0x10, 0xFF, 0x10, 211 | 0x00, 0x00, 0x00, 0xFF, 0x14, 212 | 0x00, 0x00, 0xFF, 0x00, 0xFF, 213 | 0x00, 0x00, 0x1F, 0x10, 0x17, 214 | 0x00, 0x00, 0xFC, 0x04, 0xF4, 215 | 0x14, 0x14, 0x17, 0x10, 0x17, 216 | 0x14, 0x14, 0xF4, 0x04, 0xF4, 217 | 0x00, 0x00, 0xFF, 0x00, 0xF7, 218 | 0x14, 0x14, 0x14, 0x14, 0x14, 219 | 0x14, 0x14, 0xF7, 0x00, 0xF7, 220 | 0x14, 0x14, 0x14, 0x17, 0x14, 221 | 0x10, 0x10, 0x1F, 0x10, 0x1F, 222 | 0x14, 0x14, 0x14, 0xF4, 0x14, 223 | 0x10, 0x10, 0xF0, 0x10, 0xF0, 224 | 0x00, 0x00, 0x1F, 0x10, 0x1F, 225 | 0x00, 0x00, 0x00, 0x1F, 0x14, 226 | 0x00, 0x00, 0x00, 0xFC, 0x14, 227 | 0x00, 0x00, 0xF0, 0x10, 0xF0, 228 | 0x10, 0x10, 0xFF, 0x10, 0xFF, 229 | 0x14, 0x14, 0x14, 0xFF, 0x14, 230 | 0x10, 0x10, 0x10, 0x1F, 0x00, 231 | 0x00, 0x00, 0x00, 0xF0, 0x10, 232 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 233 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 234 | 0xFF, 0xFF, 0xFF, 0x00, 0x00, 235 | 0x00, 0x00, 0x00, 0xFF, 0xFF, 236 | 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 237 | 0x38, 0x44, 0x44, 0x38, 0x44, 238 | 0x7C, 0x2A, 0x2A, 0x3E, 0x14, 239 | 0x7E, 0x02, 0x02, 0x06, 0x06, 240 | 0x02, 0x7E, 0x02, 0x7E, 0x02, 241 | 0x63, 0x55, 0x49, 0x41, 0x63, 242 | 0x38, 0x44, 0x44, 0x3C, 0x04, 243 | 0x40, 0x7E, 0x20, 0x1E, 0x20, 244 | 0x06, 0x02, 0x7E, 0x02, 0x02, 245 | 0x99, 0xA5, 0xE7, 0xA5, 0x99, 246 | 0x1C, 0x2A, 0x49, 0x2A, 0x1C, 247 | 0x4C, 0x72, 0x01, 0x72, 0x4C, 248 | 0x30, 0x4A, 0x4D, 0x4D, 0x30, 249 | 0x30, 0x48, 0x78, 0x48, 0x30, 250 | 0xBC, 0x62, 0x5A, 0x46, 0x3D, 251 | 0x3E, 0x49, 0x49, 0x49, 0x00, 252 | 0x7E, 0x01, 0x01, 0x01, 0x7E, 253 | 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 254 | 0x44, 0x44, 0x5F, 0x44, 0x44, 255 | 0x40, 0x51, 0x4A, 0x44, 0x40, 256 | 0x40, 0x44, 0x4A, 0x51, 0x40, 257 | 0x00, 0x00, 0xFF, 0x01, 0x03, 258 | 0xE0, 0x80, 0xFF, 0x00, 0x00, 259 | 0x08, 0x08, 0x6B, 0x6B, 0x08, 260 | 0x36, 0x12, 0x36, 0x24, 0x36, 261 | 0x06, 0x0F, 0x09, 0x0F, 0x06, 262 | 0x00, 0x00, 0x18, 0x18, 0x00, 263 | 0x00, 0x00, 0x10, 0x10, 0x00, 264 | 0x30, 0x40, 0xFF, 0x01, 0x01, 265 | 0x00, 0x1F, 0x01, 0x01, 0x1E, 266 | 0x00, 0x19, 0x1D, 0x17, 0x12, 267 | 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 268 | 0x00, 0x00, 0x00, 0x00, 0x00 269 | }; 270 | #endif // FONT5X7_H 271 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_GFX/license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2012 Adafruit Industries. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | - Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | - Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/Adafruit_MAX31855.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is a library for the Adafruit Thermocouple Sensor w/MAX31855K 3 | 4 | Designed specifically to work with the Adafruit Thermocouple Sensor 5 | ----> https://www.adafruit.com/products/269 6 | 7 | These displays use SPI to communicate, 3 pins are required to 8 | interface 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | BSD license, all text above must be included in any redistribution 15 | ****************************************************/ 16 | 17 | #include "Adafruit_MAX31855.h" 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | Adafruit_MAX31855::Adafruit_MAX31855(int8_t SCLK, int8_t CS, int8_t MISO) { 24 | sclk = SCLK; 25 | cs = CS; 26 | miso = MISO; 27 | 28 | //define pin modes 29 | pinMode(cs, OUTPUT); 30 | pinMode(sclk, OUTPUT); 31 | pinMode(miso, INPUT); 32 | 33 | digitalWrite(cs, HIGH); 34 | } 35 | 36 | 37 | double Adafruit_MAX31855::readInternal(void) { 38 | uint32_t v; 39 | 40 | v = spiread32(); 41 | 42 | // ignore bottom 4 bits - they're just thermocouple data 43 | v >>= 4; 44 | 45 | // pull the bottom 11 bits off 46 | float internal = v & 0x7FF; 47 | internal *= 0.0625; // LSB = 0.0625 degrees 48 | // check sign bit! 49 | if (v & 0x800) 50 | internal *= -1; 51 | //Serial.print("\tInternal Temp: "); Serial.println(internal); 52 | return internal; 53 | } 54 | 55 | double Adafruit_MAX31855::readCelsius(void) { 56 | 57 | int32_t v; 58 | 59 | v = spiread32(); 60 | 61 | //Serial.print("0x"); Serial.println(v, HEX); 62 | 63 | /* 64 | float internal = (v >> 4) & 0x7FF; 65 | internal *= 0.0625; 66 | if ((v >> 4) & 0x800) 67 | internal *= -1; 68 | Serial.print("\tInternal Temp: "); Serial.println(internal); 69 | */ 70 | 71 | if (v & 0x7) { 72 | // uh oh, a serious problem! 73 | return NAN; 74 | } 75 | 76 | // get rid of internal temp data, and any fault bits 77 | v >>= 18; 78 | //Serial.println(v, HEX); 79 | 80 | // pull the bottom 13 bits off 81 | int16_t temp = v & 0x3FFF; 82 | 83 | // check sign bit 84 | if (v & 0x2000) 85 | temp |= 0xC000; 86 | //Serial.println(temp); 87 | 88 | double centigrade = v; 89 | 90 | // LSB = 0.25 degrees C 91 | centigrade *= 0.25; 92 | return centigrade; 93 | } 94 | 95 | uint8_t Adafruit_MAX31855::readError() { 96 | return spiread32() & 0x7; 97 | } 98 | 99 | double Adafruit_MAX31855::readFarenheit(void) { 100 | float f = readCelsius(); 101 | f *= 9.0; 102 | f /= 5.0; 103 | f += 32; 104 | return f; 105 | } 106 | 107 | uint32_t Adafruit_MAX31855::spiread32(void) { 108 | int i; 109 | uint32_t d = 0; 110 | 111 | digitalWrite(sclk, LOW); 112 | _delay_ms(1); 113 | digitalWrite(cs, LOW); 114 | _delay_ms(1); 115 | 116 | for (i=31; i>=0; i--) 117 | { 118 | digitalWrite(sclk, LOW); 119 | _delay_ms(1); 120 | d <<= 1; 121 | if (digitalRead(miso)) { 122 | d |= 1; 123 | } 124 | 125 | digitalWrite(sclk, HIGH); 126 | _delay_ms(1); 127 | } 128 | 129 | digitalWrite(cs, HIGH); 130 | //Serial.println(d, HEX); 131 | return d; 132 | } 133 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/Adafruit_MAX31855.h: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is a library for the Adafruit Thermocouple Sensor w/MAX31855K 3 | 4 | Designed specifically to work with the Adafruit Thermocouple Sensor 5 | ----> https://www.adafruit.com/products/269 6 | 7 | These displays use SPI to communicate, 3 pins are required to 8 | interface 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | BSD license, all text above must be included in any redistribution 15 | ****************************************************/ 16 | 17 | 18 | #if (ARDUINO >= 100) 19 | #include "Arduino.h" 20 | #else 21 | #include "WProgram.h" 22 | #endif 23 | 24 | class Adafruit_MAX31855 { 25 | public: 26 | Adafruit_MAX31855(int8_t SCLK, int8_t CS, int8_t MISO); 27 | 28 | double readInternal(void); 29 | double readCelsius(void); 30 | double readFarenheit(void); 31 | uint8_t readError(); 32 | 33 | private: 34 | int8_t sclk, miso, cs; 35 | uint32_t spiread32(void); 36 | }; 37 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/README.txt: -------------------------------------------------------------------------------- 1 | This is the Adafruit MAX31885 Arduino Library 2 | 3 | Tested and works great with the Adafruit Thermocouple Breakout w/MAX31885K 4 | ------> http://www.adafruit.com/products/269 5 | 6 | These modules use SPI to communicate, 3 pins are required to 7 | interface 8 | 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | BSD license, check license.txt for more information 15 | All text above must be included in any redistribution 16 | 17 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_MAX31885. Check that the Adafruit_MAX31885 folder contains Adafruit_MAX31885.cpp and Adafruit_MAX31885.h 18 | 19 | Place the Adafruit_MAX31885 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/examples/lcdthermocouple/LCDthermocouple.pde: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for the Adafruit Thermocouple Sensor w/MAX31855K 3 | 4 | Designed specifically to work with the Adafruit Thermocouple Sensor 5 | ----> https://www.adafruit.com/products/269 6 | 7 | These displays use SPI to communicate, 3 pins are required to 8 | interface 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | BSD license, all text above must be included in any redistribution 15 | ****************************************************/ 16 | 17 | #include "Adafruit_MAX31855.h" 18 | #include 19 | 20 | int thermoCLK = 3; 21 | int thermoCS = 4; 22 | int thermoDO = 5; 23 | 24 | // Initialize the Thermocouple 25 | Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO); 26 | // initialize the library with the numbers of the interface pins 27 | LiquidCrystal lcd(7, 8, 9, 10, 11, 12); 28 | 29 | 30 | void setup() { 31 | Serial.begin(9600); 32 | // set up the LCD's number of columns and rows: 33 | lcd.begin(16, 2); 34 | 35 | lcd.print("MAX31855 test"); 36 | // wait for MAX chip to stabilize 37 | delay(500); 38 | } 39 | 40 | void loop() { 41 | // basic readout test, just print the current temp 42 | lcd.setCursor(0, 0); 43 | lcd.print("Int. Temp = "); 44 | lcd.println(thermocouple.readInternal()); 45 | lcd.print(" "); 46 | 47 | double c = thermocouple.readCelsius(); 48 | lcd.setCursor(0, 1); 49 | if (isnan(c)) 50 | { 51 | lcd.print("T/C Problem"); 52 | } 53 | else 54 | { 55 | lcd.print("C = "); 56 | lcd.print(c); 57 | lcd.print(" "); 58 | } 59 | 60 | delay(1000); 61 | } 62 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/examples/serialthermocouple/serialthermocouple.pde: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for the Adafruit Thermocouple Sensor w/MAX31855K 3 | 4 | Designed specifically to work with the Adafruit Thermocouple Sensor 5 | ----> https://www.adafruit.com/products/269 6 | 7 | These displays use SPI to communicate, 3 pins are required to 8 | interface 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | BSD license, all text above must be included in any redistribution 15 | ****************************************************/ 16 | 17 | #include "Adafruit_MAX31855.h" 18 | 19 | int thermoDO = 3; 20 | int thermoCS = 4; 21 | int thermoCLK = 5; 22 | 23 | Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO); 24 | 25 | void setup() { 26 | Serial.begin(9600); 27 | 28 | Serial.println("MAX31855 test"); 29 | // wait for MAX chip to stabilize 30 | delay(500); 31 | } 32 | 33 | void loop() { 34 | // basic readout test, just print the current temp 35 | Serial.print("Internal Temp = "); 36 | Serial.println(thermocouple.readInternal()); 37 | 38 | double c = thermocouple.readCelsius(); 39 | if (isnan(c)) { 40 | Serial.println("Something wrong with thermocouple!"); 41 | } else { 42 | Serial.print("C = "); 43 | Serial.println(c); 44 | } 45 | //Serial.print("F = "); 46 | //Serial.println(thermocouple.readFarenheit()); 47 | 48 | delay(1000); 49 | } -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for NewSoftSerial 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | max6675 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | readCelsius KEYWORD2 16 | readFarenheit KEYWORD2 17 | 18 | ####################################### 19 | # Constants (LITERAL1) 20 | ####################################### 21 | 22 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_MAX31855/license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2012, Adafruit Industries 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of the copyright holders nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_SSD1306/Adafruit_SSD1306.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen below must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "Adafruit_GFX.h" 26 | #include "Adafruit_SSD1306.h" 27 | 28 | // the memory buffer for the LCD 29 | 30 | static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 35 | 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 40 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 42 | 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 43 | 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 44 | 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8, 46 | 0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 48 | 0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01, 50 | 0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF, 51 | 0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 52 | 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF, 53 | 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 54 | 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F, 56 | 0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 57 | 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03, 58 | 0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 59 | 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, 60 | 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 61 | 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, 62 | 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | #if (SSD1306_LCDHEIGHT == 64) 64 | 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, 65 | 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, 66 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, 67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 | 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, 70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, 73 | 0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 74 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 75 | 0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E, 76 | 0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC, 77 | 0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06, 78 | 0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8, 79 | 0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03, 82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 83 | 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C, 84 | 0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 85 | 0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 86 | 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07, 87 | 0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 96 | #endif 97 | }; 98 | 99 | 100 | 101 | // the most basic function, set a single pixel 102 | void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { 103 | if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) 104 | return; 105 | 106 | // check rotation, move pixel around if necessary 107 | switch (getRotation()) { 108 | case 1: 109 | swap(x, y); 110 | x = WIDTH - x - 1; 111 | break; 112 | case 2: 113 | x = WIDTH - x - 1; 114 | y = HEIGHT - y - 1; 115 | break; 116 | case 3: 117 | swap(x, y); 118 | y = HEIGHT - y - 1; 119 | break; 120 | } 121 | 122 | // x is which column 123 | if (color == WHITE) 124 | buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= _BV((y%8)); 125 | else 126 | buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~_BV((y%8)); 127 | } 128 | 129 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 130 | cs = CS; 131 | rst = RST; 132 | dc = DC; 133 | sclk = SCLK; 134 | sid = SID; 135 | } 136 | 137 | // initializer for I2C - we only indicate the reset pin! 138 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) : 139 | Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 140 | sclk = dc = cs = sid = -1; 141 | rst = reset; 142 | } 143 | 144 | 145 | void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr) { 146 | _i2caddr = i2caddr; 147 | 148 | // set pin directions 149 | if (sid != -1) 150 | { 151 | // SPI 152 | pinMode(sid, OUTPUT); 153 | pinMode(sclk, OUTPUT); 154 | pinMode(dc, OUTPUT); 155 | pinMode(cs, OUTPUT); 156 | clkport = portOutputRegister(digitalPinToPort(sclk)); 157 | clkpinmask = digitalPinToBitMask(sclk); 158 | mosiport = portOutputRegister(digitalPinToPort(sid)); 159 | mosipinmask = digitalPinToBitMask(sid); 160 | csport = portOutputRegister(digitalPinToPort(cs)); 161 | cspinmask = digitalPinToBitMask(cs); 162 | dcport = portOutputRegister(digitalPinToPort(dc)); 163 | dcpinmask = digitalPinToBitMask(dc); 164 | } 165 | else 166 | { 167 | // I2C Init 168 | Wire.begin(); // Is this the right place for this? 169 | } 170 | 171 | // Setup reset pin direction (used by both SPI and I2C) 172 | pinMode(rst, OUTPUT); 173 | digitalWrite(rst, HIGH); 174 | // VDD (3.3V) goes high at start, lets just chill for a ms 175 | delay(1); 176 | // bring reset low 177 | digitalWrite(rst, LOW); 178 | // wait 10ms 179 | delay(10); 180 | // bring out of reset 181 | digitalWrite(rst, HIGH); 182 | // turn on VCC (9V?) 183 | 184 | #if defined SSD1306_128_32 185 | // Init sequence for 128x32 OLED module 186 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 187 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 188 | ssd1306_command(0x80); // the suggested ratio 0x80 189 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 190 | ssd1306_command(0x1F); 191 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 192 | ssd1306_command(0x0); // no offset 193 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 194 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 195 | if (vccstate == SSD1306_EXTERNALVCC) 196 | { ssd1306_command(0x10); } 197 | else 198 | { ssd1306_command(0x14); } 199 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 200 | ssd1306_command(0x00); // 0x0 act like ks0108 201 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 202 | ssd1306_command(SSD1306_COMSCANDEC); 203 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 204 | ssd1306_command(0x02); 205 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 206 | ssd1306_command(0x8F); 207 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 208 | if (vccstate == SSD1306_EXTERNALVCC) 209 | { ssd1306_command(0x22); } 210 | else 211 | { ssd1306_command(0xF1); } 212 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 213 | ssd1306_command(0x40); 214 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 215 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 216 | #endif 217 | 218 | #if defined SSD1306_128_64 219 | // Init sequence for 128x64 OLED module 220 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 221 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 222 | ssd1306_command(0x80); // the suggested ratio 0x80 223 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 224 | ssd1306_command(0x3F); 225 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 226 | ssd1306_command(0x0); // no offset 227 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 228 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 229 | if (vccstate == SSD1306_EXTERNALVCC) 230 | { ssd1306_command(0x10); } 231 | else 232 | { ssd1306_command(0x14); } 233 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 234 | ssd1306_command(0x00); // 0x0 act like ks0108 235 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 236 | ssd1306_command(SSD1306_COMSCANDEC); 237 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 238 | ssd1306_command(0x12); 239 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 240 | if (vccstate == SSD1306_EXTERNALVCC) 241 | { ssd1306_command(0x9F); } 242 | else 243 | { ssd1306_command(0xCF); } 244 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 245 | if (vccstate == SSD1306_EXTERNALVCC) 246 | { ssd1306_command(0x22); } 247 | else 248 | { ssd1306_command(0xF1); } 249 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 250 | ssd1306_command(0x40); 251 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 252 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 253 | #endif 254 | 255 | ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel 256 | } 257 | 258 | 259 | void Adafruit_SSD1306::invertDisplay(uint8_t i) { 260 | if (i) { 261 | ssd1306_command(SSD1306_INVERTDISPLAY); 262 | } else { 263 | ssd1306_command(SSD1306_NORMALDISPLAY); 264 | } 265 | } 266 | 267 | void Adafruit_SSD1306::ssd1306_command(uint8_t c) { 268 | if (sid != -1) 269 | { 270 | // SPI 271 | //digitalWrite(cs, HIGH); 272 | *csport |= cspinmask; 273 | //digitalWrite(dc, LOW); 274 | *dcport &= ~dcpinmask; 275 | //digitalWrite(cs, LOW); 276 | *csport &= ~cspinmask; 277 | fastSPIwrite(c); 278 | //digitalWrite(cs, HIGH); 279 | *csport |= cspinmask; 280 | } 281 | else 282 | { 283 | // I2C 284 | uint8_t control = 0x00; // Co = 0, D/C = 0 285 | Wire.beginTransmission(_i2caddr); 286 | Wire.write(control); 287 | Wire.write(c); 288 | Wire.endTransmission(); 289 | } 290 | } 291 | 292 | // startscrollright 293 | // Activate a right handed scroll for rows start through stop 294 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 295 | // display.scrollright(0x00, 0x0F) 296 | void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){ 297 | ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL); 298 | ssd1306_command(0X00); 299 | ssd1306_command(start); 300 | ssd1306_command(0X00); 301 | ssd1306_command(stop); 302 | ssd1306_command(0X01); 303 | ssd1306_command(0XFF); 304 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 305 | } 306 | 307 | // startscrollleft 308 | // Activate a right handed scroll for rows start through stop 309 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 310 | // display.scrollright(0x00, 0x0F) 311 | void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){ 312 | ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL); 313 | ssd1306_command(0X00); 314 | ssd1306_command(start); 315 | ssd1306_command(0X00); 316 | ssd1306_command(stop); 317 | ssd1306_command(0X01); 318 | ssd1306_command(0XFF); 319 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 320 | } 321 | 322 | // startscrolldiagright 323 | // Activate a diagonal scroll for rows start through stop 324 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 325 | // display.scrollright(0x00, 0x0F) 326 | void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ 327 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 328 | ssd1306_command(0X00); 329 | ssd1306_command(SSD1306_LCDHEIGHT); 330 | ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); 331 | ssd1306_command(0X00); 332 | ssd1306_command(start); 333 | ssd1306_command(0X00); 334 | ssd1306_command(stop); 335 | ssd1306_command(0X01); 336 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 337 | } 338 | 339 | // startscrolldiagleft 340 | // Activate a diagonal scroll for rows start through stop 341 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 342 | // display.scrollright(0x00, 0x0F) 343 | void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ 344 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 345 | ssd1306_command(0X00); 346 | ssd1306_command(SSD1306_LCDHEIGHT); 347 | ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); 348 | ssd1306_command(0X00); 349 | ssd1306_command(start); 350 | ssd1306_command(0X00); 351 | ssd1306_command(stop); 352 | ssd1306_command(0X01); 353 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 354 | } 355 | 356 | void Adafruit_SSD1306::stopscroll(void){ 357 | ssd1306_command(SSD1306_DEACTIVATE_SCROLL); 358 | } 359 | 360 | void Adafruit_SSD1306::ssd1306_data(uint8_t c) { 361 | if (sid != -1) 362 | { 363 | // SPI 364 | //digitalWrite(cs, HIGH); 365 | *csport |= cspinmask; 366 | //digitalWrite(dc, HIGH); 367 | *dcport |= dcpinmask; 368 | //digitalWrite(cs, LOW); 369 | *csport &= ~cspinmask; 370 | fastSPIwrite(c); 371 | //digitalWrite(cs, HIGH); 372 | *csport |= cspinmask; 373 | } 374 | else 375 | { 376 | // I2C 377 | uint8_t control = 0x40; // Co = 0, D/C = 1 378 | Wire.beginTransmission(_i2caddr); 379 | Wire.write(control); 380 | Wire.write(c); 381 | Wire.endTransmission(); 382 | } 383 | } 384 | 385 | void Adafruit_SSD1306::display(void) { 386 | ssd1306_command(SSD1306_SETLOWCOLUMN | 0x0); // low col = 0 387 | ssd1306_command(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0 388 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 389 | 390 | if (sid != -1) 391 | { 392 | // SPI 393 | *csport |= cspinmask; 394 | *dcport |= dcpinmask; 395 | *csport &= ~cspinmask; 396 | 397 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 398 | fastSPIwrite(buffer[i]); 399 | //ssd1306_data(buffer[i]); 400 | } 401 | // i wonder why we have to do this (check datasheet) 402 | if (SSD1306_LCDHEIGHT == 32) { 403 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 404 | //ssd1306_data(0); 405 | fastSPIwrite(0); 406 | } 407 | } 408 | *csport |= cspinmask; 409 | } 410 | else 411 | { 412 | // save I2C bitrate 413 | uint8_t twbrbackup = TWBR; 414 | TWBR = 12; // upgrade to 400KHz! 415 | 416 | //Serial.println(TWBR, DEC); 417 | //Serial.println(TWSR & 0x3, DEC); 418 | 419 | // I2C 420 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 421 | // send a bunch of data in one xmission 422 | Wire.beginTransmission(_i2caddr); 423 | Wire.write(0x40); 424 | for (uint8_t x=0; x<16; x++) { 425 | Wire.write(buffer[i]); 426 | i++; 427 | } 428 | i--; 429 | Wire.endTransmission(); 430 | } 431 | // i wonder why we have to do this (check datasheet) 432 | if (SSD1306_LCDHEIGHT == 32) { 433 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 434 | // send a bunch of data in one xmission 435 | Wire.beginTransmission(_i2caddr); 436 | Wire.write(0x40); 437 | for (uint8_t x=0; x<16; x++) { 438 | Wire.write((uint8_t)0x00); 439 | i++; 440 | } 441 | i--; 442 | Wire.endTransmission(); 443 | } 444 | } 445 | TWBR = twbrbackup; 446 | } 447 | } 448 | 449 | // clear everything 450 | void Adafruit_SSD1306::clearDisplay(void) { 451 | memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); 452 | } 453 | 454 | 455 | inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) { 456 | 457 | for(uint8_t bit = 0x80; bit; bit >>= 1) { 458 | *clkport &= ~clkpinmask; 459 | if(d & bit) *mosiport |= mosipinmask; 460 | else *mosiport &= ~mosipinmask; 461 | *clkport |= clkpinmask; 462 | } 463 | //*csport |= cspinmask; 464 | } 465 | 466 | inline void Adafruit_SSD1306::slowSPIwrite(uint8_t d) { 467 | for (int8_t i=7; i>=0; i--) { 468 | digitalWrite(sclk, LOW); 469 | if (d & _BV(i)) { 470 | digitalWrite(sid, HIGH); 471 | } else { 472 | digitalWrite(sid, LOW); 473 | } 474 | digitalWrite(sclk, HIGH); 475 | } 476 | } 477 | 478 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_SSD1306/Adafruit_SSD1306.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #if ARDUINO >= 100 20 | #include "Arduino.h" 21 | #else 22 | #include "WProgram.h" 23 | #endif 24 | 25 | #include 26 | 27 | #define BLACK 0 28 | #define WHITE 1 29 | 30 | #define SSD1306_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D 31 | // Address for 128x32 is 0x3C 32 | // Address for 128x32 is 0x3D (default) or 0x3C (if SA0 is grounded) 33 | 34 | /*========================================================================= 35 | SSD1306 Displays 36 | ----------------------------------------------------------------------- 37 | The driver is used in multiple displays (128x64, 128x32, etc.). 38 | Select the appropriate display below to create an appropriately 39 | sized framebuffer, etc. 40 | 41 | SSD1306_128_64 128x64 pixel display 42 | 43 | SSD1306_128_32 128x32 pixel display 44 | 45 | You also need to set the LCDWIDTH and LCDHEIGHT defines to an 46 | appropriate size 47 | 48 | -----------------------------------------------------------------------*/ 49 | #define SSD1306_128_64 50 | // #define SSD1306_128_32 51 | /*=========================================================================*/ 52 | 53 | #if defined SSD1306_128_64 && defined SSD1306_128_32 54 | #error "Only one SSD1306 display can be specified at once in SSD1306.h" 55 | #endif 56 | #if !defined SSD1306_128_64 && !defined SSD1306_128_32 57 | #error "At least one SSD1306 display must be specified in SSD1306.h" 58 | #endif 59 | 60 | #if defined SSD1306_128_64 61 | #define SSD1306_LCDWIDTH 128 62 | #define SSD1306_LCDHEIGHT 64 63 | #endif 64 | #if defined SSD1306_128_32 65 | #define SSD1306_LCDWIDTH 128 66 | #define SSD1306_LCDHEIGHT 32 67 | #endif 68 | 69 | #define SSD1306_SETCONTRAST 0x81 70 | #define SSD1306_DISPLAYALLON_RESUME 0xA4 71 | #define SSD1306_DISPLAYALLON 0xA5 72 | #define SSD1306_NORMALDISPLAY 0xA6 73 | #define SSD1306_INVERTDISPLAY 0xA7 74 | #define SSD1306_DISPLAYOFF 0xAE 75 | #define SSD1306_DISPLAYON 0xAF 76 | 77 | #define SSD1306_SETDISPLAYOFFSET 0xD3 78 | #define SSD1306_SETCOMPINS 0xDA 79 | 80 | #define SSD1306_SETVCOMDETECT 0xDB 81 | 82 | #define SSD1306_SETDISPLAYCLOCKDIV 0xD5 83 | #define SSD1306_SETPRECHARGE 0xD9 84 | 85 | #define SSD1306_SETMULTIPLEX 0xA8 86 | 87 | #define SSD1306_SETLOWCOLUMN 0x00 88 | #define SSD1306_SETHIGHCOLUMN 0x10 89 | 90 | #define SSD1306_SETSTARTLINE 0x40 91 | 92 | #define SSD1306_MEMORYMODE 0x20 93 | 94 | #define SSD1306_COMSCANINC 0xC0 95 | #define SSD1306_COMSCANDEC 0xC8 96 | 97 | #define SSD1306_SEGREMAP 0xA0 98 | 99 | #define SSD1306_CHARGEPUMP 0x8D 100 | 101 | #define SSD1306_EXTERNALVCC 0x1 102 | #define SSD1306_SWITCHCAPVCC 0x2 103 | 104 | // Scrolling #defines 105 | #define SSD1306_ACTIVATE_SCROLL 0x2F 106 | #define SSD1306_DEACTIVATE_SCROLL 0x2E 107 | #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 108 | #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 109 | #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 110 | #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 111 | #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A 112 | 113 | class Adafruit_SSD1306 : public Adafruit_GFX { 114 | public: 115 | Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS); 116 | Adafruit_SSD1306(int8_t RST); 117 | 118 | void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS); 119 | void ssd1306_command(uint8_t c); 120 | void ssd1306_data(uint8_t c); 121 | 122 | void clearDisplay(void); 123 | void invertDisplay(uint8_t i); 124 | void display(); 125 | 126 | void startscrollright(uint8_t start, uint8_t stop); 127 | void startscrollleft(uint8_t start, uint8_t stop); 128 | 129 | void startscrolldiagright(uint8_t start, uint8_t stop); 130 | void startscrolldiagleft(uint8_t start, uint8_t stop); 131 | void stopscroll(void); 132 | 133 | void drawPixel(int16_t x, int16_t y, uint16_t color); 134 | 135 | private: 136 | int8_t _i2caddr, sid, sclk, dc, rst, cs; 137 | void fastSPIwrite(uint8_t c); 138 | void slowSPIwrite(uint8_t c); 139 | 140 | volatile uint8_t *mosiport, *clkport, *csport, *dcport; 141 | uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; 142 | }; 143 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_SSD1306/README.txt: -------------------------------------------------------------------------------- 1 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 2 | 3 | Pick one up today in the adafruit shop! 4 | ------> http://www.adafruit.com/category/63_98 5 | 6 | These displays use SPI to communicate, 4 or 5 pins are required to 7 | interface 8 | 9 | Adafruit invests time and resources providing this open source code, 10 | please support Adafruit and open-source hardware by purchasing 11 | products from Adafruit! 12 | 13 | Written by Limor Fried/Ladyada for Adafruit Industries. 14 | Scrolling code contributed by Michael Gregg 15 | BSD license, check license.txt for more information 16 | All text above must be included in any redistribution 17 | 18 | To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h 19 | 20 | Place the Adafruit_SSD1306 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. 21 | 22 | You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from 23 | https://github.com/adafruit/Adafruit-GFX-Library 24 | and download/install that library as well -------------------------------------------------------------------------------- /Arduino/NeededLibraries/Adafruit_SSD1306/examples/ssd1306_128x32_i2c/ssd1306_128x32_i2c.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is an example for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x32 size display using I2C to communicate 8 | 3 pins are required to interface (2 I2C and one reset) 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define OLED_RESET 4 24 | Adafruit_SSD1306 display(OLED_RESET); 25 | 26 | #define NUMFLAKES 10 27 | #define XPOS 0 28 | #define YPOS 1 29 | #define DELTAY 2 30 | 31 | 32 | #define LOGO16_GLCD_HEIGHT 16 33 | #define LOGO16_GLCD_WIDTH 16 34 | static unsigned char PROGMEM logo16_glcd_bmp[] = 35 | { B00000000, B11000000, 36 | B00000001, B11000000, 37 | B00000001, B11000000, 38 | B00000011, B11100000, 39 | B11110011, B11100000, 40 | B11111110, B11111000, 41 | B01111110, B11111111, 42 | B00110011, B10011111, 43 | B00011111, B11111100, 44 | B00001101, B01110000, 45 | B00011011, B10100000, 46 | B00111111, B11100000, 47 | B00111111, B11110000, 48 | B01111100, B11110000, 49 | B01110000, B01110000, 50 | B00000000, B00110000 }; 51 | 52 | #if (SSD1306_LCDHEIGHT != 32) 53 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 54 | #endif 55 | 56 | void setup() { 57 | Serial.begin(9600); 58 | 59 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 60 | display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) 61 | // init done 62 | 63 | display.display(); // show splashscreen 64 | delay(2000); 65 | display.clearDisplay(); // clears the screen and buffer 66 | 67 | // draw a single pixel 68 | display.drawPixel(10, 10, WHITE); 69 | display.display(); 70 | delay(2000); 71 | display.clearDisplay(); 72 | 73 | // draw many lines 74 | testdrawline(); 75 | display.display(); 76 | delay(2000); 77 | display.clearDisplay(); 78 | 79 | // draw rectangles 80 | testdrawrect(); 81 | display.display(); 82 | delay(2000); 83 | display.clearDisplay(); 84 | 85 | // draw multiple rectangles 86 | testfillrect(); 87 | display.display(); 88 | delay(2000); 89 | display.clearDisplay(); 90 | 91 | // draw mulitple circles 92 | testdrawcircle(); 93 | display.display(); 94 | delay(2000); 95 | display.clearDisplay(); 96 | 97 | // draw a white circle, 10 pixel radius 98 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 99 | display.display(); 100 | delay(2000); 101 | display.clearDisplay(); 102 | 103 | testdrawroundrect(); 104 | delay(2000); 105 | display.clearDisplay(); 106 | 107 | testfillroundrect(); 108 | delay(2000); 109 | display.clearDisplay(); 110 | 111 | testdrawtriangle(); 112 | delay(2000); 113 | display.clearDisplay(); 114 | 115 | testfilltriangle(); 116 | delay(2000); 117 | display.clearDisplay(); 118 | 119 | // draw the first ~12 characters in the font 120 | testdrawchar(); 121 | display.display(); 122 | delay(2000); 123 | display.clearDisplay(); 124 | 125 | // draw scrolling text 126 | testscrolltext(); 127 | delay(2000); 128 | display.clearDisplay(); 129 | 130 | // text display tests 131 | display.setTextSize(1); 132 | display.setTextColor(WHITE); 133 | display.setCursor(0,0); 134 | display.println("Hello, world!"); 135 | display.setTextColor(BLACK, WHITE); // 'inverted' text 136 | display.println(3.141592); 137 | display.setTextSize(2); 138 | display.setTextColor(WHITE); 139 | display.print("0x"); display.println(0xDEADBEEF, HEX); 140 | display.display(); 141 | delay(2000); 142 | 143 | // miniature bitmap display 144 | display.clearDisplay(); 145 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 146 | display.display(); 147 | 148 | // invert the display 149 | display.invertDisplay(true); 150 | delay(1000); 151 | display.invertDisplay(false); 152 | delay(1000); 153 | 154 | // draw a bitmap icon and 'animate' movement 155 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 156 | } 157 | 158 | 159 | void loop() { 160 | 161 | } 162 | 163 | 164 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 165 | uint8_t icons[NUMFLAKES][3]; 166 | srandom(666); // whatever seed 167 | 168 | // initialize 169 | for (uint8_t f=0; f< NUMFLAKES; f++) { 170 | icons[f][XPOS] = random() % display.width(); 171 | icons[f][YPOS] = 0; 172 | icons[f][DELTAY] = random() % 5 + 1; 173 | 174 | Serial.print("x: "); 175 | Serial.print(icons[f][XPOS], DEC); 176 | Serial.print(" y: "); 177 | Serial.print(icons[f][YPOS], DEC); 178 | Serial.print(" dy: "); 179 | Serial.println(icons[f][DELTAY], DEC); 180 | } 181 | 182 | while (1) { 183 | // draw each icon 184 | for (uint8_t f=0; f< NUMFLAKES; f++) { 185 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); 186 | } 187 | display.display(); 188 | delay(200); 189 | 190 | // then erase it + move it 191 | for (uint8_t f=0; f< NUMFLAKES; f++) { 192 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); 193 | // move it 194 | icons[f][YPOS] += icons[f][DELTAY]; 195 | // if its gone, reinit 196 | if (icons[f][YPOS] > display.height()) { 197 | icons[f][XPOS] = random() % display.width(); 198 | icons[f][YPOS] = 0; 199 | icons[f][DELTAY] = random() % 5 + 1; 200 | } 201 | } 202 | } 203 | } 204 | 205 | 206 | void testdrawchar(void) { 207 | display.setTextSize(1); 208 | display.setTextColor(WHITE); 209 | display.setCursor(0,0); 210 | 211 | for (uint8_t i=0; i < 168; i++) { 212 | if (i == '\n') continue; 213 | display.write(i); 214 | if ((i > 0) && (i % 21 == 0)) 215 | display.println(); 216 | } 217 | display.display(); 218 | } 219 | 220 | void testdrawcircle(void) { 221 | for (int16_t i=0; i0; i-=5) { 249 | display.fillTriangle(display.width()/2, display.height()/2-i, 250 | display.width()/2-i, display.height()/2+i, 251 | display.width()/2+i, display.height()/2+i, WHITE); 252 | if (color == WHITE) color = BLACK; 253 | else color = WHITE; 254 | display.display(); 255 | } 256 | } 257 | 258 | void testdrawroundrect(void) { 259 | for (int16_t i=0; i=0; i-=4) { 299 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 300 | display.display(); 301 | } 302 | delay(250); 303 | 304 | display.clearDisplay(); 305 | for (int16_t i=display.width()-1; i>=0; i-=4) { 306 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 307 | display.display(); 308 | } 309 | for (int16_t i=display.height()-1; i>=0; i-=4) { 310 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 311 | display.display(); 312 | } 313 | delay(250); 314 | 315 | display.clearDisplay(); 316 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x32 size display using SPI to communicate 8 | 4 or 5 pins are required to interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define OLED_DC 11 24 | #define OLED_CS 12 25 | #define OLED_CLK 10 26 | #define OLED_MOSI 9 27 | #define OLED_RESET 13 28 | Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); 29 | 30 | #define NUMFLAKES 10 31 | #define XPOS 0 32 | #define YPOS 1 33 | #define DELTAY 2 34 | 35 | #define LOGO16_GLCD_HEIGHT 16 36 | #define LOGO16_GLCD_WIDTH 16 37 | static unsigned char PROGMEM logo16_glcd_bmp[] = 38 | { B00000000, B11000000, 39 | B00000001, B11000000, 40 | B00000001, B11000000, 41 | B00000011, B11100000, 42 | B11110011, B11100000, 43 | B11111110, B11111000, 44 | B01111110, B11111111, 45 | B00110011, B10011111, 46 | B00011111, B11111100, 47 | B00001101, B01110000, 48 | B00011011, B10100000, 49 | B00111111, B11100000, 50 | B00111111, B11110000, 51 | B01111100, B11110000, 52 | B01110000, B01110000, 53 | B00000000, B00110000 }; 54 | 55 | #if (SSD1306_LCDHEIGHT != 32) 56 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 57 | #endif 58 | 59 | void setup() { 60 | Serial.begin(9600); 61 | 62 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 63 | display.begin(SSD1306_SWITCHCAPVCC); 64 | // init done 65 | 66 | display.display(); // show splashscreen 67 | delay(2000); 68 | display.clearDisplay(); // clears the screen and buffer 69 | 70 | // draw a single pixel 71 | display.drawPixel(10, 10, WHITE); 72 | display.display(); 73 | delay(2000); 74 | display.clearDisplay(); 75 | 76 | // draw many lines 77 | testdrawline(); 78 | display.display(); 79 | delay(2000); 80 | display.clearDisplay(); 81 | 82 | // draw rectangles 83 | testdrawrect(); 84 | display.display(); 85 | delay(2000); 86 | display.clearDisplay(); 87 | 88 | // draw multiple rectangles 89 | testfillrect(); 90 | display.display(); 91 | delay(2000); 92 | display.clearDisplay(); 93 | 94 | // draw mulitple circles 95 | testdrawcircle(); 96 | display.display(); 97 | delay(2000); 98 | display.clearDisplay(); 99 | 100 | // draw a white circle, 10 pixel radius 101 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 102 | display.display(); 103 | delay(2000); 104 | display.clearDisplay(); 105 | 106 | testdrawroundrect(); 107 | delay(2000); 108 | display.clearDisplay(); 109 | 110 | testfillroundrect(); 111 | delay(2000); 112 | display.clearDisplay(); 113 | 114 | testdrawtriangle(); 115 | delay(2000); 116 | display.clearDisplay(); 117 | 118 | testfilltriangle(); 119 | delay(2000); 120 | display.clearDisplay(); 121 | 122 | // draw the first ~12 characters in the font 123 | testdrawchar(); 124 | display.display(); 125 | delay(2000); 126 | display.clearDisplay(); 127 | 128 | // draw scrolling text 129 | testscrolltext(); 130 | delay(2000); 131 | display.clearDisplay(); 132 | 133 | // text display tests 134 | display.setTextSize(1); 135 | display.setTextColor(WHITE); 136 | display.setCursor(0,0); 137 | display.println("Hello, world!"); 138 | display.setTextColor(BLACK, WHITE); // 'inverted' text 139 | display.println(3.141592); 140 | display.setTextSize(2); 141 | display.setTextColor(WHITE); 142 | display.print("0x"); display.println(0xDEADBEEF, HEX); 143 | display.display(); 144 | delay(2000); 145 | 146 | // miniature bitmap display 147 | display.clearDisplay(); 148 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 149 | display.display(); 150 | 151 | // invert the display 152 | display.invertDisplay(true); 153 | delay(1000); 154 | display.invertDisplay(false); 155 | delay(1000); 156 | 157 | // draw a bitmap icon and 'animate' movement 158 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 159 | } 160 | 161 | 162 | void loop() { 163 | 164 | } 165 | 166 | 167 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 168 | uint8_t icons[NUMFLAKES][3]; 169 | srandom(666); // whatever seed 170 | 171 | // initialize 172 | for (uint8_t f=0; f< NUMFLAKES; f++) { 173 | icons[f][XPOS] = random() % display.width(); 174 | icons[f][YPOS] = 0; 175 | icons[f][DELTAY] = random() % 5 + 1; 176 | 177 | Serial.print("x: "); 178 | Serial.print(icons[f][XPOS], DEC); 179 | Serial.print(" y: "); 180 | Serial.print(icons[f][YPOS], DEC); 181 | Serial.print(" dy: "); 182 | Serial.println(icons[f][DELTAY], DEC); 183 | } 184 | 185 | while (1) { 186 | // draw each icon 187 | for (uint8_t f=0; f< NUMFLAKES; f++) { 188 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); 189 | } 190 | display.display(); 191 | delay(200); 192 | 193 | // then erase it + move it 194 | for (uint8_t f=0; f< NUMFLAKES; f++) { 195 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); 196 | // move it 197 | icons[f][YPOS] += icons[f][DELTAY]; 198 | // if its gone, reinit 199 | if (icons[f][YPOS] > display.height()) { 200 | icons[f][XPOS] = random() % display.width(); 201 | icons[f][YPOS] = 0; 202 | icons[f][DELTAY] = random() % 5 + 1; 203 | } 204 | } 205 | } 206 | } 207 | 208 | 209 | void testdrawchar(void) { 210 | display.setTextSize(1); 211 | display.setTextColor(WHITE); 212 | display.setCursor(0,0); 213 | 214 | for (uint8_t i=0; i < 168; i++) { 215 | if (i == '\n') continue; 216 | display.write(i); 217 | if ((i > 0) && (i % 21 == 0)) 218 | display.println(); 219 | } 220 | display.display(); 221 | } 222 | 223 | void testdrawcircle(void) { 224 | for (int16_t i=0; i0; i-=5) { 252 | display.fillTriangle(display.width()/2, display.height()/2-i, 253 | display.width()/2-i, display.height()/2+i, 254 | display.width()/2+i, display.height()/2+i, WHITE); 255 | if (color == WHITE) color = BLACK; 256 | else color = WHITE; 257 | display.display(); 258 | } 259 | } 260 | 261 | void testdrawroundrect(void) { 262 | for (int16_t i=0; i=0; i-=4) { 302 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 303 | display.display(); 304 | } 305 | delay(250); 306 | 307 | display.clearDisplay(); 308 | for (int16_t i=display.width()-1; i>=0; i-=4) { 309 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 310 | display.display(); 311 | } 312 | for (int16_t i=display.height()-1; i>=0; i-=4) { 313 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 314 | display.display(); 315 | } 316 | delay(250); 317 | 318 | display.clearDisplay(); 319 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x64 size display using I2C to communicate 8 | 3 pins are required to interface (2 I2C and one reset) 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define OLED_RESET 4 24 | Adafruit_SSD1306 display(OLED_RESET); 25 | 26 | #define NUMFLAKES 10 27 | #define XPOS 0 28 | #define YPOS 1 29 | #define DELTAY 2 30 | 31 | 32 | #define LOGO16_GLCD_HEIGHT 16 33 | #define LOGO16_GLCD_WIDTH 16 34 | static unsigned char PROGMEM logo16_glcd_bmp[] = 35 | { B00000000, B11000000, 36 | B00000001, B11000000, 37 | B00000001, B11000000, 38 | B00000011, B11100000, 39 | B11110011, B11100000, 40 | B11111110, B11111000, 41 | B01111110, B11111111, 42 | B00110011, B10011111, 43 | B00011111, B11111100, 44 | B00001101, B01110000, 45 | B00011011, B10100000, 46 | B00111111, B11100000, 47 | B00111111, B11110000, 48 | B01111100, B11110000, 49 | B01110000, B01110000, 50 | B00000000, B00110000 }; 51 | 52 | #if (SSD1306_LCDHEIGHT != 64) 53 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 54 | #endif 55 | 56 | void setup() { 57 | Serial.begin(9600); 58 | 59 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 60 | display.begin(SSD1306_SWITCHCAPVCC, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64) 61 | // init done 62 | 63 | display.display(); // show splashscreen 64 | delay(2000); 65 | display.clearDisplay(); // clears the screen and buffer 66 | 67 | // draw a single pixel 68 | display.drawPixel(10, 10, WHITE); 69 | display.display(); 70 | delay(2000); 71 | display.clearDisplay(); 72 | 73 | // draw many lines 74 | testdrawline(); 75 | display.display(); 76 | delay(2000); 77 | display.clearDisplay(); 78 | 79 | // draw rectangles 80 | testdrawrect(); 81 | display.display(); 82 | delay(2000); 83 | display.clearDisplay(); 84 | 85 | // draw multiple rectangles 86 | testfillrect(); 87 | display.display(); 88 | delay(2000); 89 | display.clearDisplay(); 90 | 91 | // draw mulitple circles 92 | testdrawcircle(); 93 | display.display(); 94 | delay(2000); 95 | display.clearDisplay(); 96 | 97 | // draw a white circle, 10 pixel radius 98 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 99 | display.display(); 100 | delay(2000); 101 | display.clearDisplay(); 102 | 103 | testdrawroundrect(); 104 | delay(2000); 105 | display.clearDisplay(); 106 | 107 | testfillroundrect(); 108 | delay(2000); 109 | display.clearDisplay(); 110 | 111 | testdrawtriangle(); 112 | delay(2000); 113 | display.clearDisplay(); 114 | 115 | testfilltriangle(); 116 | delay(2000); 117 | display.clearDisplay(); 118 | 119 | // draw the first ~12 characters in the font 120 | testdrawchar(); 121 | display.display(); 122 | delay(2000); 123 | display.clearDisplay(); 124 | 125 | // draw scrolling text 126 | testscrolltext(); 127 | delay(2000); 128 | display.clearDisplay(); 129 | 130 | // text display tests 131 | display.setTextSize(1); 132 | display.setTextColor(WHITE); 133 | display.setCursor(0,0); 134 | display.println("Hello, world!"); 135 | display.setTextColor(BLACK, WHITE); // 'inverted' text 136 | display.println(3.141592); 137 | display.setTextSize(2); 138 | display.setTextColor(WHITE); 139 | display.print("0x"); display.println(0xDEADBEEF, HEX); 140 | display.display(); 141 | delay(2000); 142 | 143 | // miniature bitmap display 144 | display.clearDisplay(); 145 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 146 | display.display(); 147 | 148 | // invert the display 149 | display.invertDisplay(true); 150 | delay(1000); 151 | display.invertDisplay(false); 152 | delay(1000); 153 | 154 | // draw a bitmap icon and 'animate' movement 155 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 156 | } 157 | 158 | 159 | void loop() { 160 | 161 | } 162 | 163 | 164 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 165 | uint8_t icons[NUMFLAKES][3]; 166 | srandom(666); // whatever seed 167 | 168 | // initialize 169 | for (uint8_t f=0; f< NUMFLAKES; f++) { 170 | icons[f][XPOS] = random() % display.width(); 171 | icons[f][YPOS] = 0; 172 | icons[f][DELTAY] = random() % 5 + 1; 173 | 174 | Serial.print("x: "); 175 | Serial.print(icons[f][XPOS], DEC); 176 | Serial.print(" y: "); 177 | Serial.print(icons[f][YPOS], DEC); 178 | Serial.print(" dy: "); 179 | Serial.println(icons[f][DELTAY], DEC); 180 | } 181 | 182 | while (1) { 183 | // draw each icon 184 | for (uint8_t f=0; f< NUMFLAKES; f++) { 185 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); 186 | } 187 | display.display(); 188 | delay(200); 189 | 190 | // then erase it + move it 191 | for (uint8_t f=0; f< NUMFLAKES; f++) { 192 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); 193 | // move it 194 | icons[f][YPOS] += icons[f][DELTAY]; 195 | // if its gone, reinit 196 | if (icons[f][YPOS] > display.height()) { 197 | icons[f][XPOS] = random() % display.width(); 198 | icons[f][YPOS] = 0; 199 | icons[f][DELTAY] = random() % 5 + 1; 200 | } 201 | } 202 | } 203 | } 204 | 205 | 206 | void testdrawchar(void) { 207 | display.setTextSize(1); 208 | display.setTextColor(WHITE); 209 | display.setCursor(0,0); 210 | 211 | for (uint8_t i=0; i < 168; i++) { 212 | if (i == '\n') continue; 213 | display.write(i); 214 | if ((i > 0) && (i % 21 == 0)) 215 | display.println(); 216 | } 217 | display.display(); 218 | } 219 | 220 | void testdrawcircle(void) { 221 | for (int16_t i=0; i0; i-=5) { 249 | display.fillTriangle(display.width()/2, display.height()/2-i, 250 | display.width()/2-i, display.height()/2+i, 251 | display.width()/2+i, display.height()/2+i, WHITE); 252 | if (color == WHITE) color = BLACK; 253 | else color = WHITE; 254 | display.display(); 255 | } 256 | } 257 | 258 | void testdrawroundrect(void) { 259 | for (int16_t i=0; i=0; i-=4) { 299 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 300 | display.display(); 301 | } 302 | delay(250); 303 | 304 | display.clearDisplay(); 305 | for (int16_t i=display.width()-1; i>=0; i-=4) { 306 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 307 | display.display(); 308 | } 309 | for (int16_t i=display.height()-1; i>=0; i-=4) { 310 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 311 | display.display(); 312 | } 313 | delay(250); 314 | 315 | display.clearDisplay(); 316 | for (int16_t i=0; i http://www.adafruit.com/category/63_98 6 | 7 | This example is for a 128x64 size display using SPI to communicate 8 | 4 or 5 pins are required to interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define OLED_DC 11 24 | #define OLED_CS 12 25 | #define OLED_CLK 10 26 | #define OLED_MOSI 9 27 | #define OLED_RESET 13 28 | Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS); 29 | 30 | #define NUMFLAKES 10 31 | #define XPOS 0 32 | #define YPOS 1 33 | #define DELTAY 2 34 | 35 | #define LOGO16_GLCD_HEIGHT 16 36 | #define LOGO16_GLCD_WIDTH 16 37 | static unsigned char PROGMEM logo16_glcd_bmp[] = 38 | { B00000000, B11000000, 39 | B00000001, B11000000, 40 | B00000001, B11000000, 41 | B00000011, B11100000, 42 | B11110011, B11100000, 43 | B11111110, B11111000, 44 | B01111110, B11111111, 45 | B00110011, B10011111, 46 | B00011111, B11111100, 47 | B00001101, B01110000, 48 | B00011011, B10100000, 49 | B00111111, B11100000, 50 | B00111111, B11110000, 51 | B01111100, B11110000, 52 | B01110000, B01110000, 53 | B00000000, B00110000 }; 54 | 55 | #if (SSD1306_LCDHEIGHT != 64) 56 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 57 | #endif 58 | 59 | void setup() { 60 | Serial.begin(9600); 61 | 62 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 63 | display.begin(SSD1306_SWITCHCAPVCC); 64 | // init done 65 | 66 | display.display(); // show splashscreen 67 | delay(2000); 68 | display.clearDisplay(); // clears the screen and buffer 69 | 70 | // draw a single pixel 71 | display.drawPixel(10, 10, WHITE); 72 | display.display(); 73 | delay(2000); 74 | display.clearDisplay(); 75 | 76 | // draw many lines 77 | testdrawline(); 78 | display.display(); 79 | delay(2000); 80 | display.clearDisplay(); 81 | 82 | // draw rectangles 83 | testdrawrect(); 84 | display.display(); 85 | delay(2000); 86 | display.clearDisplay(); 87 | 88 | // draw multiple rectangles 89 | testfillrect(); 90 | display.display(); 91 | delay(2000); 92 | display.clearDisplay(); 93 | 94 | // draw mulitple circles 95 | testdrawcircle(); 96 | display.display(); 97 | delay(2000); 98 | display.clearDisplay(); 99 | 100 | // draw a white circle, 10 pixel radius 101 | display.fillCircle(display.width()/2, display.height()/2, 10, WHITE); 102 | display.display(); 103 | delay(2000); 104 | display.clearDisplay(); 105 | 106 | testdrawroundrect(); 107 | delay(2000); 108 | display.clearDisplay(); 109 | 110 | testfillroundrect(); 111 | delay(2000); 112 | display.clearDisplay(); 113 | 114 | testdrawtriangle(); 115 | delay(2000); 116 | display.clearDisplay(); 117 | 118 | testfilltriangle(); 119 | delay(2000); 120 | display.clearDisplay(); 121 | 122 | // draw the first ~12 characters in the font 123 | testdrawchar(); 124 | display.display(); 125 | delay(2000); 126 | display.clearDisplay(); 127 | 128 | // draw scrolling text 129 | testscrolltext(); 130 | delay(2000); 131 | display.clearDisplay(); 132 | 133 | // text display tests 134 | display.setTextSize(1); 135 | display.setTextColor(WHITE); 136 | display.setCursor(0,0); 137 | display.println("Hello, world!"); 138 | display.setTextColor(BLACK, WHITE); // 'inverted' text 139 | display.println(3.141592); 140 | display.setTextSize(2); 141 | display.setTextColor(WHITE); 142 | display.print("0x"); display.println(0xDEADBEEF, HEX); 143 | display.display(); 144 | delay(2000); 145 | 146 | // miniature bitmap display 147 | display.clearDisplay(); 148 | display.drawBitmap(30, 16, logo16_glcd_bmp, 16, 16, 1); 149 | display.display(); 150 | 151 | // invert the display 152 | display.invertDisplay(true); 153 | delay(1000); 154 | display.invertDisplay(false); 155 | delay(1000); 156 | 157 | // draw a bitmap icon and 'animate' movement 158 | testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH); 159 | } 160 | 161 | 162 | void loop() { 163 | 164 | } 165 | 166 | 167 | void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) { 168 | uint8_t icons[NUMFLAKES][3]; 169 | srandom(666); // whatever seed 170 | 171 | // initialize 172 | for (uint8_t f=0; f< NUMFLAKES; f++) { 173 | icons[f][XPOS] = random() % display.width(); 174 | icons[f][YPOS] = 0; 175 | icons[f][DELTAY] = random() % 5 + 1; 176 | 177 | Serial.print("x: "); 178 | Serial.print(icons[f][XPOS], DEC); 179 | Serial.print(" y: "); 180 | Serial.print(icons[f][YPOS], DEC); 181 | Serial.print(" dy: "); 182 | Serial.println(icons[f][DELTAY], DEC); 183 | } 184 | 185 | while (1) { 186 | // draw each icon 187 | for (uint8_t f=0; f< NUMFLAKES; f++) { 188 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, WHITE); 189 | } 190 | display.display(); 191 | delay(200); 192 | 193 | // then erase it + move it 194 | for (uint8_t f=0; f< NUMFLAKES; f++) { 195 | display.drawBitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK); 196 | // move it 197 | icons[f][YPOS] += icons[f][DELTAY]; 198 | // if its gone, reinit 199 | if (icons[f][YPOS] > display.height()) { 200 | icons[f][XPOS] = random() % display.width(); 201 | icons[f][YPOS] = 0; 202 | icons[f][DELTAY] = random() % 5 + 1; 203 | } 204 | } 205 | } 206 | } 207 | 208 | 209 | void testdrawchar(void) { 210 | display.setTextSize(1); 211 | display.setTextColor(WHITE); 212 | display.setCursor(0,0); 213 | 214 | for (uint8_t i=0; i < 168; i++) { 215 | if (i == '\n') continue; 216 | display.write(i); 217 | if ((i > 0) && (i % 21 == 0)) 218 | display.println(); 219 | } 220 | display.display(); 221 | } 222 | 223 | void testdrawcircle(void) { 224 | for (int16_t i=0; i0; i-=5) { 252 | display.fillTriangle(display.width()/2, display.height()/2-i, 253 | display.width()/2-i, display.height()/2+i, 254 | display.width()/2+i, display.height()/2+i, WHITE); 255 | if (color == WHITE) color = BLACK; 256 | else color = WHITE; 257 | display.display(); 258 | } 259 | } 260 | 261 | void testdrawroundrect(void) { 262 | for (int16_t i=0; i=0; i-=4) { 302 | display.drawLine(0, display.height()-1, display.width()-1, i, WHITE); 303 | display.display(); 304 | } 305 | delay(250); 306 | 307 | display.clearDisplay(); 308 | for (int16_t i=display.width()-1; i>=0; i-=4) { 309 | display.drawLine(display.width()-1, display.height()-1, i, 0, WHITE); 310 | display.display(); 311 | } 312 | for (int16_t i=display.height()-1; i>=0; i-=4) { 313 | display.drawLine(display.width()-1, display.height()-1, 0, i, WHITE); 314 | display.display(); 315 | } 316 | delay(250); 317 | 318 | display.clearDisplay(); 319 | for (int16_t i=0; i= _nextAvailableaddress ) 56 | _memSize = memSize; 57 | 58 | #ifdef _EEPROMEX_DEBUG 59 | if (_nextAvailableaddress != _base) 60 | Serial.println("Cannot change base, addresses have been issued"); 61 | 62 | if (memSize < _nextAvailableaddress ) 63 | Serial.println("Cannot change ceiling, below issued addresses"); 64 | #endif 65 | 66 | } 67 | 68 | void EEPROMClassEx::setMaxAllowedWrites(int allowedWrites) { 69 | #ifdef _EEPROMEX_DEBUG 70 | _allowedWrites = allowedWrites; 71 | #endif 72 | } 73 | 74 | int EEPROMClassEx::getAddress(int noOfBytes){ 75 | int availableaddress = _nextAvailableaddress; 76 | _nextAvailableaddress += noOfBytes; 77 | 78 | #ifdef _EEPROMEX_DEBUG 79 | if (_nextAvailableaddress > _memSize) { 80 | Serial.println("Attempt to write outside of EEPROM memory"); 81 | return -availableaddress; 82 | } else { 83 | return availableaddress; 84 | } 85 | #endif 86 | return availableaddress; 87 | } 88 | 89 | 90 | bool EEPROMClassEx::isReady() { 91 | return eeprom_is_ready(); 92 | } 93 | 94 | uint8_t EEPROMClassEx::read(int address) 95 | { 96 | return readByte(address); 97 | } 98 | 99 | bool EEPROMClassEx::readBit(int address, byte bit) { 100 | if (bit> 7) return false; 101 | if (!isReadOk(address+sizeof(uint8_t))) return false; 102 | byte byteVal = eeprom_read_byte((unsigned char *) address); 103 | byte bytePos = (1 << bit); 104 | return (byteVal & bytePos); 105 | } 106 | 107 | uint8_t EEPROMClassEx::readByte(int address) 108 | { 109 | if (!isReadOk(address+sizeof(uint8_t))) return 0; 110 | return eeprom_read_byte((unsigned char *) address); 111 | } 112 | 113 | uint16_t EEPROMClassEx::readInt(int address) 114 | { 115 | if (!isReadOk(address+sizeof(uint16_t))) return 0; 116 | return eeprom_read_word((unsigned int *) address); 117 | } 118 | 119 | uint32_t EEPROMClassEx::readLong(int address) 120 | { 121 | if (!isReadOk(address+sizeof(uint32_t))) return 0; 122 | return eeprom_read_dword((unsigned long *) address); 123 | } 124 | 125 | float EEPROMClassEx::readFloat(int address) 126 | { 127 | if (!isReadOk(address+sizeof(float))) return 0; 128 | float _value; 129 | readBlock(address, _value); 130 | return _value; 131 | } 132 | 133 | double EEPROMClassEx::readDouble(int address) 134 | { 135 | if (!isReadOk(address+sizeof(double))) return 0; 136 | double _value; 137 | readBlock(address, _value); 138 | return _value; 139 | } 140 | 141 | bool EEPROMClassEx::write(int address, uint8_t value) 142 | { 143 | return writeByte(address, value); 144 | } 145 | 146 | bool EEPROMClassEx::writeBit(int address, uint8_t bit, bool value) { 147 | updateBit(address, bit, value); 148 | } 149 | 150 | 151 | bool EEPROMClassEx::writeByte(int address, uint8_t value) 152 | { 153 | if (!isWriteOk(address+sizeof(uint8_t))) return false; 154 | eeprom_write_byte((unsigned char *) address, value); 155 | return true; 156 | } 157 | 158 | bool EEPROMClassEx::writeInt(int address, uint16_t value) 159 | { 160 | if (!isWriteOk(address+sizeof(uint16_t))) return false; 161 | eeprom_write_word((unsigned int *) address, value); 162 | return true; 163 | } 164 | 165 | bool EEPROMClassEx::writeLong(int address, uint32_t value) 166 | { 167 | if (!isWriteOk(address+sizeof(uint32_t))) return false; 168 | eeprom_write_dword((unsigned long *) address, value); 169 | return true; 170 | } 171 | 172 | bool EEPROMClassEx::writeFloat(int address, float value) 173 | { 174 | return (writeBlock(address, value)!=0); 175 | } 176 | 177 | bool EEPROMClassEx::writeDouble(int address, double value) 178 | { 179 | return (writeBlock(address, value)!=0); 180 | } 181 | 182 | bool EEPROMClassEx::update(int address, uint8_t value) 183 | { 184 | return (updateByte(address, value)); 185 | } 186 | 187 | bool EEPROMClassEx::updateBit(int address, uint8_t bit, bool value) 188 | { 189 | if (bit> 7) return false; 190 | 191 | byte byteValInput = readByte(address); 192 | byte byteValOutput = byteValInput; 193 | // Set bit 194 | if (value) { 195 | byteValOutput |= (1 << bit); //Set bit to 1 196 | } else { 197 | byteValOutput &= !(1 << bit); //Set bit to 0 198 | } 199 | // Store if different from input 200 | if (byteValOutput!=byteValInput) { 201 | writeByte(address, byteValOutput); 202 | } 203 | } 204 | 205 | bool EEPROMClassEx::updateByte(int address, uint8_t value) 206 | { 207 | return (updateBlock(address, value)!=0); 208 | } 209 | 210 | bool EEPROMClassEx::updateInt(int address, uint16_t value) 211 | { 212 | return (updateBlock(address, value)!=0); 213 | } 214 | 215 | bool EEPROMClassEx::updateLong(int address, uint32_t value) 216 | { 217 | return (updateBlock(address, value)!=0); 218 | } 219 | 220 | bool EEPROMClassEx::updateFloat(int address, float value) 221 | { 222 | return (updateBlock(address, value)!=0); 223 | } 224 | 225 | bool EEPROMClassEx::updateDouble(int address, double value) 226 | { 227 | return (writeBlock(address, value)!=0); 228 | } 229 | 230 | bool EEPROMClassEx::isWriteOk(int address) 231 | { 232 | #ifdef _EEPROMEX_DEBUG 233 | _writeCounts++; 234 | if (_allowedWrites == 0 || _writeCounts > _allowedWrites ) { 235 | Serial.println("Exceeded maximum number of writes"); 236 | return false; 237 | } 238 | 239 | if (address > _memSize) { 240 | Serial.println("Attempt to write outside of EEPROM memory"); 241 | return false; 242 | } else { 243 | return true; 244 | } 245 | #endif 246 | return true; 247 | } 248 | 249 | bool EEPROMClassEx::isReadOk(int address) 250 | { 251 | #ifdef _EEPROMEX_DEBUG 252 | if (address > _memSize) { 253 | Serial.println("Attempt to write outside of EEPROM memory"); 254 | return false; 255 | } else { 256 | return true; 257 | } 258 | #endif 259 | return true; 260 | } 261 | 262 | int EEPROMClassEx::_base= 0; 263 | int EEPROMClassEx::_memSize= 512; 264 | int EEPROMClassEx::_nextAvailableaddress= 0; 265 | int EEPROMClassEx::_writeCounts =0; 266 | 267 | EEPROMClassEx EEPROM; 268 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/EEPROMEx/EEPROMEx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Arduino/NeededLibraries/EEPROMEx/EEPROMEx.h -------------------------------------------------------------------------------- /Arduino/NeededLibraries/EEPROMEx/Examples/EEPROMBackup/EEPROMBackup.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * EEPROMBackup 3 | * 4 | * Demonstrates the usage of EEPROMvarBackup. A c++ OOP approach where a variable can store and 5 | * restore itself from EEPROM. additionally it can spread the data over definable range in EEPROM memory 6 | * to reduce memory wear 7 | 8 | * The EEPROM memory has a specified life of 100,000 write/erase cycles, 9 | * so you may need to be careful about how often you write to it. 10 | 11 | * Assuming you want your EEPROM to live for 100 years, you could write a location once per 9 hours. 12 | * However, if you spread the information of 200 memory locations, you would be able to save every 3 minutes 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | const int maxAllowedWrites = 200; 22 | const int memBase = 0; 23 | const int memCeiling = EEPROMSizeUno; 24 | 25 | time_t minTime = 1334102400; // Date: 11-4-2012 26 | time_t maxTime = 4102444800; // Date: 1-1-2100 27 | 28 | 29 | // When recalling the data from EEPROM it the EEPROMBackupVar object 30 | // needs to figure out which item to pick. To wear we have not written 31 | // an additional pointer on the EEPROM pointing to the most current item 32 | 33 | // Instead, using a comparison-function we try to figure out which item 34 | // we should fetch. Depending on the type of data you are storing you can 35 | // tailor this Compare function 36 | bool CompareFunc(const void* _current, const void* _candidate) 37 | { 38 | // Cast to the correct type 39 | const time_t* current = (const time_t*) _current; 40 | const time_t* candidate = (const time_t*) _candidate; 41 | 42 | // check if time candidate is valid 43 | if (*candidatemaxTime) { 44 | Serial.println("invalid time"); 45 | return false; 46 | } 47 | // check if time candidate is more recent than previous 48 | return (*candidate >= *current); 49 | } 50 | 51 | // Create Eeprom variables first and in the same order 52 | // instanciate with initial value, storage range, compare function and time between backups to EEPROM 53 | EEPROMBackupVar timeBackup(minTime,100,CompareFunc,1*SECS_PER_MIN); 54 | 55 | void setup() 56 | { 57 | Serial.begin(9600); 58 | 59 | // start reading from position memBase (address 0) of the EEPROM. Set maximumSize to EEPROMSizeUno 60 | // Writes before membase or beyond EEPROMSizeUno will only give errors when _EEPROMEX_DEBUG is set 61 | EEPROM.setMemPool(memBase, EEPROMSizeUno); 62 | 63 | // Set maximum allowed writes to maxAllowedWrites. 64 | // More writes will only give errors when _EEPROMEX_DEBUG is set 65 | EEPROM.setMaxAllowedWrites(maxAllowedWrites); 66 | delay(100); 67 | Serial.println(""); 68 | 69 | Serial.println("retreiving time"); 70 | timeBackup.initialize(minTime); 71 | setTime(timeBackup); 72 | } 73 | 74 | void loop() 75 | { 76 | delay(2000); 77 | timeBackup=now(); 78 | digitalClockDisplay(timeBackup); 79 | } 80 | 81 | // Display time 82 | void digitalClockDisplay(time_t _time){ 83 | tmElements_t tm; 84 | breakTime(_time, tm); 85 | 86 | Serial.print("Time: "); 87 | Serial.print(tm.Hour); 88 | Serial.print(":"); 89 | printDigits(tm.Minute); 90 | Serial.print(":"); 91 | printDigits(tm.Second); 92 | Serial.print(" Date: "); 93 | Serial.print(tm.Day); 94 | Serial.print("."); 95 | Serial.print(tm.Month); 96 | Serial.print("."); 97 | Serial.println(tm.Year+1970); 98 | } 99 | 100 | // utility function for digital clock display: prints preceding colon and leading 0 101 | void printDigits(int digits){ 102 | if(digits < 10) 103 | Serial.print('0'); 104 | Serial.print(digits); 105 | } 106 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/EEPROMEx/Examples/EEPROMEx/EEPROMEx.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * EEPROMEx 3 | * 4 | * Demonstrates reading, writing and updating data in the EEPROM 5 | * to the computer. 6 | * This example code is in the public domain. 7 | */ 8 | 9 | #include 10 | 11 | #include "Arduino.h" 12 | void issuedAdresses(); 13 | void readAndWriteByte(); 14 | void readAndWriteInt(); 15 | void readAndWriteLong(); 16 | void readAndWriteFloat(); 17 | void updateAndReadDouble(); 18 | void writeAndReadCharArray(); 19 | void writeAndReadByteArray(); 20 | void waitUntilReady(); 21 | void errorChecking(int adress); 22 | void setup(); 23 | void loop(); 24 | const int maxAllowedWrites = 80; 25 | const int memBase = 350; 26 | 27 | int addressByte; 28 | int addressInt; 29 | int addressLong; 30 | int addressFloat; 31 | int addressDouble; 32 | int addressByteArray; 33 | int addressCharArray; 34 | 35 | 36 | void issuedAdresses() { 37 | Serial.println("-----------------------------------"); 38 | Serial.println("Following adresses have been issued"); 39 | Serial.println("-----------------------------------"); 40 | 41 | Serial.println("adress \t\t size"); 42 | Serial.print(addressByte); Serial.print(" \t\t "); Serial.print(sizeof(byte)); Serial.println(" (byte)"); 43 | Serial.print(addressInt); Serial.print(" \t\t "); Serial.print(sizeof(int)); Serial.println(" (int)"); 44 | Serial.print(addressLong); Serial.print(" \t\t "); Serial.print(sizeof(long)); Serial.println(" (long)"); 45 | Serial.print(addressFloat); Serial.print(" \t\t "); Serial.print(sizeof(float)); Serial.println(" (float)"); 46 | Serial.print(addressDouble); Serial.print(" \t\t "); Serial.print(sizeof(double)); Serial.println(" (double)"); 47 | Serial.print(addressByteArray); Serial.print(" \t\t "); Serial.print(sizeof(byte)*7); Serial.println(" (array of 7 bytes)"); 48 | Serial.print(addressCharArray); Serial.print(" \t\t "); Serial.print(sizeof(char)*7); Serial.println(" (array of 7 chars)"); 49 | } 50 | 51 | // Test reading and writing byte to EEPROM 52 | void readAndWriteByte() { 53 | Serial.println("---------------------------"); 54 | Serial.println("storing and retreiving byte"); 55 | Serial.println("---------------------------"); 56 | 57 | byte input = 120; 58 | byte output = 0; 59 | EEPROM.write(addressByte,input); // same function as writeByte 60 | output = EEPROM.read(addressByte); // same function as readByte 61 | 62 | Serial.print("adress: "); 63 | Serial.println(addressByte); 64 | Serial.print("input: "); 65 | Serial.println(input); 66 | Serial.print("output: "); 67 | Serial.println(output); 68 | Serial.println(""); 69 | 70 | } 71 | 72 | // Test reading and writing int to EEPROM 73 | void readAndWriteInt() { 74 | Serial.println("--------------------------"); 75 | Serial.println("writing and retreiving int"); 76 | Serial.println("--------------------------"); 77 | 78 | int input = 30000; 79 | int output = 0; 80 | EEPROM.writeInt(addressInt,input); 81 | output = EEPROM.readInt(addressInt); 82 | 83 | Serial.print("adress: "); 84 | Serial.println(addressInt); 85 | Serial.print("input: "); 86 | Serial.println(input); 87 | Serial.print("output: "); 88 | Serial.println(output); 89 | Serial.println(""); 90 | } 91 | 92 | // Test reading and writing long to EEPROM 93 | void readAndWriteLong() { 94 | Serial.println("----------------------------"); 95 | Serial.println("writing and retreiving Long"); 96 | Serial.println("----------------------------"); 97 | 98 | long input = 200000000; 99 | long output = 0; 100 | EEPROM.writeLong(addressLong,input); 101 | output = EEPROM.readLong(addressLong); 102 | 103 | Serial.print("adress: "); 104 | Serial.println(addressLong); 105 | Serial.print("input: "); 106 | Serial.println(input); 107 | Serial.print("output: "); 108 | Serial.println(output); 109 | Serial.println(""); 110 | } 111 | 112 | // Test reading and writing float to EEPROM 113 | void readAndWriteFloat() { 114 | Serial.println("----------------------------"); 115 | Serial.println("writing and retreiving float"); 116 | Serial.println("----------------------------"); 117 | 118 | double input = 1010102.50; 119 | double output = 0.0; 120 | EEPROM.writeFloat(addressFloat,input); 121 | output = EEPROM.readFloat(addressFloat); 122 | 123 | Serial.print("adress: "); 124 | Serial.println(addressFloat); 125 | Serial.print("input: "); 126 | Serial.println(input); 127 | Serial.print("output: "); 128 | Serial.println(output); 129 | Serial.println(""); 130 | } 131 | 132 | // Test reading and updating double to EEPROM 133 | void updateAndReadDouble() { 134 | Serial.println("------------------------------"); 135 | Serial.println("updating and retreiving double"); 136 | Serial.println("------------------------------"); 137 | 138 | double input = 1000002.50; 139 | double output = 0.0; 140 | EEPROM.updateDouble(addressDouble,input); 141 | output = EEPROM.readDouble(addressDouble); 142 | 143 | Serial.print("adress: "); 144 | Serial.println(addressDouble); 145 | Serial.print("input: "); 146 | Serial.println(input); 147 | Serial.print("output: "); 148 | Serial.println(output); 149 | Serial.println(""); 150 | } 151 | 152 | // Test reading and updating a string (char array) to EEPROM 153 | void writeAndReadCharArray() { 154 | Serial.println("---------------------------------"); 155 | Serial.println("writing and reading a char array"); 156 | Serial.println("---------------------------------"); 157 | 158 | char input[] = "Arduino"; 159 | char output[] = " "; 160 | 161 | EEPROM.writeBlock(addressCharArray, input, 7); 162 | EEPROM.readBlock(addressCharArray, output, 7); 163 | 164 | Serial.print("adress: "); 165 | Serial.println(addressCharArray); 166 | Serial.print("input: "); 167 | Serial.println(input); 168 | Serial.print("output: "); 169 | Serial.println(output); 170 | Serial.println(""); 171 | } 172 | 173 | void writeAndReadByteArray() { 174 | 175 | Serial.println("---------------------------------"); 176 | Serial.println("updating and reading a byte array"); 177 | Serial.println("---------------------------------"); 178 | 179 | int itemsInArray = 7; 180 | byte initial[] = {1, 0, 4, 0, 16, 0 , 64 }; 181 | byte input[] = {1, 2, 4, 8, 16, 32, 64 }; 182 | byte output[sizeof(input)]; 183 | 184 | EEPROM.writeBlock(addressByteArray, initial, itemsInArray); 185 | int writtenBytes = EEPROM.updateBlock(addressByteArray, input, itemsInArray); 186 | EEPROM.readBlock(addressByteArray, output, itemsInArray); 187 | 188 | Serial.print("input: "); 189 | for(int i=0;i(addressByteArray, array7, itemsInArray); 257 | endMillis = millis(); 258 | Serial.print("Time to write 7 byte array (ms) : "); 259 | Serial.println(endMillis-startMillis); 260 | 261 | // Time to update 7 byte array with 7 new values 262 | startMillis = millis(); 263 | EEPROM.updateBlock(addressByteArray, arraydif7, itemsInArray); 264 | endMillis = millis(); 265 | Serial.print("Time to update 7 byte array with 7 new values (ms): "); 266 | Serial.println(endMillis-startMillis); 267 | 268 | // Time to update 7 byte array with 3 new values 269 | startMillis = millis(); 270 | EEPROM.updateBlock(addressByteArray, arrayDif3, itemsInArray); 271 | endMillis = millis(); 272 | Serial.print("Time to update 7 byte array with 3 new values (ms): "); 273 | Serial.println(endMillis-startMillis); 274 | 275 | // Time to read 7 byte array 276 | startMillis = millis(); 277 | EEPROM.readBlock(addressByteArray, output, itemsInArray); 278 | endMillis = millis(); 279 | Serial.print("Time to read 7 byte array (ms) : "); 280 | Serial.println(endMillis-startMillis); 281 | } 282 | 283 | // Check if we get errors when writing too much or out of bounds 284 | void errorChecking(int adress) { 285 | Serial.println("-------------------------------------------------------------"); 286 | Serial.println("Check if we get errors when writing too much or out of bounds"); 287 | Serial.println("-------------------------------------------------------------"); 288 | // Be sure that _EEPROMEX_DEBUG is enabled 289 | 290 | Serial.println("Write outside of EEPROM memory"); 291 | EEPROM.writeLong(EEPROMSizeUno+10,1000); 292 | Serial.println(); 293 | 294 | Serial.println("Trying to exceed number of writes"); 295 | for(int i=1;i<=20; i++) 296 | { 297 | if (!EEPROM.writeLong(adress,1000)) { return; } 298 | } 299 | Serial.println(); 300 | } 301 | 302 | 303 | void setup() 304 | { 305 | Serial.begin(9600); 306 | 307 | // start reading from position memBase (address 0) of the EEPROM. Set maximumSize to EEPROMSizeUno 308 | // Writes before membase or beyond EEPROMSizeUno will only give errors when _EEPROMEX_DEBUG is set 309 | EEPROM.setMemPool(memBase, EEPROMSizeUno); 310 | 311 | // Set maximum allowed writes to maxAllowedWrites. 312 | // More writes will only give errors when _EEPROMEX_DEBUG is set 313 | EEPROM.setMaxAllowedWrites(maxAllowedWrites); 314 | delay(100); 315 | Serial.println(""); 316 | 317 | // Always get the adresses first and in the same order 318 | addressByte = EEPROM.getAddress(sizeof(byte)); 319 | addressInt = EEPROM.getAddress(sizeof(int)); 320 | addressLong = EEPROM.getAddress(sizeof(long)); 321 | addressFloat = EEPROM.getAddress(sizeof(float)); 322 | addressDouble = EEPROM.getAddress(sizeof(double)); 323 | addressByteArray = EEPROM.getAddress(sizeof(byte)*7); 324 | addressCharArray = EEPROM.getAddress(sizeof(char)*7); 325 | 326 | // Show adresses that have been issued 327 | issuedAdresses(); 328 | 329 | // Read and write different data primitives 330 | readAndWriteByte(); 331 | readAndWriteInt(); 332 | readAndWriteLong(); 333 | readAndWriteFloat(); 334 | updateAndReadDouble(); 335 | 336 | // Read and write different data arrays 337 | writeAndReadCharArray(); 338 | writeAndReadByteArray(); 339 | 340 | // Test EEPROM access time 341 | waitUntilReady(); 342 | 343 | // Test error checking 344 | errorChecking(addressLong); 345 | } 346 | 347 | void loop() 348 | { 349 | // Nothing to do during loop 350 | } 351 | 352 | 353 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/EEPROMEx/Examples/EEPROMVar/EEPROMVar.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * EEPROMVar 3 | * 4 | * Demonstrates the usage of EEPROMvar. A c++ OOP approach 5 | * where a variable can store and restore itself from EEPROM 6 | * This example code is in the public domain. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | // start reading from the first byte (address 120) of the EEPROM 13 | 14 | const int maxAllowedWrites = 20; 15 | const int memBase = 120; 16 | 17 | void readAndWriteVar(EEPROMVar &floatVar) { 18 | Serial.println("----------------------------------------------"); 19 | Serial.println("writing and retreiving EEPROMVar of type float"); 20 | Serial.println("----------------------------------------------"); 21 | 22 | floatVar = 10.5; // EEPROMVar supports = operator 23 | floatVar++; // EEPROMVar supports ++ operator 24 | floatVar+=8.5; // EEPROMVar supports += operator 25 | floatVar/=2; // EEPROMVar supports /= operator 26 | 27 | float input = floatVar; 28 | floatVar.save(); // store EEPROMVar to EEPROM 29 | 30 | floatVar = 0.0; // reset 31 | floatVar.restore(); // restore EEPROMVar to EEPROM 32 | 33 | Serial.print("adress: "); 34 | Serial.println(floatVar.getAdress()); 35 | Serial.print("input: "); 36 | Serial.println(input); 37 | Serial.print("output: "); 38 | Serial.println(floatVar); 39 | Serial.println(); 40 | } 41 | 42 | void setup() 43 | { 44 | Serial.begin(9600); 45 | delay(100); 46 | Serial.println(); 47 | 48 | // start reading from position memBase (address 0) of the EEPROM. Set maximumSize to EEPROMSizeUno 49 | // Writes before membase or beyond EEPROMSizeUno will only give errors when _EEPROMEX_DEBUG is set 50 | EEPROM.setMemPool(memBase, EEPROMSizeUno); 51 | 52 | // Set maximum allowed writes to maxAllowedWrites. 53 | // More writes will only give errors when _EEPROMEX_DEBUG is set 54 | EEPROM.setMaxAllowedWrites(maxAllowedWrites); 55 | 56 | // Create Eeprom variables first and in the same order 57 | EEPROMVar eepromFloat(5.5); // initial value 5.5 58 | 59 | readAndWriteVar(eepromFloat); 60 | } 61 | 62 | void loop() 63 | { 64 | // Nothing to do during loop 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/EEPROMEx/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For EEPROMEx 3 | ####################################### 4 | 5 | ####################################### 6 | # Methods and Functions EEPROMEx (KEYWORD2) 7 | ####################################### 8 | 9 | isReady KEYWORD2 10 | setMemPool KEYWORD2 11 | setMaxAllowedWrites KEYWORD2 12 | getAdress KEYWORD2 13 | 14 | read KEYWORD2 15 | readByte KEYWORD2 16 | readInt KEYWORD2 17 | readLong KEYWORD2 18 | readFloat KEYWORD2 19 | readDouble KEYWORD2 20 | readBlock KEYWORD2 21 | 22 | write KEYWORD2 23 | writeByte KEYWORD2 24 | writeInt KEYWORD2 25 | writeLong KEYWORD2 26 | writeFloat KEYWORD2 27 | writeDouble KEYWORD2 28 | writeBlock KEYWORD2 29 | 30 | update KEYWORD2 31 | updateByte KEYWORD2 32 | updateInt KEYWORD2 33 | updateLong KEYWORD2 34 | updateFloat KEYWORD2 35 | updateDouble KEYWORD2 36 | updateBlock KEYWORD2 37 | 38 | ####################################### 39 | # Instances (KEYWORD2) 40 | ####################################### 41 | 42 | EEPROMEx KEYWORD2 43 | 44 | ####################################### 45 | # Constants (LITERAL1) 46 | ####################################### 47 | 48 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/Examples/PID_AdaptiveTunings/PID_AdaptiveTunings.ino: -------------------------------------------------------------------------------- 1 | /******************************************************** 2 | * PID Adaptive Tuning Example 3 | * One of the benefits of the PID library is that you can 4 | * change the tuning parameters at any time. this can be 5 | * helpful if we want the controller to be agressive at some 6 | * times, and conservative at others. in the example below 7 | * we set the controller to use Conservative Tuning Parameters 8 | * when we're near setpoint and more agressive Tuning 9 | * Parameters when we're farther away. 10 | ********************************************************/ 11 | 12 | #include 13 | 14 | //Define Variables we'll be connecting to 15 | double Setpoint, Input, Output; 16 | 17 | //Define the aggressive and conservative Tuning Parameters 18 | double aggKp=4, aggKi=0.2, aggKd=1; 19 | double consKp=1, consKi=0.05, consKd=0.25; 20 | 21 | //Specify the links and initial tuning parameters 22 | PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); 23 | 24 | void setup() 25 | { 26 | //initialize the variables we're linked to 27 | Input = analogRead(0); 28 | Setpoint = 100; 29 | 30 | //turn the PID on 31 | myPID.SetMode(AUTOMATIC); 32 | } 33 | 34 | void loop() 35 | { 36 | Input = analogRead(0); 37 | 38 | double gap = abs(Setpoint-Input); //distance away from setpoint 39 | if(gap<10) 40 | { //we're close to setpoint, use conservative tuning parameters 41 | myPID.SetTunings(consKp, consKi, consKd); 42 | } 43 | else 44 | { 45 | //we're far from setpoint, use aggressive tuning parameters 46 | myPID.SetTunings(aggKp, aggKi, aggKd); 47 | } 48 | 49 | myPID.Compute(); 50 | analogWrite(3,Output); 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/Examples/PID_Basic/PID_Basic.ino: -------------------------------------------------------------------------------- 1 | /******************************************************** 2 | * PID Basic Example 3 | * Reading analog input 0 to control analog PWM output 3 4 | ********************************************************/ 5 | 6 | #include 7 | 8 | //Define Variables we'll be connecting to 9 | double Setpoint, Input, Output; 10 | 11 | //Specify the links and initial tuning parameters 12 | PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT); 13 | 14 | void setup() 15 | { 16 | //initialize the variables we're linked to 17 | Input = analogRead(0); 18 | Setpoint = 100; 19 | 20 | //turn the PID on 21 | myPID.SetMode(AUTOMATIC); 22 | } 23 | 24 | void loop() 25 | { 26 | Input = analogRead(0); 27 | myPID.Compute(); 28 | analogWrite(3,Output); 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/Examples/PID_RelayOutput/PID_RelayOutput.ino: -------------------------------------------------------------------------------- 1 | /******************************************************** 2 | * PID RelayOutput Example 3 | * Same as basic example, except that this time, the output 4 | * is going to a digital pin which (we presume) is controlling 5 | * a relay. the pid is designed to Output an analog value, 6 | * but the relay can only be On/Off. 7 | * 8 | * to connect them together we use "time proportioning 9 | * control" it's essentially a really slow version of PWM. 10 | * first we decide on a window size (5000mS say.) we then 11 | * set the pid to adjust its output between 0 and that window 12 | * size. lastly, we add some logic that translates the PID 13 | * output into "Relay On Time" with the remainder of the 14 | * window being "Relay Off Time" 15 | ********************************************************/ 16 | 17 | #include 18 | #define RelayPin 6 19 | 20 | //Define Variables we'll be connecting to 21 | double Setpoint, Input, Output; 22 | 23 | //Specify the links and initial tuning parameters 24 | PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT); 25 | 26 | int WindowSize = 5000; 27 | unsigned long windowStartTime; 28 | void setup() 29 | { 30 | windowStartTime = millis(); 31 | 32 | //initialize the variables we're linked to 33 | Setpoint = 100; 34 | 35 | //tell the PID to range between 0 and the full window size 36 | myPID.SetOutputLimits(0, WindowSize); 37 | 38 | //turn the PID on 39 | myPID.SetMode(AUTOMATIC); 40 | } 41 | 42 | void loop() 43 | { 44 | Input = analogRead(0); 45 | myPID.Compute(); 46 | 47 | /************************************************ 48 | * turn the output pin on/off based on pid output 49 | ************************************************/ 50 | if(millis() - windowStartTime>WindowSize) 51 | { //time to shift the Relay Window 52 | windowStartTime += WindowSize; 53 | } 54 | if(Output < millis() - windowStartTime) digitalWrite(RelayPin,HIGH); 55 | else digitalWrite(RelayPin,LOW); 56 | 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/PID_v1.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * Arduino PID Library - Version 1.0.1 3 | * by Brett Beauregard brettbeauregard.com 4 | * 5 | * This Library is licensed under a GPLv3 License 6 | **********************************************************************************************/ 7 | 8 | #if ARDUINO >= 100 9 | #include "Arduino.h" 10 | #else 11 | #include "WProgram.h" 12 | #endif 13 | 14 | #include 15 | 16 | /*Constructor (...)********************************************************* 17 | * The parameters specified here are those for for which we can't set up 18 | * reliable defaults, so we need to have the user set them. 19 | ***************************************************************************/ 20 | PID::PID(double* Input, double* Output, double* Setpoint, 21 | double Kp, double Ki, double Kd, int ControllerDirection) 22 | { 23 | 24 | myOutput = Output; 25 | myInput = Input; 26 | mySetpoint = Setpoint; 27 | inAuto = false; 28 | 29 | PID::SetOutputLimits(0, 255); //default output limit corresponds to 30 | //the arduino pwm limits 31 | 32 | SampleTime = 100; //default Controller Sample Time is 0.1 seconds 33 | 34 | PID::SetControllerDirection(ControllerDirection); 35 | PID::SetTunings(Kp, Ki, Kd); 36 | 37 | lastTime = millis()-SampleTime; 38 | } 39 | 40 | 41 | /* Compute() ********************************************************************** 42 | * This, as they say, is where the magic happens. this function should be called 43 | * every time "void loop()" executes. the function will decide for itself whether a new 44 | * pid Output needs to be computed. returns true when the output is computed, 45 | * false when nothing has been done. 46 | **********************************************************************************/ 47 | bool PID::Compute() 48 | { 49 | if(!inAuto) return false; 50 | unsigned long now = millis(); 51 | unsigned long timeChange = (now - lastTime); 52 | if(timeChange>=SampleTime) 53 | { 54 | /*Compute all the working error variables*/ 55 | double input = *myInput; 56 | double error = *mySetpoint - input; 57 | ITerm+= (ki * error); 58 | if(ITerm > outMax) ITerm= outMax; 59 | else if(ITerm < outMin) ITerm= outMin; 60 | double dInput = (input - lastInput); 61 | 62 | /*Compute PID Output*/ 63 | double output = kp * error + ITerm- kd * dInput; 64 | 65 | if(output > outMax) output = outMax; 66 | else if(output < outMin) output = outMin; 67 | *myOutput = output; 68 | 69 | /*Remember some variables for next time*/ 70 | lastInput = input; 71 | lastTime = now; 72 | return true; 73 | } 74 | else return false; 75 | } 76 | 77 | 78 | /* SetTunings(...)************************************************************* 79 | * This function allows the controller's dynamic performance to be adjusted. 80 | * it's called automatically from the constructor, but tunings can also 81 | * be adjusted on the fly during normal operation 82 | ******************************************************************************/ 83 | void PID::SetTunings(double Kp, double Ki, double Kd) 84 | { 85 | if (Kp<0 || Ki<0 || Kd<0) return; 86 | 87 | dispKp = Kp; dispKi = Ki; dispKd = Kd; 88 | 89 | double SampleTimeInSec = ((double)SampleTime)/1000; 90 | kp = Kp; 91 | ki = Ki * SampleTimeInSec; 92 | kd = Kd / SampleTimeInSec; 93 | 94 | if(controllerDirection ==REVERSE) 95 | { 96 | kp = (0 - kp); 97 | ki = (0 - ki); 98 | kd = (0 - kd); 99 | } 100 | } 101 | 102 | /* SetSampleTime(...) ********************************************************* 103 | * sets the period, in Milliseconds, at which the calculation is performed 104 | ******************************************************************************/ 105 | void PID::SetSampleTime(int NewSampleTime) 106 | { 107 | if (NewSampleTime > 0) 108 | { 109 | double ratio = (double)NewSampleTime 110 | / (double)SampleTime; 111 | ki *= ratio; 112 | kd /= ratio; 113 | SampleTime = (unsigned long)NewSampleTime; 114 | } 115 | } 116 | 117 | /* SetOutputLimits(...)**************************************************** 118 | * This function will be used far more often than SetInputLimits. while 119 | * the input to the controller will generally be in the 0-1023 range (which is 120 | * the default already,) the output will be a little different. maybe they'll 121 | * be doing a time window and will need 0-8000 or something. or maybe they'll 122 | * want to clamp it from 0-125. who knows. at any rate, that can all be done 123 | * here. 124 | **************************************************************************/ 125 | void PID::SetOutputLimits(double Min, double Max) 126 | { 127 | if(Min >= Max) return; 128 | outMin = Min; 129 | outMax = Max; 130 | 131 | if(inAuto) 132 | { 133 | if(*myOutput > outMax) *myOutput = outMax; 134 | else if(*myOutput < outMin) *myOutput = outMin; 135 | 136 | if(ITerm > outMax) ITerm= outMax; 137 | else if(ITerm < outMin) ITerm= outMin; 138 | } 139 | } 140 | 141 | /* SetMode(...)**************************************************************** 142 | * Allows the controller Mode to be set to manual (0) or Automatic (non-zero) 143 | * when the transition from manual to auto occurs, the controller is 144 | * automatically initialized 145 | ******************************************************************************/ 146 | void PID::SetMode(int Mode) 147 | { 148 | bool newAuto = (Mode == AUTOMATIC); 149 | if(newAuto == !inAuto) 150 | { /*we just went from manual to auto*/ 151 | PID::Initialize(); 152 | } 153 | inAuto = newAuto; 154 | } 155 | 156 | /* Initialize()**************************************************************** 157 | * does all the things that need to happen to ensure a bumpless transfer 158 | * from manual to automatic mode. 159 | ******************************************************************************/ 160 | void PID::Initialize() 161 | { 162 | ITerm = *myOutput; 163 | lastInput = *myInput; 164 | if(ITerm > outMax) ITerm = outMax; 165 | else if(ITerm < outMin) ITerm = outMin; 166 | } 167 | 168 | /* SetControllerDirection(...)************************************************* 169 | * The PID will either be connected to a DIRECT acting process (+Output leads 170 | * to +Input) or a REVERSE acting process(+Output leads to -Input.) we need to 171 | * know which one, because otherwise we may increase the output when we should 172 | * be decreasing. This is called from the constructor. 173 | ******************************************************************************/ 174 | void PID::SetControllerDirection(int Direction) 175 | { 176 | if(inAuto && Direction !=controllerDirection) 177 | { 178 | kp = (0 - kp); 179 | ki = (0 - ki); 180 | kd = (0 - kd); 181 | } 182 | controllerDirection = Direction; 183 | } 184 | 185 | /* Status Funcions************************************************************* 186 | * Just because you set the Kp=-1 doesn't mean it actually happened. these 187 | * functions query the internal state of the PID. they're here for display 188 | * purposes. this are the functions the PID Front-end uses for example 189 | ******************************************************************************/ 190 | double PID::GetKp(){ return dispKp; } 191 | double PID::GetKi(){ return dispKi;} 192 | double PID::GetKd(){ return dispKd;} 193 | int PID::GetMode(){ return inAuto ? AUTOMATIC : MANUAL;} 194 | int PID::GetDirection(){ return controllerDirection;} 195 | 196 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/PID_v1.h: -------------------------------------------------------------------------------- 1 | #ifndef PID_v1_h 2 | #define PID_v1_h 3 | #define LIBRARY_VERSION 1.0.0 4 | 5 | class PID 6 | { 7 | 8 | 9 | public: 10 | 11 | //Constants used in some of the functions below 12 | #define AUTOMATIC 1 13 | #define MANUAL 0 14 | #define DIRECT 0 15 | #define REVERSE 1 16 | 17 | //commonly used functions ************************************************************************** 18 | PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and 19 | double, double, double, int); // Setpoint. Initial tuning parameters are also set here 20 | 21 | void SetMode(int Mode); // * sets PID to either Manual (0) or Auto (non-0) 22 | 23 | bool Compute(); // * performs the PID calculation. it should be 24 | // called every time loop() cycles. ON/OFF and 25 | // calculation frequency can be set using SetMode 26 | // SetSampleTime respectively 27 | 28 | void SetOutputLimits(double, double); //clamps the output to a specific range. 0-255 by default, but 29 | //it's likely the user will want to change this depending on 30 | //the application 31 | 32 | 33 | 34 | //available but not commonly used functions ******************************************************** 35 | void SetTunings(double, double, // * While most users will set the tunings once in the 36 | double); // constructor, this function gives the user the option 37 | // of changing tunings during runtime for Adaptive control 38 | void SetControllerDirection(int); // * Sets the Direction, or "Action" of the controller. DIRECT 39 | // means the output will increase when error is positive. REVERSE 40 | // means the opposite. it's very unlikely that this will be needed 41 | // once it is set in the constructor. 42 | void SetSampleTime(int); // * sets the frequency, in Milliseconds, with which 43 | // the PID calculation is performed. default is 100 44 | 45 | 46 | 47 | //Display functions **************************************************************** 48 | double GetKp(); // These functions query the pid for interal values. 49 | double GetKi(); // they were created mainly for the pid front-end, 50 | double GetKd(); // where it's important to know what is actually 51 | int GetMode(); // inside the PID. 52 | int GetDirection(); // 53 | 54 | private: 55 | void Initialize(); 56 | 57 | double dispKp; // * we'll hold on to the tuning parameters in user-entered 58 | double dispKi; // format for display purposes 59 | double dispKd; // 60 | 61 | double kp; // * (P)roportional Tuning Parameter 62 | double ki; // * (I)ntegral Tuning Parameter 63 | double kd; // * (D)erivative Tuning Parameter 64 | 65 | int controllerDirection; 66 | 67 | double *myInput; // * Pointers to the Input, Output, and Setpoint variables 68 | double *myOutput; // This creates a hard link between the variables and the 69 | double *mySetpoint; // PID, freeing the user from having to constantly tell us 70 | // what these values are. with pointers we'll just know. 71 | 72 | unsigned long lastTime; 73 | double ITerm, lastInput; 74 | 75 | unsigned long SampleTime; 76 | double outMin, outMax; 77 | bool inAuto; 78 | }; 79 | #endif 80 | 81 | -------------------------------------------------------------------------------- /Arduino/NeededLibraries/PID_v1/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For PID Library 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | PID KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | SetMode KEYWORD2 16 | Compute KEYWORD2 17 | SetOutputLimits KEYWORD2 18 | SetTunings KEYWORD2 19 | SetControllerDirection KEYWORD2 20 | SetSampleTime KEYWORD2 21 | GetKp KEYWORD2 22 | GetKi KEYWORD2 23 | GetKd KEYWORD2 24 | GetMode KEYWORD2 25 | GetDirection KEYWORD2 26 | 27 | ####################################### 28 | # Constants (LITERAL1) 29 | ####################################### 30 | 31 | AUTOMATIC LITERAL1 32 | MANUAL LITERAL1 33 | DIRECT LITERAL1 34 | REVERSE LITERAL1 -------------------------------------------------------------------------------- /Arduino/ReflowOvenFFLilyMenuOverWrite/ReflowOvenFFLilyMenuOverWrite.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | ReflowOvenFLily - Written to work with ReflowControllerB 3 | LilyPadUSB.bootloader.extended_fuses=0xce 4 | LilyPadUSB.bootloader.high_fuses=0xd8 5 | LilyPadUSB.bootloader.low_fuses=0xff 6 | 7 | Magic Happens Here! 8 | * 225-| x x 9 | * | x x 10 | * | x x 11 | * | x x 12 | * 200-| x x 13 | * | x | | x 14 | * | x | | x 15 | * | x | | 16 | * 150-| x | | 17 | * | x | | | 18 | * | x | | | 19 | * | x | | | 20 | * | x | | | 21 | * | x | | | 22 | * | x | | | 23 | * 30 -| x | | | 24 | * |< 60 - 90 s >|< 90 - 120 s >|< 90 - 120 s >| 25 | * | Preheat Stage | Soaking Stage | Reflow Stage | Cool 26 | * 0 |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 27 | * Time (Seconds) 28 | *********************************************************************/ 29 | 30 | #include 31 | // Includes 32 | #include // GFX Library - https://github.com/adafruit/Adafruit-GFX-Library 33 | #include // SSD Library - https://github.com/adafruit/Adafruit_SSD1306 34 | #include // Thermocouple Library - https://github.com/rocketscream/MAX31855 35 | #include // PID Library - http://playground.arduino.cc/Code/PIDLibrary 36 | // - https://github.com/br3ttb/Arduino-PID-Library/ 37 | #include // EEPROMex Library - http://playground.arduino.cc/Code/EEPROMex 38 | // OHARARP FAVICON (LCD ASSISTANT, Byte Orientation - Horizontal Width = 64 Height = 64 39 | static unsigned char PROGMEM logo[] = { 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xC0, 41 | 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 42 | 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 43 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFE, 44 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 45 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 46 | 0x7F, 0xFF, 0xFF, 0xE0, 0x03, 0xE7, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x80, 0x03, 0xCF, 0xFF, 0xFF, 47 | 0x7F, 0xFF, 0xFE, 0x00, 0x07, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x07, 0x8F, 0xFF, 0xFF, 48 | 0x7F, 0xFF, 0xF0, 0x00, 0x0F, 0x87, 0xFF, 0xFF, 0x7F, 0xFF, 0xE0, 0x00, 0x1F, 0x03, 0xFF, 0xFF, 49 | 0x7F, 0xFF, 0xC0, 0x00, 0x3E, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0x80, 0x00, 0x7E, 0x00, 0xFF, 0xFF, 50 | 0x7F, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, 0x00, 0x00, 0xFC, 0x00, 0x7F, 0xFF, 51 | 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xC0, 0x3F, 0xFF, 0x7F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x3F, 0xFF, 52 | 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 0x7F, 0xFC, 0x00, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 53 | 0x7F, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x10, 0xFE, 0x00, 0x0F, 0xFF, 54 | 0x7F, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFF, 55 | 0x7F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xFF, 56 | 0x7F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xFF, 57 | 0x7F, 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xFF, 58 | 0x7F, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 59 | 0x7F, 0xFC, 0x00, 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x7F, 0xF0, 0x00, 0x1F, 0xFF, 60 | 0x7F, 0xFE, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0x7F, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 61 | 0x7F, 0xFF, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x7F, 0xFF, 0x01, 0x9F, 0x80, 0x00, 0x7F, 0xFF, 62 | 0x7F, 0xFF, 0x80, 0x1F, 0x80, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 63 | 0x7F, 0xFF, 0xC0, 0x3E, 0x00, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0xE0, 0x7C, 0x00, 0x03, 0xFF, 0xFF, 64 | 0x7F, 0xFF, 0xF0, 0x78, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 65 | 0x7F, 0xFF, 0xFC, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF9, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 66 | 0x7F, 0xFF, 0xFB, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 67 | 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 68 | 0x7F, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 69 | 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 70 | 0x0F, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 72 | 73 | typedef enum REFLOW_STATE 74 | { 75 | REFLOW_STATE_IDLE, 76 | REFLOW_STATE_PREHEAT, 77 | REFLOW_STATE_SOAK, 78 | REFLOW_STATE_REFLOW, 79 | REFLOW_STATE_COOL, 80 | REFLOW_STATE_COMPLETE, 81 | REFLOW_STATE_TOO_HOT, 82 | REFLOW_STATE_ERROR 83 | } reflowState_t; 84 | 85 | typedef enum REFLOW_STATUS 86 | { 87 | REFLOW_STATUS_OFF, 88 | REFLOW_STATUS_ON 89 | } reflowStatus_t; 90 | 91 | typedef enum SWITCH 92 | { 93 | SWITCH_NONE, 94 | SWITCH_1, 95 | SWITCH_2, 96 | } switch_t; 97 | 98 | // ***** CONSTANTS ***** 99 | #define OLED_RESET 4 100 | float TEMPERATURE_COOL = 100; 101 | float TEMPERATURE_SOAK_MIN = 150; 102 | float TEMPERATURE_SOAK_MAX = 180; 103 | float TEMPERATURE_REFLOW_MAX = 220; 104 | float TEMP_VALUE_MENU = 0; 105 | 106 | #define SENSOR_SAMPLING_TIME 1000 107 | #define SOAK_TEMPERATURE_STEP 5 108 | #define SOAK_MICRO_PERIOD 9000 109 | #define DEBOUNCE_PERIOD_MIN 50 110 | 111 | // ***** PID PARAMETERS ***** 112 | // ***** PRE-HEAT STAGE ***** 113 | float PID_KP_PREHEAT = 300; 114 | float PID_KI_PREHEAT = 0.05; 115 | float PID_KD_PREHEAT = 350; 116 | // ***** SOAKING STAGE ***** 117 | float PID_KP_SOAK = 300; 118 | float PID_KI_SOAK = 0.05; 119 | float PID_KD_SOAK = 350; 120 | // ***** REFLOW STAGE ***** 121 | float PID_KP_REFLOW = 300; 122 | float PID_KI_REFLOW = 0.05; 123 | float PID_KD_REFLOW = 350; 124 | #define PID_SAMPLE_TIME 1000 125 | 126 | // ***** LCD MESSAGES ***** 127 | const char* ssdMessagesReflowStatus[] = { 128 | " Ready ", 129 | " Preheat ", 130 | " Soak ", 131 | " Reflow ", 132 | " Cool ", 133 | " Complete", 134 | " !HOT! ", 135 | " Error " 136 | }; 137 | 138 | // Pin Definitions 139 | int TopPin = 8; // Top Element 140 | int BotPin = 7; // Bottom Element 141 | int DoorPin =6; // Door Sense 142 | int BuzPin = A2; // Buzzer Pin 143 | int Led = 13; // Heartbeat Led 144 | 145 | int But1 = 9; // Start Button 146 | int But2 = 10; // Menu Button 147 | int But3 = 11; // Plus Button 148 | int But4 = 12; // Minus Button 149 | 150 | int thermocoupleCLKPin = A4; 151 | int thermocoupleSOPin = A3; 152 | int thermocoupleCSPin = A5; 153 | 154 | // ***** PID CONTROL VARIABLES ***** 155 | double setpoint; 156 | double input; 157 | double inputOld; //Store old Temperature 158 | double output; 159 | double kp = PID_KP_PREHEAT; 160 | double ki = PID_KI_PREHEAT; 161 | double kd = PID_KD_PREHEAT; 162 | int windowSize; 163 | unsigned long windowStartTime; 164 | unsigned long nextCheck; 165 | unsigned long nextRead; 166 | unsigned long timerSoak; 167 | unsigned long buzzerPeriod; 168 | boolean StartTest; 169 | 170 | // Reflow oven controller state machine state variable 171 | reflowState_t reflowState; 172 | // Reflow oven controller status 173 | reflowStatus_t reflowStatus; 174 | 175 | //Button Variables 176 | float MenuArray[14] = {TEMPERATURE_COOL,TEMPERATURE_SOAK_MIN,TEMPERATURE_SOAK_MAX,TEMPERATURE_REFLOW_MAX, 177 | PID_KP_PREHEAT,PID_KI_PREHEAT,PID_KD_PREHEAT, 178 | PID_KP_SOAK,PID_KI_SOAK,PID_KD_SOAK, 179 | PID_KP_REFLOW,PID_KI_REFLOW,PID_KD_REFLOW,0}; 180 | float PromTest = 0; 181 | byte ArrowArray[5] = {24,32,40,48,56}; 182 | byte ArrowIdx[13] = {0,1,2,3,0,1,2,0,1,2,0,1,2}; 183 | byte MathIdx[13] = {0,0,0,0,0,1,0,0,1,0,0,1,0}; 184 | boolean MenuFlag; 185 | boolean PlusFlag; 186 | boolean MinusFlag; 187 | 188 | byte ButtCount = 0; 189 | int MenuCount = -1; 190 | int PlusMinus = 0; 191 | 192 | // tc Error Counter 193 | int tcErrorCtr = 0; 194 | 195 | // Seconds timer 196 | int timerSeconds; 197 | 198 | // Library Setup 199 | // Specify PID control interface 200 | PID reflowOvenPID(&input, &output, &setpoint, kp, ki, kd, DIRECT); 201 | Adafruit_SSD1306 display(OLED_RESET); 202 | Adafruit_MAX31855 thermocouple(thermocoupleCLKPin, thermocoupleCSPin, thermocoupleSOPin); 203 | 204 | // Setup 205 | void setup() { 206 | // Setup Serial Baudrate 207 | Serial.begin(9600); 208 | 209 | for (int i = 0; i<12;i++){ 210 | EEPROM.writeFloat(i*4, MenuArray[i]); 211 | } 212 | 213 | 214 | 215 | 216 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 217 | display.begin(SSD1306_SWITCHCAPVCC); 218 | display.clearDisplay(); 219 | display.setCursor(0,0); 220 | display.setTextSize(2); 221 | display.setTextColor(WHITE); 222 | display.println(" EEPROM "); 223 | display.drawLine(0, 16, 127, 16, WHITE); 224 | display.display(); 225 | 226 | } 227 | 228 | // Begin Main Loop 229 | void loop(){ 230 | 231 | } 232 | 233 | -------------------------------------------------------------------------------- /Arduino/ReflowOvenFLilyMenu/ReflowOvenFLilyMenu.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | ReflowOvenFLily - Written to work with ReflowControllerC 3 | LilyPadUSB.bootloader.extended_fuses=0xce 4 | LilyPadUSB.bootloader.high_fuses=0xd8 5 | LilyPadUSB.bootloader.low_fuses=0xff 6 | 7 | Magic Happens Here! 8 | * 225-| x x 9 | * | x x 10 | * | x x 11 | * | x x 12 | * 200-| x x 13 | * | x | | x 14 | * | x | | x 15 | * | x | | 16 | * 150-| x | | 17 | * | x | | | 18 | * | x | | | 19 | * | x | | | 20 | * | x | | | 21 | * | x | | | 22 | * | x | | | 23 | * 30 -| x | | | 24 | * |< 60 - 90 s >|< 90 - 120 s >|< 90 - 120 s >| 25 | * | Preheat Stage | Soaking Stage | Reflow Stage | Cool 26 | * 0 |_ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 27 | * Time (Seconds) 28 | *********************************************************************/ 29 | 30 | #include 31 | // Includes 32 | #include // GFX Library - https://github.com/adafruit/Adafruit-GFX-Library 33 | #include // SSD Library - https://github.com/adafruit/Adafruit_SSD1306 34 | #include // Thermocouple Library - https://github.com/rocketscream/MAX31855 35 | #include // PID Library - http://playground.arduino.cc/Code/PIDLibrary 36 | // - https://github.com/br3ttb/Arduino-PID-Library/ 37 | #include // EEPROMex Library - http://playground.arduino.cc/Code/EEPROMex 38 | // OHARARP FAVICON (LCD ASSISTANT, Byte Orientation - Horizontal Width = 64 Height = 64 39 | static unsigned char PROGMEM logo[] = { 40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xC0, 41 | 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xF0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 42 | 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 43 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFE, 44 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 45 | 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 46 | 0x7F, 0xFF, 0xFF, 0xE0, 0x03, 0xE7, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x80, 0x03, 0xCF, 0xFF, 0xFF, 47 | 0x7F, 0xFF, 0xFE, 0x00, 0x07, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, 0xF8, 0x00, 0x07, 0x8F, 0xFF, 0xFF, 48 | 0x7F, 0xFF, 0xF0, 0x00, 0x0F, 0x87, 0xFF, 0xFF, 0x7F, 0xFF, 0xE0, 0x00, 0x1F, 0x03, 0xFF, 0xFF, 49 | 0x7F, 0xFF, 0xC0, 0x00, 0x3E, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0x80, 0x00, 0x7E, 0x00, 0xFF, 0xFF, 50 | 0x7F, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, 0x00, 0x00, 0xFC, 0x00, 0x7F, 0xFF, 51 | 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xC0, 0x3F, 0xFF, 0x7F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x3F, 0xFF, 52 | 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 0x7F, 0xFC, 0x00, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 53 | 0x7F, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x10, 0xFE, 0x00, 0x0F, 0xFF, 54 | 0x7F, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFF, 55 | 0x7F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xFF, 56 | 0x7F, 0xF8, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xFF, 57 | 0x7F, 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xFF, 0x7F, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xFF, 58 | 0x7F, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 59 | 0x7F, 0xFC, 0x00, 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0x7F, 0xFC, 0x00, 0x7F, 0xF0, 0x00, 0x1F, 0xFF, 60 | 0x7F, 0xFE, 0x00, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0x7F, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 61 | 0x7F, 0xFF, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x7F, 0xFF, 0x01, 0x9F, 0x80, 0x00, 0x7F, 0xFF, 62 | 0x7F, 0xFF, 0x80, 0x1F, 0x80, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, 0xC0, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 63 | 0x7F, 0xFF, 0xC0, 0x3E, 0x00, 0x01, 0xFF, 0xFF, 0x7F, 0xFF, 0xE0, 0x7C, 0x00, 0x03, 0xFF, 0xFF, 64 | 0x7F, 0xFF, 0xF0, 0x78, 0x00, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, 0x00, 0x0F, 0xFF, 0xFF, 65 | 0x7F, 0xFF, 0xFC, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0x7F, 0xFF, 0xF9, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 66 | 0x7F, 0xFF, 0xFB, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 67 | 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 68 | 0x7F, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 69 | 0x3F, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 70 | 0x0F, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 72 | 73 | typedef enum REFLOW_STATE 74 | { 75 | REFLOW_STATE_IDLE, 76 | REFLOW_STATE_PREHEAT, 77 | REFLOW_STATE_SOAK, 78 | REFLOW_STATE_REFLOW, 79 | REFLOW_STATE_COOL, 80 | REFLOW_STATE_COMPLETE, 81 | REFLOW_STATE_TOO_HOT, 82 | REFLOW_STATE_ERROR 83 | } reflowState_t; 84 | 85 | typedef enum REFLOW_STATUS 86 | { 87 | REFLOW_STATUS_OFF, 88 | REFLOW_STATUS_ON 89 | } reflowStatus_t; 90 | 91 | typedef enum SWITCH 92 | { 93 | SWITCH_NONE, 94 | SWITCH_1, 95 | SWITCH_2, 96 | } switch_t; 97 | 98 | // ***** CONSTANTS ***** 99 | #define OLED_RESET 4 100 | float TEMPERATURE_COOL = 100; 101 | float TEMPERATURE_SOAK_MIN = 150; 102 | float TEMPERATURE_SOAK_MAX = 180; 103 | float TEMPERATURE_REFLOW_MAX = 220; 104 | float TEMP_VALUE_MENU = 0; 105 | 106 | #define SENSOR_SAMPLING_TIME 1000 107 | #define SOAK_TEMPERATURE_STEP 5 108 | #define SOAK_MICRO_PERIOD 9000 109 | #define DEBOUNCE_PERIOD_MIN 50 110 | 111 | // ***** PID PARAMETERS ***** 112 | // ***** PRE-HEAT STAGE ***** 113 | float PID_KP_PREHEAT = 300; 114 | float PID_KI_PREHEAT = 0.05; 115 | float PID_KD_PREHEAT = 350; 116 | // ***** SOAKING STAGE ***** 117 | float PID_KP_SOAK = 300; 118 | float PID_KI_SOAK = 0.05; 119 | float PID_KD_SOAK = 350; 120 | // ***** REFLOW STAGE ***** 121 | float PID_KP_REFLOW = 300; 122 | float PID_KI_REFLOW = 0.05; 123 | float PID_KD_REFLOW = 350; 124 | #define PID_SAMPLE_TIME 1000 125 | 126 | // ***** LCD MESSAGES ***** 127 | const char* ssdMessagesReflowStatus[] = { 128 | " Ready ", 129 | " Preheat ", 130 | " Soak ", 131 | " Reflow ", 132 | " Cool ", 133 | " Complete", 134 | " !HOT! ", 135 | " Error " 136 | }; 137 | 138 | // Pin Definitions 139 | int TopPin = 8; // Top Element 140 | int BotPin = 7; // Bottom Element 141 | int DoorPin =6; // Door Sense 142 | int BuzPin = A2; // Buzzer Pin 143 | int Led = 13; // Heartbeat Led 144 | 145 | int But1 = 9; // Start Button 146 | int But2 = 10; // Menu Button 147 | int But3 = 11; // Plus Button 148 | int But4 = 12; // Minus Button 149 | 150 | int thermocoupleCLKPin = A3; 151 | int thermocoupleSOPin = A4; 152 | int thermocoupleCSPin = A5; 153 | 154 | // ***** PID CONTROL VARIABLES ***** 155 | double setpoint; 156 | double input; 157 | double inputOld; //Store old Temperature 158 | double output; 159 | double kp = PID_KP_PREHEAT; 160 | double ki = PID_KI_PREHEAT; 161 | double kd = PID_KD_PREHEAT; 162 | int windowSize; 163 | unsigned long windowStartTime; 164 | unsigned long nextCheck; 165 | unsigned long nextRead; 166 | unsigned long timerSoak; 167 | unsigned long buzzerPeriod; 168 | boolean StartTest; 169 | 170 | // Reflow oven controller state machine state variable 171 | reflowState_t reflowState; 172 | // Reflow oven controller status 173 | reflowStatus_t reflowStatus; 174 | 175 | //Button Variables 176 | float MenuArray[14] = {TEMPERATURE_COOL,TEMPERATURE_SOAK_MIN,TEMPERATURE_SOAK_MAX,TEMPERATURE_REFLOW_MAX, 177 | PID_KP_PREHEAT,PID_KI_PREHEAT,PID_KD_PREHEAT, 178 | PID_KP_SOAK,PID_KI_SOAK,PID_KD_SOAK, 179 | PID_KP_REFLOW,PID_KI_REFLOW,PID_KD_REFLOW,0}; 180 | float PromTest = 0; 181 | byte ArrowArray[5] = {24,32,40,48,56}; 182 | byte ArrowIdx[13] = {0,1,2,3,0,1,2,0,1,2,0,1,2}; 183 | byte MathIdx[13] = {0,0,0,0,0,1,0,0,1,0,0,1,0}; 184 | boolean MenuFlag; 185 | boolean PlusFlag; 186 | boolean MinusFlag; 187 | 188 | byte ButtCount = 0; 189 | int MenuCount = -1; 190 | int PlusMinus = 0; 191 | 192 | // tc Error Counter 193 | int tcErrorCtr = 0; 194 | 195 | // Seconds timer 196 | int timerSeconds; 197 | 198 | // Library Setup 199 | // Specify PID control interface 200 | PID reflowOvenPID(&input, &output, &setpoint, kp, ki, kd, DIRECT); 201 | Adafruit_SSD1306 display(OLED_RESET); 202 | Adafruit_MAX31855 thermocouple(thermocoupleCLKPin, thermocoupleCSPin, thermocoupleSOPin); 203 | 204 | // Setup 205 | void setup() { 206 | // Setup Serial Baudrate 207 | Serial.begin(9600); 208 | 209 | // EEPROM Read 210 | PromTest = EEPROM.readFloat(0); 211 | if (PromTest == 0) // Assume EEPROM has never been written to 212 | { 213 | // Save Hard Coded Data to EEPROM 214 | for (int i = 0; i<12;i++){ 215 | EEPROM.updateFloat(i*4, MenuArray[i]); 216 | } 217 | } 218 | else 219 | { 220 | // Read Previously Saved Values and Update Pid Variables 221 | for (int i = 0; i<12;i++){ 222 | MenuArray[i] = EEPROM.readFloat(i*4); 223 | } 224 | 225 | TEMPERATURE_COOL = MenuArray[0]; 226 | TEMPERATURE_SOAK_MIN = MenuArray[1]; 227 | TEMPERATURE_SOAK_MAX = MenuArray[2]; 228 | TEMPERATURE_REFLOW_MAX = MenuArray[3]; 229 | PID_KP_PREHEAT = MenuArray[4]; 230 | PID_KI_PREHEAT = MenuArray[5]; 231 | PID_KD_PREHEAT = MenuArray[6]; 232 | PID_KP_SOAK = MenuArray[7]; 233 | PID_KI_SOAK = MenuArray[8]; 234 | PID_KD_SOAK = MenuArray[9]; 235 | PID_KP_REFLOW = MenuArray[10]; 236 | PID_KI_REFLOW = MenuArray[11]; 237 | PID_KD_REFLOW = MenuArray[12]; 238 | } 239 | 240 | // initialize the Led pin as an output. 241 | digitalWrite(BotPin, HIGH); 242 | pinMode(Led, OUTPUT); 243 | 244 | // Init Buttons 245 | pinMode(But1, INPUT); 246 | pinMode(But2, INPUT); 247 | pinMode(But3, INPUT); 248 | pinMode(But4, INPUT); 249 | 250 | // Init Elements 251 | pinMode(TopPin, OUTPUT); 252 | pinMode(BotPin, OUTPUT); 253 | pinMode(BuzPin, OUTPUT); 254 | 255 | digitalWrite(TopPin, LOW); 256 | digitalWrite(BotPin, LOW); 257 | digitalWrite(BuzPin, LOW); 258 | 259 | // by default, we'll generate the high voltage from the 3.3v line internally! (neat!) 260 | display.begin(SSD1306_SWITCHCAPVCC); 261 | 262 | //Display OHARARP Splash Screen 263 | display.clearDisplay(); 264 | display.drawBitmap(31,0, logo, 64, 64, 1); 265 | display.display(); 266 | delay(2000); 267 | 268 | // Set window size 269 | windowSize = 5000; 270 | // Initialize time keeping variable 271 | nextCheck = millis(); 272 | // Initialize thermocouple reading variable 273 | nextRead = millis(); 274 | // Set Relow Status = OFF 275 | reflowStatus = REFLOW_STATUS_OFF; 276 | StartTest = false; 277 | } 278 | 279 | // Begin Main Loop 280 | void loop() 281 | { 282 | // Current time 283 | unsigned long now; 284 | 285 | // Test for Start Button Input 286 | if (digitalRead(But1) == HIGH) 287 | { 288 | 289 | for (int i = 0; i<5;i++){ 290 | if (digitalRead(But1) == HIGH) 291 | { 292 | ButtCount++; 293 | tone(BuzPin,4100,100); //Buzz the Buzzer 294 | delay(250); 295 | //Serial.println( ButtCount); 296 | } 297 | } 298 | 299 | if (ButtCount>=5) 300 | { 301 | reflowState = REFLOW_STATE_IDLE; 302 | StartTest = true; 303 | } 304 | else 305 | { 306 | ButtCount = 0; 307 | StartTest = false; 308 | } 309 | } 310 | else 311 | { 312 | ButtCount = 0; 313 | StartTest = false; 314 | } 315 | 316 | // Read the Menu Button 317 | if (digitalRead(But2) == HIGH) 318 | { 319 | MenuCount++; 320 | tone(BuzPin,3100,100); //Buzz the Buzzer 321 | Serial.print("MenuCount = "); Serial.println(MenuCount); 322 | delay(250); 323 | MenuFlag = true; 324 | 325 | //Menu Overflow 326 | if (MenuCount>=14) 327 | { 328 | MenuCount = 0; 329 | } 330 | } 331 | 332 | // Read the Plus Button 333 | if (digitalRead(But3) == HIGH) 334 | { 335 | tone(BuzPin,3500,100); //Buzz the Buzzer 336 | delay(100); 337 | 338 | if (MathIdx[MenuCount]==1) 339 | { 340 | MenuArray[MenuCount]=MenuArray[MenuCount]+.005; 341 | //Serial.print(MenuCount);Serial.print(MenuArray[MenuCount]); 342 | } 343 | else 344 | { 345 | MenuArray[MenuCount]=MenuArray[MenuCount]+5; 346 | //Serial.print(MenuCount);Serial.print(MenuArray[MenuCount]); 347 | } 348 | MenuFlag = true; 349 | } 350 | 351 | // Read the Minus Button 352 | if (digitalRead(But4) == HIGH) 353 | { 354 | tone(BuzPin,3700,100); //Buzz the Buzzer 355 | delay(100); 356 | 357 | if (MathIdx[MenuCount]==1) 358 | { 359 | MenuArray[MenuCount]=MenuArray[MenuCount]-.005; 360 | } 361 | else 362 | { 363 | MenuArray[MenuCount]=MenuArray[MenuCount]-5; 364 | } 365 | MenuFlag = true; 366 | } 367 | 368 | if (MenuFlag == true) 369 | { 370 | if(MenuCount >= 0 && MenuCount <=3) 371 | { 372 | display.clearDisplay(); 373 | display.setCursor(0,0); 374 | display.setTextSize(2); 375 | display.setTextColor(WHITE); 376 | display.println(" Temp Menu"); 377 | display.drawLine(0, 16, 127, 16, WHITE); 378 | 379 | display.setTextSize(1); 380 | display.setCursor(0,ArrowArray[0]); 381 | display.print(" Cool Min = ");display.print(MenuArray[0],0);display.println(" C"); 382 | display.print(" Soak Min = ");display.print(MenuArray[1],0);display.println(" C"); 383 | display.print(" Soak Max = ");display.print(MenuArray[2],0);display.println(" C"); 384 | display.print(" Reflow Max = ");display.print(MenuArray[3],0);display.println(" C"); 385 | } 386 | 387 | if(MenuCount >= 4 && MenuCount <=6) 388 | { 389 | display.clearDisplay(); 390 | display.setCursor(0,0); 391 | display.setTextSize(2); 392 | display.setTextColor(WHITE); 393 | display.println(" Preheat"); 394 | display.drawLine(0, 16, 127, 16, WHITE); 395 | 396 | display.setTextSize(1); 397 | display.setCursor(0,ArrowArray[0]); 398 | display.print(" KP = ");display.println(MenuArray[4]); 399 | display.print(" KI = ");display.println(MenuArray[5],3); 400 | display.print(" KD = ");display.println(MenuArray[6]); 401 | } 402 | 403 | if(MenuCount >= 7 && MenuCount <=9) 404 | { 405 | display.clearDisplay(); 406 | display.setCursor(0,0); 407 | display.setTextSize(2); 408 | display.setTextColor(WHITE); 409 | display.println(" Soak"); 410 | display.drawLine(0, 16, 127, 16, WHITE); 411 | 412 | display.setTextSize(1); 413 | display.setCursor(0,ArrowArray[0]); 414 | display.print(" KP = ");display.println(MenuArray[7]); 415 | display.print(" KI = ");display.println(MenuArray[8],3); 416 | display.print(" KD = ");display.println(MenuArray[9]); 417 | } 418 | 419 | if(MenuCount >= 10 && MenuCount <=12) 420 | { 421 | display.clearDisplay(); 422 | display.setCursor(0,0); 423 | display.setTextSize(2); 424 | display.setTextColor(WHITE); 425 | display.println(" Reflow"); 426 | display.drawLine(0, 16, 127, 16, WHITE); 427 | display.setTextSize(1); 428 | 429 | display.setCursor(0,ArrowArray[0]); 430 | display.print(" KP = ");display.println(MenuArray[10]); 431 | display.print(" KI = ");display.println(MenuArray[11],3); 432 | display.print(" KD = ");display.println(MenuArray[12]); 433 | } 434 | 435 | if(MenuCount >= 13) // Store Settings to Memory and EEPROM 436 | { 437 | display.clearDisplay(); 438 | display.setCursor(0,0); 439 | display.setTextSize(2); 440 | display.setTextColor(WHITE); 441 | display.println(" Settings "); 442 | display.println(" Stored "); 443 | 444 | TEMPERATURE_COOL = MenuArray[0]; 445 | TEMPERATURE_SOAK_MIN = MenuArray[1]; 446 | TEMPERATURE_SOAK_MAX = MenuArray[2]; 447 | TEMPERATURE_REFLOW_MAX = MenuArray[3]; 448 | PID_KP_PREHEAT = MenuArray[4]; 449 | PID_KI_PREHEAT = MenuArray[5]; 450 | PID_KD_PREHEAT = MenuArray[6]; 451 | PID_KP_SOAK = MenuArray[7]; 452 | PID_KI_SOAK = MenuArray[8]; 453 | PID_KD_SOAK = MenuArray[9]; 454 | PID_KP_REFLOW = MenuArray[10]; 455 | PID_KI_REFLOW = MenuArray[11]; 456 | PID_KD_REFLOW = MenuArray[12]; 457 | 458 | // Save Data to EEPROM 459 | for (int i = 0; i<12;i++){ 460 | EEPROM.updateFloat(i*4, MenuArray[i]); 461 | } 462 | } 463 | 464 | if(MenuCount < 13) 465 | { 466 | display.setCursor(0,ArrowArray[ArrowIdx[MenuCount]]); 467 | display.print("->"); 468 | } 469 | display.display(); 470 | MenuFlag = false; // Stop Updating Display 471 | } 472 | 473 | //******************************************************************************************************** 474 | // Time to read thermocouple? 475 | if (millis() > nextRead) 476 | { 477 | // Read thermocouple next sampling period 478 | nextRead += SENSOR_SAMPLING_TIME; 479 | // Read current temperature 480 | inputOld = input; //Store Old Temperature 481 | input = thermocouple.readCelsius(); 482 | if(isnan(input)) 483 | { 484 | input=inputOld; 485 | tcErrorCtr++; 486 | 487 | if (tcErrorCtr >= 5) 488 | { 489 | // Illegal operation 490 | reflowState = REFLOW_STATE_ERROR; 491 | reflowStatus = REFLOW_STATUS_OFF; 492 | } 493 | } 494 | else 495 | { 496 | tcErrorCtr = 0; 497 | } 498 | } 499 | 500 | if (millis() > nextCheck) 501 | { 502 | // Check input in the next seconds 503 | nextCheck += 1000; 504 | // If reflow process is on going 505 | if (reflowStatus == REFLOW_STATUS_ON) 506 | { 507 | // Toggle LED as system heart beat 508 | digitalWrite(Led, !(digitalRead(Led))); 509 | // Increase seconds timer for reflow curve analysis 510 | timerSeconds++; 511 | // Send temperature and time stamp to serial 512 | Serial.print(timerSeconds); 513 | Serial.print(","); 514 | Serial.println(thermocouple.readInternal()); 515 | Serial.print(","); 516 | Serial.print(setpoint); 517 | Serial.print(","); 518 | Serial.print(input); 519 | Serial.print(","); 520 | Serial.println(output); 521 | 522 | // Send temperature and time stamp to display 523 | display.clearDisplay(); 524 | display.setCursor(0,0); 525 | display.setTextSize(2); 526 | display.setTextColor(BLACK,WHITE); 527 | display.println(ssdMessagesReflowStatus[reflowState]); 528 | 529 | display.setTextColor(WHITE); 530 | display.setTextSize(1.5); 531 | display.println(); 532 | display.print("Time = ");display.print(timerSeconds);display.println(" s"); 533 | display.print("Chip = ");display.print(thermocouple.readInternal());display.println(" C"); 534 | display.print("SP = ");display.print(setpoint);display.println(" C"); 535 | display.print("Board = ");display.print(input);display.println(" C"); 536 | display.print("PID = ");display.print(output);display.println(" "); 537 | display.display(); 538 | } 539 | else 540 | { 541 | // Turn off LED 542 | digitalWrite(Led, HIGH); 543 | } 544 | 545 | // If currently in error state 546 | if (reflowState == REFLOW_STATE_ERROR) 547 | { 548 | // No thermocouple wire connected 549 | display.clearDisplay(); 550 | display.setCursor(0,0); 551 | display.setTextSize(2); 552 | display.setTextColor(WHITE); 553 | display.print("TC Error!"); 554 | display.display(); 555 | } 556 | } 557 | 558 | // Refresh The Display 559 | 560 | 561 | // Reflow oven controller state machine 562 | switch (reflowState) 563 | { 564 | case REFLOW_STATE_IDLE: 565 | // If oven temperature is still above room temperature 566 | if (input >= TEMPERATURE_COOL) 567 | { 568 | reflowState = REFLOW_STATE_TOO_HOT; 569 | // No thermocouple wire connected 570 | display.clearDisplay(); 571 | display.setCursor(0,0); 572 | display.setTextSize(2); 573 | display.setTextColor(BLACK,WHITE); 574 | display.println(" - HOT - "); 575 | display.println(input); 576 | display.display(); 577 | } 578 | else 579 | { 580 | if (StartTest == true) 581 | { 582 | display.clearDisplay(); 583 | display.setCursor(0,0); 584 | display.setTextSize(2); 585 | display.setTextColor(BLACK,WHITE); 586 | display.print(" Begin "); 587 | display.display(); 588 | 589 | // Send header for CSV file 590 | //Serial.println("Time Setpoint Input Output"); 591 | // Intialize seconds timer for serial debug information 592 | timerSeconds = 0; 593 | // Initialize PID control window starting time 594 | windowStartTime = millis(); 595 | // Ramp up to minimum soaking temperature 596 | setpoint = TEMPERATURE_SOAK_MIN; 597 | // Tell the PID to range between 0 and the full window size 598 | reflowOvenPID.SetOutputLimits(0, windowSize); 599 | reflowOvenPID.SetSampleTime(PID_SAMPLE_TIME); 600 | // Turn the PID on 601 | reflowOvenPID.SetMode(AUTOMATIC); 602 | // Proceed to preheat stage 603 | reflowState = REFLOW_STATE_PREHEAT; 604 | StartTest = false; 605 | } 606 | } 607 | break; 608 | 609 | case REFLOW_STATE_PREHEAT: 610 | reflowStatus = REFLOW_STATUS_ON; 611 | // If minimum soak temperature is achieve 612 | if (input >= TEMPERATURE_SOAK_MIN-2.5) 613 | { 614 | // Chop soaking period into smaller sub-period 615 | timerSoak = millis() + SOAK_MICRO_PERIOD; 616 | // Set less agressive PID parameters for soaking ramp 617 | reflowOvenPID.SetTunings(PID_KP_SOAK, PID_KI_SOAK, PID_KD_SOAK); 618 | // Ramp up to first section of soaking temperature 619 | setpoint = TEMPERATURE_SOAK_MIN + SOAK_TEMPERATURE_STEP; 620 | // Proceed to soaking state 621 | reflowState = REFLOW_STATE_SOAK; 622 | } 623 | break; 624 | 625 | case REFLOW_STATE_SOAK: 626 | // If micro soak temperature is achieved 627 | if (millis() > timerSoak) 628 | { 629 | timerSoak = millis() + SOAK_MICRO_PERIOD; 630 | // Increment micro setpoint 631 | setpoint += SOAK_TEMPERATURE_STEP; 632 | if (setpoint > TEMPERATURE_SOAK_MAX) 633 | { 634 | // Set agressive PID parameters for reflow ramp 635 | reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW); 636 | // Ramp up to first section of soaking temperature 637 | setpoint = TEMPERATURE_REFLOW_MAX; 638 | // Proceed to reflowing state 639 | reflowState = REFLOW_STATE_REFLOW; 640 | } 641 | } 642 | break; 643 | 644 | case REFLOW_STATE_REFLOW: 645 | // We need to avoid hovering at peak temperature for too long 646 | // Crude method that works like a charm and safe for the components 647 | if (input >= (TEMPERATURE_REFLOW_MAX-5.0)) 648 | { 649 | // Set PID parameters for cooling ramp 650 | reflowOvenPID.SetTunings(PID_KP_REFLOW, PID_KI_REFLOW, PID_KD_REFLOW); 651 | // Ramp down to minimum cooling temperature 652 | setpoint = TEMPERATURE_COOL; 653 | // Proceed to cooling state 654 | reflowState = REFLOW_STATE_COOL; 655 | 656 | // Turn Elements Off 657 | digitalWrite(TopPin, LOW); 658 | digitalWrite(BotPin, LOW); 659 | 660 | // Signal to Open Door 661 | for (int i = 0; i<10;i++){ 662 | tone(BuzPin,4100,100); //Buzz the Buzzer 663 | delay(250); 664 | } 665 | 666 | } 667 | break; 668 | 669 | case REFLOW_STATE_COOL: 670 | // If minimum cool temperature is achieve 671 | if (input <= TEMPERATURE_COOL) 672 | { 673 | // Retrieve current time for buzzer usage 674 | buzzerPeriod = millis() + 1000; 675 | 676 | for (int i = 0; i<10;i++){ 677 | tone(BuzPin,4100,500); //Buzz the Buzzer 678 | delay(250); 679 | } 680 | 681 | reflowStatus = REFLOW_STATUS_OFF; 682 | // Proceed to reflow Completion state 683 | reflowState = REFLOW_STATE_COMPLETE; 684 | } 685 | break; 686 | 687 | case REFLOW_STATE_COMPLETE: 688 | if (millis() > buzzerPeriod) 689 | { 690 | reflowState = REFLOW_STATE_IDLE; 691 | } 692 | break; 693 | 694 | case REFLOW_STATE_TOO_HOT: 695 | // If oven temperature drops below room temperature 696 | if (input < TEMPERATURE_COOL) 697 | { 698 | // Ready to reflow 699 | reflowState = REFLOW_STATE_IDLE; 700 | } 701 | break; 702 | 703 | case REFLOW_STATE_ERROR: 704 | // If thermocouple problem is still present 705 | if(isnan(input)) 706 | { 707 | // Wait until thermocouple wire is connected 708 | reflowState = REFLOW_STATE_ERROR; 709 | } 710 | else 711 | { 712 | // Clear to perform reflow process 713 | reflowState = REFLOW_STATE_IDLE; 714 | } 715 | break; 716 | } 717 | 718 | // PID computation and SSR control 719 | if (reflowStatus == REFLOW_STATUS_ON) 720 | { 721 | now = millis(); 722 | 723 | reflowOvenPID.Compute(); 724 | 725 | if((now - windowStartTime) > windowSize) 726 | { 727 | // Time to shift the Relay Window 728 | windowStartTime += windowSize; 729 | } 730 | if(output > (now - windowStartTime)) 731 | { 732 | digitalWrite(TopPin, HIGH); 733 | digitalWrite(BotPin, HIGH); 734 | } 735 | else 736 | { 737 | digitalWrite(TopPin, LOW); 738 | digitalWrite(BotPin, LOW); 739 | } 740 | } 741 | // Reflow oven process is off, ensure oven is off 742 | else 743 | { 744 | digitalWrite(TopPin, LOW); 745 | digitalWrite(BotPin, LOW); 746 | } 747 | 748 | } 749 | 750 | -------------------------------------------------------------------------------- /Operation/Images/0_Logo.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/0_Logo.JPG -------------------------------------------------------------------------------- /Operation/Images/10_ReflowCyclePeak.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/10_ReflowCyclePeak.JPG -------------------------------------------------------------------------------- /Operation/Images/11_CoolCycle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/11_CoolCycle.JPG -------------------------------------------------------------------------------- /Operation/Images/1_TempMenu.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/1_TempMenu.JPG -------------------------------------------------------------------------------- /Operation/Images/2_PreheatMenu.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/2_PreheatMenu.JPG -------------------------------------------------------------------------------- /Operation/Images/3_SoakMenu.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/3_SoakMenu.JPG -------------------------------------------------------------------------------- /Operation/Images/4_ReflowMenu.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/4_ReflowMenu.JPG -------------------------------------------------------------------------------- /Operation/Images/5_SettingsStored.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/5_SettingsStored.JPG -------------------------------------------------------------------------------- /Operation/Images/7_PreheatCycle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/7_PreheatCycle.JPG -------------------------------------------------------------------------------- /Operation/Images/8_SoakCycle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/8_SoakCycle.JPG -------------------------------------------------------------------------------- /Operation/Images/9_ReflowCycle.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/Operation/Images/9_ReflowCycle.JPG -------------------------------------------------------------------------------- /Operation/README.md: -------------------------------------------------------------------------------- 1 | This is the initial starup screen after power up. 2 | 3 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/0_Logo.JPG "Initial Logo") 4 | 5 | #Start a Reflow Profile: 6 | By default this reflow oven is set to run out of the box. A reflow procedure can be started by simply pressing and holding the "Start" button for 6 seconds. During this time a succession of 6 "beeps" from the piezo buzzer will be heard. The oven will now cycle through the Preheat, Soak, and Reflow profiles to properly reflow your pcbs. The buzzer will sound when the cool cycle begins. It is suggested that the oven door be opened to allow the reflowed assembly to cool more quickly. A fan can also be used to increase airflow and the cooling of the reflowed pcb. 7 | 8 | 9 | #Changing Reflow Profile and PID settings: 10 | By default the reflow controller is set with PID parameters that we have found to be nearly optimal for a leaded profile. There should not need to be any reason that you should need to change the default parameters. However, if you need to change the profile or the settings you can do this following the steps below. These settings can be changed without modifying the firmware on the Arduino compatible controller (Atmega 32U4). 11 | 12 | By pressing the menu button it is possible to cycle through the oven settings. Unlike previous code efforts these menu options can be changed to allow for different reflow profiles for leaded and non-leaded solder. **Settings are stored in EEPROM after completely cycling through all of the settings**. The default settings are used for the Black and Decker Infrawave ovens. You may need to adjust these settings based on your particular application. The arrow indicates the setting that is to be changed. The setting can be changed by pressing the plus and minus buttons on the control pad. 13 | 14 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/1_TempMenu.JPG "Temperature Menu") 15 | 16 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/2_PreheatMenu.JPG "Preheat Menu") 17 | 18 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/3_SoakMenu.JPG "Soak Menu") 19 | 20 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/4_ReflowMenu.JPG "Reflow Menu") 21 | 22 | ![Logo Title] (https://raw.github.com/ohararp/ReflowOven/master/Operation/Images/5_SettingsStored.JPG "Settings Stored") 23 | 24 | 25 | -------------------------------------------------------------------------------- /PcbDesignFiles/PanelLayout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/PanelLayout.jpg -------------------------------------------------------------------------------- /PcbDesignFiles/PanelReal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/PanelReal.jpg -------------------------------------------------------------------------------- /PcbDesignFiles/README.md: -------------------------------------------------------------------------------- 1 | These are the design files for the current version of the Reflow Oven Controller and Power Boards. 2 | 3 | ![Pcb Design Title] (https://github.com/ohararp/ReflowOven/blob/master/PcbDesignFiles/PanelLayout.jpg?raw=true "Panel layout") 4 | -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowControllerC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowControllerC.jpg -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowControllerC_Bom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowControllerC_Bom.pdf -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowPanelC - CADCAM.ZIP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowPanelC - CADCAM.ZIP -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowPanelC.pdsprj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowPanelC.pdsprj -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowPowerC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowPowerC.jpg -------------------------------------------------------------------------------- /PcbDesignFiles/ReflowPowerC_Bom.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ohararp/ReflowOven/74d920a97ac918131fe3843abee336fddcbc1483/PcbDesignFiles/ReflowPowerC_Bom.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Infrawave Oven: 2 | 3 | Recently I viewed Ben Heck's Reflow Oven Video and was pretty impressed with the time response of this oven. Ben uses a SSR and an external Arduino based controller to run his oven. I really like this standalone solution. Other research revealed Hobbybotics Reflow Controller and this is a very impressive build. Lots of background on PID and detailed build analysis is provided. This controller appears to be computer controlled and requires an external control box. Coupled with the handy Rocket Scream Reflow Controller Shield and Arduino source code I though I would come up with a new and novel solution to control the Black and Decker Infrawave Oven as shown below. 4 | 5 | Black and Decker Infrawave Oven 6 | 7 | Why do this?: 8 | I am in the process of releasing a whole line of led matrix products. Part of this business decision has been to bring in as much in-house manufacturing as possible. We have already received and installed our Quad IVc pick and place. This has pretty much tapped our current budget and I needed another method that would provide for a proper reflow profile of the boards I am working with. The hot plate method has worked well for us, but I have noticed a number of cold solder joints on our boards recently and this has been secretly driving me crazy. In order to properly reflow solder paste it is required to properly heat the solder to get good results as shown below. Based on my part failures I was clearly not achieving the recommend profile. 9 |

kester2

10 | I ran some tests evaluate what the reflow profile of the hotplate I was using really was and was pretty disappointed. The pcb temperature never rose above 200C. I previously attempted using a cheap reflow oven and was not happy with the performance of this unit either. It was an Oster unit with standard resistive elements. It took forever to heat up. I ran some "full on" tests on this unit to characterize its poor performance. The unit has incredibly poor rise rates of less than 0.5 C/s and the unit eventually reaches 227 deg C but only after 600 seconds. There is not enough overhead for this unit to control a full ramp reflow profile for a lead solder, much less a lead free solder. 11 |

OsterOn

12 | Teardown: 13 | 14 | Based upon Ben Heck's video I placed an order on Amazon for this oven. For $106 and Amazon Prime shipping I had the oven here in 2 days. Can't beat that! I looked around in town briefly and was unable to find this unit in any of the big box stores. It seems there was timewhere it was hard to source these ovens for awhile. Amazon seems to have made this alot easier these days. Once the unit I arrived I tore down the unit much like Ben did. When I got down to it I found two different pcbs that were used to operate the oven. The first was the main relay board that controls the top and bottom elements as shown below. 15 |

OrginalControlBoards

16 | They are one sided pcbs that very effectively cram a combination of smd and thru hole parts to control the oven. There is no temperature control built into this oven. Everything is based upon predetermined profiles. Pretty impressive if you ask me. The first board is a menu control board that communicates the users intent to the power management board. This unit uses a Holtek IC anc controls a small lcd, numerous button inputs, and several leds. The second board, contains the non-isolated power supply, 2 power relays (top and bottom elements), and the door switch input. Both are neatly tied together with a wire harness. All power input and elements are neatly wired with blade connectors. Altogether it quickly appears that by replacing these 2 boards I could effectively "hack" the oven with my own controller and input boards to make for a neat and professional package that uses the units existing LCD view window and button pads. 17 | 18 | With this in mind I decided to create a wish list of features that I would want: 19 | 20 | Control Board: 21 | 1. Leverage existing PID code 22 | 2. Oled 128x64 Display 23 | 3. Serial Bootloading 24 | 4. Wireless Data Output 25 | 26 | Power Board: 27 | 1. Isolated 5V Power supply 28 | 2. Triac Based Element Control 29 | 3. Door Switch Input (not implemented in code) 30 | 31 | Below you can see the schematic of the control board that fits these requirements. It uses an Atmega 32U4 running at 8MHz and 3.3V. Running at 3.3V will allow the uController to talk directly to the SSD1306 OLED without logic level translation. 32 |

ReflowControllerA

33 |

The power control board provides for a nice isolated input using the FSK-S5-5U from CUI/Digikey. To control the top and bottom elments 2 25 A BTAT25 smd triacs were used with MOC3032M zero cross detecting optocouplers.

34 |

ReflowPowerA

35 | PCB Design: 36 | 37 | One of the great parts of our Stencil business is having access to the 45W CO2 Laser for cutting of plastics. Armed with some calipers I proceeded to reverse engineer the shapes of the pcbs, mounting locations, and button and led locations. Using Corel Draw I came up with the shapes you see here. Cutting these on the laser allowed me to make sure the boards would fit prior to designing and ordering pcbs that wouldn't fit. Good thing since it took 4 or 5 times to make sure everything would line up. 38 |

PcbReverseEngineer

39 | Using these designs I was able to create the pcb board outlines and properly place all of the required parts. I use a Labcetner's Proteus Design Package to do my board layout. Luckily, I could leverage a number of known circuits and working designs for this project and layout went quickly. Care was taken to make sure that all the parts would be mounted in the oven without having to modify the interior components. Knowing that this was going to be a quick turn project I knew ahead of time that I was going to be using bare pcbs (no soldermask). I made sure to keep large spacing between pads and the ground and power planes. The results of this effort can be seen below. 40 |

BareBonesCombo

41 | Assembly: 42 | 43 | Reflow Panel 44 | 45 | Initial Testing: 46 | 47 | Full On - With the oven reassembled a couple of tests were run to determine the performance of the oven. The first was a full on test to see the max potential of this setup. The top graph shows the temperature of the unit over time. This shows a max temp acheived of 300C. I think the oven could have gone higher but the smoking pcb that was used as a dummy prevented this. The burnt fiberglass smell has only gone away after a week. The bottom graph is the derivative of the time data and allows us to determine the rise and fall rate of the oven. Since the data was sampled on the second this calculation was pretty easy to do. Basically, the unit is able to handle 1+ deg/s rise rate and greater than this on the cool down. Based off this data it is clear that this oven offers a lot of potential. 48 |

FullOn

49 |

Actual Reflow Testing: 50 | The image below shows how smoothly things went. I reused the existing piezo buzzer from the original pcbs and added some code to have the unit beep at me after the max reflow temperature is reached. At this time the door is opened and the unit is allowed to cool.

51 | Control3 52 | 53 | MatrixReflow 54 | 55 | Startup Video: 56 | 57 | http://youtu.be/EhMYh9KmT7Y 58 | 59 | Soak Video: 60 | 61 | http://youtu.be/6kIh7mlD550 62 | 63 | ReflowVideo: 64 | 65 | http://youtu.be/iLTvkUca_Ug 66 | 67 | Cool Down: 68 | 69 | http://youtu.be/FBCPu6zQ0Fg 70 | 71 | Final Inspection: 72 | 73 | http://youtu.be/jnSopUsd7fs 74 | 75 | Conclusion: 76 | Overall, this was a great project and I am confident that this oven can be used regularly for reflow. Having the controlled profile allows me to do other things while pcbs are reflowing. I am glad I could leverage the work of the open source community and come up with this great project. 77 | 78 | The bulk of the control code was a modification of the the Rocket Scream Control Code. The code I used can be found on Github. 79 | --------------------------------------------------------------------------------