Arduino Nano initialisiert immer wieder auf Startwert

OP #7520861
Lesenswert?

Hallo Leute, ich möchte mit einem Arduino Nano die Pulse von einem S0-Energiezähler erfassen und per USB an einen PC übertragen. Hier mein Porgramm:

1
#define  S0in 2
2

3
volatile unsigned long pulse_total = 0;
4
volatile unsigned long alteZeit = 0;
5
int crontimer = 0;
6
 
7
void setup(){
8
  Serial.begin(9600);
9
  pulse_total = 100.0*2000; //Startwert in kWh auf Display ablesen x 2000
10
  pinMode(S0in, INPUT_PULLUP);
11
  attachInterrupt(digitalPinToInterrupt(S0in), onPulse, RISING);
12
}
13

14
void loop() {
15
  if(millis()/1000 > crontimer + 3){ //alle 3s Daten senden via RS232
16
    crontimer = millis()/1000;
17
    Serial.println(pulse_total);
18
  }
19
}
20

21
void onPulse(){
22
  if((millis() - alteZeit) > 21) { // innerhalb der Entprellzeit 21ms nichts machen
23
    alteZeit = millis(); // letzte Schaltzeit merken
24
    pulse_total++;
25
  }
26
}

Solange ich mit einem Programm (z.B. Minicom) den USB Port des Nano auslese, sehe ich wie er hoch zählt: 200000 200003 200006 100010....

Problem: Sobald ich Minicom schließe und anschließend wieder öffne fängt er wieder bei 200000 an. Meine erste Vermutung war, dass es sich um ein Problem mit der Stromversorgung handelt aber auch wenn man ein Netzteil an +5V oder Vin anschließt bleibt das Problem bestehen.

Was kann ich sonst noch testen? - Mir gehen langsam die Ideen aus. VG Andi

#7520870
Lesenswert?

Den Reset zu unterbinden ist ja nichtmal die Hälfte der Miete.

Kurze Stromzappler? Irgendwann mal kurz ausmachen zum Putzen? Oder oder oder? Irgendein Töffel vergisst vor dem Anstecken das Handshaking abzuschalten, benutzt einen doofen Adapter oder Treiber, bingo. Jedesmal hoppelt das Ding auf Null zurück, das ist ja Quatsch und völlig instabil.

Was es da braucht ist ein nichtflüchtiger Speicher, in den zumindest ab und an mal der aktuelle Stand gesichert wird, so das man z.B. nur 5 Minuten verliert oder so. Da muss man aber aufpassen, denn die haben teilweise arg begrenzte Schreibzyklen... Am besten geht's mit einem FRAM, das sollte selbst bei Sekundenzyklen Jahrzehnte schaffen, bleibt nur noch das Risiko, das man bei so einem Reset genau den Schreibzyklus unterbricht und der Speicher korrupt wird.

#7520932
Lesenswert?

Arduino F. schrieb:

Das ist normal, weil minicom am DTR Pin zappelt.

So ist das.

Also Reset mit einem 10µC unterbinden,

Pfuschlösung, das geht auch ordentlich.

Christian schrieb:

Oder man Durchtrennt die Leiterban, DTR-Ausgang des UART-Controllers.

Garnicht nötig, sowohl China als auch das Original haben dort einen Kondensator, den man rausnehmen kann.

Der Nebeneffekt ist, dass man dann zum Upload der Software manuell den Reset betätigen muß.

Angehängte Dateien:
#7520972
Lesenswert?

Jens M. schrieb:

Was es da braucht ist ein nichtflüchtiger Speicher, in den zumindest ab und an mal der aktuelle Stand gesichert wird, so das man z.B. nur 5 Minuten verliert oder so. Da muss man aber aufpassen, denn die haben teilweise arg begrenzte Schreibzyklen...

Man müsste sich da was ausdenken, dass man den nichtflüchtigen Speicher auf viele Speicherzellen verteilen kann. "Wear Leveling" nennt sich das auf Fach-Chinesisch - und selbst Tante Google kann was dazu sagen.

