Programem Arduino.

....nie pasujące gdzie indziej...
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Programem Arduino.

Post autor: pier »

Witam.

Mam nadzieję że się nikt nie pogniewa jak zapytam tutaj o kilka kwestii związanych z programem w Arduino.

Mianowicie mam popularny program na ESP8266 i wyświetlaczu oled który pokazuje dane z serwera Weatherunderground i Thingspeak-a. Wyświetla te dane w czterech przewijających się "ramkach".
Dane te chciałbym przesłać przez port szeregowy i nawet to działa ale problem jest tego typu że konkretne dane wypluwa mi jak głupi przez cały czas trwania danej ramki. Powoduje to niezły bajzel przy odczycie.

Jest jakaś funkcja lub sposób dzięki któremu prześlę interesujące mnie dane tylko raz tak aby nie zatrzymywać programu?
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Tak.
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

ptja pisze:Tak.
A coś więcej?
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Ty zacznij :)
Choćby załączając kod.
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

A proszę program:

Kod: Zaznacz cały


#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <JsonListener.h>
#include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"
#include "Wire.h"
#include "WundergroundClient.h"
#include "WeatherStationFonts.h"
#include "WeatherStationImages.h"
#include "TimeClient.h"
#include "ThingspeakClient.h"

/***************************
 * Begin Settings
 **************************/

// WIFI
const char* WIFI_SSID = "";
const char* WIFI_PWD = "";


// Setup
const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 10 minutes

// Display Settings
const int I2C_DISPLAY_ADDRESS = 0x3c;
const int SDA_PIN = D6;
const int SDC_PIN = D5;

// TimeClient settings
const float UTC_OFFSET = 2;

// Wunderground Settings
const boolean IS_METRIC = true;
const String WUNDERGRROUND_API_KEY = "";
const String WUNDERGRROUND_LANGUAGE = "PL";
const String WUNDERGROUND_COUNTRY = "PL";
const String WUNDERGROUND_CITY = "Bilgoraj";

//Thingspeak Settings
const String THINGSPEAK_CHANNEL_ID = "271134";
const String THINGSPEAK_API_READ_KEY = "";

// Initialize the oled display for address 0x3c
// sda-pin=14 and sdc-pin=12
SSD1306Wire     display&#40;I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN&#41;;
OLEDDisplayUi   ui&#40; &display &#41;;

/***************************
 * End Settings
 **************************/

TimeClient timeClient&#40;UTC_OFFSET&#41;;

// Set to false, if you prefere imperial/inches, Fahrenheit
WundergroundClient wunderground&#40;IS_METRIC&#41;;

ThingspeakClient thingspeak;

// flag changed in the ticker function every 10 minutes
bool readyForWeatherUpdate = false;

String lastUpdate = "--";

Ticker ticker;

//declaring prototypes
void drawProgress&#40;OLEDDisplay *display, int percentage, String label&#41;;
void updateData&#40;OLEDDisplay *display&#41;;
void drawDateTime&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41;;
void drawCurrentWeather&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41;;
void drawForecast&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41;;
void drawThingspeak&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41;;
void drawForecastDetails&#40;OLEDDisplay *display, int x, int y, int dayIndex&#41;;
void drawHeaderOverlay&#40;OLEDDisplay *display, OLEDDisplayUiState* state&#41;;
void setReadyForWeatherUpdate&#40;&#41;;


// Add frames
// this array keeps function pointers to all frames
// frames are the single views that slide from right to left
FrameCallback frames&#91;&#93; = &#123; drawDateTime, drawCurrentWeather, drawForecast, drawThingspeak &#125;;
int numberOfFrames = 4;

OverlayCallback overlays&#91;&#93; = &#123; drawHeaderOverlay &#125;;
int numberOfOverlays = 1;

