Forum: Mikrocontroller und Digitale Elektronik Zeitverzögerung will nicht


von C-Anfänger (Gast)


Lesenswert?

Hallo,

ich probiere gerade ein Relais das ich in bestimmten Fällen anziehen 
lasse, verzögert wieder abfallen zu lassen. Doch irgendwie möchte das 
nicht ganz so wie ich das möchte. Vielleicht findet jemand meinen 
Fehler. Auszug aus dem Code:
1
set_bit(RELAIS_port,RELAIS_pin);
2
          unsigned char end = 0;
3
          unsigned int ns_on = 0;
4
          unsigned int ms_on = 0;
5
          unsigned char s_on = 0;
6
          unsigned char m_on = 0;
7
          while (end == 0) {
8
            if (ns_on < 1000) {
9
              ns_on++;
10
              _delay_us(1);
11
              if (bit_is_set(START_MODE_port,START_MODE_pin)) {end = 1;};
12
            } else {
13
              ns_on = 0;
14
              if (ms_on > mseconds_on*10) {
15
                ms_on--;
16
              } else {
17
                ms_on = 999;
18
                if (s_on > seconds_on) {
19
                  s_on--;
20
                } else {
21
                  s_on = 59;
22
                  if (m_on > minutes_on) {
23
                    m_on--;
24
                  } else {
25
                    end = 1;
26
                  }
27
                }
28
              }
29
            }
30
          }
31
          clear_bit(RELAIS_port,RELAIS_pin);
mseconds_on, seconds_on, minutes_on ist die Zeit die er warten soll, bis 
das Relais wieder abfallen soll. Dabei wird die so angezeigt: 0;0;0 Die 
Millisekunden sind hierbei nur ein Zehntel. Wenn in der Variable 1 ist, 
dann sind dies 10ms.

Doch irgendwie möchte das nicht wie ich will. Ich habe 0;2;0 
eingestellt, also 2 Sekunden doch das Relais ist weniger als eine 
Sekunde angezogen.

Vielleicht findet jemand den Fehler. Danke schonmal.

von Sascha W. (sascha-w)


Lesenswert?

dein ganzer Ansatz passt so nicht!
1. deine Zählvariablen "xx_on" müssen beim Rückwärtszählen mit dem 
Maximalwert initialisiert werden
2. wenn du z.B. 5min 30sec übergibst, dann zähen deine Sekunden immer 
nur von 59 bis 31, und dann ist schon eine Minute um

benutz einfach nur eine Variable die die Zeit *10ms angibt, und die 
zählst du alle 10ms runter bis null und gut

Sascha

von C-Anfänger (Gast)


Lesenswert?

Sascha Weber schrieb:
> benutz einfach nur eine Variable die die Zeit *10ms angibt, und die
> zählst du alle 10ms runter bis null und gut

dann muss ich davor doch alles in ms umrechnen oder?
weil ich lese meine mseconds_on, seconds_on, minutes_on aus dem EEPROM 
und deswegen hab ich 3 Variablen

von Sascha W. (sascha-w)


Lesenswert?

das ist doch so aufwendig nun auch wieder nicht! Oder ?

sonst muss die die Schleifen in etwas so aufbauen ...
1
;init
2
unsigned int ms_on = 0;
3
unsigned char s_on = 0;
4
unsigned char m_on = 0;
5
6
;..- jede ms
7
ms_on++;
8
if (ms_on>999) {
9
  ms_on=0;
10
  s_on++;
11
  if (s_on>59) {
12
    s_on=0;
13
    m_on++;
14
  }
15
}
16
if (ms_on==mseconds_on && s_on==seconds_on && m_on==minutes_on) {
17
  end=1;
18
}

Sascha

von C-Anfänger (Gast)


Lesenswert?

Also ich hab es nun so:
1
          unsigned char end = 0;
2
          unsigned int ns_on = 0;
3
          unsigned int ms_on = 0;
4
          unsigned char s_on = 0;
5
          unsigned char m_on = 0;
