#include <OneWire.h>
#include <DallasTemperature.h>
struct Pins {
unsigned int button_1_pin;
unsigned int button_2_pin;
unsigned int button_3_pin;
unsigned int led_pin;
unsigned int onewire_pin;
};
enum class ButtonPress {
Button1,
Button2,
Button3,
None
};
class TemperatureInterface {
private:
Pins pins;
OneWire onewire;
DallasTemperature sensor;
byte address[8];
bool isOperational = false;
unsigned long last_press = 0;
ButtonPress process_buttons(){
if (millis() - last_press < 200){
return ButtonPress::None;
}
if (!digitalRead(this->pins.button_1_pin)){
this->last_press = millis();
return ButtonPress::Button1;
}
else if (!digitalRead(this->pins.button_2_pin)){
this->last_press = millis();
return ButtonPress::Button2;
}
else if (!digitalRead(this->pins.button_3_pin)){
this->last_press = millis();
return ButtonPress::Button3;
}
return ButtonPress::None;
}
float* take_18_oneshots(){
float* data = new float[18]();
for (int i = 0; i<18; i++){
float temp = this->one_shot();
data[i] = temp;
digitalWrite(this->pins.led_pin, HIGH);
delay(2);
digitalWrite(this->pins.led_pin, LOW);
}
return data;
}
void sort_18(float *data){
for(int i = 0; i < 18; i++){
for(int j = 0; j < 18 - i; j++){
if(data[j] > data[j+1]){
// Zamiana miejscami elementów
float temp = data[j];
data[j] = data[j+1];
data[j+1] = temp;
}
}
}
}
float avg_16_center(float *data){
float sum = 0;
for (int i = 1; i < 17; i++){
sum += data[i];
}
return sum/16;
}
int average(int *data, int count, int start) {
long sum = 0;
for (int i = start; i < count; ++i) {
sum += data[i];
}
int log2Count = 0;
int n = count;
while (n >>= 1) ++log2Count;
return (int)((sum >> log2Count) + ((sum & ((1 << log2Count) - 1)) >= (1 << (log2Count - 1)) ? 1 : 0));
}
void castFloatsToInts(float* floatArray, int* intArray, int size) {
for (int i = 0; i < size; ++i) {
intArray[i] = (int)floatArray[i];
}
}
public:
TemperatureInterface(Pins pins) : onewire(pins.onewire_pin), pins(pins) {
this->sensor = DallasTemperature(&onewire);
memset(address, 0, sizeof(address));
}
void init(){
this->onewire.reset_search();
while(this->onewire.search(this->address)){
if (this->address[0] != 0x28)
continue;
break;
}
this->sensor.begin();
pinMode(this->pins.button_1_pin, INPUT_PULLUP);
pinMode(this->pins.button_2_pin, INPUT_PULLUP);
pinMode(this->pins.button_3_pin, INPUT_PULLUP);
pinMode(this->pins.led_pin, OUTPUT);
this->isOperational = true;
}
void print_address(){
Serial.print('[');
for(int i = 0; i < 8; i++){
Serial.print(this->address[i], HEX);
Serial.print(',');
}
Serial.println(']');
}
float one_shot(){
if(!this->isOperational)
return -1;
sensor.requestTemperatures();
return this->sensor.getTempC(this->address);
}
void update(){
switch (this->process_buttons()){
case ButtonPress::Button1 :
Serial.print("Pomiar oneshot: ");
Serial.println(this->one_shot());
break;
case ButtonPress::Button2 :
{
Serial.print("Pomiar 18 min-max avg: ");
float *data = this->take_18_oneshots();
this->sort_18(data);
Serial.println(this->avg_16_center(data));
delete data;
break;
}
case ButtonPress::Button3 :
{
float *data = this->take_18_oneshots();
this->sort_18(data);
int *data_int = new int[18]();
this->castFloatsToInts(data, data_int, 18);
int avg = this->average(data_int, 17, 1);
Serial.print("Pomiar 18 min-max avg-bit-shift: ");
Serial.println((float)avg);
/*
Biblioteka DS18B20.zip udostępnia tylko i wyłącznie pomiary w reprezentacji float:
float readTemperature(uint8_t *address);
Ze względu na to, że liczby zmiennoprzecinkowe mają skomplikowaną wewnętrzną reprezentację (IEEE 754),
która oddziela bit znaku, bity wykładnika i bity mantysy, nie podjęliśmy się implementacji uśredniania liczb zmiennoprzecinkowych
metodą przesunięcia bitowego. Lecz użyliśmy rzutowania float'ów na integery, co jest błednym podejściem.
*/
delete data;
delete data_int;
break;
}
}
}
};
TemperatureInterface* temp;
void setup() {
// put your setup code here, to run once:
while(!Serial){
delay(100);
}
Serial.begin(9600);
Pins pins = {
3,
4,
5,
6,
2
};
temp = new TemperatureInterface(pins);
temp->init();
temp->print_address();
}
void loop() {
// put your main code here, to run repeatedly:
temp->update();
}