Serielle Schnittstelle auslesen...

Anfängerfragen zum Programmieren mit PureBasic.
Cabriolöwe
Beiträge: 4
Registriert: 03.09.2014 11:01

Serielle Schnittstelle auslesen...

Beitrag von Cabriolöwe »

Hallo

Ich habe einen Atmel Mikrocontrollerboard via Serieller Schnittstelle mit dem PC verbunden um Meßdaten auszulesen.
Kommunikation Hardwaremäßig funktioniert einwandfrei.
Blos beim Auslesen der Daten habe ich Probleme.
Der Controller schickt die Meßwerte binär zu PC.

ReadSerialPortData(0, @Puffer, 1)
Wert.s = chr (Puffer)

Was muß ich ändern damit mir immer nicht nur das erste Zeichen angezeigt wird. Wenn ich in dem Read Befehl die Länge von 1 ändere wird das Zeichen nicht mehr korrekt angezeigt.

Gruß...Gerhard
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Serielle Schnittstelle auslesen...

Beitrag von ts-soft »

Hab zwar keine serielle Schnittstelle :mrgreen: , aber so in etwa sollte es Funktionieren:

Code: Alles auswählen

EnableExplicit

; ...
; ...

Define *Puffer, anzahl, Wert.s

*Puffer = AllocateMemory(1000)
anzahl = ReadSerialPortData(0, *Puffer, 1000)
Wert = PeekS(*Puffer, anzahl, #PB_Ascii)
Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
SBond
Beiträge: 266
Registriert: 22.05.2013 20:35

Re: Serielle Schnittstelle auslesen...

Beitrag von SBond »

ich sende oft Daten von meinem Arduino an meine PureBasic-Anwendungen. Daher bin ich mit dem seriellen Datenaustausch (COM-Anschluss) in Purebasic vertraut. So wie ich es interpretiere, willst du einen String empfangen und zusammensetzten. Ist das Richtig? Was hast du denn genau vor?


viele Grüße,
SBond
41 6c 73 6f 20 77 65 6e 6e 20 64 75 20 73 6f 20 76 69 65 6c 20 4c 61 6e 67 65 77 65 69 6c 65 20 68 61 73 74 2c 20 64 61 6e 6e 20 6b 61 6e 6e 73 74 20 64 75 20 61 75 63 68 20 67 6c 65 69 63 68 20 7a 75 20 6d 69 72 20 6b 6f 6d 6d 65 6e 20 75 6e 64 20 61 62 77 61 73 63 68 65 6e 2e

:D
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Serielle Schnittstelle auslesen...

Beitrag von NicTheQuick »

Ich habe für meine Mikrocontroller-Projekte dafür ein Interface gebaut für die serielle Kommunikation. Das sieht so aus:

Code: Alles auswählen

Interface Serial
	open.i(device.s, baudrate.i, parity.i = #PB_SerialPort_NoParity, dataBits.i = 8, stopBit.i = 1, handShake.i = #PB_SerialPort_NoHandshake)
	close.i()
	sendData(*buffer, length.i)
	sendChar(char.a)
	sendFloat(float.f)
	receiveData(*buffer, length.i)
	receiveChar.a()
	receiveLong.l()
	sendUnicode(unicode.u)
	receiveUnicode.u()
	receiveFloat.f()
	sendString(string.s) ; Sendet den String ohne Nullbyte am Schluss
	receiveString.s(length.i = -1, eol.c = 0)
	availableData.i()
	waitFor.i(*buffer, length.i)
	isOpen.i()
	lock()
	unlock()
	tryLock.i()
	free()
	bps.f()
	availableOutput.i()
EndInterface

Structure SerialS
	vTable.i
	
	device.s
	baudrate.i
	handle.i
	hMutex.i
	lastTime.i
	bytesSent.i
EndStructure

Procedure.i Serial_new()
	Protected *this.SerialS
	
	*this = AllocateMemory(SizeOf(SerialS))
	If Not *this : ProcedureReturn #False : EndIf
	
	*this\vTable = ?vTable_Serial
	*this\hMutex = CreateMutex()
	*this\bytesSent = 0
	
	ProcedureReturn *this
EndProcedure

Procedure.i Serial_open(*this.SerialS, device.s, baudrate.i, parity.i = #PB_SerialPort_NoParity, dataBits.i = 8, stopBit.i = 1, handShake.i = #PB_SerialPort_NoHandshake)
	If IsSerialPort(*this\handle)
		CloseSerialPort(*this\handle)
	EndIf
	
	*this\handle = OpenSerialPort(#PB_Any, device, baudrate, parity, dataBits, stopBit, handShake, 4096, 4096)
	If Not *this\handle : ProcedureReturn #False : EndIf
	
	*this\device = device
	*this\baudrate = baudrate
	
	ProcedureReturn #True
EndProcedure

OpenSerialPort(#PB_Any, "/dev/rfcomm0", 9600, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 4096, 4096)

Procedure Serial_close(*this.SerialS)
	If IsSerialPort(*this\handle)
		CloseSerialPort(*this\handle)
	EndIf
EndProcedure

Procedure Serial_sendData(*this.SerialS, *buffer, length.i)
	Protected pos.i = 0
	
	If IsSerialPort(*this\handle)
		While pos < length
			pos + WriteSerialPortData(*this\handle, *buffer + pos, length - pos)
		Wend
		*this\bytesSent + length
	EndIf
EndProcedure

Procedure Serial_sendChar(*this.SerialS, char.a)
	Protected pos.i = 0
	
	If IsSerialPort(*this\handle)
		While pos < 1
			pos + WriteSerialPortData(*this\handle, @char, 1)
		Wend
		*this\bytesSent + 1
	EndIf
EndProcedure

Procedure Serial_sendFloat(*this.Serial, float.f)
	*this\sendData(@float, SizeOf(Float))
EndProcedure

Procedure Serial_receiveData(*this.SerialS, *buffer, length.i)
	Protected pos.i = 0
	
	If IsSerialPort(*this\handle)
		While pos < length
			pos + ReadSerialPortData(*this\handle, *buffer + pos, length - pos)
		Wend
		
		ProcedureReturn length
	EndIf
	
	ProcedureReturn #False
EndProcedure

Macro Serial_receiveTYPE(__name, __t, __s, __return)
	Procedure.__s Serial_receive#__name(*this.Serial)
		Protected result.__s
		
		If (*this\receiveData(@result, SizeOf(__t)))
			ProcedureReturn result
		EndIf
		
		ProcedureReturn __return
	EndProcedure
EndMacro

Serial_receiveTYPE(Char, Character, c, 0)

Serial_receiveTYPE(Long, Long, l, 0)

Serial_receiveTYPE(Unicode, Unicode, u, 0)

Serial_receiveTYPE(Float, Float, f, 0.0)

Procedure Serial_sendUnicode(*this.SerialS, unicode.u)
	Protected pos.i = 0
	
	If IsSerialPort(*this\handle)
		While pos < 2
			pos + WriteSerialPortData(*this\handle, @unicode + 1 - pos, 2 - pos)
		Wend
		*this\bytesSent + 2
	EndIf
EndProcedure

Procedure Serial_sendString(*this.SerialS, string.s)
	Protected pos.i, length.i = Len(string)
	
	If IsSerialPort(*this\handle)
		While pos < length
			pos + WriteSerialPortData(*this\handle, @string + pos, length - pos)
		Wend
		*this\bytesSent + length
	EndIf
EndProcedure

Procedure.s Serial_receiveString(*this.SerialS, length.i = -1, eol.c = 0)
	Protected pos.i = 0, *mem, result.s = "", c.a
	
	If IsSerialPort(*this\handle)
		If length = 0 : ProcedureReturn "" : EndIf
		
		While length
			While Not ReadSerialPortData(*this\handle, @c, 1) : Wend
			If (Not c) Or (c = eol) : Break : EndIf
			result + Chr(c)
			length - 1
		Wend
	EndIf
	ProcedureReturn result
EndProcedure

Procedure.i Serial_availableData(*this.SerialS)
	If IsSerialPort(*this\handle)
		ProcedureReturn AvailableSerialPortInput(*this\handle)
	EndIf
	ProcedureReturn 0
EndProcedure

Procedure.i Serial_waitFor(*this.SerialS, *buffer.Ascii, length.i)
	Protected try.i = 0
	If IsSerialPort(*this\handle)
		Protected i.i = 0, Dim copyBuffer.a(length - 1), j.i = 0, full.i = 1
		Repeat
			While Not ReadSerialPortData(*this\handle, @copyBuffer(j), 1) : Wend
			j = (j + 1) % length
			If (full < length)
				full + 1
			Else
				For i = 0 To length - 1
					If (*buffer\a <> copyBuffer((j + i) % length))
						*buffer - i
						try + 1
						Break
					EndIf
					*buffer + 1
				Next
				If (i = length)
					Break
				EndIf
			EndIf
		ForEver
	EndIf
	ProcedureReturn #True
EndProcedure

Procedure.i Serial_isOpen(*this.SerialS)
	ProcedureReturn IsSerialPort(*this\handle)
EndProcedure

Procedure Serial_lock(*this.SerialS)
	LockMutex(*this\hMutex)
EndProcedure

Procedure Serial_unlock(*this.SerialS)
	UnlockMutex(*this\hMutex)
EndProcedure

Procedure.i Serial_tryLock(*this.SerialS)
	ProcedureReturn TryLockMutex(*this\hMutex)
EndProcedure

Procedure Serial_free(*this.SerialS)
	FreeMutex(*this\hMutex)
	FreeMemory(*this)
EndProcedure

Procedure.f Serial_bps(*this.SerialS)
	Protected newTime.i = ElapsedMilliseconds()
	Protected bps.f = *this\bytesSent / ((newTime - *this\lastTime) / 1000.0)
	*this\lastTime = newTime
	*this\bytesSent = 0
	ProcedureReturn bps
EndProcedure

Procedure.i Serial_availableOutput(*this.SerialS)
	If IsSerialPort(*this\handle)
		ProcedureReturn AvailableSerialPortOutput(*this\handle)
	EndIf
	ProcedureReturn -1
EndProcedure

DataSection
	vTable_Serial:
	Data.i @Serial_open(), @Serial_close(), @Serial_sendData(), @Serial_sendChar(), @Serial_sendFloat()
	Data.i @Serial_receiveData(), @Serial_receiveChar(), @Serial_receiveLong()
	Data.i @Serial_sendUnicode(), @Serial_receiveUniCode()
	Data.i @Serial_receiveFloat()
	Data.i @Serial_sendString(), @Serial_receiveString(), @Serial_availableData(), @Serial_waitFor()
	Data.i @Serial_isOpen(), @Serial_lock(), @Serial_unlock(), @Serial_tryLock(), @Serial_free()
	Data.i @Serial_bps(), @Serial_availableOutput()
EndDataSection
Wenn ich mal mehr Zeit finde, kommentiere ich es noch ausführlicher und stelle es in "Codes, Tipps & Tricks" ein. Außerdem wäre wohl eine Kapselung in ein Modul auch noch etwas schöner. ;)
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Serielle Schnittstelle auslesen...

Beitrag von ts-soft »

@NicTheQuick

Ich denke mal, damit ist Cabriolöwe etwas überfordert :wink:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Cabriolöwe
Beiträge: 4
Registriert: 03.09.2014 11:01

Re: Serielle Schnittstelle auslesen...

Beitrag von Cabriolöwe »

Hallo..

Etwas überfordert ist gelinde gesagt maßlos untertrieben :D
Ich Programmiere die Microcontroller mit Bascom.
Bascom sendet die Werte mit dem Print Befehl binär über die Serielle Schnittstelle.
Ich habe jetzt eine Lösung gefunden wie es funktioniert, ob es die Beste ist, kann ich nicht beurteilen.

Ich lese die Werte Zahl für Zahl binär mit Purebasic wandle sie dann mit chr und füge sie zu einem String zusammen.

readserialportdata(0, @puffer, 1)
readserialportdata(0, @puffer1, 1)
Wert.s = Chr (puffer) + Chr (puffer1)

Wie ich mehrere Zeichen auf einmal auslesen kann das habe ich noch nicht hinbekommen.
Sobald ich die Länge 1 ändere auf 2 oder 3 kann ich nicht nachvollziehen was in den Puffer geschrieben wird.
Aber ich bin was Purebasic betriffe ein absoluter Anfänger.

Gruß..Gerhard
SBond
Beiträge: 266
Registriert: 22.05.2013 20:35

Re: Serielle Schnittstelle auslesen...

Beitrag von SBond »

hallo Cabriolöwe,

Zeichen für Zeichen zusammensetzten würde ich es nicht. Da du den Print-Befehl verwendest kommt das ganze in Text-Format an, was das ganze sogar noch vereinfacht. :)
Am besten liest man die ganzen vorhandenen Daten aus dem COM-Puffer und parst die Daten. Dann vermeidest du auch mögliche Pufferüberläufe (bei Windows passiert es bei ca. 12,5 KB Daten)

Ich könnte dir heute abend dazu etwas geben. Ich müsste nur wissen, auf welchem System das ganze laufen soll (Windows?) und wie so ein Datenstrom aussieht. Sind die Messwerte gleich lang oder durch ein Zeichen getrennt? Bei einen Print-Befehl wird ja oft ein CRLF mitgesendet....
sehen deine Daten in etwa so aus?:

123
532
334
552
632

oder so 412;1345;452;742;... ?

viele Grüße,
SBond
41 6c 73 6f 20 77 65 6e 6e 20 64 75 20 73 6f 20 76 69 65 6c 20 4c 61 6e 67 65 77 65 69 6c 65 20 68 61 73 74 2c 20 64 61 6e 6e 20 6b 61 6e 6e 73 74 20 64 75 20 61 75 63 68 20 67 6c 65 69 63 68 20 7a 75 20 6d 69 72 20 6b 6f 6d 6d 65 6e 20 75 6e 64 20 61 62 77 61 73 63 68 65 6e 2e

:D
Cabriolöwe
Beiträge: 4
Registriert: 03.09.2014 11:01

Re: Serielle Schnittstelle auslesen...

Beitrag von Cabriolöwe »

Hallo SBond

Nein, ich schicke ausschließlich die Messwerte rüber...ohne Zeilenumbruch etc.

readserialportdata(0, @puffer, 1)

welches Datenformat müßte ich den verwenden um @Puffer und die Datenlänge korrekt verwenden kann.
Mit Ascii funktioniert es auch nicht, das habe ich schon ausprobiert.


Danke schon mal....Gruß....Gerhard
SBond
Beiträge: 266
Registriert: 22.05.2013 20:35

Re: Serielle Schnittstelle auslesen...

Beitrag von SBond »

Sind deine Messwerte immer ein Byte groß?
bzw. wie erkenne ich, dass ein Messwert komplett ist?

z.B. erhalte ich die Daten:26826773. Dann könnten die Werte folgende sein: 26, 82, 67, 73 oder 2682, 6773. Natürlich unter der Bedingung, dass die Zahlen als ASCII-Text interpretiert werden.

Hast du mal ein Beispiel, wie die Ausgabe von deinem Mikrocontroller aussieht?

viele Grüße,
SBond
41 6c 73 6f 20 77 65 6e 6e 20 64 75 20 73 6f 20 76 69 65 6c 20 4c 61 6e 67 65 77 65 69 6c 65 20 68 61 73 74 2c 20 64 61 6e 6e 20 6b 61 6e 6e 73 74 20 64 75 20 61 75 63 68 20 67 6c 65 69 63 68 20 7a 75 20 6d 69 72 20 6b 6f 6d 6d 65 6e 20 75 6e 64 20 61 62 77 61 73 63 68 65 6e 2e

:D
Cabriolöwe
Beiträge: 4
Registriert: 03.09.2014 11:01

Re: Serielle Schnittstelle auslesen...

Beitrag von Cabriolöwe »

Hallo S.Bond

Ich schicke mit dem Print Befehl z..b 12.00 rüber für 12.00V



mit

VorhandeneByte = availableserialportinput(0)

will ich diese anzahl überprüfen und sie dann auslesen. Wenn diese Daten ausgelesen sind will ich
dann mit writeserialportdata neue Daten anfordern.
mein "Problem" ist eigentlich nur wie ich die 5 Byte auf einmal aus dem Puffer auslesen kann und darstellen.

Gruß...Gerhard
Antworten