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?
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
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; }
int n = read(fd,data,(int) strlen(data)); Sollte es nicht sizeof(data) sein?
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.
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 | }
|
@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...
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).
@Fritz: kontrolliert, alles bei mir entsprechend deinen Bits geändert. Das Ding will nicht so wie ich... oder du
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.
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. ;-)
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.
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().
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?
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 ;-)
Schicke probeweise ein CR/LF hinten nach. Vielleicht puffert die Schnittstelle zeilenweise. Wenn es dann geht, ist die Schnittstelle nicht im RAW Modus.
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; }
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.
@peter. das meiste davon waren Schritte der Verzweiflung und Unwissenheit. Leider ändert das nur nix am Sachverhalt der Funktionalität...
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
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
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...
@ 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....
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.