Forum: PC-Programmierung Linux Uart Konfiguration


von Fabian S. (fabian727)


Angehängte Dateien:

Lesenswert?

Hi liebes Forum,

ich versuche nun schon seit mehreren Tagen ein Programm zu schreiben, 
das einen Zeichenstring über den UART an einen Microcontroller sendet.

Das Programm auf dem Microcontroller funktioniert, wenn ich es mit 
Minicom vom Computer ansteuere.
Nutze ich mein Programm und lasse Minicom im Hintergrund laufen, 
funktioniert auch das Programm.
Ist Minicom aus und ich lasse mein Programm starten, funktioniert die 
Übertragung nicht.
Ich habe den Bus mit dem Salae Logic Analyzer beobachtet, anbei das 
entsprechende Bild. Ist Minicom nicht an, so entsteht das letzte Bitflag 
(ganz rechts). Ist Minicom im Hintergrund an, so ist dieses nicht 
vorhanden.

Ich finde inzwischen keine Erklärung mehr, woran das liegt.

Wer kann mir weiterhelfen?

von Fritz G. (fritzg)


Lesenswert?

Edit: Sorry, erst jetzt deinen Code gesehen.

Dumme Frage: Baudrate usw. hast du im Programm eingestellt? Sonst kann 
man es in der Shell auch mit stty machen.

: Bearbeitet durch User
von Fabian S. (fabian727)


Lesenswert?

gibt keine dummen fragen.
ja, baudrate stelle ich mit diesen zeilen ein:

    if( cfsetispeed(&port_settings, B38400) != 0)    // set baud rates
    { cout << "couldn't set baudrate for input" << endl; }
    if( cfsetospeed(&port_settings, B38400) != 0)
    { cout << "couldn't set baudrate for output" << endl; }

von Fritz G. (fritzg)


Lesenswert?

int n = read(fd,data,(int) strlen(data));

Sollte es nicht sizeof(data) sein?

von Klaus (Gast)


Lesenswert?

Hm. Irgendwie hört sich das nach einem Treiberproblem an. Die These 
wäre, dass der Treiber korrekt geladen ist, oder auch nur korrekt 
initialisiert wird, wenn Minicom gestartet ist. Allerdings sollte das 
theoretisch Konflikte geben, da ja dann zwei Programme auf die selbe 
Schnittstelle zugreifen.

Das mit dem "Bitflag" von Deinem Bild verstehe ich nicht. Scheint mir 
irrelevant zu sein.

Poste doch mal den Code von dem PC-Programmteil.

von Klaus (Gast)


Lesenswert?

Oops. Da isser ja, der Code. Sorry.

von Fritz G. (fritzg)


Lesenswert?

