Arduinosteuerung über serielle Schnittstelle mit Batch-Datei

Hallo zusammen,

ich sitze vor folgenden Problem. Ich möchte bei meinem Arduino den Pin 3 ein- und ausschalten können. Ich habe hierfür ein passenden Arduino-Sketch geschrieben und eine passende Batch-datei. Wenn ich bei der Batch-Datei "EIN" auswähle sendet diese über die serielle Schnittstelle den Wert "1" an den Arduino und der Pin 3 wird aktiviert. Dies funktioniert auch problemlos bei "AUS" mit dem Wert "0". Jedes mal, wenn ich den Arduino von meinem Rechner abstecke und wieder anstecke muss ich in Arduino IDE die serielle Schnittstelle mit Hilfe des Serial Monitor neu herstellen. Da der Arduino an einem Rechner ohne Arduino IDE nur mit der Batch-Datei laufen soll und regelmäßig an- bzw. abgesteckt wird, bräuchte ich eine Lösung wie die serielle Schnittsstelle zwischen Batch-Datei und Arduino automatisch nach kruzer Zeit hergestellt wird.

Zur Info: Ich verwende hierfür einen Arduino Nano Every

Vielleicht kann mir ja einer von euch Profis bei diesem Problem weiterhelfen.

Viele Grüße,
Sebastian

Gib mal "serielle SST in Batch konfigurieren" in der Suchmaschine Deiner Wahl ein.
Da wirst Du Infos zu mode COMx finden.

Gruß Tommy

Du brauchst dafür:

  • die Schnittstelle
  • die Portparameter

was gibt der in der IDE unter WERKZEUGE - Boardinformationen holen als
VID:
PID:
aus?
Dann kann man das in ein Script packen.

@sebastian4321 Was steht in deiner Batch-Datei?

Probier ein Terminalprogramm aus.

Der Copilot sagt mir, dass man auf folgende Weise den Arduino-Port finden kann (wohl voraussetzend, dass nur genau einer am PC angeschlossen ist).

Win10 mit WMIC - ungetestet
@echo off
setlocal enabledelayedexpansion

:: Search for the Arduino COM port
for /f "tokens=2 delims==" %%A in ('wmic path Win32_SerialPort where "Description like '%%Arduino%%'" get DeviceID /value') do (
    set ArduinoPort=%%A
)

:: Check if the Arduino COM port was found
if defined ArduinoPort (
    echo Arduino found on port: %ArduinoPort%
    :: Add your commands to interact with the Arduino here
) else (
    echo Arduino not found. Please check the connection.
)

pause

Für Windows 11 spuckt er nur Python-Code aus. Der funktioniert, wenn man pyserial installiert hat (pip install pyserial). Die Angaben, die @my_xy_projekt in #3 abfragte, muss Du oben in dem Array noch ergänzen - wenn Dein Arduino noch nicht drinsteht.

Brauchst Du den Port auch im Rest des Batch-Files? Die Rückgabe ans System ist noch nicht drin.

Win 11 mit Python
# Python 3 code for detecting Arduino COM ports on Windows 11
# Requires: pip install pyserial

import serial.tools.list_ports

# Optional: Known Arduino Vendor IDs (VID) and Product IDs (PID)
ARDUINO_IDS = [
    ("0x2A03", "0x0043"),  # Arduino Uno
    ("0x2341", "0x0043"),  # Arduino Uno
    ("0x2341", "0x0010"),  # Arduino Mega 2560
    ("0x2341", "0x0243"),  # Arduino Nano
]

def detect_arduino_ports():
    arduino_ports = []
    ports = serial.tools.list_ports.comports()
    for port in ports:
        # Each port has attributes: device, vid, pid, description
        if port.vid is not None and port.pid is not None:
            # Compare VID/PID with common Arduino IDs
            for vid, pid in ARDUINO_IDS:
                if f"0x{port.vid:04X}" == vid and f"0x{port.pid:04X}" == pid:
                    arduino_ports.append(port.device)
        # Optional: Also filter by description containing "Arduino"
        elif "Arduino" in port.description:
            arduino_ports.append(port.device)
    return arduino_ports

# Usage example
if __name__ == "__main__":
    ports = detect_arduino_ports()
    if ports:
        print("Detected Arduino ports:", ports)
    else:
        print("No Arduino devices found.")
		

Ich weiss, wie das funktioniert.
Hab mal was für Dich.

In dem Thread 3 Posts weiter oben ist der link zum ursprungstread.

Mit Deiner Methode ist ein zweiter Arduino an einem beliebigen Port ein Störfeuer :laughing:

Die Boardinformationen bringen folgendes raus.
VID: 0x4321
PID: 0x0058

