diff --git a/Configuration.h b/Configuration.h index 8d40ede..776b94b 100644 --- a/Configuration.h +++ b/Configuration.h @@ -111,13 +111,15 @@ #define RGB_LEDS //#define RGBW_LEDS //#define MATRIX_XXL +#define LPD_ALTLAYOUT #endif /* * Welche Uhr soll benutzt werden? */ -#define DS1307 +//#define DS1307 // #define DS3231 +#define TEENSYRTC /* * Welche IR-Fernbedienung soll benutzt werden? @@ -178,6 +180,18 @@ */ #define BUTTON_TRESHOLD 300 +// Buttons sind kapazitive Button (Teensy) +#define TOUCHBUTTONS + +//! Wie viele samples gesammelt werden, bis der Durchschnitt als stabil erachtet wird +#define TOUCHSAMPLES 1500 + +//! Minimal Erhöhung des Wertes, um mal als berüht zu gelten +#define TOUCHTHRESHOLD 30 + +//! Nummer der Samples die über dem Durchschnitt liegen müssen, vermeidet spontanes Rauschen +#define NUMTOUCHSAMPLES 3 + // ------------------ DCF77-Empfaenger --------------------- /* * Fuer wieviele DCF77-Samples muessen die Zeitabstaende stimmen, damit das DCF77-Telegramm als gueltig zaehlt? diff --git a/LedDriver.h b/LedDriver.h index a99c9e5..5381d75 100644 --- a/LedDriver.h +++ b/LedDriver.h @@ -24,6 +24,7 @@ #include "Settings.h" #include "MyRTC.h" +#include "TeensyRTC.h" #include "Transitions.h" #include "Modes.h" #include "Configuration.h" @@ -32,7 +33,11 @@ extern volatile byte helperSeconds; extern Mode mode; extern Settings settings; +#ifdef TEENSYRTC +extern TeensyRTC rtc; +#else extern MyRTC rtc; +#endif extern bool evtActive; /* Treiberkonfiguration */ diff --git a/LedDriverLPD8806.cpp b/LedDriverLPD8806.cpp index 4c8d6da..d40b33c 100644 --- a/LedDriverLPD8806.cpp +++ b/LedDriverLPD8806.cpp @@ -337,12 +337,59 @@ void LedDriverLPD8806::clearData() { _strip->show(); } + +#if defined(LDP_ALT_LAYOUT) +void LedDriverLPD8806::_setEcke(uint8_t ecke, uint32_t c) { + switch(ecke) { + case 0: + _strip->setPixelColor(1, c); + break; + case 1: + // led unten links + zeile + 1. led + _strip->setPixelColor(2 + 12 + 1 , c); + break; + case 2: + // 2 * leds + 9 zeilen + 1. led + _strip->setPixelColor(2*2 + 9 *12 + 1, c); + break; + case 3: + // 10 zeilen + 3 * leds + _strip->setPixelColor(10 *12 + (3 * 2) + 1, c); + break; + } +} + +/** + * Einen X/Y-koordinierten Pixel in der Matrix setzen. + */ +void LedDriverLPD8806::_setPixel(byte x, byte y, uint32_t c) { + y = 9-y; + if (y % 2==1) { + // Gegenläufige Reiche + x = 11 -x; + } else { + // Ganz links freilassen + x = x; + } + if (y == 0) { + _strip->setPixelColor(2+x, c); + } else if (y <=8) { + _strip->setPixelColor(y*12 +4 + x, c); + } else { + // oberste reihe + _strip->setPixelColor(y*12 +6 + x, c); + } + + +} +#else /** Einen X/Y-koordinierten Pixel in der Matrix setzen. */ void LedDriverLPD8806::_setPixel(byte x, byte y, uint32_t c) { _setPixel(x + (y * 11), c); } +#endif /** Einen Pixel im Streifen setzten (die Eck-LEDs sind am Ende). @@ -376,6 +423,12 @@ void LedDriverLPD8806::_setPixel(byte num, uint32_t c) { ; } } +#elif defined(LDP_ALT_LAYOUT) + if (num < 110) { + _setPixel(num, c); + } else { + _setEcke(num-110,c); + } #else if (num < 110) { if ((num / 11) % 2 == 0) { diff --git a/LedDriverLPD8806.h b/LedDriverLPD8806.h index 5a819b4..bc2cf11 100644 --- a/LedDriverLPD8806.h +++ b/LedDriverLPD8806.h @@ -62,6 +62,10 @@ class LedDriverLPD8806 : public LedDriver { void _setPixel(byte x, byte y, uint32_t c); void _setPixel(byte num, uint32_t c); +#ifdef LDP_ALT_LAYOUT + void _setEcke(uint8_t ecke, uint32_t c); +#endif + uint32_t _wheel(byte brightness, byte wheelPos); void _clear(); diff --git a/MyIRremote.cpp b/MyIRremote.cpp index 7a9060e..f406aaf 100644 --- a/MyIRremote.cpp +++ b/MyIRremote.cpp @@ -20,6 +20,8 @@ #include "MyIRremote.h" #include "MyIRremoteInt.h" +#ifndef __arm__ + // Provides ISR #include @@ -1160,3 +1162,4 @@ void IRsend::sendDISH(unsigned long data, int nbits) { data <<= 1; } } +#endif diff --git a/MyIRremote.h b/MyIRremote.h index a625fdd..b4a35ac 100644 --- a/MyIRremote.h +++ b/MyIRremote.h @@ -15,6 +15,8 @@ #ifndef My_IRremote_h #define My_IRremote_h +// ARM benutzt die normale IRremote Bibliothek +#ifndef __arm__ // The following are compile-time library options. // If you change them, recompile the library. @@ -126,3 +128,5 @@ class IRsend #define MARK_EXCESS 100 #endif + +#endif diff --git a/MyIRremoteInt.h b/MyIRremoteInt.h index b37b385..a835469 100644 --- a/MyIRremoteInt.h +++ b/MyIRremoteInt.h @@ -17,6 +17,7 @@ #ifndef My_IRremoteint_h #define My_IRremoteint_h +#ifndef __arm__ #if defined(ARDUINO) && ARDUINO >= 100 #include @@ -515,3 +516,4 @@ extern volatile irparams_t irparams; #endif #endif +#endif diff --git a/MyRTC.h b/MyRTC.h index e0181bd..9604e27 100644 --- a/MyRTC.h +++ b/MyRTC.h @@ -44,15 +44,17 @@ class MyRTC : public TimeStamp { byte getSeconds(); -private: + int _address; byte _statusLedPin; +protected: byte _seconds; byte decToBcd(byte val); byte bcdToDec(byte val); uint8_t conv2d(const char* p); + }; #endif diff --git a/Qlockthree.ino b/Qlockthree.ino index c174de5..9c85509 100644 --- a/Qlockthree.ino +++ b/Qlockthree.ino @@ -180,11 +180,18 @@ #include "IRTranslatorMooncandles.h" #include "IRTranslatorLunartec.h" #include "IRTranslatorCLT.h" +// Der Teenys hat 256k Flash und kein Problem mit der großen Orginal Bibliothek +#ifdef __arm__ +#include +#endif + #include "MyIRremote.h" #include "MyRTC.h" +#include "TeensyRTC.h" #include "MyDCF77.h" #include "Button.h" #include "AnalogButton.h" +#include "TouchButton.h" #include "LDR.h" #include "DCF77Helper.h" #include "Renderer.h" @@ -207,7 +214,7 @@ Serial-Monitor muss mit der hier angegeben uebereinstimmen. Default: ausgeschaltet */ -// #define DEBUG +#define DEBUG #include "Debug.h" // Die Geschwindigkeit der seriellen Schnittstelle. Default: 57600. Die Geschwindigkeit brauchen wir immer, // da auch ohne DEBUG Meldungen ausgegeben werden! @@ -492,6 +499,30 @@ LedDriverLPD8806 ledDriver(13, 11); #define PIN_DCF77_LED 8 #define PIN_SPEAKER -1 +#elif defined(BOARD_TEENSY) +LedDriverLPD8806 ledDriver(7, 14); +#define PIN_MODE 16 +#define PIN_M_PLUS 15 +#define PIN_H_PLUS 17 + +#define BUTTONS_PRESSING_AGAINST LOW + +#define PIN_IR_RECEIVER 10 + +#define PIN_LDR A6 +#define IS_INVERTED true + +#define PIN_SQW_SIGNAL -1 +#define PIN_DCF77_SIGNAL 2 + +#define PIN_DCF77_PON -1 + +#define PIN_SQW_LED -1 +#define PIN_DCF77_LED 13 + +#define PIN_SPEAKER -1 +#else +#error Kein passendes Board für LPD8806 Treiber definiert #endif #endif @@ -523,9 +554,15 @@ IRTranslatorCLT irTranslatorBT; // Werden zur Kommunikation mit der // RTC verwendet. /** - Die Real-Time-Clock mit der Status-LED fuer das SQW-Signal. -*/ + * Die Real-Time-Clock mit der Status-LED fuer das SQW-Signal. + */ +#ifdef TEENSYRTC +TeensyRTC rtc(PIN_SQW_LED); +IntervalTimer rtcTimer; +#else MyRTC rtc(0x68, PIN_SQW_LED); +#endif + volatile byte helperSeconds; /** @@ -555,13 +592,21 @@ byte brightnessToDisplay; /** Die Tasten. */ +#ifdef TOUCHBUTTONS +TouchButton minutesPlusButton(PIN_M_PLUS); +TouchButton hoursPlusButton(PIN_H_PLUS); +DoubleTouchButton extModeDoubleButton(minutesPlusButton, hoursPlusButton); +TouchButton modeChangeButton(PIN_MODE); +#else Button minutesPlusButton(PIN_M_PLUS, BUTTONS_PRESSING_AGAINST); Button hoursPlusButton(PIN_H_PLUS, BUTTONS_PRESSING_AGAINST); Button extModeDoubleButton(PIN_M_PLUS, PIN_H_PLUS, BUTTONS_PRESSING_AGAINST); Button modeChangeButton(PIN_MODE, BUTTONS_PRESSING_AGAINST); +#endif // Startmode... Mode mode = STD_MODE_NORMAL; +//Mode mode = EXT_MODE_TEST; // Merker fuer den Modus vor der Abschaltung... Mode lastMode = mode; @@ -609,14 +654,25 @@ void updateFromRtc() { } } +#ifdef __arm__ +/* unistd.h inkludieren definiert auch alarm, was Problem mit Alarm Klasse macht. + * deshalb prototype fur sbrk einzeln definieren*/ +extern "C" char* sbrk(int incr); +#endif + /** Den freien Specher abschaetzen. Kopiert von: http://playground.arduino.cc/Code/AvailableMemory */ int freeRam() { - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +#ifdef __arm__ + char top; + return &top - reinterpret_cast(sbrk(0)); +#else + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +#endif } /** @@ -698,6 +754,8 @@ void setup() { #elif defined DS3231 DEBUG_PRINTLN(F("Uhrentyp ist DS3231.")); rtc.enableSQWOnDS3231(); +#elif defined TEENSYRTC + DEBUG_PRINTLN(F("Uhrentyp ist Teensy RTC (Freescale MK20)")); #else Definition_des_Uhrtyps_fehlt! In der Configuration.h muss der Uhrentyp angegeben werden! @@ -729,6 +787,16 @@ void setup() { for (int i = 0; i < 1000; i++) { analogRead(PIN_LDR); } +#ifdef TEENSYRTC + // Bei der internen RTC vom Teensy wird kein Rechtecksignal + // an einem externen pin geniert. Deshalb normaler Software Timer + // IntervalTimer ist hochpräziser Timer, eigentlich unnötig + rtcTimer.priority(255); + if(!rtcTimer.begin(updateFromRtc, 1*1000*1000)) + Serial.printf("Failed to set teensy timer\n"); +#else + attachInterrupt(0, updateFromRtc, FALLING); +#endif // rtcSQWLed-LED drei Mal als 'Hello' blinken lassen // und Speaker piepsen kassen, falls ENABLE_ALARM eingeschaltet ist. diff --git a/Settings.cpp b/Settings.cpp index 3d6de27..98a5675 100644 --- a/Settings.cpp +++ b/Settings.cpp @@ -151,7 +151,7 @@ void Settings::setDcfSignalIsInverted(boolean dcfSignalIsInverted) { /** * Zeitverschiebung */ -char Settings::getTimeShift() { +signed char Settings::getTimeShift() { return _timeShift; } @@ -166,7 +166,7 @@ void Settings::setJumpToNormalTimeout(byte jumpToNormalTimeout) { _jumpToNormalTimeout = jumpToNormalTimeout; } -void Settings::setTimeShift(char timeShift) { +void Settings::setTimeShift(signed char timeShift) { _timeShift = timeShift; } diff --git a/Settings.h b/Settings.h index 81f5be7..5e101f0 100644 --- a/Settings.h +++ b/Settings.h @@ -65,8 +65,8 @@ class Settings { boolean getDcfSignalIsInverted(); void setDcfSignalIsInverted(boolean dcfSignalIsInverted); - char getTimeShift(); - void setTimeShift(char timeShift); + signed char getTimeShift(); + void setTimeShift(signed char timeShift); byte getJumpToNormalTimeout(); void setJumpToNormalTimeout(byte jumpToNormalTimeout); @@ -88,7 +88,7 @@ class Settings { byte _brightness; boolean _enableAlarm; boolean _dcfSignalIsInverted; - char _timeShift; + signed char _timeShift; eColors _color; byte _transitionMode; byte _event; diff --git a/TeensyRTC.h b/TeensyRTC.h new file mode 100644 index 0000000..57fc1fa --- /dev/null +++ b/TeensyRTC.h @@ -0,0 +1,44 @@ +/** + * TeensyRTC + * Emuliert die MyRTC mit Teensys interner RTC + * + * @autor Arne Schwabe + * @version 0.1 + * @created 10.1.2016 + * @updated 10.1.2016 + * + * Versionshistorie: + * V0.1 First version + */ +#ifndef TEENSYRTC_H +#define TEENSYRTC_H + +#include "MyRTC.h" +#include "TimeLib.h" + +inline time_t getTeensy3Time() +{ + return Teensy3Clock.get(); +} + +class TeensyRTC : public MyRTC { +public: + TeensyRTC(byte statusLedPin) : MyRTC::MyRTC(0x0, statusLedPin) { + setSyncProvider(getTeensy3Time); + }; + + void readTime() { + time_t t=now(); + _seconds = second(t); + _minutes = minute(t); + _hours = hour(t); + _date = day(t); + _month = month(t); + // Year is only a byte + _year = year(t) % 100; + _dayOfWeek = weekday(t); + }; + void writeTime() { setTime(_hours, _minutes, _seconds, _date, _month, 2000 + _year);} +}; + +#endif diff --git a/TouchButton.cpp b/TouchButton.cpp new file mode 100644 index 0000000..4653f13 --- /dev/null +++ b/TouchButton.cpp @@ -0,0 +1,50 @@ +#include "TouchButton.h" +#include "Configuration.h" + + +bool TouchButton::pressedRaw() +{ + return getState(); +} + + +bool TouchButton::pressed() +{ + if (getState()) { + if(millis() - _lastPressTime > BUTTON_TRESHOLD) { + _lastPressTime = millis(); + return true; + } + } + return false; +} + +/** + * Wurde der Taster gedrueckt? + */ +boolean TouchButton::getState() { + if (lastRead == millis()) + return state; + boolean _retVal = false; + + int t = touchRead(pin); + samples++; + + const float alpha=0.1; + + // Moving exponential average + idleAvg = (alpha * t) + (1.0 - alpha) * idleAvg; + + if (t > idleAvg + TOUCHTHRESHOLD && samples > TOUCHSAMPLES) + samplesTouched++; + else + samplesTouched=0; + + if (t > idleAvg + TOUCHTHRESHOLD) + Serial.printf("%d: t %d, tavg %.1f, %d -> %d\r\n", pin, t, idleAvg,(int) (t- idleAvg), samplesTouched); + + state = (samplesTouched > NUMTOUCHSAMPLES); + return state; + +} + diff --git a/TouchButton.h b/TouchButton.h new file mode 100644 index 0000000..ab091b8 --- /dev/null +++ b/TouchButton.h @@ -0,0 +1,76 @@ +/** + * Button + * Kleine Klasse zum Entprellen der Tasten. + * + * @mc Arduino/RBBB + * @autor Christian Aschoff / caschoff _AT_ mac _DOT_ com + * @version 1.7 + * @created 18.2.2011 + * @updated 16.2.2015 + * + * Versionshistorie: + * V 1.1: - Kompatibilitaet zu Arduino-IDE 1.0 hergestellt. + * V 1.2: - Optimierung hinsichtlich Speicherbedarf. + * V 1.3: - Verbessertes Debugging. + * V 1.4: - Doppel-Tasten-Abfrage ermoeglicht. + * V 1.5: - Ueberlauf in millis() beruecksichtigt. + * V 1.6: - Schalten gegen LOW ermoeglicht. + * V 1.7: - Unterstuetzung fuer die alte Arduino-IDE (bis 1.0.6) entfernt. + */ +#ifndef TOUCHBUTTON_H +#define TOUCHBUTTON_H + +#include "Arduino.h" +#include "Configuration.h" + +class TouchButton { +public: + /** + * Initialisierung mit dem Pin, an dem der Taster haengt. + * + * @param pin: der Pin, an dem die Touchfläche hängt + */ + TouchButton(byte pin): state(false), pin(pin), samples(0), samplesTouched(0), idleAvg(0) {} + bool pressedRaw(); + bool pressed(); + bool getState(); + +private: + bool state; + uint8_t pin; + int samples; + int samplesTouched; + double idleAvg; + long lastRead; + unsigned long _lastPressTime; +}; + + +class DoubleTouchButton { + TouchButton & b1; + TouchButton & b2; + unsigned long _lastPressTime; + +public: + DoubleTouchButton(TouchButton & button1, TouchButton & button2): + b1(button1), b2(button2) {} + + bool pressedRaw () + { + return b1.pressedRaw() && b2.pressedRaw(); + } + + bool pressed() + { + if (pressedRaw()) { + if(millis() - _lastPressTime > BUTTON_TRESHOLD) { + _lastPressTime = millis(); + return true; + } + } + return false; + } +}; + + +#endif