Hier ist ein alter Code von mir in C, bitte vergleiche es mal, ich bin 
so müde.
1
int
2
readinput_init (void)
3
{
4
  /* 
5
   * Open modem device for reading and writing and not as controlling tty
6
   * because we don't want to get killed if linenoise sends CTRL-C.
7
   */
8
9
  fd = open (serialdev, O_RDWR | O_NOCTTY);
10
11
  if (fd < 0)
12
  {
13
    perror (serialdev);
14
    return FALSE;
15
  }
16
  didinit = TRUE;
17
  tcgetattr (fd, &oldtio);  /* save current serial port settings */
18
  bzero (&newtio, sizeof (newtio));  /* clear struct for new port settings */
19
20
  /* 
21
   * BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
22
   * CRTSCTS : output hardware flow control (only used if the cable has
23
   * all necessary lines. See sect. 7 of Serial-HOWTO)
24
   * CS8     : 8n1 (8bit,no parity,1 stopbit)
25
   * CLOCAL  : local connection, no modem contol
26
   * CREAD   : enable receiving characters
27
   */
28
  newtio.c_cflag = (11 + serialspeed) | CS8 | CLOCAL | CREAD;
29
  newtio.c_cflag &= ~(PARENB | CRTSCTS);
30
  /*
31
   * IGNPAR  : ignore bytes with parity errors
32
   * ICRNL   : map CR to NL (otherwise a CR input on the other computer
33
   * will not terminate input)
34
   * otherwise make device raw (no other input processing)
35
   */
36
  newtio.c_iflag = IGNPAR | ICRNL;
37
38
  /*
39
   * Raw output.
40
   */
41
  /*   newtio.c_oflag = 0; */
42
  newtio.c_iflag = newtio.c_oflag = newtio.c_lflag = (tcflag_t) 0;
43
  newtio.c_oflag = (ONLCR);
44
  /*
45
   * ICANON  : enable canonical input
46
   * disable all echo functionality, and don't send signals to calling program
47
   */
48
  /*    newtio.c_lflag = ICANON;  */
49
50
  /* 
51
   * initialize all control characters 
52
   * default values can be found in /usr/include/termios.h, and are given
53
   * in the comments, but we don't need them here
54
   */
55
  newtio.c_cc[VINTR] = 0;  /* Ctrl-c */
56
  newtio.c_cc[VQUIT] = 0;  /* Ctrl-\ */
57
  newtio.c_cc[VERASE] = 0;  /* del */
58
  newtio.c_cc[VKILL] = 0;  /* @ */
59
  newtio.c_cc[VEOF] = 4;  /* Ctrl-d */
60
  newtio.c_cc[VTIME] = 0;  /* inter-character timer unused */
61
  newtio.c_cc[VMIN] = 1;  /* blocking read until 1 character arrives */
62
  newtio.c_cc[VSTART] = 0;  /* Ctrl-q */
63
  newtio.c_cc[VSTOP] = 0;  /* Ctrl-s */
64
  newtio.c_cc[VSUSP] = 0;  /* Ctrl-z */
65
  newtio.c_cc[VEOL] = 0;  /* '\0' */
66
  newtio.c_cc[VREPRINT] = 0;  /* Ctrl-r */
67
  newtio.c_cc[VDISCARD] = 0;  /* Ctrl-u */
68
  newtio.c_cc[VWERASE] = 0;  /* Ctrl-w */
69
  newtio.c_cc[VLNEXT] = 0;  /* Ctrl-v */
70
  newtio.c_cc[VEOL2] = 0;  /* '\0' */
71
72
  /* 
73
   * now clean the modem line and activate the settings for the port
74
   */
75
  tcflush (fd, TCIFLUSH);
76
  tcsetattr (fd, TCSANOW, &newtio);
77
78
79
  /*
80
   * terminal settings done, now handle input
81
   * In this example, inputting a 'z' at the beginning of a line will 
82
   * exit the program.
83
   */
84
85
86
  /* restore the old port settings */
87
  /*  tcsetattr (fd, TCSANOW, &oldtio); */
88
  return TRUE;
89
}

von Fabian S. (fabian727)


Lesenswert?

@fritz: read() wird mit der anzahl an bytes, die gelesen werden können, 
aufgerufen. Diesen Wert ermittel ich durch strlen() anzahl an chars, die 
der string (char array) enthalten kann ;).
read gibt keinen Fehler zurück, sondern sogar den richtigen String. 
SOFERN minicom im Hintergrund geöffnet wird.


@Klaus: warum denkst du nicht, dass dieser Bitfehler der Ursprung ist?
Wenn ich minicom im hintergrund offen habe, ist er weg.
Mein Programm vom Controller sollte dieses Bit aufnehmen und 
abspeichern. Ist dies der Fall, wird der komplette String um 1 Char 
verschoben, die zugewiesene "Adresse" stimmt nicht mehr überein und der 
komplette String wird nicht interpretiert...

von Fritz G. (fritzg)


Lesenswert?

strlen gibt die Länge des momentanen Inhaltes an. Wenn da "Fritz" 
drinsteht, dann wirst du nur 5 Bytes lesen können, nicht mehr. Ich bin 
ziemlich sicher du meinst die Größe des Buffers (sizeof wäre in dem Fall 
auch falsch).

von Fabian S. (fabian727)


Lesenswert?

@Fritz: kontrolliert, alles bei mir entsprechend deinen Bits geändert.
Das Ding will nicht so wie ich... oder du

von Peter II (Gast)


Lesenswert?

Fabian S. schrieb:
> read() wird mit der anzahl an bytes, die gelesen werden können,
> aufgerufen. Diesen Wert ermittel ich durch strlen() anzahl an chars, die
> der string (char array) enthalten kann ;).

und was ist wenn in Daten vorher eine andere länge drin steht? strlen 
liefert nicht die Anzahl von Array zurück sondern die Anzahl der Zeichen 
mit zum ersten \0.

von 900ss (900ss)


Lesenswert?

Peter II schrieb:
> Diesen Wert ermittel ich durch strlen()

Wenn der String nicht vorher gefüllt (initialisiert mit erwarteter Länge 
) wurde, gibt strlen() evtl. 0 oder, je nach Inhalt von data irgendwas 
zurück.

Lies mal die Beschreibung zu strlen().

