Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
ArduinoNano Realtime+Temp basteln
#1
Guten Morgen,
hat mich keine Ruhe gelassen.
Musste mal mit Arduit Uno und Nano und ein DS3231 eine Uhr mit Temperaturanzeige basteln.
ja etwas unscharf mein Handy Foto....
   

was ich aber nicht hinbekomme ist die Temperatur ohne Kommastellen Anzeigen.
eventuell hilft man mir da mal auf die sprünge ?

Code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define DS3231_I2C_ADDRESS 0x68
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// SCL - pin A5
// SDA - pin A4
// To set the clock, run the sketch and use the serial monitor.
// Enter T1009224200817; the code will read this and set the clock. See the code for full details.

byte seconds, minutes, hours, day, date, month, year;
char weekDay[4];

byte tMSB, tLSB;
float temp3231;

void setup()
{
  Wire.begin();
  Serial.begin(115200);
  lcd.init();                      // initialize the lcd

  // Print a message to the LCD.
  //lcd.backlight();
  //lcd.print(weekDay); lcd.print(", "); lcd.print(date, DEC); lcd.print("."); lcd.print(month, DEC); lcd.print("."); lcd.print(year,DEC); lcd.print(" - ");
  //lcd.setCursor(0,1);
  //lcd.print(weekDay); lcd.print(", "); lcd.print(date, DEC); lcd.print("."); lcd.print(month, DEC); lcd.print("."); lcd.print(year,DEC); lcd.print(" - ");

}


void loop()
{
 
  watchConsole();
 
 
  get3231Date();
 
  Serial.print(weekDay); Serial.print(", "); Serial.print(date, DEC); Serial.print("."); Serial.print(month, DEC); Serial.print("."); Serial.print(year,DEC); Serial.print(" - ");
  Serial.print(hours, DEC); Serial.print(":"); Serial.print(minutes, DEC); Serial.print(":"); Serial.print(seconds, DEC);
  Serial.print(" - Temp: "); Serial.println(get3231Temp());
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print(weekDay); lcd.print(", "); lcd.print(date, DEC); lcd.print("."); lcd.print(month, DEC); lcd.print("."); lcd.print(year,DEC);
  lcd.setCursor(0,1);
  lcd.print(hours, DEC); lcd.print(":"); lcd.print(minutes, DEC); lcd.print(":"); lcd.print(seconds, DEC);
  lcd.print(" - "); lcd.print(get3231Temp());lcd.print((char)223); lcd.print("C");
  delay(1000);
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

void watchConsole()
{
  if (Serial.available()) {      // Look for char in serial queue and process if found
    if (Serial.read() == 84) {      //If command = "T" Set Date
      set3231Date();
      get3231Date();
      Serial.println(" ");
    }
  }
}
 
void set3231Date()
{
//T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year)
//T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99)
//Example: 02-Feb-09 @ 19:57:11 for the 3rd day of the week -> T1157193020209
// T1124154091014
  seconds = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
  minutes = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hours   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  day     = (byte) (Serial.read() - 48);
  date    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  month   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  year    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(day));
  Wire.write(decToBcd(date));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}


void get3231Date()
{
  // send request to receive data starting at register 0
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
  Wire.write(0x00); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes

  if(Wire.available()) {
    seconds = Wire.read(); // get seconds
    minutes = Wire.read(); // get minutes
    hours   = Wire.read();   // get hours
    day     = Wire.read();
    date    = Wire.read();
    month   = Wire.read(); //temp month
    year    = Wire.read();
       
    seconds = (((seconds & B11110000)>>4)*10 + (seconds & B00001111)); // convert BCD to decimal
    minutes = (((minutes & B11110000)>>4)*10 + (minutes & B00001111)); // convert BCD to decimal
    hours   = (((hours & B00110000)>>4)*10 + (hours & B00001111)); // convert BCD to decimal (assume 24 hour mode)
    day     = (day & B00000111); // 1-7
    date    = (((date & B00110000)>>4)*10 + (date & B00001111)); // 1-31
    month   = (((month & B00010000)>>4)*10 + (month & B00001111)); //msb7 is century overflow
    year    = (((year & B11110000)>>4)*10 + (year & B00001111));
  }
  else {
    //oh noes, no data!
  }
 
  switch (day) {
    case 1:
      strcpy(weekDay, "Son");
      break;
    case 2:
      strcpy(weekDay, "Mon");
      break;
    case 3:
      strcpy(weekDay, "Die");
      break;
    case 4:
      strcpy(weekDay, "Mit");
      break;
    case 5:
      strcpy(weekDay, "Don");
      break;
    case 6:
      strcpy(weekDay, "Fre");
      break;
    case 7:
      strcpy(weekDay, "Sam");
      break;
  }
}

