Forum: Mikrocontroller und Digitale Elektronik while-Schleife wird "unerlaubt verlassen"


von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Obwohl mein Anliegen wahrscheinlich schwer zu beantworten ist, versuche 
ich es mal:
Das Programm soll ein Thermostatventil, wie allg. üblich, nach der 
Temperatur regeln.
Die Regelung läuft schon nach meinen Wünschen.
Das als Anhang beigefügte Programm hängt sich aber manchmal teilweise 
auf.
Ich als Programmierlaie habe folgenden Verdacht:
Die in der main-Funktion vorhandene while- Schleife wird aus irgendeinem 
Grund "verlassen".
Das macht sich dadurch bemerkbar, dass die Tasten für AUF/ZU bzw. 
Sollwertverstellung nicht mehr reagieren sowie der Regler nicht mehr 
arbeitet. Also alles, was in der while-Schleife steht ist tot.
Die im TIMER_A enthaltenen Befehle, wie z.B. Messwert und Sollwert 
anzeigen sowie das Abspeichern auf SD-Karte läuft allerdings weiter.
Meine Frage: Kann jemand erkennen, was ich programmiertechnisch falsch 
gemacht habe?
Kann es sein, dass der Befehl break in der Funktion
"void ventil_schliessen_regler(void)"
auch die while-Schleife unter bestimmten Umständen in der  main-Funktion 
abbricht?
Ich danke schon mal allen, die sich das Programm ansehen und mit 
konkreten Hinweisen mir helfen wollen.

: Bearbeitet durch User
von Bärenmarke (Gast)


Lesenswert?

Hallo,

ich habe mir Dein Programm jetzt nicht im Detail angesehen. Lt. Standard 
verlässt ein break immer nur den "innersten" Block. Dass ein break in 
einer Funktion zur Unterbrechung des Aufrufers führt, sollte nicht 
passieren. Weil man aber nie weiß, kannst Du ans Ende von main () etwas 
basteln, was Dir eine Ausgabe erzeugt, wenn der Code (unerwartet) 
ausgeführt wird.

Ich würde eher mutmaßen, dass sich Dein Programm innerhalb der Schleife 
aufhängt...

von Einer K. (Gast)


Lesenswert?

Und ich bin erstaunt, was man doch alles in eine ISR stopfen kann...

von Joachim B. (jar)


Lesenswert?

ich habe versucht den Code zu strukturieren, ich tippe aber ob der sehr 
überfrachteten ISR das der Prozzi einfach die Lust verliert wie ich.
Es wird ja mehr in der IRQ abgearbeitet als vermutlich Zeit ist bis der 
Nächste kommt.

Sollwert als Int wird immer decrementiert ohne NULL zu prüfen da kann 
auch ein Überlauf reinspucken.

von (prx) A. K. (prx)


Lesenswert?

wolle g. schrieb:
> Kann es sein, dass der Befehl break in der Funktion
> "void ventil_schliessen_regler(void)"
> auch die while-Schleife unter bestimmten Umständen in der  main-Funktion
> abbricht?

Nein. Aber wenn das Programm neu startet, wg Versorgungs-Problemen, 
Watchdog, ... oder aufgrund von Stack-Problemen auf die Nase fällt, 
dann wird eine while-Schleife auch mal unfreiwillig verlassen.

von Peter P. Petersson (Gast)


Lesenswert?

Nein, die while wird mit an Sicherheit grenzender Wahrscheinlichkeit 
nicht  verlassen.

Als erstes solltest du deine ISRs aufräumen. Die müssen stets so kurz 
wie möglich bleiben. I. A. setzt man hier nur ein Flag, das in der 
Hauptschleife dann geprüft wird. Wenn gesetzt, wird der Code ausgeführt 
der jetzt im jeweiligen Interrupt ist und dein Flag wird zurückgesetzt.

Sollte dein Programm sich danach weiterhin aufhängen, sind die 
wahrscheinlichsten Gründe Endlosschleife oder irgendein Überlauf.

Du könntest am Ende der Main eine spezielle LED schalten um zu sehen ob 
die while(1) verlassen wurde. Aber das habe ich noch nie gehört oder 
erlebt.

von Herbert P. (Gast)


Lesenswert?

Leider fehlt da jede Menge Code. Wie groß ist der Zwischenspeicher 
definiert, der da verwendet wird? Die Zählervar t wird einmal auf 0 
gesetzt und dann immer hochgezählt. Wenn die nicht irgendwo 
zurückgesetzt wird, geht das irgendwann mal schief... Außerdem verwendet 
das Zwischenspeichern unnötige Zwischenvariablen, wenn die vom Compiler 
nicht wegoptimiert werden, kostet das unnötig Zeit und Speicher.

Das break ist unschuldig.

Gruß
Herby

von Wolle G. (wolleg)


Lesenswert?