void setup&#40;&#41; &#123;
  Serial.begin&#40;115200&#41;;
  Serial.println&#40;&#41;;
  Serial.println&#40;&#41;;

  // initialize dispaly
  display.init&#40;&#41;;
  display.clear&#40;&#41;;
  display.display&#40;&#41;;

  display.flipScreenVertically&#40;&#41;;
  display.setFont&#40;ArialMT_Plain_10&#41;;
  display.setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display.setContrast&#40;255&#41;;

  WiFi.begin&#40;WIFI_SSID, WIFI_PWD&#41;;

  int counter = 0;
  while &#40;WiFi.status&#40;&#41; != WL_CONNECTED&#41; &#123;
    delay&#40;500&#41;;
    Serial.print&#40;"."&#41;;
    display.clear&#40;&#41;;
    display.drawString&#40;64, 10, "Connecting to WiFi"&#41;;
    display.drawXbm&#40;46, 30, 8, 8, counter % 3 == 0 ? activeSymbole &#58; inactiveSymbole&#41;;
    display.drawXbm&#40;60, 30, 8, 8, counter % 3 == 1 ? activeSymbole &#58; inactiveSymbole&#41;;
    display.drawXbm&#40;74, 30, 8, 8, counter % 3 == 2 ? activeSymbole &#58; inactiveSymbole&#41;;
    display.display&#40;&#41;;

    counter++;
  &#125;

  ui.setTargetFPS&#40;30&#41;;

  ui.setActiveSymbol&#40;activeSymbole&#41;;
  ui.setInactiveSymbol&#40;inactiveSymbole&#41;;

  // You can change this to
  // TOP, LEFT, BOTTOM, RIGHT
  ui.setIndicatorPosition&#40;BOTTOM&#41;;

  // Defines where the first frame is located in the bar.
  ui.setIndicatorDirection&#40;LEFT_RIGHT&#41;;

  // You can change the transition that is used
  // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
  ui.setFrameAnimation&#40;SLIDE_LEFT&#41;;

  ui.setFrames&#40;frames, numberOfFrames&#41;;

  ui.setOverlays&#40;overlays, numberOfOverlays&#41;;

  // Inital UI takes care of initalising the display too.
  ui.init&#40;&#41;;

  Serial.println&#40;""&#41;;
display.flipScreenVertically&#40;&#41;;
  updateData&#40;&display&#41;;

display.flipScreenVertically&#40;&#41;;
  ticker.attach&#40;UPDATE_INTERVAL_SECS, setReadyForWeatherUpdate&#41;;

&#125;

void loop&#40;&#41; &#123;

  display.flipScreenVertically&#40;&#41;;

  if &#40;readyForWeatherUpdate && ui.getUiState&#40;&#41;->frameState == FIXED&#41; &#123;
    updateData&#40;&display&#41;;
  &#125;

  int remainingTimeBudget = ui.update&#40;&#41;;

  if &#40;remainingTimeBudget > 0&#41; &#123;
    // You can do some work here
    // Don't do stuff if you are below your
    // time budget.
    delay&#40;remainingTimeBudget&#41;;
  &#125;


&#125;

void drawProgress&#40;OLEDDisplay *display, int percentage, String label&#41; &#123;
  display->clear&#40;&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->drawString&#40;64, 10, label&#41;;
  display->drawProgressBar&#40;2, 28, 124, 10, percentage&#41;;
  display->display&#40;&#41;;
&#125;

void updateData&#40;OLEDDisplay *display&#41; &#123;
  drawProgress&#40;display, 10, "Updating time..."&#41;;
  timeClient.updateTime&#40;&#41;;
  drawProgress&#40;display, 30, "Updating conditions..."&#41;;
  wunderground.updateConditions&#40;WUNDERGRROUND_API_KEY, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY&#41;;
  drawProgress&#40;display, 50, "Updating forecasts..."&#41;;
  wunderground.updateForecast&#40;WUNDERGRROUND_API_KEY, WUNDERGROUND_COUNTRY, WUNDERGROUND_CITY&#41;;
  drawProgress&#40;display, 80, "Updating thingspeak..."&#41;;
  thingspeak.getLastChannelItem&#40;THINGSPEAK_CHANNEL_ID, THINGSPEAK_API_READ_KEY&#41;;
  lastUpdate = timeClient.getFormattedTime&#40;&#41;;
  readyForWeatherUpdate = false;
  drawProgress&#40;display, 100, "Done..."&#41;;
  delay&#40;1000&#41;;
