Seite 1 von 2

Serielle Schnittstelle auslesen...

Verfasst: 03.09.2014 11:33
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 03.09.2014 12:48
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 03.09.2014 14:12
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 03.09.2014 18:07
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. ;)

Re: Serielle Schnittstelle auslesen...

Verfasst: 03.09.2014 18:17
von ts-soft
@NicTheQuick

Ich denke mal, damit ist Cabriolöwe etwas überfordert :wink:

Re: Serielle Schnittstelle auslesen...

Verfasst: 04.09.2014 08:07
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 04.09.2014 10:40
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 04.09.2014 12:26
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 04.09.2014 14:40
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

Re: Serielle Schnittstelle auslesen...

Verfasst: 04.09.2014 15:06
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