Hallo,
nachfolgend mein erster "großer" Sketch, der auch tatsächlich irgendwo einen Sinn erfüllt...
Es handelt sich um einen ATTiny84, an den ein DS18S20 zur Temperaturmessung und ein einfacher 433 Mhz-Sender zur Übertragung angeschlossen ist. Alle 5 Minuten überträgt er das Temperatur-Signal und die Spannung der Stromversorgung per 433 Mhz.
Ich habe viel probiert und versucht, den Code zu vereinfachen und zu optimieren - auch habe ich mich ein wenig anderer Scripts (z.B. denen vom TinyTX-Projekt) bedient, und sie entsprechend angepasst eingefügt (nach Möglichkeit mit Quellenverweis).
Nun bin ich an einem Punkt, an dem ich den Sketch aufspielen und den Chip auf eine kleine Platine löten möchte.
Bevor ich das aber tue, wüsste ich gerne, ob man an meinem Code noch etwas verbessern oder vereinfachen kann - oder ob ich mir irgendwo grobe Schnitzer geleistet habe.
Habe irgendwie das gefühl: Wenn ich den Chip einmal irgendwo eingelötet habe, kriege ich den nie wieder "im Ganzen" raus
Vielen Dank schonmal für eure Tipps!
#include <VirtualWire.h>
#include <OneWire.h>
#include <JeeLib.h>
ISR(WDT_vect) {
Sleepy::watchdogEvent();
}
// Die ID des Sensor-Nodes. Dienst zur Identifizierung der Daten.
int NODEID = 1;
// PIN, an den das DATA-Beinchen des Temperatur-Sensor angeschlossen ist
int DS18S20_DATA_Pin = 2;
// PIN, an den das VCC-Beinchen des Temperatur-Sensors angeschlossen ist
int DS18S20_VCC_Pin = 9;
// PIN, an den der 433 Mhz Sender angeschlossen ist
int TX_Pin = 3;
// Temperatur-Variable deklarieren
float temp1;
// Interval x 60 Sekunden = Schlafzeit zwischen Sensordaten-Übermittlung
int interval = 5;
int durchlauf = interval; // Zähler für Schleife; ist gleich 5, damit bei Start des ATTiny direkt ein Temperaturwert übermittelt wird
OneWire ds(DS18S20_DATA_Pin);
void setup()
{
// VirtualWire und 433 Mhz-Sender initialisieren
vw_setup(2000); // Bits per sec
vw_set_tx_pin(TX_Pin); // PIN, an dem der 433-Transmitter angeschlossen ist
// Set the aref to the internal 1.1V reference
analogReference(INTERNAL);
// VCC-Pin des DS18S20 als Ausgang setzen
pinMode(DS18S20_VCC_Pin, OUTPUT);
// Stromsparen: ADC deaktivieren
ADCSRA &= ~ bit(ADEN);
bitSet(PRR, PRADC);
}
void loop()
{
while(durchlauf < interval) {
durchlauf = durchlauf +1;
Sleepy::loseSomeTime(60000);
}
// DS18S20-Sensor einschalten
digitalWrite(DS18S20_VCC_Pin, HIGH);
// Kurze Delay zur Initialisierung
delay(50);
// Fix: Nach dem der DS18S20 mit Strom versorgt wurde, ist die erste Temperatur-Ausgabe 85.00
// Die Temperatur wird so oft abgefragt, bis getTemp() nicht mehr 85.00 zurückliefert
while(getTemp() == 85.00) {
getTemp();
}
// Temperatur Temp1 auslesen und Vor/Nachkomma in zwei Variablen schreiben (int)
// Float-Vars lassen sich nicht mit printf() auf Arduino ausgeben! Das ist ein Workaround!
// http://forum.arduino.cc/index.php?topic=197900.msg1461205#msg1461205
temp1=getTemp()*100; // z.B. 22,59 * 100
// DS18S20 ausschalten
digitalWrite(DS18S20_VCC_Pin, LOW);
int temp1a =(int)temp1; // z.B. 2259
int temp1VOR = temp1a/100; // 22
int temp1NACH = temp1a%100; // 59
// Temperatur-String zum Versand initialisieren
char msg[20];
// msg-Variable mit Daten zum Versand füllen, die später an das WebScript übergeben werden
snprintf(msg, 20, "n=%d&t1=%d.%d&v=%d", NODEID,temp1VOR,temp1NACH,readVcc()) ;
// Daten per VirtualWire-Lib versenden
vw_send((uint8_t *)msg, strlen(msg));
// Auf kompletten Versandt warten
vw_wait_tx();
// Den Durchlauf-Zähler auf 0 setzen, damit das Interval von vorne beginnt
durchlauf = 0;
// ATTiny schlafen legen
// Sleepy::loseSomeTime(60000);
}
// getTemp() - Liest den Temperaturwert EINES angeschlossenen DS18S20-Sensor in Celsius aus
float getTemp(){
byte data[12];
byte addr[8];
if ( !ds.search(addr)) {
//no more sensors on chain, reset search
ds.reset_search();
return -1000;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); // using two's compliment
float TemperatureSum = tempRead / 16;
return TemperatureSum;
}
// readVcc()-Lib von Nathan Chantrell
// Gibt die Spannung der Stromversorgung in mV aus
// https://github.com/nathanchantrell/TinyTX/blob/master/TinyTX_DS18B20/TinyTX_DS18B20.ino
long readVcc() {
bitClear(PRR, PRADC);
ADCSRA |= bit(ADEN); // Enable the ADC
long result;
// Read 1.1V reference against Vcc
#if defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328
#endif
delay(2); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA,ADSC));
result = ADCL;
result |= ADCH<<8;
// Kalibrierung der VCC-Anzeige
// http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
// Abschnitt: Improving Accuracy
// scale_constant = internal1.1Ref * 1023 * 1000
// internal1.1Ref = 1.1 * Vcc1 (per voltmeter) / Vcc2 (per readVcc() function)
// Default: 1125300L
// Meine Konstante: 1070860L, errechnet mit 3x1,5V Batterien als VCC
result = 1070860L / result; // Back-calculate Vcc in mV; Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
ADCSRA &= ~ bit(ADEN);
bitSet(PRR, PRADC); // Disable the ADC to save power
return result;
}