Ich hatte mir schon gedacht, dass hier eine Ferndiagnose schwierig sein 
wird.
Ich versuche mal, mit meinen spärlichen Programmierkenntnissen  die 
Antworten zu "analysieren".

a) der Befehl break in "void ventil_schliessen_regler(void)" hat keinen 
Einfluss auf die Schleife in main().

b) Peter P. Petersson schrieb:
> Als erstes solltest du deine ISRs aufräumen. Die müssen stets so kurz
> wie möglich bleiben. I. A. setzt man hier nur ein Flag, das in der
> Hauptschleife dann geprüft wird. Wenn gesetzt, wird der Code ausgeführt
> der jetzt im jeweiligen Interrupt ist und dein Flag wird zurückgesetzt.
Wie muss man das machen? Was ist ein Flag?
Ich dachte, mit:
b=b+1;
if (b >9)reglerstart=1;         //beeinflusst Abtastzeit 10x4=40

in TIMER_A  hätte ich die gesamte Reglerfunktion  aus der ISR 
herausgenommen.
Der Regler wird nur alle 40s (Timertakt 4s * b=10 --> 40s) aufgerufen, 
um dann in der while-Schleife (if (reglerstart==1)regler();)
bearbeitet zu werden.
M.E. ist die Zeit von 4s zwischen zwei Aufrufen für 
zwischenspeicher_1();  auf_SD_karte_schreiben(); sollwert_anzeigen(); 
usw. (alles ms-Bereich)
 rel. groß

c) Joachim B. schrieb:
> Es wird ja mehr in der IRQ abgearbeitet als vermutlich Zeit ist bis der
> Nächste kommt.
>
> Sollwert als Int wird immer decrementiert ohne NULL zu prüfen da kann
> auch ein Überlauf reinspucken.
Wie sollte deshalb die Variable Sollwert deklariert werden?

d) Herbert P. schrieb:
> Leider fehlt da jede Menge Code.

Richtig. Diesen code habe ich vor allem deshalb weggelassen, da dieser 
in meinem als Datenspeicher bezeichneten Programm problemlos läuft.
Diesen Datenspeicher wollte ich "nur" für meine Experimente 
(Thermostatventilregler + Tasten+ Motoransteuerung) erweitern, indem ich 
weitere Funktionen hinzugefügt habe.

e) Peter P. Petersson schrieb:
> Nein, die while wird mit an Sicherheit grenzender Wahrscheinlichkeit
> nicht  verlassen.
Das kann ich zwar nicht beurteilen, aber warum geht  nach einem 
"Absturz" keine Taste mehr und der Regler regelt nicht mehr?

f) Aus den Antworten würde ich zunächst entnehmen, dass ich 
wahrscheinlich keine Fehler gemacht habe, die sofort ins Auge fallen.


Vielleicht wird aber mein Fehler doch noch gefunden.

von Joachim B. (jar)


Lesenswert?

wolle g. schrieb:
>> Sollwert als Int wird immer decrementiert ohne NULL zu prüfen da kann
>> auch ein Überlauf reinspucken.
> Wie sollte deshalb die Variable Sollwert deklariert werden?

ja was ist dein Ziel?
Darf bei NULL erreichen WEITER decrementiert werden?
Entweder du prüfst vorher

if(sollwert<erlaubter_sollwert) sollwert=sollwert+1;
if(sollwert>0) sollwert=sollwert-1;

ich weiss das doch nicht was du willst!

Du musst wissen in welchen Grenzen sollwert laufen DARF

> f) Aus den Antworten würde ich zunächst entnehmen, dass ich
> wahrscheinlich keine Fehler gemacht habe, die sofort ins Auge fallen.
> Vielleicht wird aber mein Fehler doch noch gefunden.

gewagte Annahme weil dein Programm nicht tut was es soll!

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

wolle g. schrieb:
> b) Peter P. Petersson schrieb:
>> Als erstes solltest du deine ISRs aufräumen. Die müssen stets so kurz
>> wie möglich bleiben. I. A. setzt man hier nur ein Flag, das in der
>> Hauptschleife dann geprüft wird. Wenn gesetzt, wird der Code ausgeführt
>> der jetzt im jeweiligen Interrupt ist und dein Flag wird zurückgesetzt.
> Wie muss man das machen? Was ist ein Flag?

Ein Flag ist eine binäre (boolsche) Variable, die nurn true (wahr) oder 
falsch ist. Damit steuert man Abläufe zwischen Programmteilen, hier der 
ISR und der Hauptschleife.

Siehe Interrupt

> in TIMER_A  hätte ich die gesamte Reglerfunktion  aus der ISR
> herausgenommen.
> Der Regler wird nur alle 40s (Timertakt 4s * b=10 --> 40s) aufgerufen,

