Forum: Mikrocontroller und Digitale Elektronik Zähler (Up/Down) für industriellen Einsatz


von Bernd M. (spezi)


Lesenswert?

Hallo und guten Morgen,

bevor ich anfange, dumme Fragen zu stellen, stelle ich mich kurz vor:

Mein Name ist Bernd, komme aus der Steiermark (AT), bin 28 jahre jung, 
gelernter Mess- & Regeltechniker.

Ich arbeite als Elektro-Instandhalter in einem Industriebetrieb, den ich 
hier aber nicht vorstellen möchte.

Und da wäre ich auch schon bei meinem Problem:
Ich habe eine Walze mit einem Umfang von 239cm. Bei jedem Umlauf wird 
ein Initiator (ind. Näherungssensor) betätigt, welcher mir einen 
24V-Impuls für die Dauer der Belegung ausgibt.
Über ein Auswertegerät werden diese Impulse erfasst und über IC's der 
40er-Baureihe umgewandelt.
Für jeden Meter, also 100cm, wird ein Impuls aus diesem Auswertegerät 
ausgegeben (und an einen externen Laufmeterzähler[Impulszähler] 
geschickt), dementsprechend wird auch der Zählerwert um 100 
dekrementiert. Dies ist so lange der Fall, so lange der Zählwert >= 100 
ist.

Sollten nun 100 Impulse von der  Walze kommen, so entspricht dies einer 
Länge von 100*239cm = 23900cm = 239m. Es sollten nun auch auf dem 
externen Zähler der Zahlenwert "239" zu lesen sein.


Leider funktioniert der Code, den ich bis jetzt geschrieben habe, nicht. 
bzw. wird nur ein Impuls ausgegeben. Wahrscheinlich ist es eh nur eine 
Kleinigkeit, die ich übersehe, oder ein Denkfehler. Aber ich komme nicht 
mehr weiter.

Anbei der Code: Vl. kann mir hier jemand weiterhelfen.
Schon mal danke im Vorraus ;-)
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
5
int main(void)
6
{
7
8
  DDRA = 0x00;            // PORTA = Eingänge
9
  DDRB = 0xff;            // PORTB = Ausgänge
10
//  DDRD = 0xff;            // PORTD = Ausgänge
11
  
12
  PORTA = 0xff;
13
  PORTB = 0b00000000;          // Ausgänge ausschalten
14
//  PORTD = 0x00;            // Ausgänge ausschalten
15
  
16
  int i = 0;              // Zaehler deklarieren und auf Default (0) setzen 
17
18
  while(1)              // Beginn der Endlosschleife
19
  {
20
  
21
    if (! (PINA & (1 << PINA0)))   // Taster S1 abfragen (Auf PINA0)
22
    {
23
      i = i + 239;        // Zaehler inkrementieren
24
      _delay_ms(200);        // Zeit vertrödeln  
25
      }              // Ende if-Schleife
26
          
27
      while (i >= 100)      // vergleiche Zählerwert mit Vorgabe
28
      {
29
        i = i - 100;      // Solange i >= 100, 100 von i abziehen
30
        PORTB = 0x03;      // Ausgang für Zähler
31
        _delay_ms(50);      // Impulsdauer
32
        PORTB = 0x00;      // Asugang wieder löschen
33
      }              // Ende while-Schleife
34
  }                  // Ende while(1)-Schleife
35
}                    // Ende main-Schleife

PS: Die Anlage verfügt über eine SPS, die das Laufmetersignal von einem 
Laserzähler erhält und auch dementsprechend umrechnet und abarbeitet. 
Ich habe auch schon ein SPS-Programm für den Anwendungsfall mit dem 
Initiator geschrieben, jedoch ist dieser Ini nur dann im Einsatz, wenn 
der Laserzähler ausfällt.

von soundmachine (Gast)


Lesenswert?

Hi, ich würde schonmal nicht mit delay arbeiten, was ist wenn während 
des delays ein weiterer Impuls kommt, den erkennst du dann garnicht.
So 100% hab ich die Aufgabenstellung zwar noch nicht geblickt aber 2 
Sachen fallen mit auf:

1. Integer ist bei guten 32000schluss, dann gibts einen Überlauf
2. Du verwendest keine Flankenauswertung, d.h. wenn der Imopuls länger 
als 250ms da ist wird er 2 mal gezählt

von Jürgen S. (jurs)


Lesenswert?

