【发布时间】:2023-03-21 15:20:01
【问题描述】:
我有一个 C 程序 (win32 api),它通过串行 (USB) 与我的 Arduino Mega 通信。
我可以通过 IDE 的串行监视器与 Arduino 正常通信。
如果我插入我的 Arduino 并运行 C 程序,端口似乎没有正确打开并且没有通信。 在这种情况下,如果我从 Arduino 的 IDE(或其他串行程序)打开串行监视器,然后再次关闭它,C 程序就可以正常工作了。
这是我来自 C 程序的端口代码(在本例中,它传递了 5,因为这是 Arduino 正在使用的端口):
CSerialPort.h:
#pragma once
#include <Windows.h>
#define CP_BAUD_RATE_1200 CBR_1200
#define CP_BAUD_RATE_9600 CBR_9600
#define CP_BAUD_RATE_1155 CBR_1155
#define CP_BAUD_RATE_4800 CBR_4800
#define CP_BAUD_RATE_19200 CBR_19200
#define CP_DATA_BITS_5 5
#define CP_DATA_BITS_6 6
#define CP_DATA_BITS_7 7
#define CP_DATA_BITS_8 8
#define CP_STOP_BITS_ONE ONESTOPBIT
#define CP_STOP_BITS_TWO TWOSTOPBITS
#define CP_STOP_BITS_ONE_AND_HALF ONE5STOPBITS
#define CP_PARITY_NOPARITY NOPARITY
#define CP_PARITY_ODD ODDPARITY
#define CP_PARITY_EVEN EVENPARITY
#define CP_PARITY_MARK MARKPARITY
#define CP_PARITY_SPACE SPACEPARITY
typedef HANDLE PORT;
PORT OpenPort(int idx);
void ClosePort(PORT com_port);
int SetPortBaudRate(PORT com_port, int rate);
int SetPortDataBits(PORT com_port, int databits);
int SetPortStopBits(PORT com_port, int stopbits);
int SetPortParity(PORT com_port, int parity);
int GetPortBaudRate(PORT com_port);
int GetPortDataBits(PORT com_port);
int GetPortStopBits(PORT com_port);
int GetPortParity(PORT com_port);
int SendData(PORT com_port,const char * data);
int ReciveData(PORT com_port, char * databuffer,int bufferlen);
CSerialPort.c
#include "CSerialPort.h"
#include <time.h>
PORT OpenPort(int idx)
{
HANDLE hComm;
TCHAR comname[100];
wsprintf(comname, TEXT("\\\\.\\COM%d"), idx);
hComm = CreateFile(comname, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
0, // No Sharing
NULL, // No Security
OPEN_EXISTING,// Open existing port only
0, // Non Overlapped I/O
NULL); // Null for Comm Devices
if (hComm == INVALID_HANDLE_VALUE)
return NULL;
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(hComm, &timeouts) == FALSE)
return NULL;
if (SetCommMask(hComm, EV_RXCHAR) == FALSE)
return NULL;
return hComm;
}
void ClosePort(PORT com_port)
{
CloseHandle(com_port);
}
int SetPortBaudRate(PORT com_port, int rate)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE BAUD STATE");
return FALSE;
dcbSerialParams.BaudRate = rate;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortDataBits(PORT com_port, int bits)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE DATABITS STATE");
return FALSE;
dcbSerialParams.ByteSize = bits;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortStopBits(PORT com_port, int bits)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE STOP STATE");
return FALSE;
dcbSerialParams.StopBits = bits;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int SetPortParity(PORT com_port, int parity)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
printf("FALSE PARITY STATE");
return FALSE;
dcbSerialParams.Parity = parity;
Status = SetCommState(com_port, &dcbSerialParams);
return Status;
}
int GetPortBaudRate(PORT com_port)
{
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.BaudRate;
}
int GetPortDataBits(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.ByteSize;
}
int GetPortStopBits(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.StopBits;
}
int GetPortParity(PORT com_port) {
DCB dcbSerialParams = { 0 };
BOOL Status;
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
Status = GetCommState(com_port, &dcbSerialParams);
if (Status == FALSE)
return -1;
return dcbSerialParams.Parity;
}
int SendData(PORT com_port, const char * data)
{
DWORD dNoOFBytestoWrite = strlen(data);
DWORD dNoOfBytesWritten;
BOOL Status = WriteFile(com_port,
data,
dNoOFBytestoWrite,
&dNoOfBytesWritten,
NULL);
if (Status == FALSE)
return -1;
return dNoOfBytesWritten;
}
int ReciveData(PORT com_port, char * data, int len)
{
DWORD dwEventMask;
DWORD NoBytesRead;
BOOL Status = WaitCommEvent(com_port, &dwEventMask, NULL);
if (Status == FALSE) {
return FALSE;
}
Status = ReadFile(com_port, data, len, &NoBytesRead, NULL);
data[NoBytesRead] = 0;
if (Status == FALSE) {
return FALSE;
}
return TRUE;
}
测试代码:
#include "CSerialPort.h"
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
bool sendComms(char * msgSndPtr, int portNum)
{
auto p1 = OpenPort(portNum);
SetPortBaudRate(p1, CP_BAUD_RATE_9600);
SetPortDataBits(p1, CP_DATA_BITS_8);
SetPortStopBits(p1, CP_STOP_BITS_ONE);
SetPortParity(p1, CP_PARITY_NOPARITY);
SendData(p1, msgSndPtr);
ClosePort(p1);
printf("%s sent.\n", msgSndPtr); //debug
//strcpy(msgSndPtr,"");
return 1;
}
bool receiveComms(char * msgRecPtr, int portNum)
{
bool status = 0;
strcpy(msgRecPtr,"");
SetPortBaudRate(portNum, CP_BAUD_RATE_9600);
SetPortDataBits(portNum, CP_DATA_BITS_8);
SetPortStopBits(portNum, CP_STOP_BITS_ONE);
SetPortParity(portNum, CP_PARITY_NOPARITY);
auto p1 = OpenPort(portNum);
status = ReciveData(p1, msgRecPtr, 50);
ClosePort(p1);
if (!status) //if nothing is received, cancel out and show error
{
return 0;
}
else
{
printf("%s received.\n", msgRecPtr); //debug
return 1;
}
}
void main()
{
char msgRec[50];
char * msgRecPtr = msgRec;
char msgSnd[50];
char * msgSndPtr = msgSnd;
while (!(strcmp("end",msgRecPtr)))
{
sendComms(msgSndPtr, 5);
receiveComms(msgRecPtr, 5);
printf("sent: %s\n, msgSndPtr);
printf("received: %s\n, msgRecPtr);
}
}
arduino 代码:
int i = 0;
void setup()
{
// Initiate Serial
Serial.begin(9600);
while (!Serial) ; // wait for serial port to connect. Needed for native USB
Serial.println("serial ready");
}
void loop()
{
Serial.println("testing comms");
i++
delay (150);
if (i == 10) {
Serial.println("end");
}
}
如果有人在使用 win32 时遇到过这个问题,或者知道串行监视器如何打开它的端口,那将非常有帮助。
编辑:澄清一下,一旦端口成功打开一次(由除我的 C 程序之外的任何程序),我的 C 程序就可以正常工作并且可以成功打开/关闭端口,直到下一次电源循环。
谢谢
【问题讨论】:
-
请在您的 Win32 程序中显示您设置波特率、位、奇偶校验、停止位和握手的代码。这些值应该与 Arduino 中的设置相匹配。
-
@fpiette 我在打开端口之前设置了波特率、位、停止位和奇偶校验。我将它们设置为 8N1,我认为这是 Arduino 的默认值。我已经编辑了问题以显示这一点。
-
我建议你尝试使用PuTTY,它是免费的并且可以通过串口进行通信。您可以轻松地使用串行 com 端口设置。然后,一旦您获得了正确的参数,就可以专注于您自己的 Win32 程序。要调试它,您可以使用两条背靠背的 USB/RS232 电缆(交叉电缆)。一个连接到您自己的程序,一个连接到 PuTTY。当它这样工作时,用 Arduino 替换 PuTTY。
-
我经常使用DockLight 来使用 PC 和 Arduino 开发我的 RS232 应用程序。就像我在上面的评论中建议的那样使用 PuTTY。
-
你确定这是给
GetCommState()的COM端口号,而不是句柄?
标签: c arduino serial-port