Wenn gleich es hier vielleicht OK sein mag, so nutzt man in den 
allermeisten Fällen keinen so tierisch langsamen Timer. Meistens läßt 
man den mit 1-100ms Periodendauer laufen und generiert für langsamere 
Ereignisse und Aufrufe einen Teiler in Software, sprich, man zählt einen 
Zähler hoch, der nur all N Durchläufe eine Aktion auslöst. Damit bleibt 
man flexibler und kann viele, verschieden schnelle Dinge tun bzw. 
steuern.

> M.E. ist die Zeit von 4s zwischen zwei Aufrufen für
> zwischenspeicher_1();  auf_SD_karte_schreiben(); sollwert_anzeigen();
> usw. (alles ms-Bereich)
>  rel. groß

Kann sein, ist aber trotzdem Mist, wenn das alles im Interrupt passiert. 
Denn damit sind andere Interrupts während dieser Zeit ausgebremst, im 
Extremfall werden sogar welche verschluckt.

>> Sollwert als Int wird immer decrementiert ohne NULL zu prüfen da kann
>> auch ein Überlauf reinspucken.
> Wie sollte deshalb die Variable Sollwert deklariert werden?

Das hat mit dem Deklarieren wenig zu tun.
>
> d) Herbert P. schrieb:
>> Leider fehlt da jede Menge Code.
>
> Richtig. Diesen code habe ich vor allem deshalb weggelassen, da dieser
> in meinem als Datenspeicher bezeichneten Programm problemlos läuft.
> Diesen Datenspeicher wollte ich "nur" für meine Experimente
> (Thermostatventilregler + Tasten+ Motoransteuerung) erweitern, indem ich
> weitere Funktionen hinzugefügt habe.
>
> e) Peter P. Petersson schrieb:
>> Nein, die while wird mit an Sicherheit grenzender Wahrscheinlichkeit
>> nicht  verlassen.
> Das kann ich zwar nicht beurteilen, aber warum geht  nach einem
> "Absturz" keine Taste mehr und der Regler regelt nicht mehr?
>
> f) Aus den Antworten würde ich zunächst entnehmen, dass ich
> wahrscheinlich keine Fehler gemacht habe, die sofort ins Auge fallen.
>
> Vielleicht wird aber mein Fehler doch noch gefunden.

Sowas hier ist totaler Anfängermüll

>int >ZWI1,ZWI2,ZWI3,ZWI4,ZWI5,ZWI6,ZWI7,ZWI8,ZWI9,ZW20,ZW21,ZW22,ZW23,ZW24,Z W25
>,ZW26,ZW27,ZW28 ;

Schon mal was von einem Array gehört?

int buffer[28];

Dann ist nämlich der Zugriff DEUTLICH einfacher, vor allem wenn man 
größere Datenmengen verschieben will. Mal ganz davon abgesehen, daß 
diese Variabeln und deren Nutzung maximal sinnlos sind. Man merkt 
sofort, daß du BASCOM geschädigt bist ;-)

1
void zwischenspeichern_1(void)    //eine Zwischentabelle wird im RAM angelegt
2
{
3
mmc_buffer[t++] = hub >> 8;          
4
mmc_buffer[t++] = hub & 0xFF;
5
mmc_buffer[t++] = esum >> 8;          
6
mmc_buffer[t++] = esum & 0xFF;
7
mmc_buffer[t++] = e >> 8;
8
mmc_buffer[t++] = e & 0XFF;
9
mmc_buffer[t++] = temp16 >> 8;
10
mmc_buffer[t++] = temp16 & 0XFF;
11
mmc_buffer[t++] = y >> 8;
12
mmc_buffer[t++] = y & 0XFF;
13
mmc_buffer[t++] = sollwert >> 8;
14
mmc_buffer[t++] = sollwert & 0XFF;
15
mmc_buffer[t++] = umdrehung_zu >> 8;
16
mmc_buffer[t++] = umdrehung_zu & 0XFF;
17
mmc_buffer[t++] = umdrehungen_auf >> 8;
18
mmc_buffer[t++] = umdrehungen_auf & 0XFF;
19
}

: Bearbeitet durch User
von Wolle G. (wolleg)


Lesenswert?

Joachim B. schrieb:
> ja was ist dein Ziel?
> Darf bei NULL erreichen WEITER decrementiert werden?

Bin ich hier auf dem Holzweg?
Mit "unsigned int b,k,f,l, reglerstart,t,sollwert;" gibt es m. E. keine 
negativen Werte. oder?

Falk B. schrieb:
> Ein Flag ist eine binäre (boolsche) Variable, die nurn true (wahr) oder
> falsch ist. Damit steuert man Abläufe zwischen Programmteilen, hier der
> ISR und der Hauptschleife.
>
> Siehe Interrupt
Ehrlich gesagt, das, was hier (Siehe Interrupt ) erläutert wurde, habe 
ich nicht so richtig kapiert.
Vielleicht kann jemand meinen TIMER_A nach diesen Regeln als Beispiel 
mit den Flags umschreiben.
Meine Vorstellungen an dieser Stelle:
a) Beibehaltung der 4s für das Einsammeln (und Anzeigen) von Daten und 
Eintragen der (8) Werte in den Zwischenspeicher.
Der Zwischenspeicher soll bei t=512 geleert und der Inhalt auf einen 
Sektor einer SD-Karte übertragen werden.
Damit die SD-Karte ohne Datenverlust herausgenommen werden kann, muss 
der aktuelle Stand (ausgabe_sektorenrest();) angezeigt werden. (läuft 
eigentlich nach meinen Wünschen)

