Strona 1 z 1

Programem Arduino.

: czwartek 15 cze 2017, 21:17
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?

: czwartek 15 cze 2017, 21:37
autor: ptja
Tak.

: czwartek 15 cze 2017, 21:50
autor: pier
ptja pisze:Tak.
A coś więcej?

: czwartek 15 cze 2017, 22:29
autor: ptja
Ty zacznij :)
Choćby załączając kod.

: piątek 16 cze 2017, 08:02
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.

: piątek 16 cze 2017, 12:27
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.

: piątek 16 cze 2017, 13:27
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?

: piątek 16 cze 2017, 13:35
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?

: piątek 16 cze 2017, 14:04
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ź.

: piątek 16 cze 2017, 14:22
autor: ptja
To po prostu nie wysyłaj prognozy przez port szeregowy.

: piątek 16 cze 2017, 16:24
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.

: piątek 16 cze 2017, 16:59
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).

: piątek 16 cze 2017, 20:45
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.

: piątek 16 cze 2017, 21:13
autor: ptja
Dlaczego wysyłasz po jednym znaku? Nie lepiej np. Serial.println("-2"); ?

: piątek 16 cze 2017, 21:53
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.