=====Ein Projekt für den Haushalt - Ein „Arduino based“ Küchenwecker .-) ===== **August 2016** In Arbeit - noch nicht komplett! Aufgabe: Küchenwecker * Anzeige der Zeit über ein klassisches LED Display * Zeiteinstellung für die wichtigsten Zeiten über einzelne Taster * Genaue Zeiteinstellung über einen Drehknopf mit logarithmischer Skala (d.h. die ersten Minuten können schnell genau eingestellt werden, bei längeren Zeit muss nicht lang gedreht werden ) * Die abgelaufene Zeit wird über eine LED Ring visualisiert * Batterie Betrieb * Das ganze muss dann noch in ein Holzgehäuse passen **Fazit des ersten Versuches:** Über ein Poti die Zeit einzustellen ist zwar möglich und geht dann auch irgendwie, allerdings muss hier doch mehr Aufwand betrieben werden als im ersten Schritt geplant. Einfache ist es wohl hier einen Drehencoder einzusetzen, durch den digitalen Ansatz verspricht das ein genaueres Einstellen der gewünschten Zeit ohne großen Beschaltungsaufwand. Das Prinzip, einfach die Spannung über den Poti mit dem integrierten AD und der Versorgungsspannung als Referenzwert zu messen, ist viel zu ungenau, die gemessenen Werte schwanken pro Messung sehr stark mit der Versorgungsspannung der Arduino. Zu diesem Problem siehe auch [[raspberry:raspberry_gpio_read_adc0831#verbesserung_-_stabile_spannungsreferenz|Einen AD Wandler ADC0831 mit dem Raspberry PI verwenden - Verbesserung - Stabile Spannungsreferenz]] Die Ursache liegt in dem leichten Schwankungen der Betriebsspannung, die mag zwar nur gering sein, hier wirkt sich das aber sehr störend aus. Eine Referenzspannungsquelle bringt hier auch nicht viel, wir hätte zwar eine stabile Referenz aber der zu messende Wert würde ja noch genauso schwanken. Als Lösung setze ich nun eine externe Referenzspannung (LM336 2.5v) und eine stabilisierte Spannungsversorgung (LM 317, geschaltet für 2.5v) als Eingang für unseren Spannungsteiler ein. Das ist in sich stabil und damit lässt sich die Zeit "analog" ohne große Schwankungen einstellen. Zur Erinnerung, uns geht es ja nur darum über den Spannungsabfall die Zeit zwischen 0 und 60 einzuteilen, was wir genau messen spielt keine Rolle solange es nur schön gleichmäßig proportional ausgewertet werden kann. Für die Eingabe vom festen Zeit Werte per Taster/Drehschalter wird auch ein analog Eingang verwendet. Am Analog Pin 2 liegt eine Kette von Widerständen (wieder über unseres stabilisierte Spannung von ~2,5V), je nach Schalterstellung ergibt sich ein Spannungsabfall aus den Werten des Widerstandsnetz und dieser wird wiederum gemessen und in die entsprechende Zeit umgesetzt. Um beide Regeln zu verwenden, wird geprüft ein Veränderung bim Poit stattfindet, wird eine Veränderung gemessen wird der Wert des Poti verwandt und nicht die Werte der Widerstandskette. Demnächst mehr ---- ==== Version 1 mit analogen Potentiometer und ein LED Display mit dem Treiber Baustein MAX7219 ==== === Material - Version 1=== * Adafruit Uno 328 5v 16Mhz * Potentiometer Log 1K aus der Bastelkiste * 7 digit 8 segment digital LED Display mit dem MAX7219 Im ersten Schritt wird das Einstellen der Zeit über ein Potentiometer realisiert, d.h. die abgefallene Spannung über den Poti wird gemessen und eine Zeit zwischen 10 Sekunden und 120*60 Sekunden umgerechnet. Das erste Ergebnis kann leider nicht überzeugen, die Messung der Spannung schwankt auch bei keiner Veränderung des Poti zu stark, daher muss auf eine Stabilisierung der Spannung gesetzt werden. Im ersten Versuch im Sketch etwas her umgerechnet und gerundet damit das Ergebnis so einigermaßen gleichmäßig verteilt ist, das kann nun entfallen, da mit der externen Spannungsreferenz und einen Spannungsstabilisator das gelesene Ergebnis recht stabil bleibt. ---- === Anschluss der 7 Segment Anzeige MAX72xxx === Durch den MAX7219 Chip können mit wenig Verkabelungsaufwand 8 Ziffern dargestellt werden. 5 Anschlussleitung und schon kann es losgehen: Modul => Arduino CLK --------> Pin 11 - Takt CS --------> Pin 10 - Cip Select DIN --------> Pin 12 - Data In GND --------> GND VCC --------> 5V Die Library [[http://wayoda.github.io/LedControl/pages/software|"LedControl"]] beschreibt die Programmierung und ist einfach über die Library Funktion in der IDE einbindbar. {{ :elektronik:import_lib_git_ledcontrol.png?400 |LED Control für den MAX72xxx einbinden}} ---- === Anschluss Poti === Poti => Arduino 1 -- ----> GND 2 -- ----> Pin A0 3 -- ----> 5V Spannungsversorgung des Poti mit 2,54v mit dem LM327 * http://www.ti.com/lit/ds/snvs775k/snvs775k.pdf Schaltbild: {{ :playgrounds:raspberry:lm317_als_spannungsreferenz_v01.png | LM 317 Standard Beschaltung}} Muss ich noch neu zeichnen, ist aus dem raspi Projekt. Ich einen LM 317 im TO-92 Gehäuse mit 2 * 470Ohm beschaltet und ~2,54V damit erzielt. Referenzspannung erzeugen von 2,54V mit dem LM336 2.5 * http://www.ti.com/lit/ds/symlink/lm336-2.5-n.pdf Hier über zwei Dioden und einen Poti genau den gleichen Wert wie in obiger Schaltung erzielt. Zur Vereinfachung könnte man dann wohl sogar auf die Referenz verzichten und gleich die Spannung hinter den LM337 verwenden, andersherum geht es allerdings nicht, die Referenzspannungquelle lässt sich nicht belasten! ---- === Anschluss Start Button=== Mit Pulldown Widerstand Taster => Arduino 1 -- ----> Pin 1 und GND über -|_ 1K_|- 2 -- ----> 5V ---- === Anschluss Lautsprecher === Um hier etwas akustisch zu signalisieren erst mal einen Lautsprecher angeschlossen. Lautsprecher => Arduino Rot --------> Pin 9 - PWM Pin Schwarz --------> GND ---- === Der erste Sketch für die Version 1=== Noch mit einem MAX7219 Display: //Control the MAX7219 LED Driver #include // add the 7 Segment LED // pin 12 is connected to the DataIn // pin 11 is connected to the CLK // pin 10 is connected to LOAD // only one MAX72xx Chip // LedControl(dataPin,clockPin,csPin,numDevices) LedControl seg71=LedControl(12,11,10,1); // Port definition const int READ_POTI_IN_PIN = 0; const int READ_START_BUTTON_PIN=2; const int SPEACKER_PIN=9; // Seconds Timerange const int TIME_RANGE=(60*60); //min and max values read over the analog in const int MIN_POTI_VALUE=0; const int MAX_POTI_VALUE=1023; //devider for one second in the range of the poti float SEC_TICK= (float)TIME_RANGE/(float)(MAX_POTI_VALUE-MIN_POTI_VALUE); float calc_seconds=0; //var to read the poti int poti_sum=0; int poti_value=0; int poti_value_last=0; int jitter_check=0; int jitter_ignore=3; //time int minutes=0; int seconds=0; int total_seconds=0; //Buttons for the down timer int start_countButton=LOW; boolean start_countdown=false; //---------------------- void setup() { // Open serial communications for debug Serial.begin(57600); // wait for serial port to connect while (!Serial) { ; } Serial.println("Start projekt Kitchen timer"); //debug Serial.println("------Parameter "); Serial.print("TIME_RANGE :: "); Serial.print(TIME_RANGE); Serial.println(" "); Serial.print("SEC_TICK :: "); Serial.print(SEC_TICK); Serial.println(" "); //Display //The MAX72XX is in power-saving mode on startup, //we have to do a wakeup call seg71.shutdown(0,false); //Set the brightness to a medium values seg71.setIntensity(0,8); //clear the display seg71.clearDisplay(0); //set the internal referenz value //INTERNAL // use the 5v power //DEFAULT //use external ref //EXTERNAL analogReference(EXTERNAL); //enable the Start count button as interrupt pinMode(READ_START_BUTTON_PIN, INPUT); // Attach the interrupt to the ISR vector attachInterrupt(0, pin_ISR, RISING); //speacker pinMode(SPEACKER_PIN,OUTPUT); } //-- run void loop() { // check if the is Button was pressed if (start_countdown==true) { // do the countdown countDown(total_seconds); } // try to read the time input // unit the start button was pressed if (start_countdown==false) { //calculate the time minutes=0; seconds=0; //first calculate in Float Values! calc_seconds = getPotiValue(); //Float to int to get only seconds total_seconds=calc_seconds; //debug Serial.print("Calc Value from poti_value:: "); //debug Serial.print(poti_value); //debug Serial.print(" calc_seconds :: "); //debug Serial.print(calc_seconds); //debug Serial.print(" total_seconds :: "); //debug Serial.println(total_seconds); // to hit some important values easier // set the display to some important times if we are in the range of: switch(total_seconds){ //0,5 min case 28 ... 32 : total_seconds=30;break; //1 min case 58 ... 62 : total_seconds=60*1;break; // 2min case 110 ... 130 : total_seconds=60*2;break; // 3min case 170 ... 190 : total_seconds=60*3;break; //4 min case 240 ... 250 : total_seconds=60*4;break; // 5min case 290 ... 310 : total_seconds=60*5;break; // 8min case 470 ... 490 : total_seconds=60*8;break; // 10min case 590 ... 610 : total_seconds=60*10;break; // 15min case 890 ... 910 : total_seconds=60*15;break; // 20min case 1180 ... 1220 : total_seconds=60*20;break; // 30min case 1780 ... 1820 : total_seconds=60*30;break; // 45min case 2660 ... 2740 : total_seconds=60*45;break; // 60min case 3590 ... 3620 : total_seconds=60*60;break; } // set the display setTime(total_seconds); //wait 0.1 sec delay(50); } } //interrupt method void pin_ISR() { Serial.println("Start Counter was pressed"); if (start_countdown) { start_countdown=false; } else { start_countdown=true; } } // simple speacker PWM Modulation to hear something void bell() { for (int i=0;i<3;i++){ for (unsigned char i=0; i <255; i++) { analogWrite(SPEACKER_PIN,i); delay(2); } analogWrite(SPEACKER_PIN,0); for (unsigned char i=255; i >0; i--) { analogWrite(SPEACKER_PIN,i); delay(2); } analogWrite(SPEACKER_PIN,0); } } // get the value of the poti and return the value in seconds! // read the value of the poti to set the time float getPotiValue(){ // workaround against the jitter of the read values! // at the end with external ref and voltage regulator for the poti every thing was solved // at the end obsolete // read 5 times to the a avg value int avg_reads=5; poti_sum=0; for(int i=0;i get this value from the analogRead :: "); //debug Serial.println(poti_value); poti_sum=poti_sum+poti_value; delay(10); } // check if the new value is near by the old value jitter_check=abs((poti_sum/avg_reads) - poti_value_last); //debugSerial.print("Jitter Check:: "); //debugSerial.print(jitter_check); //debugSerial.print(" Act value :: "); //debugSerial.println(poti_sum/avg_reads); // if the value has not changed a lot ignore! if ( jitter_check > jitter_ignore) { poti_value=poti_sum/avg_reads; } else { poti_value=poti_value_last; } poti_value_last=poti_value; //adjust the jitter to the range switch(poti_value){ case 0 : jitter_ignore=1; break; case 50 ... 130 : jitter_ignore=2; break; case 131 ... 250 : jitter_ignore=3; break; case 251 ... 500 : jitter_ignore=4; break; case 501 ... 750 : jitter_ignore=5; break; case 751 ... MAX_POTI_VALUE : jitter_ignore=6; break; } //debugSerial.print("AVG Poti Value of the last 0,5 sec :: "); //debugSerial.print(poti_value); //debugSerial.print(" Last Value was :: "); //debugSerial.println(poti_value_last); //return seconds! return (float)poti_value * SEC_TICK; } //count down timer void countDown(int last_seconds){ //loop down while (last_seconds!=0) { setTime(last_seconds); //wait one second delay(1000); if (start_countdown) { last_seconds=last_seconds-1; } else { last_seconds=0; } } //stop down count start_countdown=false; printDots(100); bell(); } // set time on the display // Format Minute:Second // void setTime(int act_seconds){ // calculate the Minutes if (act_seconds > 59){ minutes=act_seconds/60; seconds=act_seconds-(minutes*60); } else { seconds=act_seconds; minutes=0; } Serial.print("Time :: "); Serial.print(minutes); Serial.print("::"); Serial.print(seconds); Serial.print(" -- Total Seconds :: "); Serial.println(act_seconds); // Format Minute:Second printDigit(minutes,seconds); } // print dots // pro Progress and to show the end of the timer void printDots(int t){ //progress dot's seg71.clearDisplay(0); for (int i=0;i<9;i++){ seg71.setChar(0,i,'.',false); delay(t); } //clear the display seg71.clearDisplay(0); } // print the time on the display // Format Minute:Second // t minutes , p seconds // void printDigit(int t,int p) { int tones; int ttens; int pones; int ptens; boolean negative=false; if(t < -99 || t > 99) return; if(t<0) { negative=true; t=t*-1; } tones=t%10; pones=p%10; t=t/10; p=p/10; ttens=t%10; ptens=p%10; if(negative) { //print character '-' in the leftmost column seg71.setChar(0,7,'-',false); } else { //print a blank in the sign column seg71.setChar(0,7,' ',false); } seg71.setDigit(0,5,(byte)ttens,false); seg71.setDigit(0,4,(byte)tones,true); seg71.setDigit(0,3,(byte)ptens,false); seg71.setDigit(0,2,(byte)pones,false); } ---- ---- ==== Version 2 mit dem LED Display LiteON LTC 4620HG + NeoPixel Ring und einem MP3 Modul ==== In der zweiten Version wird ein MAX7219 Display zerlegt um nur die Platine und den Treiber Chip zu nützen. Billiger als einen neuen MAX7219 Chip zu kaufen .-). Der Lautsprecher wird durch ein MP3 Modul ersetzt. === Material Version 2 === * Adafruit Metro Mini 328 5v 16Mhz * Adafruit NeoPixel Ring siehe http://www.exp-tech.de/adafruit-neopixel-ring-16-x-5050-rgbw-leds-w-integrated-drivers-natural-white-4500k * 7 digit 4 segment LED display für die Zeitanzeige ( [[http://datasheet.octopart.com/LTC-4620HG-Lite-On-datasheet-37210612.pdf|LiteON LTC 4620HG]] * Treiber für das einfache LED Display (MAX7219 umbau?) * Drehencoder * MP3 Modul === Adafruit NeoPixel Ring=== Die Drehbewegung am Poti und das Herunterzählen der Zeit wird mit einem 16* Adafruit NeoPixel Ring realisiert. Der Adafruit NeoPixel Ring basiert auf 16 RGBW NeoPixel (5050 große LEDs) . Diese LEDs verfügt über interne 4 LEDs (rot, grün , blau und weiß ) und einem eingebetteten Mikrocontroller, die Helligkeit und Farbe jedes R / G / B / W kann mit 8- Bit-PWM-Genauigkeit ( also 32- Bit-Farbtiefe pro Pixel) eingestellt werden. Die LEDs sind durch Schieberegister gesteuert und es ist nur 1 digitaler Ausgang-Pin notwendig, um die erforderlichen Daten zu senden. Die PWM ist in jedem LED-Chip eingebaut, so dass die Farbe einer LED eingestellt und dieser Werte wird automatisch für jede LED weitergeführt. Siehe Details unter https://learn.adafruit.com/adafruit-neopixel-uberguide !Achtung Bei der Initialisierung des Treibers für den Ring muss NEO_RGB verwendet werden! // Which pin on the Arduino is connected to the NeoPixels? #define PIX_PIN 6 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 16 // When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals. // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) <=== This Pixel Ring ! Adafruit_NeoPixel pix_ring = Adafruit_NeoPixel(NUMPIXELS, PIX_PIN, NEO_RGBW+ NEO_KHZ800); ===Sound=== "Klingelt" der Küchenwecker soll diesen Melodie abgespielt werden => https://www.youtube.com/watch?v=LfPklJNNECk Dazu wird ein MP3 Modul eingesetzt, Mein Modul MP3 GPD2846a Modul habe ich von diesem Händler erworben: http://www.ebay.de/itm/272272687227 , funktioniert und kam recht schnell (2Wochen) an. MP3 auf eine Mini SD Karte kopieren, Lautsprecher und Spannungsversorgung an das Modul löten und dann kann es los gehen. Übersicht: {{ :elektronik:mp3_modul_gpd2846a_overview_v01.png?500 | MP3 Modul gpd2846a anschließen }} Dann wird es allerdings etwas komplizierter, die "Buttons" für das Modul bauen auf einem Widerstandsnetz auf. Um diese von einen Arduino zu schalten, müssen die "Buttons auf "Ground" gezogen werden. Dazu habe ich mich entschieden einfach eine mosfet zum Schalten zu verwenden wie in [[elektronik:led_mosfet_schalten_modul|Ein einfaches LED Modul mit MOSFET 2N7002-ET1G und einer Jumpo LED]]. Dann ist das schön entkoppelt und es sollte funktioniere. Dann gleich mal los basteln und das testen. Mehr zum Erfolg des ganzen demnächst Die einfachste Variante ist die einfach die Versorgungsspannung zu aktivieren, dann fängt das Modul ganz automatisch an die einzige MP3 Datei auf der Karte abzuspielen, aber das ist schon fast unsportlich einfach ;-) . ---- ====Quellen ==== Schalter-taster http://www.voelkner.de/products/42339/Impulsschalter-Schwarz.html http://www.voelkner.de/products/209390/Printtaster-Blau.html http://www.voelkner.de/products/61097/Eingabetaste-Rot-Beleuchtet.html LED ansteuern * http://wayoda.github.io/LedControl/pages/software Messen * http://www.elektronik-labor.de/Arduino/Ohmmeter.html * http://tronixstuff.com/2012/02/29/tutorial-analog-input-for-multiple-buttons-part-two/ Messungenauigkeit * http://www.skillbank.co.uk/arduino/measure.htm * http://blog.fiftythree.com/posts/measuring-battery-voltage * https://hackingmajenkoblog.wordpress.com/2016/02/01/making-accurate-adc-readings-on-the-arduino/ LM 317 für eine einfache Referenzspannungsquelle dienen: * => http://www.k7mem.com/Electronic_Notebook/power_supplies/lm317.html * => http://www.dieelektronikerseite.de/Elements/LM317%20-%20Welche%20Spannung%20darf%20es%20sein.htm NeoPixel * https://learn.adafruit.com/adafruit-neopixel-uberguide/neopixel-rings * https://learn.sparkfun.com/tutorials/ws2812-breakout-hookup-guide * https://steelcityelectronics.com/electronics/neopixel-htu21d-weather-station/ * http://www.ansteron.com/?p=tutorials&id=33 Doku: * https://www.arduino.cc/en/Reference/AnalogReference ==MP3 Player mit dem GPD2846A== * Working Voltage: 3.7V Lithium Battery 600MA or 5V USB Power Supply * Chip:GPD2846A * Chip Footprint:SOP16 * PCB Size:34.23MM*22.33MM*1MM * with 2W Mixed mono * Supports MP3 format playback * Supports USB audio mode * Supports 3 types FM radio chip : RDA5807, BK1080 and RTC6207E. * Does not support infrared remote control and USB device mode Datenblatt: * http://www.datasheetcafe.com/gpd2846a-datasheet-gpd2846/ * http://www.datasheetspdf.com/datasheet/GPD2846.html Beispiele * http://www.102g.ru/electronics/datasheets/Audio/Codec/ * http://www.102g.ru/electronics/datasheets/Audio/Codec/GPD2806A.pdf * http://www.guslab.com.ua/2015/12/mp3-microsd-gpd2846a.html ==MP3 Player mit dem gpd2856c == Datasheet: * http://www.datasheetbay.com/search/gpd2856c-009a.pdf.html Beispiele: * http://mysku.ru/blog/aliexpress/34724.html