Wie kann ich das am besten ins Skript packen?

Ich überleg noch, wie ich Dir das baue.
Hat WIN 10/11 reg.exe an Board?
In der Commandozeile ausgeführt, sollte reg.exe wenigstens ne Hlfeseite ausgeben.
Dann muss ich mal sehen, ob ich Dir ein Script bauen kann.
Hab seit 2015 kein Windows mehr, das dauert also länger als 3 Zeilen Code :slight_smile:

// EDIT: Ich werd mir versuchen zu morgen einen Remote-Arbeitsplatz auf einer alten Windowsmaschine zu organisieren; Wenn das klappt, bau ich Dir das zusammen daa sich inhaltlich zwischen den Windowsversionen sich anscheinend nichts wesentliches geändert hat.

reg /?

REG Befehl [Parameterliste]

Befehl [ QUERY | ADD | DELETE | COPY |
SAVE | LOAD | UNLOAD | RESTORE |
COMPARE | EXPORT | IMPORT | FLAGS ]

Rückgabecode: (Mit Ausnahme von REG COMPARE)

0 - Erfolgreich
1 - Fehlgeschlagen

Geben Sie Folgendes ein, um die Hilfe für einen Befehl anzuzeigen:

REG Befehl /?

Beispiele:

REG QUERY /?
REG ADD /?
REG DELETE /?
REG COPY /?
REG SAVE /?
REG RESTORE /?
REG LOAD /?
REG UNLOAD /?
REG COMPARE /?
REG EXPORT /?
REG IMPORT /?
REG FLAGS /?

Zu welchem Teil brauchst Du Details?

Gruß Tommy

Ok, den gibt es noch. Dann geht das auch mit dem Batch-Script.

Meine ursprüngliche Idee ist

REM Laufende Nummer fuer Datensatz
set _num=0 
REM den gesamten Registryzweig ...
set "RegistryPath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB"
REM ... auslesen und zur Weiterverarbeitung jeden Eintrag uebergeben
for /F "delims=" %%I in ('reg.exe QUERY "%RegistryPath%"') do (
REM uebergibt den kompletten Registrypath mit VID/PID:
	call :getVendor "%%I"
)
// Der Code stammt aus einem alten Projekt - hatte ich die Tage erst in der Hand

und dann damit weiter arbeiten.

auf der Kommandozeile müsste:

reg.exe QUERY "RegistryPath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB"

den Inhalt ausgeben der dann gesplittet wird.
Passend zu PID/VID wird dann der COM-Port abgebildet.
Damit ist sichergestellt, dass zu PID/VID auch immer der richtige COM-Port gefunden wird. An die Baudrate kommt man dann via Mode.

Super danke für deine Bemühungen. Bin mal gespannt

Kannst Du mal bitte die folgende BATCH ausführen?
Wenn der Every dran ist, dann müsste der sich zum Schluß auf dem Bildschirm finden.

:START
@echo off
setlocal enabledelayedexpansion
cls
REM set locdir=c:\x
REM set configfile=cfg.cfg
REM // Prüfung ob cfg dort liegt
REM if not exist "!configfile!" (
REM 	Echo. Konfigurationsdatei "!locdir!\!configfile!" nicht gefunden. Abbruch!
REM 	goto bye
REM )

REM Laufende Nummer fuer Datensatz
set _num=0 
REM den gesamten Registryzweig ...
set "RegistryPath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB"
REM ... auslesen und zur Weiterverarbeitung jeden Eintrag uebergeben
for /F "delims=" %%I in ('reg.exe QUERY "%RegistryPath%"') do (
REM uebergibt den kompletten Registrypath mit VID/PID:
	call :getVendor "%%I"
)
goto :printBoard
REM ENDE Programm
goto :bye



:getVendor

@echo .
REM uebergibt Path mit ID/Seriennummer
for /F "delims=" %%I in ('reg.exe QUERY %1 ') do (
	call :setVar "%%I"
)
REM Ende getVendor
goto :bye

:setVar
REM holt die Angaben zum Namen des Boards
for /F  "tokens=1,2* delims= " %%A in ('reg.exe QUERY %1 /v FriendlyName 2^>NUL') do (
    set "_name=%%C" 
    REM holt die Angaben zum Port des Boards
    for /F "tokens=1,3*" %%D in ('reg.exe QUERY "%~1\Device Parameters" /v PortName 2^>NUL' ) do (
		set "_port=%%E"
		REM holt die VID/PID und Seriennummer/ID
		for /F "tokens=6,7 delims='\' " %%F in ("%~1") do (
			set _pid=%%F
			set _id=%%G
		)
	) 
)

if #%_port% NEQ # (
  goto checkPort  
)
REM Ende setVar
goto :bye

