|
/** |
|
* Jednoduchá meteo stanice, která měří aktuální teplotu |
|
* pomocí termistoru na analogovém pinu A0. |
|
* |
|
* Výsledky měření se zobrazují na 2x16 LCD displeji |
|
* připojeném přes I2C sběrnici. |
|
* |
|
* Pomocí dvou tlačítek lze měnit hodnoty, které se na |
|
* displeji zobrazují. |
|
*/ |
|
|
|
#include <LiquidCrystal_I2C.h> |
|
|
|
#define THERMISTOR_PIN A0 |
|
#define BUTTON_A_PIN 2 |
|
#define BUTTON_B_PIN 3 |
|
|
|
#define R1 (9.78) // Rezistor R1 na napěťovém děliči, kOhm |
|
#define R0 (10.0) // Rezistivita termistoru při teplotě T0, kOhm |
|
#define T0 298.15 // Teplota T0 termistoru, Kelvin |
|
#define B 4050.0 // Beta parametr použitého termistoru, Kelvin |
|
|
|
// Speciální symboly pro LCD displej. |
|
// Pro potřeby naší meteo stanice definujeme 3 speciální |
|
// znaky: znak stupně, "e" s čárkou, "u" s kroužkem a |
|
// řecké písmeno Omega. |
|
// Tyto znaky budou uloženy v paměti LCD pod čísly 1 až 4. |
|
// Pomůcka: https://maxpromer.github.io/LCD-Character-Creator/ |
|
byte stupen[] = { |
|
B01110, B01010, B01110, B00000, |
|
B00000, B00000, B00000, B00000 |
|
}; |
|
|
|
byte e_dlouhe[] = { |
|
B01010, B00100, B01110, B10001, |
|
B11110, B10000, B01110, B00000 |
|
}; |
|
|
|
byte u_krouzek[] = { |
|
B00110, B00110, B10001, B10001, |
|
B10001, B10011, B01101, B00000 |
|
}; |
|
|
|
byte omega[] = { |
|
B00000, B00000, B01110, B10001, |
|
B10001, B01010, B11011, B00000 |
|
}; |
|
|
|
// Inicializace knihovny LiquidCrystal pro ovládání |
|
// 2x16 LCD displeje přes I2C sběrnici. |
|
LiquidCrystal_I2C lcd(0x27, 16, 2); |
|
|
|
static bool display_update = false; |
|
static int8_t display_value = 0; |
|
|
|
static uint16_t temperature_measurement = 0; |
|
static uint16_t temperature_adc = 0; |
|
static float temperature_resistivity = 0; |
|
static float temperature_current = 0; |
|
static float temperature_average = 0; |
|
|
|
// Stavové proměnné obou tlačítek A a B. |
|
// Hodnota `true` znamená, že tlačítko bylo aktivováno. |
|
volatile bool button_A_state = false; |
|
volatile bool button_B_state = false; |
|
|
|
static uint32_t last_temperature_measurement = 0; |
|
static uint32_t last_display_update = 0; |
|
|
|
// Obsluha přerušení pro tlačítko A. |
|
void button_A_handler() { |
|
static unsigned long last_interrupt_time = 0; |
|
unsigned long interrupt_time = millis(); |
|
|
|
// Pokud přerušení přijde v kratší době jak 200 ms od |
|
// posledního přerušení, považujeme takovou událost za |
|
// zákmit a ignorujeme. |
|
if (interrupt_time - last_interrupt_time > 200) { |
|
button_A_state = true; |
|
} |
|
|
|
last_interrupt_time = interrupt_time; |
|
} |
|
|
|
// Obsluha přerušení pro tlačítko B. |
|
// Tento kód je téměř identický s obsluhou tlačítka A. |
|
void button_B_handler() { |
|
static unsigned long last_interrupt_time = 0; |
|
unsigned long interrupt_time = millis(); |
|
|
|
// Pokud přerušení přijde v kratší době jak 200 ms od |
|
// posledního přerušení, považujeme takovou událost za |
|
// zákmit a ignorujeme. |
|
if (interrupt_time - last_interrupt_time > 200) { |
|
button_B_state = true; |
|
} |
|
|
|
last_interrupt_time = interrupt_time; |
|
} |
|
|
|
void setup() { |
|
Serial.begin(9600); |
|
|
|
// Inicializace LCD knihovny, zapnutí podsvícení |
|
// a uložení speciálních znaků do paměti LCD. |
|
lcd.init(); |
|
lcd.clear(); |
|
lcd.backlight(); |
|
lcd.createChar(1, stupen); |
|
lcd.createChar(2, e_dlouhe); |
|
lcd.createChar(3, u_krouzek); |
|
lcd.createChar(4, omega); |
|
|
|
// Tímto aktivujeme obsluhu přerušení pro piny 2 a 3, na kterých máme |
|
// připojeny tlačítka A a B. |
|
// Obsluha bude reagovat pouze na sestupnou hranu (falling edge) |
|
// signálu tlačítka. |
|
attachInterrupt(digitalPinToInterrupt(BUTTON_A_PIN), button_A_handler, FALLING); |
|
attachInterrupt(digitalPinToInterrupt(BUTTON_B_PIN), button_B_handler, FALLING); |
|
} |
|
|
|
void loop() { |
|
// Do proměnné `now` si uložíme aktuální počet milisekund |
|
// od posledního restartu. Tímto si počítáme čas potřebný |
|
// k měření teploty. |
|
uint32_t now = millis(); |
|
|
|
if(button_A_state) { |
|
display_value++; |
|
display_value = constrain(display_value, 0, 3); |
|
Serial.print("Zobrazuji "); Serial.println(display_value); |
|
display_update = true; |
|
button_A_state = false; |
|
} |
|
|
|
if(button_B_state) { |
|
display_value--; |
|
display_value = constrain(display_value, 0, 3); |
|
Serial.print("Zobrazuji "); Serial.println(display_value); |
|
display_update = true; |
|
button_B_state = false; |
|
} |
|
|
|
// Jednou za 1000 ms provedeme měření teploty a její |
|
// zobrazení na displeji. |
|
if((now - last_temperature_measurement) > 1000) { |
|
last_temperature_measurement = now; |
|
|
|
// Převod analogové hodnoty napětí na termistoru |
|
// na rezistivitu. |
|
uint16_t adc = analogRead(THERMISTOR_PIN); |
|
float R_temp = (R1 * adc) / (1024 - adc); |
|
|
|
// Sheinhart-Hart výpočet teploty z rezistivity |
|
// termistoru. |
|
float steinhart = R_temp / R0; |
|
steinhart = log(steinhart); // Přirozený logaritmus |
|
steinhart /= B; |
|
steinhart += (1 / T0); |
|
steinhart = 1 / steinhart; |
|
steinhart -= 273.15; |
|
|
|
temperature_adc = adc; |
|
temperature_resistivity = R_temp; |
|
temperature_current = steinhart; |
|
temperature_average += steinhart; |
|
temperature_measurement++; |
|
|
|
Serial.print("T1:"); |
|
Serial.println(steinhart); |
|
} |
|
|
|
// Hodnoty na displeji budeme aktualizovat jednou za 1000 ms |
|
// nebo pokud je nastavena proměnná `display_update`. |
|
if((display_update) || ((now - last_display_update) > 1000)) { |
|
display_update = false; |
|
|
|
if(display_value == 0) { |
|
lcd.setCursor(0, 0); |
|
lcd.print("Aktualni teplota"); |
|
lcd.setCursor(0, 1); |
|
lcd.print(temperature_current); |
|
lcd.print("\1C "); |
|
} else if(display_value == 1) { |
|
lcd.setCursor(0, 0); |
|
lcd.print("Pr\3m\2rna teplota"); |
|
lcd.setCursor(0, 1); |
|
lcd.print(temperature_average / temperature_measurement); |
|
lcd.print("\1C "); |
|
} else if(display_value == 2) { |
|
lcd.setCursor(0, 0); |
|
lcd.print("Rezistivita "); |
|
lcd.setCursor(0, 1); |
|
lcd.print(temperature_resistivity); |
|
lcd.print(" k\4 "); |
|
} else if(display_value == 3) { |
|
lcd.setCursor(0, 0); |
|
lcd.print("Hodnota ADC "); |
|
lcd.setCursor(0, 1); |
|
lcd.print(temperature_adc); |
|
lcd.print(" "); |
|
} |
|
} |
|
} |