float get3231Temp()
{
  //temp registers (11h-12h) get updated automatically every 64s
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
 
  if(Wire.available()) {
    tMSB = Wire.read(); //2's complement int portion
    tLSB = Wire.read(); //fraction portion
   
    temp3231 = (tMSB & B01111111); //do 2's math on Tmsb
    temp3231 += ( (tLSB >> 6) * 0.25 ); //only care about bits 7 & 8
  }
  else {
    //oh noes, no data!
  }
   
  return temp3231;
}

eventuell schaff ich das in den ESP32 mit einzubinden , auf 4 Zeiliges display in den unteren 2 Reihen.
mfg Bernd
Zitieren
#2
Hallo Bernd,

wenn Du die Kommastellen (ohne Rundung) einfach abgeschnitten haben willst, musst Du den Rückgabewert der Funktion von get3231Temp() von float auf int casten. Also: lcd.print((int) get3231Temp()); Möchtest du Runden, würde ich einfach 0.5 zur Temperatur hinzuaddieren und dann auf int casten:
(int)(getTemp3231() + 0.5);

Und wie gesagt kannst Du das RTC-Modul parallel zum Display betreiben ohne neue GPIOs zu belegen, denn I2C ist ein Bussystem bei dem die Busteilnehmer unterschiedliche Adressen haben. Das RTC-Modul hat ja  die Adresse #define DS3231_I2C_ADDRESS 0x68 und das LCD 0x27, siehe LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 .

?mage Der Microcontroller ist der Master, Display und RTC sind die Slaves. Aber auf dem Foto sieht es so aus als wenn Du das schon umgesetzt hast?
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#3
Guten Tag,
ja, hatte ich so umgesetzt wie in der PM geschrieben.
Der DS3231 hat übrigens 2 verschiedee adressen, hatte ich so ausgelesen mit I2C scanner.
Und Funzt auf dem Nano und Uno.
Also dann so: lcd.print(" - "); lcd.print((int) get3231Temp()); lcd.print((char)223); lcd.print("C"); ?
oder dann so:lcd.print(" - "); lcd.print(int)(getTemp3231() + 0.5); lcd.print((char)223); lcd.print("C"); ?
Danke.
mfg Bernd

ps. mal zu Segor fahren, neues PinBrett holen
Zitieren
#4
Und noch etwas Bernd, der Uno und Nano hat GPIOs die 5V-tolerant sind, der ESP32 mag da nur max. Vdd+0.3V und Vdd maximal ist 3.6V, insgesamt als obere Grenze also 3.9V am GPIO.

Du kannst schauen ob das RTC-Modul auch auf der 3.3V-Schiene des NodeMCU läuft, dann sind die High-Pegel der RTC auf SDA (also die Antworten des Moduls) auch passend. Mein Display läuft bei mir zwar mit 5V, aber da es selbst nur Signale vom ESP32 mit Highpegel bei 3.3V empfängt und nichts auf SDA sendet (somit kommen keine 5V auf SDA), ist es kein Problem. Ich habe deshalb auf eine Pegelanpassung auf dem Datenbus des Displays verzichtet.
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#5
Guten Tag,
ok, werd ich beherzigen.
Ich habe mir dann mal ein 4x20 Display bei Segor gekauft.
Und gleich alles umgesetzt, Datum und Uhrzeit auf die Unteren Beiden Zeilen gelegt.
Die Uhrzeit und Datum wird einmalig manuell eingegeben > in der seriellen Konsole > T1009224200817 >
Secunde, Minute, Stunde, Wochentag, Tag, Monat, Jahr.
Sieht ganz gut aus. Das der momentane Code:

Code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define DS3231_I2C_ADDRESS 0x68
LiquidCrystal_I2C lcd(0x27,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// SCL - pin A5
// SDA - pin A4
// To set the clock, run the sketch and use the serial monitor.
// Enter T1009224200817; the code will read this and set the clock. See the code for full details.

byte seconds, minutes, hours, day, date, month, year;
char weekDay[4];

byte tMSB, tLSB;
float temp3231;

void setup()
{
  Wire.begin();
  Serial.begin(115200);
  lcd.init();                      // initialize the lcd

  // Print a message to the LCD.
  //lcd.backlight();
  //lcd.print(weekDay); lcd.print(", "); lcd.print(date, DEC); lcd.print("."); lcd.print(month, DEC); lcd.print("."); lcd.print(year,DEC); lcd.print(" - ");
  //lcd.setCursor(0,1);
  //lcd.print(weekDay); lcd.print(", "); lcd.print(date, DEC); lcd.print("."); lcd.print(month, DEC); lcd.print("."); lcd.print(year,DEC); lcd.print(" - ");

}


void loop()
{
 
  watchConsole();
 
 
 
  get3231Date();
 
  Serial.print(weekDay); Serial.print(", "); Serial.print(date, DEC); Serial.print("."); Serial.print(month, DEC); Serial.print("."); Serial.print(year,DEC); Serial.print(" - ");
  Serial.print(hours, DEC); Serial.print(":"); Serial.print(minutes, DEC); Serial.print(":"); Serial.print(seconds, DEC);
  Serial.print(" - Temp: "); Serial.println(get3231Temp());
  lcd.backlight();
  lcd.setCursor(0,2);
  if (weekDay <10)
  {lcd.print("0");}
  lcd.print(weekDay); lcd.print(" ,   ");
  if (date <10)
  {lcd.print("0");}
  lcd.print(date, DEC); lcd.print(".");
  if (month <10)
  {lcd.print("0");}
  lcd.print(month, DEC); lcd.print("."); lcd.print(20);lcd.print(year,DEC);
  lcd.setCursor(0,3);
  if (hours <10)
  {lcd.print("0");}
  lcd.print(hours, DEC);
  lcd.print(":");
  if (minutes <10)
  {lcd.print("0");}
  lcd.print(minutes, DEC); lcd.print(":");
  if (seconds <10)
  {lcd.print("0");}
  lcd.print(seconds, DEC);
  lcd.print("        "); lcd.print((int) get3231Temp()); lcd.print((char)223); lcd.print("C");
  delay(1000);
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

void watchConsole()
{
  if (Serial.available()) {      // Look for char in serial queue and process if found
    if (Serial.read() == 84) {      //If command = "T" Set Date
      set3231Date();
      get3231Date();
      Serial.println(" ");
    }
  }
}
 
void set3231Date()
{
//T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year)
//T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99)
//Example: 02-Feb-09 @ 19:57:11 for the 3rd day of the week -> T1157193020209
// T1124154091014
  seconds = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
  minutes = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hours   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  day     = (byte)  (Serial.read() - 48);
  date    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  month   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  year    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(day));
  Wire.write(decToBcd(date));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}


void get3231Date()
{
  // send request to receive data starting at register 0
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
  Wire.write(0x00); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes

  if(Wire.available()) {
    seconds = Wire.read(); // get seconds
    minutes = Wire.read(); // get minutes
    hours   = Wire.read(); // get hours
    day     = Wire.read();
    date    = Wire.read();
    month   = Wire.read(); //temp month
    year    = Wire.read();
       
    seconds = (((seconds & B11110000)>>4)*10 + (seconds & B00001111)); // convert BCD to decimal
    minutes = (((minutes & B11110000)>>4)*10 + (minutes & B00001111)); // convert BCD to decimal
    hours   = (((hours & B00110000)>>4)*10 + (hours & B00001111)); // convert BCD to decimal (assume 24 hour mode)
    day     = (day & B00000111); // 1-7
    date    = (((date & B00110000)>>4)*10 + (date & B00001111)); // 1-31
    month   = (((month & B00010000)>>4)*10 + (month & B00001111)); //msb7 is century overflow
    year    = (((year & B11110000)>>4)*10 + (year & B00001111));
  }
  else {
    //oh noes, no data!
  }
 
  switch (day) {
    case 1:
      strcpy(weekDay, "Son");
      break;
    case 2:
      strcpy(weekDay, "Mon");
      break;
    case 3:
      strcpy(weekDay, "Die");
      break;
    case 4:
      strcpy(weekDay, "Mit");
      break;
    case 5:
      strcpy(weekDay, "Don");
      break;
    case 6:
      strcpy(weekDay, "Frei");
      break;
    case 7:
      strcpy(weekDay, "Sam");
      break;
  }
}

float get3231Temp()
{
  //temp registers (11h-12h) get updated automatically every 64s
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
 
  if(Wire.available()) {
    tMSB = Wire.read(); //2's complement int portion
    tLSB = Wire.read(); //fraction portion
   
    temp3231 = (tMSB & B01111111); //do 2's math on Tmsb
    temp3231 += ( (tLSB >> 6) * 0.25 ); //only care about bits 7 & 8
  }
  else {
    //oh noes, no data!
  }
   
  return temp3231;
}
   

mfg Bernd
Zitieren
#6
Guten Tag,
ich habe jetzt mal versucht das ganze auf den ESP32 zu uppen,
bricht aber mit Fehlermeldung ab.
Da stimmt was mit der Anzeige ausgabe nicht.
sketch ist der von oben. Da weis ich nicht weiter.
Wenn ich die Zeilen mit dem if weglasse funzt es aber. die if befehle sind um das Datum und Uhrzeit immer 2 Stellig anzeigen zu lassen.
mfg Bernd

Zitat:Arduino: 1.8.3 (Windows 7), Board: "ESP32 Dev Module, QIO, 80MHz, 115200, None"

WARNUNG: Bibliothek LiquidCrystal_I2C-master behauptet auf (avr) Architektur(en) ausgeführt werden zu können und ist möglicherweise inkompatibel mit Ihrem derzeitigen Board, welches auf (esp32) Architektur(en) ausgeführt wird.
C:\Users\klammi\Documents\Arduino\RTC-Clock\RTC-Clock.ino: In function 'void loop()':

RTC-Clock:49: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]

   if (weekDay <10)

                ^