&#125;



void drawDateTime&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41; &#123;
  display->setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  String date = wunderground.getDate&#40;&#41;;
  int textWidth = display->getStringWidth&#40;date&#41;;
  display->drawString&#40;64 + x, 5 + y, date&#41;;
  display->setFont&#40;ArialMT_Plain_24&#41;;
  String time = timeClient.getFormattedTime&#40;&#41;;
  textWidth = display->getStringWidth&#40;time&#41;;
  display->drawString&#40;64 + x, 15 + y, time&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_LEFT&#41;;

  Serial.println&#40;time&#41;;
  
&#125;

void drawCurrentWeather&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41; &#123;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_LEFT&#41;;
  display->drawString&#40;40 + x, 5 + y, wunderground.getWeatherText&#40;&#41;&#41;;

  display->setFont&#40;ArialMT_Plain_24&#41;;
  String temp = wunderground.getCurrentTemp&#40;&#41; + "°C";
  display->drawString&#40;50 + x, 15 + y, temp&#41;;
  int tempWidth = display->getStringWidth&#40;temp&#41;;

  display->setFont&#40;Meteocons_Plain_42&#41;;
  String weatherIcon = wunderground.getTodayIcon&#40;&#41;;
  int weatherIconWidth = display->getStringWidth&#40;weatherIcon&#41;;
  display->drawString&#40;22 + x - weatherIconWidth / 2, 05 + y, weatherIcon&#41;;
&#125;


void drawForecast&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41; &#123;
  drawForecastDetails&#40;display, x, y, 0&#41;;
  drawForecastDetails&#40;display, x + 44, y, 2&#41;;
  drawForecastDetails&#40;display, x + 88, y, 4&#41;;
&#125;

void drawThingspeak&#40;OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y&#41; &#123;
  display->setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->drawString&#40;64 + x, 0 + y, "Thingspeak"&#41;;

  
  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->drawString&#40;20 + x, 30 + y, thingspeak.getFieldValue&#40;0&#41; + "°C"&#41;;
  display->drawString&#40;20 + x, 15 + y, thingspeak.getFieldValue&#40;3&#41;&#41;;
  display->drawString&#40;32 + x, 15 + y, "V"&#41;;
  display->drawString&#40;90 + x, 15 + y, thingspeak.getFieldValue&#40;1&#41; + "%"&#41;;
  display->drawString&#40;90 + x, 30 + y, thingspeak.getFieldValue&#40;2&#41; + "hPa"&#41;;



  Serial.print&#40;" TEMP-"&#41;;
  Serial.print&#40;thingspeak.getFieldValue&#40;0&#41;&#41;;
  Serial.print&#40;" NAP-"&#41;;
  Serial.print&#40;thingspeak.getFieldValue&#40;3&#41;&#41;;
  Serial.print&#40;" RH-"&#41;;
  Serial.print&#40;thingspeak.getFieldValue&#40;1&#41;&#41;;
  Serial.print&#40;" PRESS-"&#41;;
  Serial.println&#40;thingspeak.getFieldValue&#40;2&#41;&#41;;


  
  
&#125;



void drawForecastDetails&#40;OLEDDisplay *display, int x, int y, int dayIndex&#41; &#123;
  display->setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  String day = wunderground.getForecastTitle&#40;dayIndex&#41;.substring&#40;0, 3&#41;;
  day.toUpperCase&#40;&#41;;
  display->drawString&#40;x + 20, y, day&#41;;

  display->setFont&#40;Meteocons_Plain_21&#41;;
  display->drawString&#40;x + 20, y + 12, wunderground.getForecastIcon&#40;dayIndex&#41;&#41;;

 
  Serial.print&#40;wunderground.getForecastIcon&#40;dayIndex&#41;&#41;;
  Serial.print&#40;","&#41;;
  Serial.println&#40;day&#41;;

  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->drawString&#40;x + 20, y + 34, wunderground.getForecastLowTemp&#40;dayIndex&#41; + "|" + wunderground.getForecastHighTemp&#40;dayIndex&#41;&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_LEFT&#41;;
