Forum: Mikrocontroller und Digitale Elektronik Arduino S0 Konverter


von Rugby (Gast)


Lesenswert?

Hallo,

Ich lese mit meinen Arduino die Led Impulse vom Stromzähler, klappt 
soweit alles auch. Da ich für eine weiteres Gerät die Signale auf  ein 
S0 konformes Signal (30ms High, 30ms LOW haben muss stellt sich 
folgendes Problem. Der Zähler gibt pro kWh 10.000 Impulse aus. Nach der 
S0 Normung  sind maximal 16,67 Hz erlaubt, was mit 6000W schon erreicht 
ist. Jetzt wollte ich in der Arduino Software einen Zähler verbauen, der 
nur jedes 10te Signal durchlässt, also aus 10.000 1.000 macht.
Es folgt nun das Problem, dass er bei Beachtung der S0 Normung Nicht 
alle Impulse erfassen kann. (Outputsignal wird mit Delay 30ms definiert) 
Interruptionen sind leider nicht möglich,  da die Auswertung über ein 
Analogeingang erfolgt.
Könnt ihr mir weiterhelfen. Code folgt noch.

von Karl (Gast)


Lesenswert?

Rugby schrieb:
> Es folgt nun das Problem, dass er bei Beachtung der S0 Normung Nicht
> alle Impulse erfassen kann. (Outputsignal wird mit Delay 30ms definiert)
> Interruptionen sind leider nicht möglich,  da die Auswertung über ein
> Analogeingang erfolgt.
> Könnt ihr mir weiterhelfen. Code folgt noch.

Was hat das Eine mit dem Anderem zutun? Ein Timerinterupt nach 30 ms 
geht nicht, wenn man den ADC verwendet? Das wäre mir neu. Bei 16 Hz geht 
das sogar one Timer. Ließ einfach mal "Blink without delay"!

von Rugby (Gast)


Lesenswert?

Hier erstnochmal der Code:
1
   
2
const int ledPin13 = 13;
3
4
int analog0;
5
6
void setup() {
7
  
8
  pinMode(ledPin13, OUTPUT);
9
  
10
  
11
}
12
13
void loop() {
14
  
15
  analog0 = analogRead(0);  
16
17
if (analog0 > 300){ 
18
  digitalWrite(ledPin13, HIGH);
19
  delay(30);
20
  }
21
      else { 
22
      digitalWrite(ledPin13, LOW);
23
      //delay(30);
24
      };  
25
 
26
}

ja mein Problem ist es, dass er nicht jedes Signal erfasst, da er dann 
noch bei delay hängt. Und außerdem soll das Signal trotzdem noch S0 
konform sein. Jemand eine Idee?

von Dieter S. (Gast)


Lesenswert?

Rugby schrieb:
> ja mein Problem ist es, dass er nicht jedes Signal erfasst, da er dann
> noch bei delay hängt. Und außerdem soll das Signal trotzdem noch S0
> konform sein. Jemand eine Idee?

Du beschreibst deinen Fehler schon selbst.
Das delay() muss raus. Ersetze es durch millis oder wie es en 
"BlinWithoutDelay" beschrieben ist.

von Jay Low (Gast)


Lesenswert?

Hallo,

ich habe da mal eben was zusammen geschrieben.
1
const int ledPin13 = 13;
2
3
unsigned int subS0Pulses = 0;
4
unsigned int lastAnalogValue = 0;
5
boolean generateOutput = false;
6
int outputPulseDuration = 0;
7
8
const unsigned int s0PulsesRef = 10; // [sub S0 pulses]
9
// Make sure s0PulseOnTime/tickDuration has no remainder.
10
// Same is true for s0PulseOffTime/tickDuration.
11
const unsigned int tickDuration = 1; // [ms]
12
const unsigned int s0PulseOnTime = 30; // [ms]
13
const unsigned int s0PulseOffTime = 30; // [ms]
14
15
void setup()
16
{
17
  pinMode(ledPin13, OUTPUT); 
18
}
19
20
void loop()
21
{
22
  // Detect rising edge
23
  int analogValue = analogRead(0);
24
  if((analogValue     >  300) &&
25
     (lastAnalogValue <= 300))
26
  {
27
    // Remember analog value for the next time.
28
    subS0Pulses++;
29
  }
30
  lastAnalogValue = analogValue;
31
  // Only every tenth pulse should generate an output impulse
32
  if(subS0Pulses >= s0PulsesRef && generateOutput == false)
33
  {
34
    generateOutput = true;
35
    outputPulseDuration = 0;
36
    subS0Pulses -= s0PulsesRef;
37
  }
38
  // Generate output impulse
39
  if(generateOutput == true)
40
  {
41
    if(outputPulseDuration < (s0PulseOnTime  / tickDuration))
42
    {
43
      digitalWrite(ledPin13, HIGH);
44
      outputPulseDuration++;
45
    }
46
    else if((outputPulseDuration >= (s0PulseOnTime  / tickDuration)) &&
47
            (outputPulseDuration <  (s0PulseOffTime / tickDuration)))
48
    {
49
      digitalWrite(ledPin13, LOW);
50
      outputPulseDuration++;
51
    }
52
    else
53
    {
54
      generateOutput = false;
55
    }
56
  }
57
  delay(tickDuration);
58
}

Ich habe weder eine IDE oder gar Hardware. Soll heissen: Da sind 
bestimmt noch einige Unstimmigkeiten - oder gar richtige Fehler - 
enthalten.


Die Idee ist, dass du nicht darauf wartest, dass die Befehle nach 
einander abgearbeitet werden und das Programm erst danach erst einen 
erneuten Durchlauf der Schleife beginnt.
Stattdessen wird die die Schleife alle <tickDuration>/1ms durchlaufen. 
Siehe ganz unten das delay().
Ein Durchlauf beginnt damit, dass der ADC ausgelesen wird. Anschliessend 
wird der aktuelle und der alte Wert verglichen ob es eine steigende 
Flanke gibt(die LED vom Zähler angeht). Wenn das der Fall ist, wird 
subS0Pulses um 1 erhöht.
Danach wird überprüft ob schon genug Impulse gezählt wurden und gerade 
kein Impuls ausgegeben wird. Falls ja wird ein neuer Impuls angestossen.
Dies geschieht im letzten IF-Block.
Mit <outputPulseDuration> wird dabei gezählt, der wievielte Durchlauf 
von loop() es gerade ist und somit auch was gerade passieren soll.
Es wird nur kurz der Ausgabe-Pin gesetzt und die Zählervariable erhöht - 
viel mehr passiert in diesem IF-Block nicht und das Programm läuft 
direkt in den delay().

CU,
Jay

von Rugby (Gast)


Lesenswert?

Danke Jay für den Code.

Habe diesen Code ausgetestet. Nun habe ich das Problem, das nach dem 
10ten Zählimpuls die LED leuchtet, dann aber nicht wieder ausgeht. Habe 
versucht im Code was zu ändern, leider ohne erfolg. Kanst du mir da 
bitte weiterhelfen?

Mfg Rugby

von Rugby (Gast)


Lesenswert?

Dazu sei gesagt, dass der Zähler immer wieder von 0 bis 10 hochzählt. 
Zählen klappt also.

von Rugby (Gast)


Lesenswert?

Kein anderer eine Idee??

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.