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