6
          while (end == 0) {
7
            if (ns_on < 1000) {
8
              ns_on++;
9
              _delay_us(1);
10
              if (bit_is_set(START_MODE_port,START_MODE_pin)) {end = 1;};
11
            } else {
12
              if (ms_on < 1000) {
13
                ms_on++;
14
              } else {
15
                ms_on = 0;
16
                if (s_on < 60) {
17
                  s_on++;
18
                } else {
19
                  s_on = 0;
20
                  if (m_on < 60) {
21
                    m_on++;
22
                  }
23
                }
24
              }
25
            }
26
            if (ms_on == (mseconds_on*10) && s_on == seconds_on && m_on == minutes_on) {
27
              end = 1;
28
            }
29
          }
Aber es ist keine Änderung in Sicht d.h. es ist sind nicht die Sekunden, 
die ich eingestellt habe.

von Sascha W. (sascha-w)


Lesenswert?

ns_on sollte beim erreichen von 1000 auch wieder auf 0 gestellt werden!
Sonst dauern die ms anschließend nur noch µs.

Sascha

von Peter D. (peda)


Lesenswert?

Für eine Zeitverzögerung kann ich Dir das hier empfehlen:

Beitrag "Wartezeiten effektiv (Scheduler)"

Dann kannst Du das auch für mehrere Relais machen.


Peter

von C-Anfänger (Gast)


Lesenswert?

Also ich habs nun rausbekommen. Ich hab dabei nur was komisches 
festgestellt. Ich habe ms_on nur bis 500 zählen lassen? komisch.... Hier 
nur der funktionierende:
1
          unsigned char end = 0;
2
          unsigned int ns_on = 0;
3
          unsigned int ms_on = 0;
4
          unsigned char s_on = 0;
5
          unsigned char m_on = 0;
6
          while (end == 0) {
7
            if (ns_on < 1000) {
8
              ns_on++;
9
              _delay_us(1);
10
              if (bit_is_set(START_MODE_port,START_MODE_pin)) {end = 1;};
11
            } else {
12
              ns_on = 0;
13
              if (ms_on < 500) {
14
                ms_on++;
15
              } else {
16
                ms_on = 0;
17
                if (s_on < 60) {
18
                  s_on++;
19
                } else {
20
                  s_on = 0;
21
                  if (m_on < 60) {
22
                    m_on++;
23
                  }
24
                }
25
              }
26
            }
27
            if (ms_on == (mseconds_on) && s_on == seconds_on && m_on == minutes_on) {
28
              end = 1;
29
            }
30
          }

von Sascha W. (sascha-w)


Lesenswert?

Wie schnell ist dein AVR getaktet? Evl. verursacht der Overhead um 
delay_us(1) schon so viel Zeit das sich die Ausführungsdauer dort 
verdoppelt.

Wenn du die Zeiten im ms-Bereich einstellen willst, wird die einzig 
brauchbare Lösung die Verwendung eines Timers werden. Damit bekommst du 
eine saubere Zeitbasis von 1ms, und dein AVR kann nebenbei auch noch was 
anderes machen.

Sascha

von C-Anfänger (Gast)


Lesenswert?

Mein AVR ist bei 16 Mhz getaktet und ich nutze schon ein Timer im 
CTC-Mode um das andere Intervall zu takten. Aber bis jetzt funktioniert 
alles und dann ist gut. Fehlen nur noch 2 Buchsen und mein Gerät ist 
fertig. ;)

von Sascha W. (sascha-w)


Lesenswert?

nun ja bei 16MHz vertut die delay_us(1) genau 16 Takte, dann haben wir 
die Loop mit 8-Bit-Vergleich, den ns_on 16-Bit-Vergleich, eine 
16-Bit-Addition, den Bit-Test und ein paar Jump's. Kein Wunder das da 
noch mal die selbe Anzahl an Takten zustandekommt. Und dann immer mal 
noch ein Interrupt?!

Vielleicht kannst du den Takt ja von deinem vorhandenen Timer ableiten?
Wenn du das nicht willst, dann lasse die ns_on-Schleife nur bis 500 
laufen, sonst kannst du ja auch nur die ms-Verzögerungszeiten im Bereich 
von 0..500 einstellen.

Sascha

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.