:checkPort
REM Test, ob das Board angeschlossen ist
mode %_port%: | findstr "%_port%:" >NULL
if %ERRORLEVEL% EQU 0 (
	REM baut Datensatz fuer aktive Boards
	set /a _num=%_num%+1
	set _device[!_num!].Name=!_name!
	set _device[!_num!].Pid=!_pid!
	set _device[!_num!].ID=!_id!
	set _device[!_num!].Port=!_port!
)
set _port=
set _name=
REM Ende checkPort
goto :bye
REM REGISTRY ENDE


:printBoard
if %_num% GTR 0 (
	Echo. Angeschlossene Board^(s^) gefunden:
	Echo.
	for /l %%i in (1,1,%_num%) do ( 
		Echo. %%i - !_device[%%i].Name! mit S/N !_device[%%i].ID! an Schnittstelle !_device[%%i].Port!:
		REM !_device[%%i].Pid!
	)
) else (
	Echo. KEIN angeschlossenes Board gefunden
)
Echo.
REM ENDE printBoard
goto :bye

:bye
PAUSE
endlocal

Es empfiehlt sich das in ein Verzeichnis "c:\x" als "x.bat" zu speichern und dann die Commandozeile aufzumchen, in das Verzeichnis zu springen und dort x aufzurufen.
Auch wenn ich am Ende eine Pause drin habe, hab ich keine Ahnung, ob das Fenster offen bleibt.

Versuche das auch ruhig mit mehreren Controllern gleichzeitig am Rechner. Alles was einen COM-Port hat, sollte sich in der Liste wiederfinden.

Tommy, sag mal da der TO sich nicht mehr meldet, weisst Du ob der every eine eigenständige Seriennummer (wie die originalen ARDUINO UNO/MEGA) hat?

Hat er, ist halt ein original Arduino.

Super.
Dann kann man über die SN arbeiten; Sonst hätte man bei 2 gleichen Boards evtl. manuell auswählen müssen.

Dann mach ichs mal fertig.

Da hier nichts mehr passiert, mach ich den Sack zu.
Es gibt einen Testsketch:

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.println(F("Start..."));
  Serial.write(0x1A);

  pinMode(LED_BUILTIN, OUTPUT);

}

void loop() {
  getSerialSwitch();
}

void getSerialSwitch()
{
  if (Serial.available())
  {
    char c = Serial.read();
    if (isPrintable(c))
    {
      switch (c)
      {
        case '0': digitalWrite(LED_BUILTIN, LOW); break;
        case '1': digitalWrite(LED_BUILTIN, HIGH); break;
      }
      Serial.print(F("DigitalPin "));
      Serial.print(LED_BUILTIN);
      Serial.print(F(" ist "));
      if (digitalRead(LED_BUILTIN))
        Serial.println(F("EIN"));
      else
        Serial.println(F("AUS"));
    }
    Serial.write(0x1A);
  }
}

Dazu die folgende Batch. Im oberen Teil ist klar, was definiert werden muss.

@ECHO off & setlocal enabledelayedexpansion
:START

::::::::::::::::::
:: DEINE DATEN  ::
::::::::::::::::::

SET MYVID=2A03
SET MYPID=0043
:: Wennn keine Seriennummer eingetragen, wird nur auf PID/VID geprüft
SET MYSER=

:: Daten der Schnittstelle
SET MYBAUD=115200
SET MYPARITY=n
SET MYDATA=8
SET MYSTOP=1

:: wenn nichts übergeben sende diesen Parameter (0 oder 1)
SET default=1

:: Reset des Controllers auslösen (wenn LEER == inaktiv)
SET reset=