Bernd M. schrieb:

Also wenn ich Deinen Code mal etwas verdichte, komme ich auf das:

 i = i + 239;        // Zaehler inkrementieren
 while (i >= 100)      // vergleiche Zählerwert mit Vorgabe
 {
   i = i - 100;      // Solange i >= 100, 100 von i abziehen
 }              // Ende while-Schleife

???

von soundmachine (Gast)


Lesenswert?

#include <avr/io.h>
#include <util/delay.h>


int main(void)
{

  DDRA = 0x00;            // PORTA = Eingänge
  DDRB = 0xff;            // PORTB = Ausgänge
//  DDRD = 0xff;            // PORTD = Ausgänge

  PORTA = 0xff;
  PORTB = 0b00000000;          // Ausgänge ausschalten
//  PORTD = 0x00;            // Ausgänge ausschalten

  double i = 0;
  int Input_neu = 0;
int Input_alt = 0;

  while(1)              // Beginn der Endlosschleife
  {
  Input_neu = (PINA & (1 << PINA0);
    if (Input_neu == 1 && Input_alt ==0)
    {
      i = i + 239;        // Zaehler inkrementieren
    }              // Ende if-Schleife
  Input_alt = (PINA & (1 << PINA0);


    while (i >= 100)      // vergleiche Zählerwert mit Vorgabe
    {
      i = i - 100;      // Solange i >= 100, 100 von i abziehen
      PORTB = 0x03;      // Ausgang für Zähler
      _delay_ms(50);      // Impulsdauer
      PORTB = 0x00;      // Asugang wieder löschen
    }              // Ende while-Schleife
  }                  // Ende while(1)-Schleife
}                    // Ende main-Schleife







Sorry programmiere momentan ´von Berufswegen viel SCL, kann sein dass 
der Syntax nicht 100% stimmt

von Bernd M. (spezi)


Lesenswert?

danke für die flinke antwort ;-)

zu deinen Antworten:

1) die Eingangs-Impulse sollen nicht gesammelt und danach einzeln, 
sondern kontinuierlich, d.h bei i >= 100, ausgegeben werden.

2) Der Impuls ist auch bei einer minimalen Maschinengeschwindigkeit 
relativ kurz (ca. 200ms), die 250ms sind nur für Testzwecke eingestellt. 
Das mit dem "Verzählen" ist bei einer Tagesproduktion von ~400.000lfm 
nicht so genau ;-)

Wie schaut's code-technisch aus: warum will das bei mir nicht 
funktionieren?

danke

von soundmachine (Gast)


Lesenswert?

ach und noch was fällt mir auf...wenn du den ausgangsimouls abschaltest 
müsste ja auch noch 50ms als delay rein, sonst schalter er immer den 
ausgang 50ms an, dann für 1 zyklus aus und sofort wieder an...darin 
dürfte wohl dein haupter fehler liegen...

#include <avr/io.h>
#include <util/delay.h>


int main(void)
{

  DDRA = 0x00;            // PORTA = Eingänge
  DDRB = 0xff;            // PORTB = Ausgänge
//  DDRD = 0xff;            // PORTD = Ausgänge

  PORTA = 0xff;
  PORTB = 0b00000000;          // Ausgänge ausschalten
//  PORTD = 0x00;            // Ausgänge ausschalten

  double i = 0;
  int Input_neu = 0;
int Input_alt = 0;

  while(1)              // Beginn der Endlosschleife
  {
  Input_neu = (PINA & (1 << PINA0);
    if (Input_neu == 1 && Input_alt ==0)
    {
      i = i + 239;        // Zaehler inkrementieren
    }              // Ende if-Schleife
  Input_alt = (PINA & (1 << PINA0);


    while (i >= 100)      // vergleiche Zählerwert mit Vorgabe
    {
      i = i - 100;      // Solange i >= 100, 100 von i abziehen
      PORTB = 0x03;      // Ausgang für Zähler
      _delay_ms(50);      // Impulsdauer
      PORTB = 0x00;      // Asugang wieder löschen
      _delay_ms(50);      // Nulldurchgang des Impulses
    }              // Ende while-Schleife
  }                  // Ende while(1)-Schleife
}                    // Ende main-Schleife

von Bernd M. (spezi)


Lesenswert?

danke für die prompte bedienung, meine herrschaften, ich werde das ganze 
gleich einmal versuchen.

bei korrekter funktion gibts natürlich ein feedback ;-)

danke und schönen tag noch

von Jürgen S. (jurs)


Lesenswert?

Bernd M. schrieb:
> danke für die prompte bedienung, meine herrschaften, ich werde das ganze
> gleich einmal versuchen.
>
> bei korrekter funktion gibts natürlich ein feedback ;-)

Wird allmählich knapp mit den Delays bei 400.000lfm pro Tag.

400.000 m / (2,39m * 86400 s) =  1,94 Umdrehungen pro Sekunde 
durchschnittlich.

Pro Umdrehung hast Du aber schon 200 ms Delay am Anfang und bei jedem 
Substraktionsvorgang zweimal 50 ms, also insgesamt 2* 2*50 = 200 ms. 
Macht zusammen 400 ms Delay. Auf diese Art messbare Höchstdrehzahl: 2,5 
pro Sekunde.

Wenn also die Höchstgeschwindigkeit der Maschine nur um 25% höher liegt 
als die durchschnittliche Tagesgeschwindigkeit, funktioniert es mit 
diesen Delays nicht mehr. Vermutlich.

Und wenn bei Stillstand der Maschine der Taster S1 auf dauernd ON steht, 
wird laufend hochgezählt, trotz stehender Maschine?

von Bernd M. (spezi)


Lesenswert?

So, das von soundmachine modifizierte Programm wurde noch ein klein 
wenig abgewandelt (minimalst) und funktioniert wunderbar ;-)
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
  double i = 0;
5
  int Input_neu = 0;
6
  int Input_alt = 0;
7
8
int main(void)
9
{
10
11
  DDRA = 0x00;            // PORTA = Eingänge
12
  DDRB = 0xff;            // PORTB = Ausgänge
13
//  DDRD = 0xff;            // PORTD = Ausgänge
14
15
  PORTA = 0xff;
16
  PORTB = 0b00000000;          // Ausgänge ausschalten
17
//  PORTD = 0x00;            // Ausgänge ausschalten
18
19
  while(1)              // Beginn der Endlosschleife
20
    {
21
      Input_neu = (!(PINA & (1 << PINA0)));
22
      if (Input_neu == 1 && Input_alt ==0)
23
      {
24
          i = i + 239;        // Zaehler inkrementieren
25
      }
26
                 
27
      Input_alt = (PINA & (1 << PINA0));
28
  
29
      while (i >= 100)        // vergleiche Zählerwert mit Vorgabe
30
      {
31
          i = i - 100;        // Solange i >= 100, 100 von i abziehen
32
          PORTB = 0x03;        // Ausgang für Zähler
33
          _delay_ms(200);      // Impulsdauer
34
         PORTB = 0x00;        // Asugang wieder löschen
35
        _delay_ms(200);    // Pausedauer
36
      }              
37
    }                  
38
}

von Jürgen S. (jurs)


Lesenswert?

Bernd M. schrieb:
>       Input_neu = (!(PINA & (1 << PINA0)));
>       if (Input_neu == 1 && Input_alt ==0)
>       {
>           i = i + 239;        // Zaehler inkrementieren
>       }

Ja, so mache ich das bei meinen einfachen tastenbetätigten 
Blinkschaltungen auch immer: Anzahl der gedrückten Tasten merken, und 
wenn im nachfolgenden Schleifendurchlauf die Anzahl der gedrückten 
Tasten größer ist als vorher, dann die entsprechende Aktion ausführen.

>       while (i >= 100)        // vergleiche Zählerwert mit Vorgabe
>       {
>           i = i - 100;        // Solange i >= 100, 100 von i abziehen
>           PORTB = 0x03;        // Ausgang für Zähler
>           _delay_ms(200);      // Impulsdauer
>          PORTB = 0x00;        // Asugang wieder löschen
>         _delay_ms(200);    // Pausedauer
>       }

Da i über 300 werden kann, wird die Schleife bis zu dreimal durchlaufen, 
mit je 2*200 ms delay = 3*2*200 = 1200 ms. Das funktioniert nur mit 
Drehzahlen der Walze von unter eins pro Sekunde. Nach meiner groben 
Rechnung und Deinen Angaben dreht die Walze aber fast zweimal pro 
Sekunde, oder? Ich würde nochmal genau prüfen, ob nicht nur überhaupt 
gezählt wird, sondern bei entsprechender Drehzahl der Maschine auch 
alles gezählt wird und wegen der Delayzeiten nicht manche 
Zählerweiterschaltungen ausfallen.

von soundmachine (Gast)


Lesenswert?

Kann Jürgen nur beipflichenten, falls das der Fall sein sollte muss man 
die ImpulsAUSGABE in ein Timergesteuertes Interrupt verlagern was aber 
auch kein großer Akt ist. Kannst dich ja diesbezüglich bei Bedarf 
nochmal melden.
Ansonsten freuts mich dass es funzt :-)

von Bernd M. (spezi)


Lesenswert?

Hallo Jürgen,

der Code stammt von soundmachine (an dieser Stelle nochmals danke 
dafür).

Wie gesagt, die Delayzeiten sind nur deswegen so hoch, damit ich die 
quasikorrekte Funktion auf meinem Eval-Board testen kann. In der 
"echten" Steuerung werden die Werte natürlich auf ein Mindestmaß 
reduziert, sodass sich hier "hoffentlich" die impulse nicht 
überschneiden.
Bei 400m/min und 2,39m/Umdrehung, also knapp 170 Umdrehungen/min wird 
das zwar etwas "empirisch", sollte aber auch realisierbar sein.

von Peter D. (peda)


Lesenswert?

Bernd M. schrieb:
> 2) Der Impuls ist auch bei einer minimalen Maschinengeschwindigkeit
> relativ kurz (ca. 200ms)

Das sind für einen MC Ewigkeiten.
Ich würde zum Entprellen raten. Das unterdrückt dann auch Störimpulse 
(lange Leitung).
Z.B. bei 4-fach Abtastung und 5ms Entprellzeit muß ein Puls mindestens 
20ms lang sein.


Bernd M. schrieb:
> Das mit dem "Verzählen" ist bei einer Tagesproduktion von ~400.000lfm
> nicht so genau ;-)

Du solltest schon so programmieren, daß es ganz genau ist. Seitens des 
MCs gibts da kein Limit.
Sobald Du Fehler im Programm hast, weißt Du ja nicht, wie ungenau Du 
dadurch wirst.


Peter

von frank (Gast)


Lesenswert?

deine uC hat vermutlich einen ext. interrupt. Den sollte man auch nutzen 
wenn man ihn sowieso hat. du kannst sogar einstellen wann er auslösen 
soll (steigende flanke, fallende, beide, usw.)

zum entprellen könnte man einen der internen Timer nutzen

von Karl H. (kbuchegg)


Lesenswert?

frank schrieb:
> deine uC hat vermutlich einen ext. interrupt. Den sollte man auch nutzen
> wenn man ihn sowieso hat. du kannst sogar einstellen wann er auslösen
> soll (steigende flanke, fallende, beide, usw.)

Würde ich ehrlich gesagt nicht machen.
Bei 40cm Walzenradius hat er ja nicht beliebig hohe Drehzahlen. D.h. mit 
Polling in der üblichen PeDa Entprellkonfiguration sollte er eigentlich 
das Auslangen finden. Selbst wenn der Sensor, der da drann hängt nicht 
prellt, schadet es auch nicht, da eine Entprellung drann zu hängen. Wie 
Peter schon sagte: letztendlich kommt das der Störsicherheit zu gute. 
Und das soll ja noch nie geschadet haben.

Externer Interrupt ist ok, wenn man nicht Entprellen muss UND das ganze 
auch nach schnell sein muss. Wenn beides aber nicht gegeben ist, ist 
PeDa Entprellen auch nicht übermässig mehr Aufwand und hat den Vorteil, 
dass er vom Entwicklungsbrett zur realen Anlage nichts verändern muss.


Und die while-Schleife

   while( i > 100 )

hätte ich durch ein if ersetzt und das sukzessive Runterzählen der 
Hauptschleife überlassen.

von frank (Gast)


Lesenswert?

edit:
1
volatile uint16_t counter;
2
3
int main(void)
4
{
5
        PORTD= 1<<PD2
6
        MCUCR = 1<<ISC01 | 1<<ISC00;    //interupt Pin INT0 rising edge
7
        GICR = 1<<INT0
8
        sei();
9
}
10
 
11
ISR(int0_vect)
12
{
13
        counter+=1; // 1 <=> 239
14
}

fehlt noch der timer zur entprellung sowie die ausgabe der daten. das 
ganze ist mehr oder minder aus dem gedächnis, möchte nicht ausschließen 
registersettings vergessen zuhaben :P

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.