kostenloser Webspace werbefrei: lima-city


Linux termios und RS232

lima-cityForumProgrammiersprachenC/C++ und D

  1. Autor dieses Themas

    darkpandemic

    Kostenloser Webspace von darkpandemic

    darkpandemic hat kostenlosen Webspace.

    Hallo alle miteinander,

    ich habe ein Problem unter Linux mit meinem Arduino zu kommunizieren.
    Die gewünschte Konfiguration der seriellen Schnittstelle ist wie folgt:
    - Lesen und Schreiben
    - 8 Bit Daten
    - 1 Stoppbit
    - kein Paritätsbit
    - keine Flußkontrolle (weder Soft- noch Hardware)
    - 115200 Baud
    - blockierendes Lesen mit 100ms Timeout
    - Falls möglich Öffnen der Schnittstelle ohne dass DTR auf LOW geht

    Hier ist mein bisheriger Testcode, von dem ich eigentlich glaubte, dass er alles nötige enthält (funktioniert nicht):
    int serial_open(const char * device)
    {
        int fd;
        struct termios settings = {0};
    
        cfsetispeed(&settings, B115200);
        cfsetospeed(&settings, B115200);
    
        /* 8 bit data */
        settings.c_cflag |= CS8;
        /* enable reading */
        settings.c_cflag |= CREAD;
        /* local line */
        settings.c_cflag |= CLOCAL;
        /* blocked reading */
        settings.c_cc[VMIN] = 128;
        /* set 100ms timeout */
        settings.c_cc[VTIME] = 1;
    
        if((fd = open(device, O_RDWR|O_NOCTTY|O_NDELAY))<0)
        {
            fprintf(stderr, "Error: serial_open: open() failed.\n");
            return -1;
        }
    
        if(tcsetattr(fd, TCSANOW, &settings))
        {
            fprintf(stderr, "Error: serial_open: tcsetattr() failed.\n");
            close(fd);
            return -1;
        }
    
        return fd;
    }
    cfmakeraw() habe ich auch schon versucht und hiermit auch schon. Bisher kein Erfolg. Dazu kommt, dass ohne das O_NDELAY-Flag bei open() kein Timeout ausgelöst wird (read() kehrt nicht zurück) und mit dem Flag wird gar nicht gewartet. D.h. der Wert in c_cc[VTIME] wird in beiden Fällen ignoriert.
    Mit folgendem Python-Skript habe ich es schon einmal geschafft:
    # -*- coding: utf-8 -*-
    import sys
    import time
    import serial
    
    try:
        ser = serial.Serial('/dev/ttyACM0', 115200, timeout=1)
    except:
        print "Error: can not open serial port."
        sys.exit()
    
    time.sleep(1.5)
    
    ser.write('R')
    c = ser.read(1)
    if len(c) == 0:
        print "Error: controller is not responding."
        ser.close()
        sys.exit()
    elif c != "R":
        print "Error: invalid response from controller."
        ser.close()
        sys.exit()
    
    ser.write("SaSbScSdSeSfSgSh")
    
    ser.close()
    Allerdings führen Timeouts unter einer Sekunde dazu, dass die serielle Schnittstelle geschrottet wird (in der folge nur noch I/O-Fehler) und der DTR-Pin wird beim Öffnen auf LOW gesetzt. Also ist das auch nicht wirklich toll.

    Falls jemand eine Lösung weiß oder einen evtl. zielführenden Hinweis hat würde ich mich sehr Freuen.

    Schon einmal Danke!
  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. Na ja zumindest was den DTR Pin angeht würde mir die Idee kommen den manuell wieder high zu setzen falls das etwas hilft, in meinem Script das ich in diesem Thread als Beispiel verwendet habe ist eine entsprechende Anweisung für Python vorhanden die sich sicher mit C ebenfalls umsetzen lassen würde.

    Was den Rest angeht ist mir aktuell schleierhaft was du vorhast, da du keinen Arduino Code angegeben hast gehe ich davon aus das du das Programmierinterface zum Arduino öffnen möchtest und das kann meiner auffassung nach so nicht gehen weil die Kommunikation mit dem Programmer nicht so schnell und nicht ohne Flusskontrolle möglich ist, ich kann mich aber irren.
  4. Autor dieses Themas

    darkpandemic

    Kostenloser Webspace von darkpandemic

    darkpandemic hat kostenlosen Webspace.

    Hallo fatfox,

    danke für die Antwort. Das Problem mit dem DTR-Pin ist, dass jedesmal, wenn man den seriellen Port öffnet (egal ob per minicom, Python oder C) der Pin kurz auf Low und dann wieder auf High geht. Das führt dazu, dass das Arduino einen Reset macht und ich 1,5-2 Sekunden warten muss bevor das Arduino wieder einsatzbereit ist. Unter Windows passiert sowas nicht von daher hätte ich halt gehofft, dass es unter Linux auch möglich ist den Port zu öffnen ohne eine Reset auszulösen.
    Ansonsten will ich einfach nur Daten an das Arduino senden und die Antwort wieder empfangen (nicht Programmieren).
    Der Vollständigkeit halber hier auch noch die wichtigsten Teile des Arduino-Codes:
    ...
    
    static bool checkSerial()
    {
        uint8_t c;
        
        if(!Serial.available())
            return false;
    
        c = Serial.read();
        
        switch(c)
        {
            case 'R':
            {
                Serial.write('R');
                anim_delay = 250;
                anim_idx = 0;
                anim_frame = 0;
                return true;
            }
            case 'S':
            {
                while(!Serial.available())
                    delay(100);
                    
                c=Serial.read();
                setOutput(c);
                delay(anim_delay);
                return true;
            }
        }
    }
    
    ...
    
    void setup()
    {
        pinMode(PIN_BUTTON, INPUT);
        pinMode(PIN_ENCODER_A, INPUT);
        pinMode(PIN_ENCODER_B, INPUT);
        
        digitalWrite(PIN_ENCODER_A, HIGH);
        digitalWrite(PIN_ENCODER_B, HIGH);
        digitalWrite(PIN_BUTTON, HIGH);
        
        pinMode(PIN_DATA, OUTPUT);
        pinMode(PIN_CLOCK, OUTPUT);
        pinMode(PIN_LATCH, OUTPUT);
        
        setOutput(0);
    
        button_pressed = false;
        encoder_state = getEncoderState(PIN_ENCODER_A, PIN_ENCODER_B);
        anim_delay = 250;
        anim_idx = 0;
        anim_frame = 0;
        time = millis();
        
        Serial.begin(115200);
    }
    
    /*****************************************
     * main loop                             *
     *****************************************/
    void loop()
    {
        if(checkSerial())
            return;
            
        checkEncoder();
        checkButton();
        
        if(anim_idx == ANIMATION_COUNT)
        {
            if(millis()-time > 5)
            {
                int val = analogRead(PIN_POTI);
                val = map(val, 0, 1023, 0, 8);
                
                char c = 0;
                
                for(int i = 0; i< val;i++)
                {
                    c <<= 1;
                    c |= 1;
                }
                
                setOutput(c);
            }
        }
        else if(millis()-time > anim_delay)
        {
            anim_frame++;
            if(anim_frame >= ANIMATION_SIZE[anim_idx])
                anim_frame = 0;
                
            setOutput(ANIMATION[anim_idx][anim_frame]);  
            time = millis();
        }
    }
    Allerdings funktioniert der Arduino-Code einwandfrei.
    Mittlerweile habe ich es zumindest geschafft, dass ich zuverlässig senden kann aber empfangen geht gar nicht.
    Wenn ich mich z.B. erst mit minicom verbinde, dann kann ich ein 'R' schicken und bekomme dieses dann auch zurück.
    Wenn ich den seriellen Port mit C öffne und den Port genauso einstelle wie es minicom gemacht hat, dann kann ich zwar senden bekomme aber keine Antwort. Wenn ich es danach mit minicom oder Python versuche können diese zwar auch noch senden bekommen aber auch keine Antwort mehr.
    Irgendwo scheint da was mächtig schief zu laufen und ich weiß einfach nicht wo.
  5. Sende mal einen Wagenrücklauf oder wahlweise andere Zeilenendzeichen mit und schau ob du das Absturzverhalten simulieren kannst.

    Lass dir die Anzahl der Bytes im eingangspuffer über 2 leds anzeigen oder so, wenn ich recht vermute hast du einmal genau 1 Byte und einmal mehr wobei das zunächst gelesene dann vermutlich durch deine Abfrage nicht definiert ist.

    Vermutung: Es wird ein Zeilenendzeichen mit Übertragen das deine Auswertung zunichte macht (es fehlt auf dem arduino glaube ich eine Angabe für undefiniertes Byte und ein abfangen von einem leeren Eingangspuffer [Rückgabe von Serial Read = -1])

    Das könnte dich auf die Spur bringen...

    Beitrag zuletzt geändert: 8.1.2012 22:56:06 von fatfox
  6. Autor dieses Themas

    darkpandemic

    Kostenloser Webspace von darkpandemic

    darkpandemic hat kostenlosen Webspace.

    Hallo fatfox,

    wiedereinmal danke für Deine Unterstützung.
    Das Arduino ist im Moment wieder Lichtorgel auf meinem Schreibtisch. Es gibt einen Taster, mit dem man zwischen verschiedenen Animationen umschalten kann, einen Drehencoder mit dem man die Geschwindigkeit regeln kann und noch einen Poti der bei einer "Animation" als Regler verwendet wird. Die Ausgabe erfolgt über ein Schieberegister, an dem zur Zeit 8 LEDs hängen.
    Wenn man dem Arduino ein 'R' schickt, dann wird die Animation in den Ausgangszustand zurückversetzt und ein 'R' an den Rechner zurückgeschickt.
    Wenn man dem Arduino ein 'S' schickt, dann wartet das Arduino auf ein weiteres Byte und schreibt dieses dann für die Dauer eines Animationsframes in das Schieberegister. D.h. die LEDs zeigen das Bitmuster an.
    Alle anderen Zeichen werden vom Arduino einfach ignoriert und machen keine Probleme da der switch/case ja nur auf 'R' und 'S' reagiert. Da vor jedem Serial.read() mit Serial.available() geprüft wird, ob es etwas zu lesen gibt kommt der Fall, dass Serial.read() -1 zurückliefert gar nicht vor es sei den ich würde nach einem 'S' ein 0xFF senden.
    Ich weiß, dass alles was ich an das Arduino sende auch dort ankommt (die LEDs zeigen es ja an) und ich weiß auch, dass das Arduino auf das 'R' richtig reagiert, da es unter Windows ja problemlos funktioniert (C / C# / HTerm) und an den RX/TX LEDs auf dem Board sieht man es auch. Und wenn der Rechner frisch gestartet ist dann funktioniert es mit minicom erstmal tadellos und mit Python meistens (manchmal gibt es auch dort nach dem zweiten oder dritten Lauf plötzlich Aussetzer -> Port lässt sich nicht mehr öffnen).
    Jedenfalls werde ich das mit den Zeilenumbrüchen mal ausprobieren. Vielleicht frisst Linux es ja wenn man ihm ein "R\n" zurücksendet.

  7. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!