Mehrere Bibliotheken wurden für "LiquidCrystal_I2C.h" gefunden
 Benutzt: C:\Users\klammi\Documents\Arduino\libraries\LiquidCrystal_I2C-master
 Nicht benutzt: C:\Users\klammi\Documents\Arduino\libraries\esp32-lcd-master
exit status 1
ISO C++ forbids comparison between pointer and integer [-fpermissive]

Dieser Bericht wäre detaillierter, wenn die Option
"Ausführliche Ausgabe während der Kompilierung"
in Datei -> Voreinstellungen aktiviert wäre.
Zitieren
#7
Die Variable "weekDay" ist als char weekDay[4] definiert und stellt als weekDay einen Zeiger auf einen aus 4*char bestehenden Speicherbereich. Du vergleichst also einen Zeiger ob dieser kleiner 10 ist. Der Compiler für den ESP32 meldet das: "ISO C++ forbids comparison between pointer and integer [-fpermissive]", sprich in diesem Compilermode ist es nicht erlaubt.  

In get3231Date() wird dem Speicherbereich weekDay -(4*Character, also 4*"Buchstabe")- in:

 switch (day) {
   case 1:
     strcpy(weekDay, "Son");
     break;
   case 2:
     strcpy(weekDay, "Mon");
     break;
   case 3:
     strcpy(weekDay, "Die");
     break;
   case 4:
     strcpy(weekDay, "Mit");
     break;
   case 5:
     strcpy(weekDay, "Don");
     break;
   case 6:
     strcpy(weekDay, "Frei");
     break;
   case 7:
     strcpy(weekDay, "Sam");
     break;
 }

ein Wochentag als Zeichenkette zugewiesen.

