Hallo ans Netz,
ich stehe gerade etwas auf der Leitung.
Ich habe ein Gerät was sich mit AT Befehlen steuern lässt.
Dem schicke ich einen AT Befehl bis es mir mit "OK" antwortet. Das macht
es auch.
1
if(strstr((char*)usart1_buffer,"OK"))
2
{
3
HAL_GPIO_WritePin(LED_R_GPIO_Port,LED_R_Pin,RESET);//red LED ON
4
}
Beim zweiten Befehl frage ich das Gerät nach der Anzahl der
gespeicherten Datensätze. Das Gerät antwortet auch (ASCI):
1
usart1_buffer[0]=53
2
usart1_buffer[1]=50
3
usart1_buffer[2]=/r
Das Problem: Er sendet erst die erste Ziffer, dann die zweite. Aber eben
immer an eine Stelle des Arrays. "53" = 5, "50" = 2. Macht 52 Datensätze
(das passt auch, hab auf der SD Karte nachgeschaut). Wie kriege ich das
ganze in einen uint16, damit ich damit normal weiterrechnen kann? Ich
habe dafür keinen string Befehl gefunden (oder kann ihn nicht richtig
anwenden). Ich müsste ja alle Stellen im Array durchgehen bis "/r"
kommt. Die Zahl kann auch drei oder vierstellig sein.
Ich bin mir fast sicher das es da was brauchbares "von der Stange" gibt,
ich finde es nur nicht und komm nicht drauf.
Vielen Dank!
Was kommt den vor den Ziffern?
Du könntest, wenn ich dich richtig verstanden habe, das erste Auftreten
von '\r' im Array suchen, von da rückwärts gehen bis du etwas siehst,
was keine Ziffer ist. Ab da+1 dann strtoul() aufrufen.
Manni schrieb:> Nichts, der Befehl sendet direkt die erste Ziffer in buffer[0].
Dann hilft strtol() bzw. das schon genannte atoi().
Manni schrieb:> Ok, aber dann bekomme ich doch eine 5 und eine 2 raus.
Nein. Du bekommst eine Zahl zurück, nicht irgendwelche einzelnen
Ziffern.
Björn W. schrieb:> value = (buffer0-48)+(buffer1-48)
Komplett daneben. Davon abgesehen, dass es schlechter Stil ist,
"magische" Zahlen wie "48" zu schreiben, darfst du mal drüber
nachdenken, was aus deiner Rechnung heraus kommt … ganz davon abgesehen,
dass sie die Bedingung, dass es auch drei oder vier Ziffern sein können,
völlig ignoriert.
Jörg W. schrieb:> Dann hilft strtol() bzw. das schon genannte atoi().
OK, danke. Wenn ich das Beispiel von Steve nehme, dann klappt es. Dazu
kopiere ich halt den ganzen "buffer" in den string "str". Dann kommt bei
val = 52 raus. Passt erstmal soweit. Sollte ja auch mit 3 und 4 Stellen
klappen. Für bessere Vorschläge bin ich offen, funktional ist es erstmal
das was ich wollte. Danke!
Manni schrieb:> Dazu kopiere ich halt den ganzen "buffer" in den string "str".
Du musst da nichts kopieren. Du kannst strtol() direkt auf deinen Buffer
loslassen.
ps: Der Unterschied zwischen strtol() und atoi() ist, dass du bei der
erstgenannten Funktion noch eine Variable angeben kannst, in der du
erfährst, bis zu welcher Stelle der Parser gekommen ist. Das sollte bei
dir ja immer ein '\r' sein, ansonsten ist was foul.
atoi() ist äquivalent zu
Jörg W. schrieb:> (int)strtol(nptr, NULL, 10)
Das muss ich mal selbst probieren hier im Code um dafür ein Feeling zu
kriegen.
Vielen Dank für eure Hilfe!
Björn W. schrieb:> Jörg W. schrieb:>> Komplett daneben.>> ...war auch nur son Knaller aus der Hüfte>> Aber ist alles richtig was du bemängelst.
Nicht nur ein Knaller, sondern absolut falsch im Ergebnis ...
Manni schrieb:> Wie kriege ich das> ganze in einen uint16, damit ich damit normal weiterrechnen kann? Ich> habe dafür keinen string Befehl gefunden
Doch, den gibt es. Typisch nimmt man sscanf, um formatierte Eingaben in
Variablen zu speichern.
Und im Gegensatz zu atoi sagt Dir sscanf auch, wieviel Argumente es
lesen konnte, d.h. Du weißt, ob wirklich eine "0" empfangen wurde.
Das Internet ist voll von Erklärungen und Beispielen dazu, z.B.:
https://cplusplus.com/reference/cstdio/sscanf/
Peter D. schrieb:> Typisch nimmt man sscanf, um formatierte Eingaben in Variablen> zu speichern.
s/nimmt/nahm/ Inzwischen sagt die manual page zu sscanf
1
BUGS
2
Numeric conversion specifiers
3
Use of the numeric conversion specifiers produces Undefined
This is a bug in the ISO C standard, and not an inherent design
7
issue with the API. However, current implementations are not
8
safe from that bug, so it is not recommended to use them.
9
Instead, programs should use functions such as strtol(3) to
10
parse numeric input. This manual page deprecates use of the
11
numeric conversion specifiers until they are fixed by ISO C.
> Und im Gegensatz zu atoi sagt Dir sscanf auch, wieviel Argumente es> lesen konnte, d.h. Du weißt, ob wirklich eine "0" empfangen wurde.
strtol() sagt es noch genauer: einmal per *endptr und zusätzlich wird
overflow erkannt (errno == ERANGE). Ich würde vorschlagen, gewöhn' dich
gleich an strtol(), strtoul(), strtoll()...
Ich kann zwar jetzt kein C, aber von der Logik her ist das doch
einfach :
- die Größe des Array abfragen
- in einer Schleife bis zum vorletzten iterieren (letztes ist ja "\r")
- in einem String aneinanderpappen Basic: s = s + Chr$(Val(A[index]))
- nach der Schleife s in einen INT konvertieren (zahl = Val(s) )
- dann kannst du damit rechnen.
Müßte in C entsprechend gehen, egal wie groß das Array auch ist.
Heinz B. schrieb:> einfach :> - die Größe des Array abfragen> - in einer Schleife bis zum vorletzten iterieren (letztes ist ja "\r")
noch einfacher: bis zum ersten Zeichen, das keine gültige Ziffer ist.
Genau das gibt es mit strtol() gratis. Bonus: strtol() funktioniert mit
jeder Basis von 2 und 36, nicht nur dezimal und hex. Und erkennt
optional den Prefix 0 und 0x und demnächst auch 0b.
Bauform B. schrieb:> Use of the numeric conversion specifiers produces Undefined> Behavior for invalid input.
Keine Ahnung, wie sie auf diese schräge Interpretation kommen. UB
entsteht, wenn die Konvertierung nicht zum Typ des Arguments passt,
bspw. für %s ein Zeiger auf int geliefert wird. Das Verhalten für
fehlerhafte Eingaben ist sehr wohl definiert.
Ich würde trotzdem eher stro*l benutzen, wenn es nur um eine einzelne
Zahl geht.
All das wird durch einen typecast von strto*l nach (int) allerdings
genauso wenig behoben – und ist mit an Sicherheit grenzender
Wahrscheinlichkeit für das Thema des TEs völlig irrelevant.
Wenn man das wirklich vermeiden will, spielt es so gut wie keine Rolle,
ob man in scanf() einfach nur "long"-Formate benutzt (und entsprechende
Parameter natürlich), oder ob man das mit strto*l() macht – in jedem
Falle muss man die domain boundary checks hinterher durchführen, wenn
der Wertebereich kleiner als der von long sein soll.
Ich kann mich nicht erinnern, ob mir jemals eine nackte Zahl als Antwort
an den Kopf geschmissen wurde. Ich parse meistens mehrere Argumente
zusammen und das geht mit sscanf recht bequem. Bei Strings gebe ich auch
immer die Pufferlänge mit an, damit kein Überlauf möglich ist.
Peter D. schrieb:> Ich kann mich nicht erinnern, ob mir jemals eine nackte Zahl als Antwort> an den Kopf geschmissen wurde.
Naja, es geht hier ja nicht um menschliche Eingaben, sondern um eine
AT-Protokoll-Antwort. Selbst bei den alten Modems gab es da schon
genügend Befehle, die einem als Antwort einfach eine nackte Zahl
produziert haben.