In Abständen von z.B. 40s soll der Regler (void regler (void) ) 
aktiviert werden.

von Joachim B. (jar)


Lesenswert?

wolle g. schrieb:
> Joachim B. schrieb:
>> ja was ist dein Ziel?
>> Darf bei NULL erreichen WEITER decrementiert werden?
>
> Bin ich hier auf dem Holzweg?
> Mit "unsigned int b,k,f,l, reglerstart,t,sollwert;" gibt es m. E. keine
> negativen Werte. oder?

eben drum

wenn ein unsigned int sollwert auf 0 ist, was passiert bei sollwert = 
sollwert-1?

wie groß ist sollwert dann? (und darf das sein?)

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

wolle g. schrieb:
>> Darf bei NULL erreichen WEITER decrementiert werden?
>
> Bin ich hier auf dem Holzweg?

Sicher. ;-)

> Mit "unsigned int b,k,f,l, reglerstart,t,sollwert;" gibt es m. E. keine
> negativen Werte. oder?

Oder. Was passiert, wenn man von einem unsigned Wert mit 0 etwas 
subrahiert?

a) der Wert bleibt bei Null
b) es gibt einen Unterlauf und die Zahl ist plötzlich riesengroß


>> Siehe Interrupt
> Ehrlich gesagt, das, was hier (Siehe Interrupt ) erläutert wurde, habe
> ich nicht so richtig kapiert.

Dann lies es noch einmal und denk in Ruhe drüber nach.

> Vielleicht kann jemand meinen TIMER_A nach diesen Regeln als Beispiel
> mit den Flags umschreiben.
> Meine Vorstellungen an dieser Stelle:
> a) Beibehaltung der 4s für das Einsammeln (und Anzeigen) von Daten und
> Eintragen der (8) Werte in den Zwischenspeicher.

Kein Thema.

> Der Zwischenspeicher soll bei t=512 geleert und der Inhalt auf einen
> Sektor einer SD-Karte übertragen werden.

Dito.

> Damit die SD-Karte ohne Datenverlust herausgenommen werden kann, muss
> der aktuelle Stand (ausgabe_sektorenrest();) angezeigt werden. (läuft
> eigentlich nach meinen Wünschen)

Vermutlich aber nicht solide, denn du bist ein Laie.

> In Abständen von z.B. 40s soll der Regler (void regler (void) )
> aktiviert werden.

Etwa so.
1
volatile uint8_t flag_10ms;
2
3
...
4
uint16_t timer_messen, timer_regler;
5
6
while(1) {
7
    if (flag_10ms) {
8
        flag_10ms = 0;
9
10
        timer_messen++;
11
        if (timer_messen == 400 ) {
12
            timer_messen = 0;
13
            // hier Meßwerte auslesen etc.
14
        }
15
    
16
        timer_regler++;
17
        if (timer_regler == 4000 ) {
18
            timer_regler = 0;
19
            // hier Regler aufrufen
20
        }
21
    }
22
}
23
24
// läuft mit 10ms Periodendauer
25
26
Interrupt(TimerA) {
27
   flag_10ms = 1;
28
}

Deine anderen Interrupts sind auch eher ungünstig. Sowas macht man mit 
einem periodischen Aufruf passender Funktion. Damit kann man nämlich 
auch diese sowieso zeitunkritischen Signale per Software entprellen, 
siehe Entprellung.

von Hannes J. (hannes_j)


Lesenswert?

Schau dir das Codebeispiel von Falk genau an. Er setzt im Interrupt nur 
ein Signal, dass der Interrupt aufgetreten ist. Der Rest passiert in der 
while(1) der main(). Auf diese Weise wird das Hauptprogramm nur so kurz 
wie möglich aufgehalten. Das ist wichtig damit bei vielen vorhandenen 
Interrupts nicht irgendwann Situationen entstehen, in denen dein 
Programm nur noch im Interrupt steckt. Ob es das tut lässt sich oft 
schwer abschätzen. Ich war schon sehr oft in der Situation dass ich 
dachte "Eigentlich kann es nicht am Interrupt liegen", aber genau das 
tat es.

Wenn du wirklich Zeitkritische Operationen ausführen willst wie z. B. 
Datentransfer, dann kannst du den Code dafür auch direkt im Interrupt 
ausführen. Aber immer so schlank und wenig wie möglich.

von Falk B. (falk)


Lesenswert?