Die Anweisung if (weekDay<10)   {lcd.print("0");} macht in meinen Augen wenig Sinn. Wollte man hier schauen ob der erste Buchstabe als ASCII-Code kleiner 10 ist und dann eine "0" ausgeben? Der Wert der Variable weekDay würde so oder so in der nächsten Anweisung lcd.print(weekDay) ausgegeben, da diese nicht im Block der If-Bedingung steht. Dann wäre if (weekDay[0]<10) doch passender, wenn auch in meinen Augen sinnlos, aber es würde vom ESP32-Compiler wenigstens übersetzt werden.

Möglicherweise wollte man hier auch schauen ob dem Zeiger ein Wert im Speicher zugewiesen wurde, falls die Variable "day" durch die Switch-Anweisung in get3231Date() fällt und somit kein "Werktag" in den Speicherbereich des Zeigers weekDay kopiert wurde. Dann wäre aber ein Default-Wert in der Switch-Anweisung machbar.

Was der Ur-Autor also mit if (weekDay<10) bezwecken wollte, kann ich nicht mehr nachvollziehen.

Bei   if (date <10) ;   if (month <10) ; ....  if (seconds <10) ergibt sich hingegen ein Sinn! Hier wird eine führende Null bei einstelligen numerischen Variablenwerten vorgesetzt. Aber bei weekDay erkenne ich den Sinn nicht. Vielleicht ein anderer Forennutzer?

Ich würde den Codepart auskommentieren, denn der weekday wird so oder so als Zeichenkette (Son, Mon ,... ) ausgegeben, da der print-Befehl für weekDay hinter der If-Bedingung steht und die Bedingung weekDay<10 praktisch nicht auftritt.

Gruß Bernhard
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#8
Guten Tag,

Bernhard Du hast vollkommen Recht
jaaa...das weekDay das mein Fehler...ich war mal ne runde Blind. Smiley26
Das nehm ich da gleich raus.
Sollte ja nur für die Zahlen gelten aus einstellig zweistellig machen, wegen der besseren Ansicht.
Aber bei Text ist das ja ungültig...man man bin ich blind.

Danke

mfg Bernd
Zitieren
#9
Guten Morgen,
ich bin ein Schritt weiter (ich stand nicht vor einem Abgrund Angel )
Ich habe jetzt das Radio und die Uhr auf dem Display.
Aber...das radio funzt nicht richtig. Smiley57
Der Drehencoder scheint teilweise blockiert, das radio abgehackt.
Da scheint sich was zu verhakeln. Smiley19 
Könnte sich das mal jemand bitte anschauen

Code:
// Bibliotheken einbinden
#include <WiFiClient.h>
#include <WiFi.h>
#include <Adafruit_VS1053.h>
#include <LiquidCrystal_I2C.h>
#include "Programmliste.h"
#include <TaskScheduler.h>
#include <DS3231.h>
#include <Wire.h>
#define DS3231_I2C_ADDRESS 0x68
//LiquidCrystal_I2C lcd(0x27, 20, 4);

byte seconds, minutes, hours, day, date, month, year;
char weekDay[4];
byte tMSB, tLSB;
float temp3231;

Scheduler ts;

// Deklaration der Funktionen die im Scheduler ablaufen sollen
void Task_Drehencoder();
void Task_Umschaltung();
Task task_Drehencoder(1,  TASK_FOREVER,  &Task_Drehencoder);
Task task_Programmumschaltung(1000, TASK_FOREVER, &Task_Umschaltung);

// Zugangsdaten zum WLAN
char* ssid     = "+++++";
const char* password = "++++++";

// Webstream GoodTimeOldies: listen.181fm.com/181-goodtime_64k.aac
char* programmname;
char* hostrechner = "listen.181fm.com";
char* pfad = "/181-goodtime_64k.aac";
int httpPort = 80;


// Anschlussschema des VS1053-DSP
#define VS1053_CS      17  // VS1053 Chip Select Pin
#define VS1053_DCS     16  // VS1053 Data/Command Select Pin
#define VS1053_DREQ    34  // VS1053 Data request
#define VS1053_MOSI    25  // VS1053 MOSI
#define VS1053_MISO    26  // VS1053 MISO
#define VS1053_CLK     32  // VS1053 Clock Pin
#define VS1053_RESET   27  // VS1053 reset pin (-1 unbelegt)