&#125;

void drawHeaderOverlay&#40;OLEDDisplay *display, OLEDDisplayUiState* state&#41; &#123;
  display->setColor&#40;WHITE&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  String time = timeClient.getFormattedTime&#40;&#41;.substring&#40;0, 5&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_LEFT&#41;;
  display->drawString&#40;0, 54, time&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_RIGHT&#41;;
  String temp = wunderground.getCurrentTemp&#40;&#41; + "°C";
  display->drawString&#40;128, 54, temp&#41;;
  display->drawHorizontalLine&#40;0, 52, 128&#41;;
&#125;

void setReadyForWeatherUpdate&#40;&#41; &#123;
  Serial.println&#40;"Setting readyForUpdate to true"&#41;;
  readyForWeatherUpdate = true;
&#125;

Chciałbym aby dane wysyłane były tylko raz po wywołaniu konkretnej ramki. Teraz dane są wysyłane non stop przez cały czas trwania ramki, powoduje to niezły bajzel przy odczycie.

Pewnie bym sobie z tym poradził gdybym potrafił wysyłane wartości zapisać do zmiennych, wtedy porównanie nowego odczytu do starego, jeśli się różnią to wysyłam jeśli brak różnicy to nie wysyłam.
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Nie znam tych bibliotek, ale zgaduję, że uaktualniają i dane o pogodzie i ekran "swoim tempem", tzn. kolejne wywołania funkcji rysują kolejne fazy (animacje ramek) w razie potrzeby.

Nie wiem, na ile Ty znasz ich działanie, więc zaproponuję takie rozwiązanie:

Kod: Zaznacz cały

#define CO_ILE_MS_WYSYLAC_SERIAL 1000
unsigned long ostatniaWysylka = 0
a w loop:

Kod: Zaznacz cały

if &#40;&#40;unsigned long&#41;&#40;millis&#40;&#41; - ostatniaWysylka&#41; >= CO_ILE_MS_WYSYLAC_SERIAL&#41; &#123;
   ostatniaWysylka = millis&#40;&#41;;
   Serial.print....
&#125;
ten if możesz włożyć w "if (remainingTimeBudget > 0) "

W ten sposób uniezależnisz całkowicie wysyłanie danych przez port od wyświetlania.
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

Poradziłem sobie z tym inaczej.

Sprawdzam czy są różnice w nowym i starym odczycie, jeśli są to wysyłam dane na uart.
Działa to ładnie.

Mam tylko problem z ramką ForecastDetails. W ramce tej jako że wyświetla ona prognozowaną pogodę na trzy dni,zmieniają się i ikony pogody i dni. Nie mam więc do czego porównywać odczytów bo zawsze są inne i zawsze następuje wysyłanie danych. Tak jak pisałem wcześniej powoduje to straszny burdel podczas odczytywania z Uart-a.

Masz jakiś pomysł jak to rozwiązać?

A i jeszcze jedno . Jak ze zmiennej "time" usunąć sekundy?
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Dobry pomysł z wysyłaniem wyłącznie po zmianie.

Porównuj prognozy per dzień (tzn. np. zrób tablicę indeksowaną numerem dnia) i porównuj jedynie te same dni.

Czy w funkcji drawHeaderOverlay nie masz wycinania części łańcucha z czasem, czyli właśnie tego, co chcesz?
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

ptja pisze: Porównuj prognozy per dzień (tzn. np. zrób tablicę indeksowaną numerem dnia) i porównuj jedynie te same dni.
Ha gdybym ja wiedział o czym Piszesz. Zapomniałem dodać że dopiero raczkuję w Arduino.

A rzeczywiście mam już gotowe formatowanie czasu. Dzięki za podpowiedź.
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

To po prostu nie wysyłaj prognozy przez port szeregowy.
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

