Uzyskałem wyświetlacz z lekkim uszkodzeniem w postaci nieczynnych poziomych linii, wyeliminowałem te linie wykorzystując odpowiednie graficzne ułożenie (przerwy między ramkami w grafice wyświetlacza widocznym na zdjęciu).
Sterownik wyświetlacza działa na bibliotece u8glib i Timelib.h dla Arduino. Sterownik jest tak zaprogramowany aby przyjmował czas w postaci czasu unixowego (czas w sekundach od początku epoki) i wiadomości tekstowe które wyświetli w dwóch ramkach pod datą. Informacje te są przesyłane z ESP8266 poprzez UART.
0x02 to znak początku wiadomości,
0x03 to znak końca wiadomości
Można przesłać 3 typy informacji w postaci:
znak początku"0x02" parametr, informacja znak końca"0x03"
linia pierwsza: 0x02 1, ramka pierwsza 0x03
linia druga: 0x02 2, ramka druga 0x03
i czas w postaci czasu unixowego.
ESP8266 poprzez WiFi pobiera czas z wskazanego serwera czasu (biblioteka Timelib.h), wykorzystuję również bibliotekę Timezone.h - aby dostosować czas do obowiązującego w Polsce (czas letni/zimowy), ponieważ czas z serwera to UTC 0. Informacje pogodowe pobierane są z serwera Open Weather Maps - aby z niego korzystać należy założyć darmowe konto i wygenerować klucz API potrzebny do obsługi zapytań tego serwera.
Początkowo próbowałem skorzystać z biblioteki JSON dla Arduino do odczytu informacji pogodowych, lecz zrezygnowałem z tego na rzecz własnego 'parsowania' danych. Dane zwracane przez bibliotekę miały własny format danych, które ciężko konwersować do innych typów.
[Przy próbie załadowania tych kodów do mikrokontrolerów upewnij się, że masz załadowane potrzebne biblioteki użyte w kodzie.]
Kod dla Arduino Nano jako sterownik wyświetlacza
#include "U8glib.h" U8GLIB_T6963_240X128 u8g(7, 8, 9, 10, 11, 12, 14, 15, 4, 5, 2, 3, 6); // 8Bit Com: D0..D7: 7,8,9,10,11,12,14,15, cs=4, a0=5, wr=2, rd=3, reset=6 #include <TimeLib.h> short DN; //Returns the number of day in the year short WN; //Returns the number of the week in the year int Hour = 0, Min = 0, Sec = 0, lastSecond = 0; char Hh[] = "00", Mm[] = "00", Ss[] = "00"; String stringHour, stringMinute, stringSecond, stringTime, stringDate, stringWeek; String info_1 = "Infomation line 1", info_2 = "Infomation line 2"; // SERRIAL #define numChars 255 char tempChars[numChars]; char messageFromPC[numChars] = {0}; int integerFromPC = 0; //chars for serial: char startChar = 0x02; char stopChar = 0x03; void draw(void) { u8g.setFont(u8g_font_fub42n); u8g.drawStr( 0, 47, stringTime.c_str() ); u8g.drawRFrame(0, 0, 240, 55, 1); //ramka na godzinę u8g.drawBox(0, 50, (second() * 4), 4); // pasek sekund pod godzina u8g.setFont(u8g_font_fub30n); u8g.drawStr( 2, 90, stringDate.c_str() ); u8g.drawRFrame(0, 56, 214, 36, 1); //ramka na datę u8g.drawRFrame(215, 56, 25, 36, 1); //ramka na tydzień u8g.setFont(u8g_font_profont10); u8g.drawStr( 218, 66, "WEEK" ); u8g.setFont(u8g_font_fub14); u8g.drawStr( 216, 87, stringWeek.c_str() ); u8g.drawRFrame(0, 93, 240, 15, 1); // pierwsza ramka informacyjna u8g.setFont(u8g_font_profont12); u8g.drawStr( 3, 104, info_1.c_str() ); u8g.drawRFrame(0, 110, 240, 18, 1); // pierwsza ramka informacyjna u8g.drawStr( 3, 124, info_2.c_str() ); } void recvWithStartEndMarkers() { bool starting, transmitting; byte len = 0, pointer = 0; char rc; char buffer_1[numChars]; while (Serial.available() > 0) { rc = Serial.read(); if (rc == startChar) { starting = true; } else if (transmitting && pointer < len) { buffer_1[pointer++] = rc; } else if (starting) { len = rc; pointer = 0; starting = false; transmitting = true; } else if (transmitting && pointer == len) { transmitting = false; if (rc == stopChar) { while (pointer < numChars) { buffer_1[pointer++] = 0; } char * strtokIndx = 0; // this is used by strtok() as an index strtokIndx = strtok(buffer_1, ","); // get the first part - the integer integerFromPC = atoi(strtokIndx); // convert this part to an integer Serial.println(strtokIndx); strtokIndx = strtok(NULL, ","); // this continues where the previous call left off strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC switch (integerFromPC) { case 1: info_1 = messageFromPC; break; case 2: info_2 = messageFromPC; break; case 3: setTime( ((String)messageFromPC).toInt() ); break; default: //Serial.println("Incorrect number"); break; } } } } } //============ void setup(void) { Serial.begin(9600); pinMode(13, OUTPUT); digitalWrite(13, HIGH); //setSyncProvider( requestSync); //set function to call when sync required Serial.println("Data Format to send: <number,massage> "); Serial.println("line 1: 0x02 1, line 1 massage 0x03 "); Serial.println("line 2: 0x02 2, line 2 massage 0x03 ");
Serial.println("set time: 0x02 3,unix stamp 0x03 "); // flip screen, if required // u8g.setRot180(); setTime(1586858400); } void loop(void) { recvWithStartEndMarkers(); date_to_string(); time_to_string(); DayWeekNumber(year(), month(), day(), weekday()); u8g.firstPage(); do { draw(); } while ( u8g.nextPage() ); delay(500); } void time_to_string() { stringHour = ""; stringMinute = ""; stringSecond = ""; stringTime = ""; // adding 0 if number if less than 0 if (hour() < 10) { stringHour = stringHour + "0" + hour(); } else stringHour = stringHour + hour(); if (minute() < 10) { stringMinute = stringMinute + "0" + minute(); } else stringMinute = stringMinute + minute(); if (second() < 10) { stringSecond = stringSecond + "0" + second(); } else stringSecond = stringSecond + second(); // time as a one string stringTime = stringHour + ":" + stringMinute + ":" + stringSecond; } void date_to_string() { String stringYear = "", stringMonth = "", stringDay = ""; stringYear = year(); if (month() < 10) { stringMonth = stringMonth + "0" + month(); } else stringMonth = month(); if (day() < 10) { stringDay = stringDay + "0" + day(); } else stringDay = day(); // date as a one string stringDate = stringYear + "-" + stringMonth + "-" + stringDay; } void DayWeekNumber(unsigned int y, unsigned int m, unsigned int d, unsigned int w) { int days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // Number of days at the beginning of the month in a not leap year. stringWeek = ""; //Start to calculate the number of day if (m == 1 || m == 2) { DN = days[(m - 1)] + d; //for any type of year, it calculate the number of days for January or february } // Now, try to calculate for the other months else if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) { //those are the conditions to have a leap year DN = days[(m - 1)] + d + 1; // if leap year, calculate in the same way but increasing one day } else { //if not a leap year, calculate in the normal way, such as January or February DN = days[(m - 1)] + d; } // Now start to calculate Week number if (w == 0) { WN = (DN - 7 + 10) / 7; //if it is sunday (time library returns 0) } else { WN = (DN - w + 10) / 7; // for the other days of week } stringWeek = WN; }
Kod dla ESP8266
#include <ESP8266WiFi.h> #include <TimeLib.h> #include <WiFiUdp.h> #include <Timezone.h> const char* ssid = "ssid"; // SSID of local network const char* password = "pass"; // Password on network String APIKEY = "APIKEY"; String CityID = "YourCity"; //Your City WiFiClient client; char servername[] = "api.openweathermap.org"; // remote server we will connect to String result; int counter = 10; long Timer1 = 0; String weatherDescription = ""; String weatherLocation = ""; float temperature, temp_max, temp_min; int humidity; int pressure; long Sunrise; long Sunset; double Speed; long Temp_min; long Temp_max; long Visibility; // TIME: static const char ntpServerName[] = "time.nist.gov"; const int timeZone = 0; // Central European Time //=0 because use TimeZone lib WiFiUDP Udp; unsigned int localPort = 8888; // local port to listen for UDP packets time_t getNtpTime(); void digitalClockDisplay(); void printDigits(int digits); void sendNTPpacket(IPAddress &address); TimeChangeRule myDST = {"EDT", Last, Sun, Mar, 2, 120}; // Daylight time = UTC - 4 hours TimeChangeRule mySTD = {"EST", Last, Sun, Nov, 2, 60}; // Standard time = UTC - 5 hours Timezone myTZ(myDST, mySTD); TimeChangeRule *tcr; time_t prevDisplay = 0; // when the digital clock was displayed time_t utc; time_t local; void setup() { pinMode(2, OUTPUT); digitalWrite(2,LOW); Serial.begin(9600); WiFi.begin(ssid, password); //Serial.println();Serial.println(); //Serial.println("connecting: "); while (WiFi.status() != WL_CONNECTED) { delay(500); //Serial.print("."); } //Serial.println("WiFi Connected"); //Serial.println(WiFi.localIP()); Udp.begin(localPort); //Serial.println(Udp.localPort()); setSyncProvider(getNtpTime); setSyncInterval(300); utc = now(); local = myTZ.toLocal(utc, &tcr); //Serial.println(); //printDateTime(utc, "UTC"); //printDateTime(local, tcr -> abbrev); SendData("3," + (String)local); delay(1000); getWeatherData(); } // ############## MAIN LOOP ############## int tick = 0; void loop() { if (millis() - Timer1 > 60000) { Timer1 = millis(); tick++; if(tick > 9){ getWeatherData(); tick = 0; } } } // ######## END OF MAIN LOOP ############ //client function to send/receive GET request data. void getWeatherData() { //starts client connection, checks for connection if (client.connect(servername, 80)) { client.println("GET /data/2.5/weather?q=" + CityID + "&lang=pl&units=metric&APPID=" + APIKEY); client.println("Host: api.openweathermap.org"); client.println("User-Agent: ArduinoWiFi/1.1"); client.println("Connection: close"); client.println(); } else { //error message if no client connect Serial.println("connection failed"); Serial.println(); } while (client.connected() && !client.available()) { //waits for data delay(1); } result = ""; //connected or data available while (client.connected() && client.available()) { //gets byte from ethernet buffer char c = client.read(); if (c != 0) { result = result + c; } } client.stop();//stop client //Serial.println("<2,Try>"); if ( result.indexOf("\"temp\":") > 1 ) { temperature = ParseDataOpenWeatherMaps(result, "temp").toFloat(); humidity = ParseDataOpenWeatherMaps(result, "humidity").toFloat(); pressure = ParseDataOpenWeatherMaps(result, "pressure").toFloat(); temp_max = ParseDataOpenWeatherMaps(result, "temp_max").toFloat(); temp_min = ParseDataOpenWeatherMaps(result, "temp_min").toFloat(); weatherDescription = ParseDataOpenWeatherMaps(result, "description"); weatherDescription.remove(0, 1); //delete first char " weatherDescription.remove(weatherDescription.length() - 1); // delete last char " SendData("1,T:" + roundAndString(temperature) + "(" + roundAndString(temp_min) + "/" + roundAndString(temp_max) + ")'C H:" + (String)humidity + " P:" + (String)pressure + "hPa" ); delay(2000); SendData("2," + weatherDescription); delay(2000); local = myTZ.toLocal(now(), &tcr); SendData("3," + (String)local); } //Serial.println(); //printDateTime(utc, "UTC"); //printDateTime(local, tcr -> abbrev); delay(1000); } String ParseDataOpenWeatherMaps(String input, String parameter) { parameter = "\"" + parameter + "\":"; String workingPhraseString = input.substring(input.indexOf(parameter), input.indexOf(parameter) + 56); char endMarker = ','; char rc; byte i = 0; while ( rc != endMarker ) { rc = workingPhraseString[i]; i++; } byte whereStart = input.indexOf(parameter) + parameter.length(); byte whereEnd = input.indexOf(parameter) + i - 1; return input.substring(whereStart, whereEnd); } // ################# SEND DATA ##################### void SendData(String input) { Serial.write(0x02); Serial.write((byte)input.length()); Serial.print(input); Serial.write(0x03); Serial.println(input.length()); } String roundAndString(float input) { input = round(input * 10) / 10; String output = (String)(input); output.remove(output.length()-1, 1); return output; } void printDigits(int digits) { // utility for digital clock display: prints preceding colon and leading 0 Serial.print(":"); if (digits < 10) Serial.print('0'); Serial.print(digits); } /*-------- NTP code ----------*/ const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets time_t getNtpTime() { IPAddress ntpServerIP; // NTP server's ip address while (Udp.parsePacket() > 0) ; // discard any previously received packets //Serial.println("Transmit NTP Request"); // get a random server from the pool WiFi.hostByName(ntpServerName, ntpServerIP); //Serial.print(ntpServerName); //Serial.print(": "); //Serial.println(ntpServerIP); sendNTPpacket(ntpServerIP); uint32_t beginWait = millis(); while (millis() - beginWait < 1500) { int size = Udp.parsePacket(); if (size >= NTP_PACKET_SIZE) { //Serial.println("Receive NTP Response"); Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer unsigned long secsSince1900; // convert four bytes starting at location 40 to a long integer secsSince1900 = (unsigned long)packetBuffer[40] << 24; secsSince1900 |= (unsigned long)packetBuffer[41] << 16; secsSince1900 |= (unsigned long)packetBuffer[42] << 8; secsSince1900 |= (unsigned long)packetBuffer[43]; return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; } } Serial.println("No NTP Response :-("); return 0; // return 0 if unable to get the time } // send an NTP request to the time server at the given address void sendNTPpacket(IPAddress &address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); //NTP requests are to port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } void printDateTime(time_t t, const char *tz) { char buf[32]; char m[4]; // temporary storage for month string (DateStrings.cpp uses shared buffer) strcpy(m, monthShortStr(month(t))); sprintf(buf, "%.2d:%.2d:%.2d %s %.2d %s %d %s", hour(t), minute(t), second(t), dayShortStr(weekday(t)), day(t), m, year(t), tz); Serial.println(buf); }
Pomocne linki:
wątek na forum Arduino: Topic: Serial Input Basics - updated - jak działa komunikacja UART i przykładowe kody (bazowałem głównie na przykładzie nr 5)
Open Weather Maps API - stąd można pozyskać dane środowiskowe (temperatura, wilgotność, itd...)
Kod pokolorowałem tutaj: hilite.me
Jak dodać płytkę ESP w Arduino opisałem w innym poście
Brak komentarzy:
Prześlij komentarz