Hannes J. schrieb:
> Schau dir das Codebeispiel von Falk genau an. Er setzt im Interrupt nur
> ein Signal, dass der Interrupt aufgetreten ist. Der Rest passiert in der
> while(1) der main(). Auf diese Weise wird das Hauptprogramm nur so kurz
> wie möglich aufgehalten.

Der Interrupt ;-)

von Wolle G. (wolleg)


Lesenswert?

Joachim B. schrieb:
>> Mit "unsigned int b,k,f,l, reglerstart,t,sollwert;" gibt es m. E. keine
>> negativen Werte. oder?
>
> eben drum
>
> wenn ein unsigned int sollwert auf 0 ist, was passiert bei sollwert =
> sollwert-1?

Diese Sichtweise habe ich jetzt verstanden.
Da aber der Sollwert bei meiner Anwendung niemals unter 320 (20°C) 
eingestellt wurde, kann dies vermutlich nicht die Absturzursache gewesen 
sein. Werde trotzdem das Programm entsprechend ändern.

Falk B. schrieb:
> Etwa so.
>volatile uint8_t flag_10ms;
>while(1) {
>    if (flag_10ms) {
>        flag_10ms = 0;
>.....

Sind meine Zeilen:
 while(1)
    {
    if (reglerstart==1)regler();
    ....
   }
und in TIMER_A die Zeilen:
{….
b=b+1;                          //b wird alle 4s um 1 erhöht
if (b >9)reglerstart=1; // hier wird  mein 40s-flag gesetzt
…
}
nicht mit den obigen vergleichbar?
Jetzt müsste ich nur noch ein  4s-flag für die weiteren Funktionen 
setzen.

Ich möchte  bei den 4s-Takt bleiben, damit man den µC evtl. ca. 4s-x 
schlafen legen kann. (in Zukunft Batteriebetrieb)

von Hannes J. (hannes_j)


Lesenswert?

Zukünftig könntest du dir mal die millis()-Funktion vom Arduino 
anschauen und evtl übernehmen. Die benutzt im Endeffekt einen Timer um 
fortlaufend Millisekunden zu zählen. Denke dabei lernst du auch noch 
einiges. Wirklich schwer ist sie dabei nicht und besonders gut geeignet 
wenn du in der Hauptschleife häufig viele unterschiedliche Funktionen in 
bestimmten zeitlichen Abständen aufrufen willst. Dabei wird nur ein 
einziger Interrupt benötigt.

Das ganze sieht dann in etwa so aus:
1
unsigned long millisAlt = 0;
2
3
...
4
5
while(1)
6
{
7
   if(millis()-millisAlt > 4000)
8
   {
9
      millisAlt = millis();
10
      // Tue etwas alle 4 Sekunden
11
   }
12
}

Kann aber auch sein dass das für den Anfang etwas viel ist. Dann stelle 
es lieber hinten an.

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Hannes J. schrieb:
> while(1)
> {
>    if(millis()-millisAlt < 4000)
>    {
>       millisAlt = millis();
>       // Tue etwas alle 4 Sekunden
>    }
> }

Ja, fast. Anders rum wirds ein Schuh.
https://forum.arduino.cc/index.php?topic=503368.0

leo

von Hannes J. (hannes_j)


Lesenswert?

Steht doch > .. ;-)

von leo (Gast)


Lesenswert?

Hannes J. schrieb:
> Steht doch > .. ;-)

Jetzt schon ;-)
leo

von Falk B. (falk)


Lesenswert?

wolle g. schrieb:

> Sind meine Zeilen:
>  while(1)
>     {
>     if (reglerstart==1)regler();
>     ....
>    }
> und in TIMER_A die Zeilen:
> {….
> b=b+1;                          //b wird alle 4s um 1 erhöht
> if (b >9)reglerstart=1; // hier wird  mein 40s-flag gesetzt
> …
> }
> nicht mit den obigen vergleichbar?

Nein, denn die Masse der Funktionsaufrufe liegt im Interrupt. Und 
währenddessen sind beim AVR alle anderen Interrupts blockiert.

> Jetzt müsste ich nur noch ein  4s-flag für die weiteren Funktionen
> setzen.

Nein, du mußt die ganzen Funktionsaufrufe aus dem Interrupt entfernen.

Ach so, du hast ja gar keinen AVR, sondern einen MSP430. Kann der 
verschachtelte Interrupts? Egal, das Konzept ist trotzdem ungünstig.

> Ich möchte  bei den 4s-Takt bleiben, damit man den µC evtl. ca. 4s-x
> schlafen legen kann. (in Zukunft Batteriebetrieb)

Ja und? Das kann die richtige Methode auch.

von Norbert S. (norberts)


Lesenswert?

Falk B. schrieb:
> Man merkt
> sofort, daß du BASCOM geschädigt bist ;-)

Man merkt sofort, daß Du von Bascom keinen blassen Schimmer hast.

von Falk B. (falk)


