In meinem kleinen Projekt kommuniziert mein Atmel2560 über MCP2515 mit einem CAN Bus Client. Dabei muss der CPU alle 100ms eine Nachricht senden und der Client gibt dann antwort. Dies habe ich mit einer Timer Library gelöst.
Auch dieser Teil funktioniert - soweit. Hier liegt aber das Problem der ZEIT. Wenn ich einen Request sende und den Header und Body parse um zu sehen ob alles OK ist, vergehen schon mal 80ms -130ms, je nach dem wie schnell halt auch die Internetverbindung ist und wie schnell der Server antwortet. Im schlimmsten Fall halt so lange dass die 100ms die ich zur verfügung habe, überschritten werden. Somit fällt ein 100ms Takt aus, oder kommt zu spät. Somit denkt der Client das der Master nicht mehr am CAN Bus ist und meldet sich ab.
Hier muss ich noch erwähnen das der Master den Client zu beginn noch starten muss und der Client dann vom Pre-Operational in den Operational Mode geht.
Ich müsste also einen Request senden, zurück in den Loop gehen, und erst dann, wenn die Antwort vom Server da ist, diese prüfen.
Oder einfach das "Fire-and-Forget" Prinzip. Request los senden und einfach hoffen er kommt an und mit dem Loop weiter fahren. Ist nicht meine erste Wahl.
Wie könnte ich das lösen?
Hat da jemand eine Idee?
Du möchtest sowas wie Multitasking, auf dem Arduino ist es quasi parallele Verarbeitung.
Ich würde das mit millis() machen, aber da Du schon was mit Timer eingebunden hast, geht es auch mit einer Bibliothek. Ich verwende MsTimer2, weil diese einen Interrupt verwendet, für den 100 ms Takt. Weil ich Deine Hardware nicht habe, blinkt bei mir eine LED.
Die Kommunikation mit dem Server simuliere ich mit dem seriellen Monitor der IDE.
Ich hoffe, Du kannst das Prinzip für Deine Anwendung übernehmen.
Das Programm basiert auf dem Bibliotheksbeispiel FlashLed.
/*
MsTimer2 is a small and very easy to use library to interface Timer2 with
humans. It's called MsTimer2 because it "hardcodes" a resolution of 1
millisecond on timer2
For Details see: http://www.arduino.cc/playground/Main/MsTimer2
*/
#include <MsTimer2.h>
#if ARDUINO >= 100
const int led_pin = LED_BUILTIN; // 1.0 built in LED pin var
#else
const int led_pin = 13; // default to pin 13
#endif
void flash() // Interrupt Service Routine
{
static boolean output = HIGH;
digitalWrite(led_pin, output);
output = !output;
}
void setup()
{
pinMode(led_pin, OUTPUT);
MsTimer2::set(100, flash); // 100ms period
MsTimer2::start();
Serial.begin(9600);
Serial.println("\nAntwort anfordern mit 'a'");
}
void loop()
{
if (Serial.available() > 0)
{
char inByte = Serial.read();
if (inByte == 'a')
{
Serial.print("Antwort angekommen ");
Serial.println(millis() / 1000);
Serial.println("\nNeue Antwort anfordern ");
}
}
}
noiasca:
zeig mal den kompletten Abschnitt deines "sendData ". vermutlich solltest du zwischen Senden und empfangen nicht blockierend warten sonder auftrennen und den empfangsteil in den loop übernehmen und somit deinem can-heartbeat wieder die möglichkeit geben zu senden.
ja das stimmt zurzeit ist das ein Teil. Du hat recht, ich könnte das mal auseinander nehmen.
if (checkWifi() && ((millis() - timers.sendData) > (configuration.charging.interval * 60000))) {
unsigned long starttime = millis();
sendData();
Serial.print("Send Data total time in ms: ");
Serial.println(millis() - starttime);
timers.sendData = millis();
}
Output
Send Data total time in ms: 137
Send Data total time in ms: 146
Send Data total time in ms: 140
Send Data total time in ms: 145
Send Data total time in ms: 147
Send Data total time in ms: 142
Send Data total time in ms: 138
Send Data total time in ms: 139
if (sendChargingData()) {
chargingDataSended = true;
}
boolean sendChargingData() {
.... hier wird der content erstellt....
if (put(hostConfig.host, hostConfig.port, hostConfig.pageNameChargingData, content)) {
if (getStatusCode() == 201) {
return true;
}
}
return false;
}
Hier im letzten Teil sieht man das ich sende und dann gleich warte bis ich die Antwort vom Server habe. Gemäss @noiaska könnte ich diesen Teil zerlegen.
Als erstes werde ich mir mal den Vorschlag von @agmue anschauen, dieser Vorschlag erscheint mir so auf die schnelle den einfacheren Ansatz zu sein, vielleicht täusche ich mich mal wieder.
@agmue, die MsTimer2 scheint eine interessante lib für meinen zweck zu sein. egal mit was der MCU beschäftigt ist, er wird durch den Interrupt des MsTimers unterbrochen und kehrt danach wieder zurück.