:: Ergebnis vom Controller empfangen (wenn LEER == inaktiv # Achtung dauert etwas!)
SET receive=1


::::::::::::::::::::::::::::::::
:: AB HIER NICHTS MEHR ÄNDERN ::
::::::::::::::::::::::::::::::::

MODE con: cols=140 lines=80

:: Übergabeparameter merken
SET para=%1

:: War nicht 1
IF "!para!" NEQ "1" (

	:: War auch nicht 0
	IF "!para!" NEQ "0" (

		:: defaultwert setzen
		SET para=%default%
)	)

:: Das lesen der Registry dauert evtl.!
:: Jeder lesevorgang macht einen Punkt
SET _point=*

:: Laufende Nummer fuer Datensatz
SET _num=0 

:: den gesamten Registryzweig ...
SET "RegistryPath=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB"

:: ... auslesen und zur Weiterverarbeitung jeden Eintrag uebergeben
FOR /F "delims=" %%I in ('reg.exe QUERY "%RegistryPath%"') do (

	:: uebergibt den kompletten Registrypath mit VID/PID:
	CALL :getVendor "%%I"
)
CALL :printBoard
CALL :execute

:: ENDE Programm
endlocal
GOTO :bye


:getVendor
CLS
ECHO. Suche aktive Schnittstelle %_point%
SET _point=%_point%*

:: uebergibt Path mit ID/Seriennummer

FOR /F "delims=" %%I in ('reg.exe QUERY %1 ') do (
	CALL :setVar "%%I"
)

:: Ende getVendor
GOTO :EOF

:setVar
:: holt die Angaben zum Namen des Boards
FOR /F  "tokens=1,2* delims= " %%A in ('reg.exe QUERY %1 /v FriendlyName 2^>NUL') do (

	SET "_name=%%C" 

	:: holt die Angaben zum Port des Boards
	FOR /F "tokens=1,3*" %%D in ('reg.exe QUERY "%~1\Device Parameters" /v PortName 2^>NUL' ) do (
		SET "_port=%%E"
		:: holt die VID/PID und Seriennummer/ID
		FOR /F "tokens=6,7 delims='\' " %%F in ("%~1") do (
			SET _pidvid=%%F
			SET _id=%%G
)	)	) 

IF #%_port% NEQ # (
	GOTO checkPort 
)

:: Ende setVar
GOTO :EOF


:checkPort
:: Test, ob das Board angeschlossen ist
MODE %_port%: | findstr "%_port%:" >NULL

IF %ERRORLEVEL% EQU 0 (

	:: teilt pidvid auf
	FOR /F "tokens=2,4 delims='&_' " %%A in ("!_pidvid!") do (
		SET _pid=%%B
		SET _vid=%%A
	)

	:: baut Datensatz fuer aktive Boards
	SET /a _num=%_num%+1
	SET _device[!_num!].Name=!_name!
	SET _device[!_num!].Pid=!_pid!
	SET _device[!_num!].Vid=!_vid!
	SET _device[!_num!].ID=!_id!
	SET _device[!_num!].Port=!_port!

)
set _port=
set _name=
:: Ende checkPort
GOTO :EOF
:: REGISTRY ENDE


:printBoard
IF %_num% GTR 0 (
	ECHO. Aktive Schnittstelle^(n^) gefunden:
	ECHO. 
	FOR /l %%i in (1,1,%_num%) do ( 
		ECHO. %%i - !_device[%%i].Name! mit ID !_device[%%i].ID! an Schnittstelle !_device[%%i].Port!: # VID:!_device[%%i].vid! # PID:!_device[%%i].Pid!
	)
) ELSE (
	ECHO. KEIN angeschlossenes Board gefunden
)
ECHO.
:: ENDE printBoard
GOTO :EOF


:execute
:: zählt durch alle Elemente
FOR /l %%i in (1,1,!_num!) do ( 

	:: überprüft PID, VID, Seriennummer
	IF !_device[%%i].Pid! EQU !MYPID! (

		IF !_device[%%i].Vid! EQU !MYVID! (

			:: Wenn Seriennummer vorhanden
			IF DEFINED MYSER (

				:: Wenn Seriennummer übereinstimmt
				IF !_device[%%i].ID! EQU !MYSER! (
					SET prog=true
				)
			) ELSE (			
			
				:: Wenn keine Seriennummer vorgegeben
				SET prog=true
	)	)	)
	
	:: Wenn freigegeben
	IF DEFINED prog (
	
		:: wenn reset aktiv besonderer HINWEIS
		IF DEFINED reset (
	
			SET _dtr=ON
			SET receive=ON
			COLOR F4
			ECHO.  ACHTUNG: Controller wird resettet! Pin geht in default!

			) ELSE (

			:: reset verhindern
			SET _dtr=OFF
		)

		:: wenn alles passt dann loslegen
		MODE !_device[%%i].Port!: baud=!MYBAUD! parity=!MYPARITY! data=!MYDATA! stop=!MYSTOP! dtr=!_dtr! rts=OFF to=ON

	        :: sendet befehl
		ECHO. . !para! > !_device[%%i].Port!:

		:: wartet auf Antwort
		IF DEFINED receive (
		        TYPE !_device[%%i].Port!:
			ECHO.
)	)	)



GOTO :EOF
:bye
COLOR
Pause

Schliesslich sieht das dann so aus:


Die ID des UNO ist rausradiert :slight_smile:
Das Skript läuft vollständig automatisch.
Wenn eine 0 übergeben wird, wird eine 0 gesendet, wenn eine 1 übergeben wird, wird eine 1 gesendet.
Wenn nichts übergeben wird, kann im Skript festgelegt werden, wass passieren soll. - Aktuell sendet er eine 1.

HINWEIS: Die Quittung braucht sehr lange.