Hallo,
ich arbeite gerade an einer Kombination aus Pythonskript und
Mikrocontrollerprogrammierung in C bei der ich einen ARM Cortex-M3 vom
Typ ADuCM301 über UART ansteuern möchte.
In diesem Skript soll erstmal ein String, später mehrere Strings,
seriell an den µC gesendet werden. Hierzu verwende ich das Modul
PySerial (http://pyserial.sourceforge.net/) dessen Funktion
serial.Serial.write ich nutze um einen eingegeben Text seriell
weiterzuleiten. Das C-Programm welches ich auf den Controller geflasht
habe soll diesen Text nun verarbeiten und entsprechend Fälle abklären um
dann einen String zurückzuschicken.
Beispiel: Ich schicke den String: "Hallo" und möchte, dass er eine
Funktion ausführt wo dann "Hallo zurück" über UART gesendet wird und von
meinem Pythonskript ausgegeben.
Mit einzelnen Zeichen funktionierte das ganz gut, aber ich kriege das
irgendwie nicht hin, dass das auch mit einem String funktioniert. Ich
habe schon versucht die gesendeten Zeichen in einen Array zu schreiben
und jedesmal das Shift Register zu entleeren bis alle Zeichen durch
sind, aber ich kriege nur eine fehlerhafte Ausgabe.
Bin dankbar für jede Antwort.
Gruß
VH
VH schrieb:> ich arbeite gerade an einer Kombination aus Pythonskript und> Mikrocontrollerprogrammierung in C> Mit einzelnen Zeichen funktionierte das ganz gut, aber ich kriege das> irgendwie nicht hin, dass das auch mit einem String funktioniert. Ich> habe schon versucht die gesendeten Zeichen in einen Array zu schreiben> und jedesmal das Shift Register zu entleeren bis alle Zeichen durch> sind, aber ich kriege nur eine fehlerhafte Ausgabe.
Also, das Problem liegt eindeutig im C-Code ODER im Python-Code.
Genaueres können wir von hier aus nicht erkennen.
> Bin dankbar für jede Antwort.
Gerne
DioCfg(pADI_GP1,0x9);// port 1 configured for UART
10
11
printf("\nADuCM301 UART Program!\r\n");
12
13
while(1)
14
{
15
//Own Extensions
16
//scanf("%s %i %i", eingabe, &a, &b);
17
for(inti=0;eingabe[i]!='\n';i++){
18
eingabe[i]=pADI_UART->COMRX;
19
while((pADI_UART->COMLSR&(1<<6))==0);
20
}
21
printf("\nYour input was: %s\n",eingabe);
22
//uart_puts(eingabe);
23
if(eingabe=="12")
24
UART_test_function();
25
}
Der Controller nimmt meine seriellen Eingaben schon an, verarbeitet das
aber nicht wie gewünscht. Wenn ich "12" eingebe sollte eigentlich diese
UART_test_function ausgeführt werden, stattdessen bekomme ich aber was
kryptisches zurück:
1
Enter your commands below.
2
Insert 'exit' to leave
3
Send to UART: 12
4
>>B¿EðÀQñ
5
6
7
Send to UART: 12
8
>>
9
10
11
Send to UART: 12
12
>>Your input was: 444444444444444444444444444
13
14
15
Send to UART: 12
16
>>EêÁ!ɶñ
17
Ýcúöë@êB¿EðÀQñ
18
19
20
Send to UART: 12
21
>>
22
23
24
Send to UART: 12
25
>>Your input was: 444444444444444444444444444
26
27
28
Send to UART: 12
29
>>EêÁ!ɶñ
30
Ýcúöë@êB¿EðÀQñ
Hat das alles evtl. mit Laufzeitverzögerung zu tun? Anscheinend
speichert er mir die gesendeten Werte nicht wie gewünscht in meinen
Eingabepuffer hinein sondern kommt auf irgendwelche abstrusen Werte. Mit
einzelnen Zeichen hat das ganz gut funktioniert, aber mit der
Zeichenkette krieg ich es einfach nicht hin. Ich glaube, dass ich in der
Verarbeitung im C-Code irgendwas falsch mache, weiß aber nicht genau
was.
VH schrieb:> Auf dem Controller läuft folgendes Programm:> char eingabe[] = "";
Dieses Array hat eine Länge von 1.
Alle Strings die eine strlen größer als 0 haben, passen da nicht hinein.
Du wirst von Python gewohnt sein, dass du Strings einfach zuweisen
kannst und dann wird die String-Variable ohne dein Zutun größer. Nur: C
funktioniert nicht so.
> //Own Extensions> //scanf("%s %i %i", eingabe, &a, &b);> for(int i = 0; eingabe[i] != '\n'; i++){> eingabe[i] = pADI_UART->COMRX;> while((pADI_UART->COMLSR & (1 << 6))==0);> }
Man mag mich engstirnig nennen. Aber ist die logische Reihenfolge nicht
eigentlich:
zuerst darauf warten, dass ein Zeichen vorliegt
und erst dann dieses Zeichen abspeichern
> if(eingabe == "12")
No.
Strings können nicht so verglichen werden
> Hat das alles evtl. mit Laufzeitverzögerung zu tun?
Nein,
Es hat damit zu tun, dass du kein C Buch hast.
Während du dir eines besorgst, kannst du das wichtigste erst mal hier
nachlesen:
String-Verarbeitung in C
Ach, ich hab noch vergessen:
Bedenke, dass in C ein korrekter String mit einem '\0' Zeichen aufhört.
Von alleine kommt das aber nicht ans Stringende, wenn du den String
Zeichen um Zeichen aufbaust. Das muss schon dein Programm machen!
Zusätzlich zu Karl-Heinz Ausführungen:
-----------------------------
input([prompt])
Equivalent to eval(raw_input(prompt)).
Warning
This function is not safe from user errors! It expects a valid
Python expression as input; if the input is not syntactically valid, a
SyntaxError will be raised. Other exceptions may be raised if there is
an error during evaluation. (On the other hand, sometimes this is
exactly what you need when writing a quick script for expert use.)
If the readline module was loaded, then input() will use it to
provide elaborate line editing and history features.
Consider using the raw_input() function for general input from
users.
-----------------------------
Norbert schrieb:> Zusätzlich zu Karl-Heinz Ausführungen:>> -----------------------------> input([prompt])>> Equivalent to eval(raw_input(prompt)).>> Warning
So war das in Python 2. Vieles (wenn nicht alles) spricht aber dafür,
dass der Threaderöffner Python 3 verwendet.
Yalu X. schrieb:> So war das in Python 2. Vieles (wenn nicht alles) spricht aber dafür,> dass der Threaderöffner Python 3 verwendet.
Das interessiert mich jetzt.
Hier war die Vorgabe:
1
eingabe = input('Send to UART: ')
2
if eingabe == 'exit':
3
ser.close()
4
exit()
5
else:
6
ser.write(eingabe.encode('latin1'))
7
out = b''
8
time.sleep(1)
9
out = ser.readline()
10
if out != b'':
11
print(">>" + out.decode('latin1'))
Wie bzw. woran erkennt man die Python Version?
PS. b'' gilt nicht, denn es ist absolut korrekt auch in 2.6.6 ;-)
@ Karl Heinz Buchegger:
Danke für die konstruktive Hilfe und für den Tipp, der Link vor allem
war sehr hilfreich. Ich denke ich muss aber noch einen Weg finden den
String richtig zu verarbeiten, aber damit bin ich schon auf dem
entscheidenenden Weg.
@Norbert:
Ich nutze Python 3, da funktioniert raw_input() nicht mehr.
@SNR:
Ja, ich arbeite mit einer Baudrate von 9600. Das hat soweit auch alles
geklappt, folgendes Codeschnipsel verwende ich für die Initialisierung:
Ich hab das ganze jetzt noch ein wenig angepasst und folgende Funktion
geschrieben zum Auslesen eines gesendeten Bytes via UART:
1
int main (void)
2
{
3
char eingabe[255] = "12";
4
5
WdtGo(T3CON_ENABLE_DIS); // Disable Watchdog
6
DioCfg(pADI_GP4, 0x10); // Enable P4.2
7
DioOen(pADI_GP4, BIT2); // P4.2 as output
8
9
UrtLinCfg(0, 9600, COMLCR_WLS_8BITS, COMLCR_PEN_DIS); // UART Config, 8 Bit wordlength, no parity, 1 Stop Bit, Baudrate = 9600
10
DioCfg(pADI_GP1,0x9); // port 1 configured for UART
11
12
printf ( "\nADuCM301 UART Program!\r\n");
13
14
while(1)
15
{
16
uart_readline(eingabe);
17
printf("\nYour input was: %s\n", eingabe);
18
if(eingabe[0] == '1' && eingabe[1] == '2') //Call Testfunction if String is "12"
19
UART_test_function();
20
21
DioTgl(pADI_GP4,BIT2);
22
Delay();
23
}
24
}
25
26
void uart_readline(char* str){
27
char c;
28
unsigned int index = 0;
29
30
while (1){
31
while((pADI_UART->COMLSR & (1 << 6))==0);
32
c = pADI_UART->COMRX;
33
if (c != -1){
34
if (c == '\n'){ /* ASCII: NewLine */
35
str[index] = '\0';
36
return;
37
}
38
else{
39
str[index] = c;
40
index++;
41
}
42
}
43
}
44
}
Ich rufe das ganze in der main-Funktion auf indem ich als String die
Texteingabe an die Funktion sende. Diese soll dann schrittweise ein Byte
auslesen immer wenn COMTX/COMRX und das Shift Register leer ist.
Wenn die Funktion aufgerufen wird wird mein Array jedoch leider nicht
inkrementiert obwohl ich die Indexvariable hochzähle. Somit schreibt er
auch nichts relevantes in meinen Stringbuffer rein.
Woran kann das liegen?
VH schrieb:> Wenn die Funktion aufgerufen wird wird mein Array jedoch leider nicht> inkrementiert
Die Aussage ergibt keinen Sinn.
Ein Array kann sowieso nicht inkrementiert werden.
> obwohl ich die Indexvariable hochzähle.
Na, dann passt es doch. Zumindest der Teil.
> Somit schreibt er> auch nichts relevantes in meinen Stringbuffer rein.
Na, irgendwas muss er aber 'reinschreiben'. Was ist das? Wo kommt es her
und ist es dort vielleicht schon falsch?
Bist du sicher, dass dieser Teil hier
1
while((pADI_UART->COMLSR&(1<<6))==0);
2
c=pADI_UART->COMRX;
richtig ist? Wenn du dir danach das c ansiehst, steht da das korrekte
Zeichen drinnen? Es ist zb eine sehr sehr gute Idee, wenn du zu
Debug-Zwecken dieses c über die UART gleich mal zum Sender
zurückschickst. Auf einem Terminalprogramm muss dann das Zeichen
auftauchen. Du drückst die Taste 'A' und wenn dann auf dem ganzen Weg
zum µC und wieder zurück irgendwas unvorhergesehenes passiert, dann
taucht bei dir im Terminal dann eben kein 'A' auf sondern was anderes
(oder auch gar nichts). Sowas ist dann immer ein deutliches Indiz, dass
etwas nicht stimmt.
Hallo,
ich habe meinen Code nun soweit, dass ich diverse Daten sende und
empfange.
Den Code im Mikrocontroller habe ich mal ganz einfach durch eine
for-Schleife realisieren wollen um zu sehen ob überhaupt die Daten die
ich aus dem Skript hinaus schicke überhaupt ankommen:
1
2
while(1){
3
for(inti=0;eingabe[i]!='\n'&&i<10;i++){//Empfange String aus maximal 10 Zeichen
if(eingabe[0]=='1'&&eingabe[1]=='2')//Rufe Testfunktion auf wenn String "12" ist
10
UART_test_function();
11
else{
12
printf("Please try something else!");
13
}
14
15
DioTgl(pADI_GP4,BIT2);
16
Delay();
17
}
18
}
Mein Pythonskript sieht aktuell wie folgt aus:
1
import time
2
import sys
3
import serial
4
import codecs
5
6
#configure the serial connections (the parameters differs on time)
7
ser = serial.Serial(
8
port = 3,
9
baudrate = 9600,
10
)
11
12
#ser.open()
13
ser.isOpen()
14
15
print("Enter your commands below.\nInsert 'exit' to leave")
16
17
def write(s):
18
for c in s:
19
ser.write(c.encode('ascii'))
20
ser.flushInput()
21
time.sleep(0.01)
22
23
while 1:
24
#get keyboard input
25
eingabe = input('Send to UART: ')
26
if eingabe == 'exit':
27
ser.close()
28
exit()
29
else:
30
#send character to the device
31
write(eingabe)
32
out = b''
33
time.sleep(1)
34
ser.flush()
35
while ser.inWaiting() > 0:
36
# out += ser.read(1)
37
out = ser.readline()[:-2]
38
if out != b'':
39
print(">>" + out.decode('ascii'))
40
else:
41
print(">> could not read anything!")
42
ser.flushOutput()
Ich sende also durch eine eingabe einen String an den Controllerport und
je nachdem was der Controller damit macht möchte ich die richtige
Ausgabe haben. Jetzt ist es aber so, dass wenn ich beispielsweise die
Zeichen "12" sende, der Controller 10 mal die 2 empfängt auf Grund der
for-Schleife. Meine Eingabe lautet für ihn also "2222222222". Wenn ich
"12345" ist es 10 mal die 5 usw. also der Controller empfängt immer nur
das letzte Zeichen und nimmt dieses als endgültig für alle anderen
Zeichen an.
Eine typische Ein- und Ausgabe sieht wie folgt aus:
1
Enter your commands below.
2
Insert 'exit' to leave
3
Send to UART: 12
4
>>Please try something else!
5
Send to UART: 12
6
>>Your input was: 2222222222
7
Send to UART: 24
8
>>Please try something else!
9
Send to UART: 35
10
>>Please try something else!
11
Send to UART: 35
12
>>Please try something else!
13
Send to UART: 35
14
>>Please try something else!
15
Send to UART: 36
16
>>Your input was: 6666666666
17
Send to UART: 37
18
>>Your input was: 7777777777
19
Send to UART: 58
20
>>Please try something else!
Wie schaffe ich es, dass meine Strings richtig erkannt werden?
Mein Eingabestring stimmt soweit, wenn ich das in Python überprüfe,
anscheinend kann mein Controllerprogramm die Daten nur nicht richtig
empfangen.
Dein Controllerprogramm arbeitet mit uart_readline(eingabe). Aber dein
Pythonprogramm sendet keine "ASCII: NewLine" sondern nur einzelne
Zeichen aus dem String. Versuche mal in def write(s) nach der for
Schleife ein "ASCII: NewLine" zu senden, um den Strom von Zeichen
abzuschliessen.
Wieso verwendest du input (d.h. mit Auswertung der Eingabe durch
Python) statt raw_input zu benutzen?
Krapao schrieb:> Dein Controllerprogramm arbeitet mit uart_readline(eingabe). Aber dein>> Pythonprogramm sendet keine "ASCII: NewLine" sondern nur einzelne>> Zeichen aus dem String. Versuche mal in def write(s) nach der for>> Schleife ein "ASCII: NewLine" zu senden, um den Strom von Zeichen>> abzuschliessen.
Ok, wenn ich die Zeile
1
ser.write('\n'.encode('ascii'))
am Ende meiner write-Funktion im Pythonskript mit einfüge, so dass noch
ein NewLine als letztes Zeichen gesendet wird, landet mein Skript im
else-Zweig
1
print(">> could not read anything!")
weil anscheinend der Fall der gleiche bleibt, dass nur das letzte
eingegebene Zeichen vom Mikrocontrollerprogramm gelesen wird. Somit hab
ich keine Ausgabe.
> Wieso verwendest du input (d.h. mit Auswertung der Eingabe durch>> Python) statt raw_input zu benutzen?
Bei Python 3 funktioniert raw_input nicht mehr, da spuckt er mir ständig
den Fehler aus, dass es diese Funktion nicht gibt.
VH schrieb:>> Wieso verwendest du input (d.h. mit Auswertung der Eingabe durch>>>> Python) statt raw_input zu benutzen?>> Bei Python 3 funktioniert raw_input nicht mehr, da spuckt er mir ständig> den Fehler aus, dass es diese Funktion nicht gibt.
Da die Verwendung von input() etwas Verwirrung zu stiften scheint:
http://docs.python.org/py3k/whatsnew/3.0.html
"PEP 3111: raw_input() was renamed to input(). That is, the new
input() function reads a line from sys.stdin and returns it with the
trailing newline stripped. It raises EOFError if the input is
terminated prematurely. To get the old behavior of input(), use
eval(input())."
Sorry, bin noch mit Python 2 verbandelt.
@ VH
Ich an deiner Stelle würde µC Programm und Python Skript trennen. Es
bringt IMHO nix an zwei (vier!) Fronten zu kämpfen: Python-Send,
µC-Empfang, µC-Send und Python-Empfang.
Essentiell ist ein Mitschnitt aller Daten, die tatsächlich über die
serielle Leitung flitzen und die Zuordnung wer was macht. DAS kann man
mit einem "neutralen Beobachter", d.h. einem Terminalprogramm und ggf.
einem realen oder virtuellen Loopback herausfinden.
In beiden Codeschnippseln finde ich Sachen, die mir komisch vorkommen:
Im µC Code fehlt mir eine saubere, d.h. vollständige Initialisierung des
eingabe-Puffers sowie der saubere Nullbyte-Abschluss nach dem Empfangen.
Ohne ist es nicht verwunderlich, wenn Murks gesendet wird. Dann fehlt
mir die Funktion der µC Senderoutine - schickt die ein Newline mit (die
Pyhthonseite erwartet es) oder nicht?
Im Python-Code verwundern mich die Positionen flush-Routinen. Den
Eingangspuffer flushen nach jedem gesendeten Zeichen und den
Ausgangspuffer nach einer empfangenen Zeile? Und dass du bei einer
empfangenen Zeile zwei Zeichen am Ende abschnippelst ist OK? Passt das
zu der unbekannten µC-Sendefunktion?