// LCD
#define DISPLAY_SDA_PIN 21
#define DISPLAY_SCL_PIN 22

#define DISPLAY_X 20
#define DISPLAY_Y 4

#define DISPLAY_I2C_ADRESSE 0x27

// Dreh-Encoder
#define pinA 35
#define pinB 39
#define pinC 36 //SW-Pin

int encoderPosCount = 0;
int pinALast;
int aVal;

// LCD
LiquidCrystal_I2C lcd(DISPLAY_I2C_ADRESSE, DISPLAY_X, DISPLAY_Y);

// Dekoderinstanz erstellen
Adafruit_VS1053 VS1053Dekoder = Adafruit_VS1053(VS1053_MOSI, VS1053_MISO, VS1053_CLK, VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ);

// MP3 Datenpuffer
uint8_t mp3buff[32];

// Einen WiFi-Client für HTTP/TCP-Verbindungen erstellen
WiFiClient client;

// Aktuell eingeschaltetes Programm
int iProgrammnummer = 0;

void setup() {
  Serial.begin(115200); // Serielle Console für Fehlersuche

  lese_Programmliste();
  if (stationen[iProgrammnummer] != NULL) {
    programmname = stationen[iProgrammnummer]->get_Programmname();
    hostrechner = stationen[iProgrammnummer]->get_Host();
    pfad = stationen[iProgrammnummer]->get_Pfad();
  }

  Wire.begin(DISPLAY_SDA_PIN, DISPLAY_SCL_PIN);
  lcd.begin(DISPLAY_X, DISPLAY_Y);
  lcd.init();
  lcd.backlight();

  if (! VS1053Dekoder.begin())
  { // initialisiere VS1053-Dekoder
    Serial.println(F("Kein VS1053-DSP-Dekoder gefunden"));
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("BOOT: VS1053 FAIL");
    while (1) delay(10);
  }

  Serial.println(F("VS1053-DSP-Dekoder gefunden"));
  // Einstellung Standardlaustärke (links, rechts)
  VS1053Dekoder.setVolume(7, 7);

  // WIFI-Client initialisieren
  Serial.print("Verbinde mit Netzwerk-SSID "); Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("BOOT: WLAN...");
  }

  Serial.print("WIFI-Verbindung hergestellt. ");
  Serial.println("IP-Adresse: ");  Serial.println(WiFi.localIP());
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("BOOT: WLAN OK");
  lcd.setCursor(0, 1);
  lcd.print(WiFi.localIP());
  delay(3000);

  Serial.print("Verbinde zum Audiostream: ");  Serial.println(hostrechner);

  if (!client.connect(hostrechner, httpPort)) {
    Serial.println("Verbindung fehlgeschlagen!");
    return;
  }

  // URI zur Anfrage erzeugen
  Serial.print("Verbindung steht, stelle Anfrage-URL: ");
  Serial.println(pfad);

  client.print(String("GET ") + pfad + " HTTP/1.1\r\n" +
               "Host: " + hostrechner + "\r\n" +
               "Connection: close\r\n\r\n");

  pinMode (pinA, INPUT);
  pinMode (pinB, INPUT);

  pinALast = digitalRead(pinA);

  ts.init(); // der ThreadScheduler wird initialisiert

  ts.addTask(task_Drehencoder);
  ts.addTask(task_Programmumschaltung);
  task_Drehencoder.enable();
  task_Programmumschaltung.enable();

  UpdateDisplay();
}


void loop()
{
  ts.execute();
  // DSP für weitere Daten bereit?
  if (VS1053Dekoder.readyForData()) {
    if (client.available() > 0) {
      // Datenpuffer füllen
      uint8_t bytesread = client.read(mp3buff, 32);
      // und zum Dekoder schicken
      VS1053Dekoder.playData(mp3buff, bytesread);
    }
  }
}

void UpdateDisplay() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("P"); lcd.print(iProgrammnummer); lcd.print(" ");
  lcd.print(programmname);
}