Lesenswert?

Norbert S. schrieb:
> Man merkt sofort, daß Du von Bascom keinen blassen Schimmer hast.

Und du von Humor. Naja, als BASCOM-Fanboy bist du entschuldigt.

von Norbert S. (norberts)


Lesenswert?

Moin,

Ich bin eher nur gerade empfindlich und angefressen, nachdem ich den ach 
so tollen C-Code Anderer studiere und Bascom immer so belächelt wird.
Da wird auch gepfuscht ohne Ende.

Gruß,
Norbert

von Falk B. (falk)


Lesenswert?

Norbert S. schrieb:
> Moin,
>
> Ich bin eher nur gerade empfindlich und angefressen, nachdem ich den ach
> so tollen C-Code Anderer studiere und Bascom immer so belächelt wird.
> Da wird auch gepfuscht ohne Ende.

Das ist richtig, aber kein Ausgleich oder Rechtfertigung von Schwächen 
bzw. Begrenzungen von BASCOM.

BASCOM hat seine Berechtigung und Nische.

von Wolle G. (wolleg)


Angehängte Dateien:

Lesenswert?

Ich habe versucht, entsprechend den Hinweisen zu den flags, das Programm 
umzubauen.
Leider kein Erfolg. Im Gegenteil: Das umgebaute Programm spinnt noch 
mehr als das Ursprungsprogramm. Z.B.: nach einer kurzen Betätigung einer 
Taste für ZU oder AUF läuft der Motor bis zum Anschlag. Danach werden 
blinkende Nullen angezeigt. Nur ein Zurücksetzen des µC setzt diesem 
Verhalten ein Ende.
Hier kurze Ausschnitte des "neuen" Programms:
while(1)
    {
    if (flag_reglerstart)
    {
    flag_reglerstart=0;
    b++;
    if (b>4)
    {b=0;
    regler();
    }
    }
    if (flag_4s)
      {
      flag_4s=0;
       Blitz_gelb();
       temp_messung_starten();          //alle angeschlossenen DS18B20
       wandlung();                      //gehört zu DS18B20
       DS18B20_lesen_DS18B20nr16();
       regelabweichung_anzeigen(); // in "DS10-g0126-LMK62-SD.h" 
enthalten
       esum_anzeigen();
       sollwert_anzeigen();
       hub_anzeigen();
       temp_16_anzeigen();
       zwischenspeichern_1();
       ausgabe_sektorenrest();
       auf_SD_karte_schreiben();
    }
    if (P3IN&BIT7)         //P3.7  Taste: Temp.-Sollwert hochzählen
    {  pause1();
    if (sollwert>500)sollwert=500;
       sollwert=sollwert+1;
       sollwert_anzeigen();
       pause1();
    }
   ...........
interrupt (TIMERA0_VECTOR) Timer_A(void)
    {
      flag_4s=1;
      flag_reglerstart=1;
     }

Im Anhang das geänderte Programm.
Bestimmt habe ich neue Fehler eingebaut.

von Teo D. (teoderix)


Lesenswert?

wolle g. schrieb:
> interrupt (TIMERA0_VECTOR) Timer_A(void)
>     {
>       flag_4s=1;
>       flag_reglerstart=1;
>      }

1. Halte ich es für ziemlich unwahrscheinlich, das der Timer nur alle 4s 
überlauft.
2. Zwei Flags für ein und den selben Schei..?

3. Nur noch drei Antworten von einem ><(()°> entfernt.
4. Abreißen, 1-2T Pause machen (ein Buch etc. übers Programmieren lesen) 
und neu beginnen.

von Falk B. (falk)


Lesenswert?

wolle g. schrieb:
> Ich habe versucht, entsprechend den Hinweisen zu den flags, das Programm
> umzubauen.

Deine Formatierung ist schlecht. Die Klammerebenen und Einrückungen sind 
schlecht lesbar und unsinnig.

Eher so! Du mußt alle Tabulatoren in Leerzeichen umwandeln, alle 
besseren Editoren können das auf Knopfdruck.
1
    uint8_t tmp, p3old, p2old;
2
3
    while(1) {
4
        if (flag_reglerstart) {
5
            flag_reglerstart=0;
6
            b++;
7
            if (b>4) {
8
                b=0;
9
                regler();
10
             }
11
        }
12
    
13
        if (flag_4s) {
14
            flag_4s=0;
15
            Blitz_gelb();
16
            temp_messung_starten();          // alle angeschlossenen DS18B20
17
            wandlung();                      // gehört zu DS18B20
18
            DS18B20_lesen_DS18B20nr16();
19
            regelabweichung_anzeigen();      // in "DS10-g0126-LMK62-SD.h" enthalten
20
            esum_anzeigen();
21
            sollwert_anzeigen();
22
            hub_anzeigen();
23
            temp_16_anzeigen();
24
            zwischenspeichern_1();
25
            ausgabe_sektorenrest();
26
            auf_SD_karte_schreiben();  
27
        }
28
29
        // das hier ist falsch!
30
/*
31
        if (P3IN&BIT7) {        //P3.7  Taste: Temp.-Sollwert hochzählen
32
            pause1();
33
            if (sollwert>500)sollwert=500;
34
            sollwert=sollwert+1;
35
            sollwert_anzeigen();
36
            pause1();
37
        }
38
39
        if (P3IN&BIT6) {        //P3.6   Taste: Temp.-Sollwert abwärts zählen
40
            pause1();
41
            if (sollwert<200)sollwert=200;
42
            sollwert=sollwert-1;
43
            sollwert_anzeigen();
44
            pause1();
45
        }
46
47
        if (P2IN&BIT0) {       // P2.0  Taste: Ventil-AUF gedrückt
48
            AUF=1;
49
            P4OUT &=~BIT0;     // LED rot   P4.0 EIN
50
            P2OUT &=~BIT4;     // AUF-fahren
51
        } else { 
52
            AUF=0;
53
            P4OUT |=BIT0;
54
            P2OUT |=BIT4;   //Halt
55
        }
56
    
57
        if (P2IN&BIT1) {      // P2.1  Taste: Ventil-ZU wird gedrückt
58
            ZU=1;
59
            P3OUT &= ~BIT0;   // ZU-fahren
60
        } else {
61
            ZU=0;
62
            P4OUT |= BIT1;     // LED gelb   P4.1 AUS
63
            P3OUT |= BIT0;    //Halt
64
        }
65
66
*/
67
68
        // eher so mit Flankenerkennung
69
70
        if (flag_100ms) {
71
            flag_100ms = 0;
72
73
            tmp = P3IN;
74
            if ((tmp & BIT7) && !(p3old & BIT7) ) {        //P3.7  Taste: Temp.-Sollwert hochzählen
75
                pause1();
76
                sollwert=sollwert+1;
77
                if (sollwert>500) sollwert=500;
78
                sollwert_anzeigen();
79
                pause1();
80
            }
81
    
82
            if ((tmp & BIT6) && !(p3old & BIT6) ) {        //P3.6   Taste: Temp.-Sollwert abwärts zählen
83
                pause1();
84
                sollwert=sollwert-1;
85
                if (sollwert<200) sollwert=200;
86
                sollwert_anzeigen();
87
                pause1();
88
            }
89
            p3old = tmp;
90
    
91
            tmp = P2IN;
92
            if ((tmp & BIT0) & !(p2old & BIT0) ) {       // P2.0  Taste: Ventil-AUF gedrückt
93
                AUF=1;
94
                P4OUT &=~BIT0;     // LED rot   P4.0 EIN
95
                P2OUT &=~BIT4;     // AUF-fahren
96
            } else { 
97
                AUF=0;
98
                P4OUT |=BIT0;
99
                P2OUT |=BIT4;   //Halt
100
            }
101
        
102
            if ( (tmp & BIT1) !(p2old & BIT1) ) {      // P2.1  Taste: Ventil-ZU wird gedrückt
103
                ZU=1;
104
                P3OUT &= ~BIT0;   // ZU-fahren
105
            } else {
106
                ZU=0;
107
                P4OUT |= BIT1;     // LED gelb   P4.1 AUS
108
                P3OUT |= BIT0;    //Halt
109
            }
110
            p2old = tmp;
111
        }
112
    }

> Leider kein Erfolg. Im Gegenteil: Das umgebaute Programm spinnt noch
> mehr als das Ursprungsprogramm.

Was zu erwarten war. Die Hinweise waren richtig, aber kein Wundermittel.
Deine Tastenauswertung ist untauglich. Du hattest vorher nur Glück, daß 
die in einem Pin Change Interrupt versteckt war. Damit reagierten die 
Codeabschitte immer nur auf einen Flankenwechsel. Jetzt in der 
Hauptschleife ist sie das nicht mehr und der Fehler wird voll wirksam. 
Die Hauptschleife wird SEHR SCHNELL immer wider durchlaufen, 
dementsprechend rasend schnell werden dein Sollwerte hoch und runter 
gezählt. Da reden wir hier von mehreren Dutzend kHz!

Du brauchst eine Auswertung der Flanke in Software. Siehe Artikel 
Entprellung. Ich hab es mal ansatzweise skizziert.

> Z.B.: nach einer kurzen Betätigung einer
> Taste für ZU oder AUF läuft der Motor bis zum Anschlag. Danach werden
> blinkende Nullen angezeigt. Nur ein Zurücksetzen des µC setzt diesem
> Verhalten ein Ende.
> Hier kurze Ausschnitte des "neuen" Programms:

Was soll das? Der Anhang reicht und der ist vollständig.

> Im Anhang das geänderte Programm.
> Bestimmt habe ich neue Fehler eingebaut.

SICHER! Denn dir fehlt grundlegendes Verständnis.

von Wolle G. (wolleg)


Lesenswert?

Teo D. schrieb:
> 1. Halte ich es für ziemlich unwahrscheinlich, das der Timer nur alle 4s
> überlauft.
nur dazu:
siehe "void Timer_einstellen(void)"
und dann nachrechnen!
>(ein Buch etc. übers Programmieren lesen)
>und neu beginnen.
Toller Beratungshinweis! Darauf muss man erst einmal kommen.

Falk B. schrieb:
> Die Hauptschleife wird SEHR SCHNELL immer wider durchlaufen,
> dementsprechend rasend schnell werden dein Sollwerte hoch und runter
> gezählt. Da reden wir hier von mehreren Dutzend kHz!
Richtig.
Damit man die Sollwertänderungen auf der Anzeige verfolgen kann, wurde 
"pause1();" eingefügt. ---funktioniert. Mein "Tastenprogramm" fußt auf 
den Beiträgen im  Beitrag "Taster abfragen".
Jetzt habe ich das Programm für die Tasten mal nach  Deinem Vorschlag 
umgebaut.
Die Spinnerei ist zwar weg, aber nach ein paar Tastenbetätigungen hängt 
sich das Programm wieder auf. (reagiert nicht mehr auf eine Taste). 
Schade
> SICHER! Denn dir fehlt grundlegendes Verständnis.
Und Du meinst, diese Einschätzung hilft mir weiter.

von Norbert S. (norberts)


Lesenswert?

wolle g. schrieb:
> Denn dir fehlt grundlegendes Verständnis.
> Und Du meinst, diese Einschätzung hilft mir weiter.

Könnte sie, wenn Du sie beherzigen und erstmal kleinere Brötchen backen 
würdest.
Du hast nicht nur ein kleines Problem sondern bist mit der Aufgabe 
ziemlich überfordert.
Du frickelst irgendwie herum, um das zum Laufen zu bekommen, verstehst 
aber gar nicht, was Du da tust.
"Hängt sich auf" gibt es nicht! Du schickst den µC irgendwo hin, wo er 
nicht mehr tut, was Du von ihm willst.

Gruß,
Norbert

von Wolle G. (wolleg)


Lesenswert?

Das hat mit dem Thema wenig zu tun:
Norbert S. schrieb:
> Könnte sie, wenn Du sie beherzigen und erstmal kleinere Brötchen backen
> würdest.
Wie groß dürften die kleineren Brötchen sein?

>Du hast nicht nur ein kleines Problem sondern bist mit der Aufgabe
>ziemlich überfordert.
Warum sagst Du das?
Wenn jemand sein Problem allein lösen könnte, dann brauchte er hier im 
Forum nicht zu fragen und man könnte das Forum schließen.

Eigentlich wollte ich nicht derartig reagieren. Aber es kommt in letzter 
Zeit häufiger vor, dass jemand  auf ähnliche Art angemacht wird.

Obwohl sich hier im Forum viele als  Hobby mit Elektronik (auch µC) 
beschäftigen, kommen sie doch aus den verschiedensten Fachrichtungen.

: Bearbeitet durch User
von El Ef (Gast)


Lesenswert?

wolle g. schrieb:
> Die Spinnerei ist zwar weg, aber nach ein paar Tastenbetätigungen hängt
> sich das Programm wieder auf

Wenn sich das reproduzieren lässt könnte man ja mal mit dem Debugger 
schauen wo man landet, wenn nicht mehr auf Tasten reagiert wird.
Wenn es z.B. ein Hardfault Handler ist dann schauen welche Flags gesetzt 
sind usw.

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> SICHER! Denn dir fehlt grundlegendes Verständnis.

wolle g. schrieb:
> Norbert S. schrieb:
>> Könnte sie, wenn Du sie beherzigen und erstmal kleinere Brötchen backen
>> würdest.
> Wie groß dürften die kleineren Brötchen sein?
>
>>Du hast nicht nur ein kleines Problem sondern bist mit der Aufgabe
>>ziemlich überfordert.
> Warum sagst Du das?

deswgen?

Falk B. schrieb:
> // das hier ist falsch!
> /*
>         if (P3IN&BIT7) {        //P3.7  Taste: Temp.-Sollwert hochzählen
>             pause1();
>             if (sollwert>500)sollwert=500;
>             sollwert=sollwert+1;
>             sollwert_anzeigen();
>             pause1();
>         }

das hatten wir doch schon mal besprochen!

wenn der sollwert 500 nicht übersteigen soll:
if (sollwert>500)sollwert=500;

warum inkrementierst du NACH der Abfrage?
sollwert=sollwert+1;

es hört sich böse an, aber du durchdenkst dein Programm nicht.

Ist wie beim Backen, Backzeit 50 Minuten, du schaust auf die Uhr, die 50 
Minuten sind um und statt zu stoppen gibst du noch mehr Backzeit 
dazu.....

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.