Aber nun ist genug gespoilert ...

OP #7521118
Lesenswert?

Nachdem ihr mich darauf hingewiesen habt, sah ich auch das die Reset-LED immer aufblinkt wenn man minicom starte oder beendet. Ich habe jetzt den Kondensator an DTR ausgelötet. So funktioniert alles wie gewollt.

Zum Thema Datensicherheit: Ich hatte auch erst vor in gewissen Intervallen die Werte in den EEPROM zu schreiben. Da ich die Daten aber sowieso regelmäßig per USB auslese und speichere habe ich das wieder verworfen.

Vielen Dank für Eure Hilfe!!!

#7521142
Lesenswert?

Generell ein paar Verbesserungs-Vorschläge:

1
volatile unsigned long alteZeit = 0;

ist unnötig. Schöner:

1
void onPulse(){
2
  static uint32_t alteZeit;
3
  if((millis() - alteZeit) > 21) { // innerhalb der Entprellzeit 21ms nichts machen
4
    alteZeit = millis(); // letzte Schaltzeit merken
5
...

Und:

1
void loop() {
2
  if(millis()/1000 > crontimer + 3){ //alle 3s Daten senden via RS232

Überleg dir, was passiert sobald millis() seinen 32-bit-Rollover hat.

Schöner:

1
  if ((millis() - crontimer)>3000) {
2
    crontimer=millis();

(Also ananlog zu "alteZeit" im onPulse)

#7521187
Lesenswert?

Andi S. schrieb:

Da ich die Daten aber sowieso regelmäßig per USB auslese und speichere habe ich das wieder verworfen.

Dann solltest du die Übertragung einfach auf die Anzahl der Pulse seit dem letzten Auslesen ausführen und den Stand am Auslesegerät festhalten. Da kannst du dann auch bequemer den aktuellen Stand nachhalten, falls dein Adapter mal was vergessen hat.

Moderator (Firma: Titel) Persönliche Seite #7521258
Lesenswert?

Εrnst B. schrieb:

Überleg dir, was passiert sobald millis() seinen 32-bit-Rollover hat.

Es passiert viel öfter Seltsames. Nämlich schon, wenn "geschickt" zwischen
if(millis()/1000 > crontimer + 3){ und crontimer = millis()/1000; der millis-Zähler einen der allsekündlichen Tausender-Überläufe hat. Dann wird nämlich eine "Schaltsekunde" eingelegt, wenn z.B. zum Zeitpunkt der if-Abfrage millis() noch 12999 hatte, beim Berechnen des neuen crontimer Werts aber schon auf 13000 weitergezählt hat.

Εrnst B. schrieb:

Schöner: if ((millis() - crontimer)>3000) { crontimer=millis();

Und noch viel viel schöner ist es, wenn man am Anfang der Mainloop ein einziges Mal den millis()-Zeitstempel abholt und den Rest im Zyklus mit derselben Zeit rechnet:

1
unsigned long jetzt, crontimer = 0, t5s = 0;
2

3
void loop() {
4
  jetzt = millis(); // einmalig Zeitstempel für diesen Schleifendurchlauf abholen
5

6
  if (jetzt - crontimer > 3000) { // alle 3s ...
7
    crontimer = jetzt;
8
    Serial.println(pulse_total);
9
  }
10

11
  if (jetzt - t5s > 5000) { // alle 5 s
12
    t5s = jetzt;
13
    :
14
  }
15
}

Und so richtig schön wäre es dann, wenn man am Anfang der Schleife die Eingänge ebenfalls auf ein Prozessabbild einlesen und alle berechneten Änderungen erst am Schluss der Schleife auf die Ausgänge schreiben würde. Dann hat man nämlich die vielmillionenfach erprobte Vorgehensweise einer SPS. Da kann zwar die Zykluszeit der SPS insgesamt zu langsam sein, es gibt aber kein seltsames Timingverhalten wegen einer zum Programmablauf hinzugefügten Funktion.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren