Externí přerušení

Wiring, C++, C, Java, ...
Pravidla fóra
Toto subfórum slouží k řešení obecných otázek kolem programování (konstrukce, knihovny, alokace paměti, ...)
Odpovědět
T_O_M
Příspěvky: 25
Registrován: 15 srp 2017, 22:05
Reputation: 0

Externí přerušení

Příspěvek od T_O_M » 19 čer 2020, 22:08

Jdu si pro radu ohledně externího přerušení. Chci počítat pulsy z elektroměru přes výstup S0. Zapojení - +5V na S0+, S0- na vstup a rezistor 10k proti zemi.
Impulsy načítám přes externí interrupt. Samotné počítání na náběžnou hranu by fungovalo. Standardní impuls má cca 30ms, ale je tam dost rušení (zatím jsem nezkoušel zapojit hned u elektroměru, možná by to problém úplně vyřešilo). Proto chci měřit délku impulsu. To dělám tak, že jakmile přijde přerušení na náběžné hraně, tak zaznamenám čas, přepnu na pinu přerušení na sestupnou hranu a v dalším přerušení od stejného pinu spočítám délku trvání pulzu. Problém je v tom, že první přerušení chodí v pořádku, ale druhé nepravidelně vynechává. Někdy vynechá každý druhý impuls, jindy projde pět pulzů v pořádku a další dva vynechá. Tím pádem, když si zobrazím aktuální příkon, tak tam, kde je vynechaný impuls, tak padne na polovinu (viz náhled). Bohužel nemám k dispozici osciloskop, ale nemyslím si že by tam chodil nějak velkej balast. Každopádně teď mě chodí cca 1 puls za 3s, pokud tedy vynechá přerušení na konci pulsu, tak si arduino myslí, že ten puls má 3s, což ve skutečnosti nemá (když měřím měřákem, tak je tam čistá 0). Na všech 4 přerušeních (Arduino Leonardo Pro Micro) se to chová stejně.

Dělám někde vyloženě chybu? Mám to řešit jiným způsobem?

Kód: Vybrat vše

#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>

#define LED1 7

byte mac[] = {
    0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(10, 10, 10, 250);
byte influx_ip[]{10, 10, 10, 225};
int influx_port = 8089; // influx port

String input[4] = {
    "elm1",
    "elm2",
    "elm3",
    "voda",
};

unsigned long int_start_time[4];
unsigned long int_stop_time[4];
unsigned long int_last_time[4];
unsigned long pulse_time[4];
int power[3];
byte p[4] = {0, 0, 0, 0};
boolean puls = false;

EthernetUDP Udp;

void setup()
{
    pinMode(0, INPUT);
    pinMode(1, INPUT);
    pinMode(2, INPUT);
    pinMode(3, INPUT);
    pinMode(4, INPUT);
    pinMode(LED1, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(9, OUTPUT);

    Ethernet.init(10);
    Ethernet.begin(mac, ip);
    Serial.begin(9600);
    /*while (!Serial)
    {
        ; // wait for serial port to connect. Needed for native USB port only
    }
    if (Ethernet.hardwareStatus() == EthernetNoHardware)
    {
        Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
        while (true)
        {
            delay(1); // do nothing, no point running without Ethernet hardware
        }
    }
    if (Ethernet.linkStatus() == LinkOFF)
    {
        Serial.println("Ethernet cable is not connected.");
    }
    */

    // start UDP
    Udp.begin(influx_port);

    attachInterrupt(0, ISR0_start, RISING);
    attachInterrupt(1, ISR1_start, RISING);
    attachInterrupt(2, ISR2_start, RISING);
    attachInterrupt(3, ISR3_start, RISING);
    digitalWrite(9, HIGH);
}

void loop()
{
    String line;
    unsigned long last_time;
    unsigned long current_time;

    if (puls == true)
    {

        Serial.println(p[0]);
        Serial.println(p[1]);
        Serial.println(p[2]);
        Serial.println(p[3]);

        current_time = millis();
        if (current_time - last_time >= 500)
        {
            influxdb();
        }
    }
}

void ISR0_start()
{
    int_start(0);
}
void ISR0_stop()
{
    int_stop(0);
}
void ISR1_start()
{
    int_start(1);
}
void ISR1_stop()
{
    int_stop(1);
}
void ISR2_start()
{
    int_start(2);
}
void ISR2_stop()
{
    int_stop(2);
}
void ISR3_start()
{
    int_start(3);
}
void ISR3_stop()
{
    int_stop(3);
}

void int_start(byte pin)
{
    detachInterrupt(pin);
    int_start_time[pin] = micros();
    digitalWrite(8, HIGH);
    Serial.print("Přerušení start pin");
    Serial.print(pin);
    Serial.print(" čas: ");
    Serial.println(int_start_time[pin]);
    switch (pin) {
        case 0:
          attachInterrupt(0, ISR0_stop, FALLING);
          break;
        case 1:
          attachInterrupt(1, ISR1_stop, FALLING);
          break;
        case 2:
          attachInterrupt(2, ISR2_stop, FALLING);
          break;
        case 3:
          attachInterrupt(3, ISR3_stop, FALLING);
          break;         
    }
}

void int_stop(byte pin)
{
    detachInterrupt(pin);
    int_stop_time[pin] = micros();

    digitalWrite(8, LOW);
    pulse_time[pin] = int_stop_time[pin] - int_start_time[pin];

    Serial.print("Přerušení STOP pin");
    Serial.print(pin);
    Serial.print(" čas: ");
    Serial.println(int_stop_time[pin]);
    Serial.print("Impuls: ");
    Serial.println(pulse_time[pin]);

    if (pin == 3)
    {
        int_last_time[pin] = micros();
        p[pin]++;
        puls = !puls;
    }
    else
    {
        if (pulse_time[pin] >= 29000 && pulse_time[pin] <= 31000)
        {
            power[pin] += 3600000000000 / 800 / (int_stop_time[pin] - int_last_time[pin]);
            int_last_time[pin] = micros();
            p[pin]++;
            puls = !puls;
        }
    }
    switch (pin) {
        case 0:
          attachInterrupt(0, ISR0_start, RISING);
          break;
        case 1:
          attachInterrupt(1, ISR1_start, RISING);
          break;
        case 2:
          attachInterrupt(2, ISR2_start, RISING);
          break;
        case 3:
          attachInterrupt(3, ISR3_start, RISING);
          break;         
    }
    Serial.println("--- opouštím int_stop ---");    
}

void influxdb()
{
    String line;
    String tarif;
    Udp.beginPacket(influx_ip, influx_port);
    //int tarif = digitalRead(4);

    if (digitalRead(4) == 1)
    {
        tarif = "NT";
        digitalWrite(LED1, HIGH);
    }
    else
    {
        tarif = "VT";
        digitalWrite(LED1, LOW);
    }

    for (int i = 0; i < 3; i++)
    {
        if (p[i] > 0)
        {
            line = String("elektro,name=");
            line += String(input[i]);
            line += String(",tarif=");
            line += String(tarif);
            line += String(" power=");
            line += String(power[i] / p[i]);
            line += String(",value=");
            line += String(p[i]);

            Udp.print(line);

            p[i] = 0;
            power[i] = 0;
            Serial.print("Délka pulzu: ");
            Serial.println(pulse_time[i]);
        }
    }

    if (p[3] > 0)
    {
        line = String("voda,name=");
        line += String(input[3]);
        line += String(" value=");
        line += String(p[3] * 10);

        Udp.print(line);

        p[3] = 0;
        Serial.print("Délka pulzu: ");
        Serial.println(pulse_time[3]);
    }

    Serial.println(line);
    Serial.println("Sending UDP packet...");

    Udp.endPacket();
    puls = !puls;
}
Garfický výstup:
Snímek z 2020-06-19 21-34-34.png
Výstup v monitoru:
Přerušení start pin0 čas: 360618916
Přerušení STOP pin0 čas: 360649336
Impuls: 30420
--- opouštím int_stop ---
Přerušení start pin0 čas: 360650180
1
0
0
0
Délka pulzu: 30420
elektro,name=elm1,tarif=VT power=157,value=1
Sending UDP packet...
Přerušení STOP pin0 čas: 374163228
Impuls: 13513048
--- opouštím int_stop ---
Přerušení start pin0 čas: 387637984
Přerušení STOP pin0 čas: 387668428
Impuls: 30444
--- opouštím int_stop ---
Přerušení start pin0 čas: 387669268
1
0
0
0
Délka pulzu: 30444
elektro,name=elm1,tarif=VT power=166,value=1
Sending UDP packet...
Z tohoto mě zase přijde, že chyba je v náběžné hraně přerušení, kdy cca 1ms po skončení pulzu naskočí nový (označené), který tam ale určitě být nemá.

T_O_M
Příspěvky: 25
Registrován: 15 srp 2017, 22:05
Reputation: 0

Re: Externí přerušení

Příspěvek od T_O_M » 19 čer 2020, 22:34

Tak alespoň částečně vyřešeno.
Ze zoufalství jsem připojil paralelně k S0 kondenzátor 100n a je po problému. Teď jen otázka, co to bude dělat při vyšších frekvencích. Těch 100n asi bude moc. Uměl by někdo spočítat, co tam dát za kapacitu? Teoreticky by mělo chodit maximálně 3.8imp/s.

ondraN
Příspěvky: 932
Registrován: 08 srp 2019, 20:01
Reputation: 0

Re: Externí přerušení

Příspěvek od ondraN » 20 čer 2020, 07:26

Myslím, že problém dělá vysoká impedance přenosové linky. Čím je vyší, tím je větší i různé indukované rušení. A pak jsou hrany impulsů "chlupaté" a málo strmé, což může způsobovat to, že se přerušení negeneruje, nebo se generuje falešně. Zkusil bych snížit impedanci linky, blokovat ji kondenzátory a před vstup do arduina zapojit schmittův obvod, třeba s obvodem 555, třeba tento https://www.petervis.com/dictionary-of- ... rcuit.html.

Odpovědět

Kdo je online

Uživatelé prohlížející si toto fórum: Žádní registrovaní uživatelé a 15 hostů