Du brauchst statt dessen ..... Was anderes. ;-)

von Fabian S. (fabian727)


Lesenswert?

es wird:     memset(&data[0],0,16);
vor aufruf der read funktion aufgerufen.
Es existiert somit kein '\0'.
Somit wird die komplette länge des strings genommen.

sizeof() gibt bei "1:0,0,0!\n" 8 zurück. strlen() 9. Ich bevorzuge die 9 
bytes zu schicken.

von Fabian S. (fabian727)


Lesenswert?

selbst wenn ich die read Funktion nicht aufrufe, funktioniert es nicht.
Ich möchte lediglich einen String schicken, daraufhin soll der 
microcontroller die farbe der angeschlossenen rgb-led ändern.

schicke ich den string in minicom, so funktionierts.
schicke ich ihn mit meinem Programm, funktionierts nicht.
schicke ich ihn mit programm und minicom im hintergrund, funktionierts.
Alles ohne aufruf von read().

von Peter II (Gast)


Lesenswert?

Fabian S. schrieb:
> memset(&data[0],0,16);
> vor aufruf der read funktion aufgerufen.
> Es existiert somit kein '\0'.
> Somit wird die komplette länge des strings genommen.

es sind nur \0 drin oder was glaubst du was den 0 von memset macht?

von Fabian S. (fabian727)


Lesenswert?

ich habe nun den code hierzu abgewandelt:

    memset(&data[0],0,16);
    data[15] = '\0';
    serialport.receive(&data[0]);

somit wird erst alles genullt -> gar kein \0
und danach wird der letzte auf \0 gesetzt....

es hat leider nichts an meiner write-funktion geändert. Der mc reagiert 
trotzdem nicht so wie er soll ;-)

von Peter II (Gast)


Lesenswert?

Fabian S. schrieb:
> somit wird erst alles genullt -> gar kein \0

\0 ist null.

von Fritz G. (fritzg)


Lesenswert?

Schicke probeweise ein CR/LF hinten nach. Vielleicht puffert die 
Schnittstelle zeilenweise.
Wenn es dann geht, ist die Schnittstelle nicht im RAW Modus.

von Fabian S. (fabian727)


Lesenswert?

Es ist leider keine Änderung zu sehen.

p.s.: ich schicke bereits dauerhaft ein LF mit.
Ich habe alle Varianten durchgeschickt.

Damit ihr nicht mehr raten müsst, wie meine Main aussieht:

int main(int argc, char *argv[])
{
    terminal serialport;
    char data[16] = "1:0,0,0!\n";
    serialport.send(&data[0]);
    usleep(10000);
    memset(&data[0],0,16);
    data[15] = '\0';
    serialport.receive(&data[0]);
    serialport.~terminal();
    return 0;
}

von Peter II (Gast)


Lesenswert?

Fabian S. schrieb:
> Damit ihr nicht mehr raten müsst, wie meine Main aussieht:

irgendwie versucht du alles anders zu machen als üblich.

serialport.send(&data[0]);  ->   serialport.send(data);
memset(&data[0],0,16);  -> memset(data,0,sizeof(data) );

data[15] = '\0'; -> kompletter Unsinn da stehen schon 0 drin

serialport.receive(&data[0]); -> serialport.receive(data);
serialport.~terminal();  -> macht man auch nicht. Das macht der Compiler 
wenn der Gültigkeitsbereich verlassen wird.

von Fabian S. (fabian727)


Lesenswert?

@peter.

das meiste davon waren Schritte der Verzweiflung und Unwissenheit.
Leider ändert das nur nix am Sachverhalt der Funktionalität...

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Kurzer einschub für alle:
Dieser Thread ist eine weiterführung/neustart von diesem Thread hier: 
Beitrag "arduino nano seriell (rs232) <-> usb linux (ubuntu14.04) Port Config"

So, zurück zum Problem:
Es handelt sich um ein Arduino-Board (Das ist wichtig!). Arduino-Boards 
melden sich unter Linux als Modem (ttyACM! Fabian hat das ganze per 
udev in ttyPWM umbenannt... warum auch immer), unter BSD 8 ebenfalls 
Modem (cuaU).
Kurzer erkenntnis Gewinn: Es wird der Modemtreiber benutzt (auch diese 
feststelung ist wichtig zum verstehen!).
Unter BSD 8 (ja ja, es geht hier um Umbunut, ich weiß, ich erklär ja 
nur...) wird der Controller auf dem Arduino-Board resetet (Softreset), 
sobald der Serielleport geschlossen wird. Sowas muss man abschalten, 
unter BSD heißt das Flag irgendwas mit "Hang Up...", um die Verbindung 
zu beenden. Und genau dieses Modem-Hang-Up sorgt unter BSD für einen 
Reset.
Man kann die Arduino-Boards mittels RTS/DTS resetten... ach momentmal, 
die leitungen gibt es ja gar nicht bei einem USB-Kabel. Das Signal wird 
also per Software generiert und vom Arduino-USB-Seriellwandler (meistens 
ein kleiner Atmega) in ein Reset-Signal umgewandelt.