void Task_Umschaltung() {
  if (iProgrammnummer != encoderPosCount) {
    if (stationen[encoderPosCount] != NULL) {
      iProgrammnummer = encoderPosCount;
      programmname = stationen[iProgrammnummer]->get_Programmname();
      hostrechner = stationen[iProgrammnummer]->get_Host();
      pfad = stationen[iProgrammnummer]->get_Pfad();

      Serial.print("Kanalwechsel, neuer Stream:"); Serial.print(hostrechner); Serial.println(pfad);
      if (!client.connect(hostrechner, httpPort)) {
        Serial.println("Verbindung fehlgeschlagen!");
        return;
      }

      Serial.println("Verbindungswechsel... VS1053-Reset ... ");
      VS1053Dekoder.reset(); // für schnellere Neudekodierung
      VS1053Dekoder.setVolume(7, 7);
      client.print(String("GET ") + pfad + " HTTP/1.1\r\n" +
                   "Host: " + hostrechner + "\r\n" +
                   "Connection: close\r\n\r\n");

      UpdateDisplay();
    }
  }
}

void Task_Drehencoder() {
  aVal = digitalRead(pinA);
  if ((pinALast == LOW) && (aVal == HIGH)) {
    if (digitalRead(pinB) == LOW) {
      if (encoderPosCount == 0)
        encoderPosCount = MAXPROG;

      encoderPosCount--;
      Serial.print("runterschalten:");
    } else {
      if (encoderPosCount > MAXPROG - 2)
        encoderPosCount = -1;

      encoderPosCount++;
      Serial.print("hochschalten:");
    }
    Serial.println(encoderPosCount);
  }
  pinALast = aVal;

//void loop()

  watchConsole();
  get3231Date();

  //Serial.print(weekDay); Serial.print(", "); Serial.print(date, DEC); Serial.print("."); Serial.print(month, DEC); Serial.print("."); Serial.print(year, DEC); Serial.print(" - ");
  //Serial.print(hours, DEC); Serial.print(":"); Serial.print(minutes, DEC); Serial.print(":"); Serial.print(seconds, DEC);
  //Serial.print(" - Temp: "); Serial.println(get3231Temp());
  lcd.backlight();
  lcd.setCursor(0, 2);
  lcd.print(weekDay); lcd.print(" ,   ");
  if (date < 10)
  {
    lcd.print("0");
  }
  lcd.print(date, DEC); lcd.print(".");
  if (month < 10)
  {
    lcd.print("0");
  }
  lcd.print(month, DEC); lcd.print("."); lcd.print(20); lcd.print(year, DEC);
  lcd.setCursor(0, 3);
  if (hours < 10)
  {
    lcd.print("0");
  }
  lcd.print(hours, DEC);
  lcd.print(":");
  if (minutes < 10)
  {
    lcd.print("0");
  }
  lcd.print(minutes, DEC); lcd.print(":");
  if (seconds < 10)
  {
    lcd.print("0");
  }
  lcd.print(seconds, DEC);
  lcd.print("        "); lcd.print((int) get3231Temp()); lcd.print((char)223); lcd.print("C");
  delay(1000);
}

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}

void watchConsole()
{
  if (Serial.available()) {      // Look for char in serial queue and process if found
    if (Serial.read() == 84) {      //If command = "T" Set Date
      set3231Date();
      get3231Date();
      Serial.println(" ");
    }
  }
}

void set3231Date()
{
  //T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year)
  //T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99)
  //Example: 02-Feb-09 @ 19:57:11 for the 3rd day of the week -> T1157193020209
  // T1124154091014
  seconds = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.
  minutes = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48));
  hours   = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48));
  day     = (byte)  (Serial.read() - 48);
  date    = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48));
  month   = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48));
  year    = (byte) ((Serial.read() - 48) * 10 +  (Serial.read() - 48));
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(day));
  Wire.write(decToBcd(date));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}
