S kolegami sa chodievame od neskorého leta do jari otužovať a chcel som vedieť aká je tá voda vlastne teplá, teda skôr aká je studená. Doma som použil už viac krát presné Maximácke 1-wire teplomery DS18B20, takže voľba snímača bola jasná. Medzi hračkami sa povaľoval aj lacný OLED displej z ebay-u (ešte lacnejší…),ktorý má I2C rozhranie a radič SSD1306. Celé je to tak jednoduché, že by bol hriech nevyužiť maličký 8-pinový ATTINY85 (8kB FLASH, 2kB SRAM), ktorý kúpite aj u nás za 2 eurá, žiaľ v SMD prevedení jedine cez net.
8kB na program nie je veľa, preto som použil len dve knižnice – TinyWireM a OneWire. Zapojenie je úplne jednoduché, dá sa použiť aj univerzálny plošný spoj, fantázii sa medze nekladú.
Tu je celý kód (na stiahnutie ZIP), vysvetlenie a návod pod ním + návod ako program nahrať do mikroprocesoru.
#include <TinyWireM.h> #include <OneWire.h> #include "font6x8.h" #include "font8X16.h" #define SSD1306_SA 0x3C // adresa OLED displeja OneWire ds(4); // HW PIN 3 byte adrT1[8] = {0x28, 0x4B, 0x6F, 0x88, 0x04, 0x00, 0x00, 0xB6}; //unikatny identifikator/adresa snimaca void setup(){ TinyWireM.begin(); ds.reset_search(); ssd1306_init(); ssd1306_fillscreen(0x00); ssd1306_char_f6x8(0, 0, "Aktualna teplota"); } void loop() { byte data[12]; char cc1[20]; ds.reset(); ds.select(adrT1); ds.write(0x44, 1); // zacni meranie teploty delay(1000); // aspon 750ms, radsej viac, neponahlame sa ds.reset(); ds.select(adrT1); ds.write(0xBE); // precitaj scratchpad for (byte i = 0; i < 9; i++) data[i] = ds.read(); float celsius = ((data[1] << 8) + data[0]) * 0.0625; dtostrf(celsius,5,2,cc1); //skonvertuj double na char* ssd1306_char_f8x16(0, 2, cc1); //vypis teplotu ssd1306_char_f8x16(45, 2, "`C"); //a symbol stupnov delay(500); } // ---------------------------------------------------------------------------- void ssd1306_init(void){ byte cmds[] = {0xAE, 0xA8, 0x3F, 0xD3, 0x00, 0xB0, 0x00, 0x10, 0x20, 0x00, 0x40, 0x81, 0xCF, 0xA1, 0xC8, 0xA6, 0xD5, 0x80, 0xD9, 0xF1, 0xDA, 0x12, 0xDB, 0x30, 0x2E, 0x8D, 0x14, 0xAF}; for(byte i = 0; i < sizeof(cmds); i++) ssd1306_send_command(cmds[i]); } void ssd1306_send_command(uint8_t command){ TinyWireM.beginTransmission(SSD1306_SA); TinyWireM.send(0x80); TinyWireM.send(command); TinyWireM.endTransmission(); } void ssd1306_send_data(uint8_t data){ TinyWireM.beginTransmission(SSD1306_SA); TinyWireM.send(0x40); TinyWireM.send(data); TinyWireM.endTransmission(); } void ssd1306_setpos(uint8_t x, uint8_t y){ TinyWireM.beginTransmission(SSD1306_SA); TinyWireM.send(0x00); TinyWireM.send(0xb0+y); TinyWireM.send(((x&0xf0)>>4)|0x10); TinyWireM.send((x&0x0f)|0x01); TinyWireM.endTransmission(); } void ssd1306_fillscreen(uint8_t fill_Data){ uint8_t m,n; for(m=0;m<8;m++){ ssd1306_send_command(0xb0+m); //page0-page1 ssd1306_send_command(0x00); //low column start address ssd1306_send_command(0x10); //high column start address for(n=0;n<128;n++) ssd1306_send_data(fill_Data); } } void ssd1306_char_f6x8(uint8_t x, uint8_t y, const char ch[]){ uint8_t c,i,j=0; while(ch[j] != '\0'){ c = ch[j] - 32; if(x>126){ x=0; y++; } ssd1306_setpos(x,y); for(i=0;i<6;i++) ssd1306_send_data(pgm_read_byte(&ssd1306xled_font6x8[c*6+i])); x += 6; j++; } } void ssd1306_char_f8x16(uint8_t x, uint8_t y,const char ch[]){ uint8_t c=0,i=0,j=0; while (ch[j]!='\0'){ c = ch[j] - 32; if (x>120){ x=0; y++; } ssd1306_setpos(x,y); for(i=0;i<8;i++) ssd1306_send_data(pgm_read_byte(&ssd1306xled_font8X16[c*16+i])); ssd1306_setpos(x,y+1); for(i=0;i<8;i++) ssd1306_send_data(pgm_read_byte(&ssd1306xled_font8X16[c*16+i+8])); x+=8; j++; } }
Fonty a grafické funkcie som trochu upravil (zdroj) pre moje potreby a samotný kód v hlavnej slučke loop je taký jednoduchý, že hádam stačia len komentáre v kóde. Skompilovaný kód má necelých 7kB, ale dal by sa ešte trochu osekať, hlavne ak by sa použil len jeden font, prípadne fonty uložiť do externej I2C EEPROM – ale nebolo treba. Na krabičku by sa zišla 3D tlačiareň – ale bude musieť stačiť krabička od Tic-Tac 🙂 No a napájane zabezpečí aj CR2032 3V batéria, odber cca 6mA.
Pridaj komentár