Auch unter Linux bin ich da schon in (wenn auch andere) Probleme 
gelaufen. Ich kann der Stelle nur den Tipp geben: Probier das ganze mal 
mit einem echten USB-Seriell-Wandler, z.B. diesen hier: 
http://shop.in-circuit.de/product_info.php?cPath=38&products_id=80
Also: Arduino -> USB-Seriell-Wandler -> PC
Was ist jetzt der Unterschied? Ganz einfach, der gepostete Wandler 
meldet sich als ttyUSB, benutzt also einen anderen Treiber, womit ich 
bisher keins der Probleme hatte, die ich mit dem ACM-Treiber hatte.

Das ist soweit meine Erfahrung mit dem Arduino-Sch*** >:-[

Fabian S. schrieb:
> int main(int argc, char *argv[])
> {
>     terminal serialport;
>     char data[16] = "1:0,0,0!\n";
>     serialport.send(&data[0]);
>     usleep(10000);
>     memset(&data[0],0,16);
>     data[15] = '\0';
>     serialport.receive(&data[0]);
>     serialport.~terminal();
>     return 0;
> }
Über den Destruktor schließt du den Seriellenport... Ich Wette 5 Euro 
(für die Forums-Kasse!), das der eine Clock genau dieser Modem-Hang-Up 
mist ist.
Der unterschied mit Minicom wird der sein, das Minicom genau das 
abschalten wird. "Tunnel" das ganze mal über die (oben gepostete) 
USB-UART-Bridge.

Grüße

von N.G: (Gast)


Lesenswert?

Fürs Protokoll:

0 ist '\0'
0 (also als zahl) wird im String als die Escape-Sequenz '\0' 
dargestellt, der Wert ist aber genauso 0.

Abweichend davon ist '0' zu sehen, das ist nämlich die 
ASCII-Repräsentation von der Zahl 0 (also als "Buchstabe")

'0' != 0
'0' != '\0'
 0  == '\0'

Mit diesem Wissen sollte die auffallen, dass strlen etwas anderes 
zurückgibt, als du dir vorstellst

von Fabian S. (fabian727)


Lesenswert?

ja es ist Ubuntu und es ist ein Arduino... mit einem schönen AVR-DRAGON 
programmiert.

Die Hardware mag ein Atmega mit Quarz und und USB <-> RS232 Wandler 
sein, hat aber nicht mehr viel mit Arduino IDE sein. Wie gesagt mit 
Eclipse und AVR DRAGON sein.


Die 5Euro kannst du einzahlen... ich habe bereits ein sleep(10) vor dem 
Destruktor eingebaut. D.h. das Board hätte 10 sek. lang die Farbe ändern 
müssen.... es ist leider nicht geschehen.
Womit du recht hast: Minicom unterdrückt/ verhindert dies tatsächlich...

von Fabian S. (fabian727)


Lesenswert?

@ N.G.

thanks für den Hinweis. Diesem war ich mir tatsächlich nicht bewusst.

int main(int argc, char *argv[])
{
    terminal serialport;
    char data[16] = "1:0,0,0!\n";
    serialport.send(data);
    sleep(10);
    return 0;
}

Mit den ganzen Hinweisen mal meine neue main.


Kein receive mehr, um weitere Fehler auszugrenzen -> weniger Code.

sleep(10) um den Destruktor rauszuzögern....

von Fabian S. (fabian727)


Angehängte Dateien:

Lesenswert?

so nach langer weiterer zeit, bin ich auf den Trichter gekommen.

Schuld scheint mir tatsächlich dieses 1 Bit zu sein. Getriggert vermute 
ich jedoch wird es vom microcontroller.

Rufe ich die send funktion 2 mal hintereinander auf und schreibe ich die 
chars einzeln mit 400 us pause dazwischen, stellt der controller um.


Somit stellt sich nur noch die Frage. Wo ist der Fehler im mc-programm?

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.