【问题标题】:C Program not opening Serial on Arduino MegaC 程序未在 Arduino Mega 上打开 Serial
【发布时间】: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


【解决方案1】:

我已经修复了你的代码!

主要错误是:

Incorrect use of COM port number where a handle was required
Closing the port after sending data and before receiving response which flush input buffer
Almost no error check which prohibed to know what was wrong

在测试代码中,主循环不正确。没有数据发送,并且在收到“end”时中断循环是错误的。

我在打开端口后移动了一次 COM 端口参数化(也可以在 OpenPort 内部)。

您处理接收的方式与您定义的通信协议有关。我没有触及那部分。如果它是我的软件,我会将协议设计为面向行的协议,即发送和接收的每条消息都将以 CRLF 对终止的行的形式出现。然后可以循环接收,累积所有字符,直到找到行尾。

这里在固定源代码之后。还有很多rom需要增强。

测试代码:

#include "CSerialPort.h"
#include <stdio.h>     
#include <windows.h>
#include <stdlib.h>

bool SetComParameters(PORT comPort, int rate, int dataBits, int stopBits, int parity)
{
    if (!SetPortBaudRate(comPort, CP_BAUD_RATE_9600)) {
        fprintf(stderr, "Unable to set baudrate\n");
        return 0;
    }
    if (!SetPortDataBits(comPort, CP_DATA_BITS_8)) {
        fprintf(stderr, "Unable to set data bits\n");
        return 0;
    }

    if (!SetPortStopBits(comPort, CP_STOP_BITS_ONE)) {
        fprintf(stderr, "Unable to set stop bits\n");
        return 0;
    }
    if (!SetPortParity(comPort, CP_PARITY_NOPARITY)) {
        fprintf(stderr, "Unable to set parity\n");
        return 0;
    }
    return 1;
}

bool sendComms(char* msgSndPtr, PORT comPort)
{
    SendData(comPort, msgSndPtr);
    return 1;
}

bool receiveComms(char* msgRecPtr, PORT comPort)
{
    bool status = 0;
    strcpy(msgRecPtr, "");
    status = ReceiveData(comPort, msgRecPtr, 50);
    return status;
}

void main()
{
    char msgRec[50];
    char* msgRecPtr = msgRec;
    char msgSnd[50];
    char* msgSndPtr = msgSnd;
    int portNum = 1;
    PORT com_port = OpenPort(portNum);                            
    if (com_port == NULL) {
        fprintf(stderr, "Unable to open COM%d\n", portNum);
        return;
    }

    if (!SetComParameters(com_port, CP_BAUD_RATE_9600, CP_DATA_BITS_8, CP_STOP_BITS_ONE, CP_PARITY_NOPARITY)) {
        fprintf(stderr, "Error setting parameters\n");
        return;
    }

    do {   // FPiette use of do/while instead of while loop
        strcpy(msgSnd, "Hello\r\n");
        if (!sendComms(msgSndPtr, com_port)) {  
            fprintf(stderr, "sendComs failed\n");
            break;
        }
        printf("sent: %s\n", msgSndPtr);

        if (!receiveComms(msgRecPtr, com_port)) {
            fprintf(stderr, "receiveComms failed\n");
            break;
        }
        printf("received: %s\n", msgRecPtr);
    } while (strcmp("end", msgRecPtr));

    ClosePort(&com_port);

    printf("Done.\n");
}

CSerialPort.c:

#include <stdio.h>
#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)
{
    if (com_port && *com_port) {
        CloseHandle(*com_port);
        *com_port = NULL;
    }
}

int SetPortBaudRate(PORT com_port, int rate)
{
    DCB dcbSerialParams = { 0 };
    BOOL Status;
    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
    Status = GetCommState(com_port, &dcbSerialParams);
    if (Status == FALSE)
        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)
        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)
        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)
       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 ReceiveData(PORT com_port, char* data, int len)
{
    DWORD dwEventMask = 0;
    DWORD NoBytesRead = 0;
    BOOL Status = WaitCommEvent(com_port, &dwEventMask, NULL);
    if (Status == FALSE)
        return FALSE;
    Status = ReadFile(com_port, data, len, &NoBytesRead, NULL);
    if (Status == FALSE)
        return FALSE;
    data[NoBytesRead] = 0;
    return TRUE;
}

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

#define bool BOOL

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 ReceiveData(PORT com_port, char* databuffer, int bufferlen);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多