ptja pisze:To po prostu nie wysyłaj prognozy przez port szeregowy.
Muszę to jest główny cel ESP8266. Docelowe urządzenie będzie z wyświetlaczem 3.5' obsługiwanym przez Atmega128. Atmega właśnie będzie 'ciągnąć' dane z ESP.
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Możesz też zrobić "brzydko", ale prosto. Zrób trzy zmienne (zestawy zmiennych). Zapisz do nich wartości: do pierwszej zmiennej (zestawu zmiennych) wartość (wartości) prognozy na dzień X, do drugiej - na dzień Y, a do trzeciej na dzień Z. Potem, jak znów pobierzesz prognozę na konkretny dzień, to porównaj jej wartości z tymi zapamiętanymi dla danego dnia - i wyślij, jeśli będzie inna. Po wysłaniu zapisz wartość (wartości), żeby kolejne porównanie było z tą właśnie wysłaną.

No i polecam: http://helion.pl/ksiazki/jezyk-ansi-c-p ... jansic.htm (na pewno da się znaleźć kopię w sieci).
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

Pokombinowałem i wyszło.

Kod: Zaznacz cały

void drawForecastDetails&#40;OLEDDisplay *display, int x, int y, int dayIndex&#41; &#123;
  display->setTextAlignment&#40;TEXT_ALIGN_CENTER&#41;;
  display->setFont&#40;ArialMT_Plain_10&#41;;
  String day = wunderground.getForecastTitle&#40;dayIndex&#41;.substring&#40;0, 3&#41;;
  day.toUpperCase&#40;&#41;;
  display->drawString&#40;x + 20, y, day&#41;;

  display->setFont&#40;Meteocons_Plain_21&#41;;
  display->drawString&#40;x + 20, y + 12, wunderground.getForecastIcon&#40;dayIndex&#41;&#41;;


 wgfi0 = wunderground.getForecastIcon&#40;0&#41;;
 wgfi2 = wunderground.getForecastIcon&#40;2&#41;;
 wgfi4 = wunderground.getForecastIcon&#40;4&#41;;

  if &#40;wgfi0 != oldwgfi0 || wgfi2 != oldwgfi2 || wgfi4 != oldwgfi4&#41;&#123;  
  Serial.print&#40;"Forecast-"&#41;;
  Serial.print&#40;wgfi0&#41;;
  Serial.print&#40;"-"&#41;;
  Serial.print&#40;"0"&#41;;
  Serial.print&#40;","&#41;;
  Serial.print&#40;wgfi2&#41;;
  Serial.print&#40;"-"&#41;;
  Serial.print&#40;"1"&#41;;
  Serial.print&#40;","&#41;;
  Serial.print&#40;wgfi4&#41;;
  Serial.print&#40;"-"&#41;;
  Serial.println&#40;"2"&#41;;
  oldwgfi0 = wgfi0;
  oldwgfi2 = wgfi2;
  oldwgfi4 = wgfi4;
  &#125;


  display->setFont&#40;ArialMT_Plain_10&#41;;
  display->drawString&#40;x + 20, y + 34, wunderground.getForecastLowTemp&#40;dayIndex&#41; + "|" + wunderground.getForecastHighTemp&#40;dayIndex&#41;&#41;;
  display->setTextAlignment&#40;TEXT_ALIGN_LEFT&#41;;
&#125;

Tematu nie zamykam bo pewnie jeszcze się gdzieś zawiesze.
ptja
Posty: 2414
Rejestracja: poniedziałek 31 gru 2012, 12:44
Lokalizacja: Łódź

Post autor: ptja »

Dlaczego wysyłasz po jednym znaku? Nie lepiej np. Serial.println("-2"); ?
--
pozdrawiam,
Jarek Andrzejewski
Awatar użytkownika
pier
Posty: 1467
Rejestracja: poniedziałek 21 lut 2011, 09:02
Lokalizacja: Biłgoraj-Sól

Post autor: pier »

ptja pisze:Dlaczego wysyłasz po jednym znaku? Nie lepiej np. Serial.println("-2"); ?
To tylko na razie tak jest. Zmian będzie jeszcze więcej. Chcę jeszcze dołożyć do czujnika zewnętrznego sensor oświetlenia, odczyt faz księżyca z Weatherunderground no i muszę jeszcze jakoś sformatować lepiej te dane wysyłane przez Uart.
ODPOWIEDZ