void get3231Date()
{
  // send request to receive data starting at register 0
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
  Wire.write(0x00); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes

  if (Wire.available()) {
    seconds = Wire.read(); // get seconds
    minutes = Wire.read(); // get minutes
    hours   = Wire.read(); // get hours
    day     = Wire.read();
    date    = Wire.read();
    month   = Wire.read(); //temp month
    year    = Wire.read();

    seconds = (((seconds & B11110000) >> 4) * 10 + (seconds & B00001111)); // convert BCD to decimal
    minutes = (((minutes & B11110000) >> 4) * 10 + (minutes & B00001111)); // convert BCD to decimal
    hours   = (((hours & B00110000) >> 4) * 10 + (hours & B00001111)); // convert BCD to decimal (assume 24 hour mode)
    day     = (day & B00000111); // 1-7
    date    = (((date & B00110000) >> 4) * 10 + (date & B00001111)); // 1-31
    month   = (((month & B00010000) >> 4) * 10 + (month & B00001111)); //msb7 is century overflow
    year    = (((year & B11110000) >> 4) * 10 + (year & B00001111));
  }
  else {
    //oh noes, no data!
  }

  switch (day) {
    case 1:
      strcpy(weekDay, "Son");
      break;
    case 2:
      strcpy(weekDay, "Mon");
      break;
    case 3:
      strcpy(weekDay, "Die");
      break;
    case 4:
      strcpy(weekDay, "Mit");
      break;
    case 5:
      strcpy(weekDay, "Don");
      break;
    case 6:
      strcpy(weekDay, "Frei");
      break;
    case 7:
      strcpy(weekDay, "Sam");
      break;
  }
}

float get3231Temp()
{
  //temp registers (11h-12h) get updated automatically every 64s
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);

  if (Wire.available()) {
    tMSB = Wire.read(); //2's complement int portion
    tLSB = Wire.read(); //fraction portion

    temp3231 = (tMSB & B01111111); //do 2's math on Tmsb
    temp3231 += ( (tLSB >> 6) * 0.25 ); //only care about bits 7 & 8
  }
  else {
    //oh noes, no data!
  }
  return temp3231;
}

   

Ich bin dann mal wieder drei Tage im Benjamin Franklin...
bis denne Bernd
Zitieren
#10
Du kannst deine lange Routine, die zudem noch ein  delay(1000); enthält, nicht in einer TaskRoutine -die jede Millisekunde den Encoder auf Drehänderung pollt und schnell arbeiten muss- parken. Raus damit aus dem Polling. Du hast immer noch nicht die Grundaufgabe erfüllt und Dich mit C/C++ beschäftigt und das Testprogramm verstanden!

Zur Anzeige:
Wenn man etwas, nach dem Reboot und während des laufenden Systems [ loop() ], aufs Display schreiben will, macht man das am Besten zentral in einer Routine. Wie wäre es mit der schon bestehenden Funktion UpdateDisplay() ? Bietet sich diese Funktion nicht schon vom Namen her regelrecht dafür an?

Diese Funktion [also UpdateDisplay()] kannst Du aus einem neuen Task aus aufrufen, der jede Sekunde (also alle 1000ms) vom TaskScheduler ausgeführt wird, dann wird auch deine Sekundenanzeige wunderbar aktualisiert (aber nur wenn dein delay im Programmablauf verschwindet). Und lcd.backlight(); brauchst Du auch nicht mehrmals aufrufen! Die Hintergrundbeleuchtung ist ja schon angeschaltet.


PS: Deine WLAN-Zugangsdaten müssen auch nicht im Forum stehen. Lösche Sie doch einfach und ersetze Sie durch "xxx".
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#11
Hallo Bernd,

bist Du denn klar gekommen mit dem Umschreiben des Testprogramms?

Viele Bastlergrüße
Bernhard
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#12
Guten Abend,
nein..habe alles erstmal weggestellt.
Ich schaff es momentan gesundheitlich nicht mich zu konzentrieren. Das Wetter und die Chemo haben mich voll im Griff.
Könnte den ganzen Tag schlafen. Aber wenns mir besser geht dann setz ich mich da wieder ran.
mfg Bernd
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  "Web-Sprechfunkgerät" basteln, bauen? snzgl 28 6.265 10.01.2019, 10:01
Letzter Beitrag: Bernhard45

Gehe zu: