没有与连接的串行端口通信?

Posted

技术标签:

【中文标题】没有与连接的串行端口通信?【英文标题】:No communication to a connected serial port? 【发布时间】:2019-01-14 10:37:20 【问题描述】:

我正在尝试连接到通过我的基于 Linux 的 PC 中的 USB 串行端口连接的 Arduino Mega 2560 单元。

使用 C 代码,我正在尝试发送和接收简单的文本字符串,只是我能够在双方发送和接收。

在 Arduino 上:

int incomingByte = 0;    // for incoming serial data

void setup() 
    Serial.begin(19200);    // opens serial port, sets data rate to 9600 bps


void loop() 
  // send data only when you receive data:
  if (Serial.available() > 0) 

    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print((char)incomingByte);
  


基本上只是一个检查是否有串行数据的循环,如果有,则读取并打印回来。有一个 (char) 转换,所以我会立即看到发送的数据就是我返回的数据(Linux 端)

对于 Linux 代码,我使用相当标准的代码来打开我发现的端口 here

我将 Arduino 称为​​“Table”,因为它最终会通过 USB 命令操作移动的桌子。

C 文件:

#include "TableFunctions.h"

bool connected=false;
int fd;
char *portname;


int set_interface_attribs (int fd, int speed, int parity)

        connected=false;
        struct termios tty;
        struct termios tty_old;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        
                printf("PC: Error %d from tcgetattr  \n", errno);
                return -1;
        
        tty_old = tty;

        cfsetospeed (&tty, (speed_t)B19200);
        cfsetispeed (&tty, (speed_t)B19200);

        //tty.c_cflag |= B19200;
        tty.c_cflag     &=  ~PARENB;            // Make 8n1
        tty.c_cflag     &=  ~CSTOPB;
        tty.c_cflag     &=  ~CSIZE;
        tty.c_cflag     |=  CS8;

        tty.c_cflag     &=  ~CRTSCTS;           // no flow control
        tty.c_cc[VMIN]   =  1;                  // read doesn't block
        tty.c_cc[VTIME]  =  5;                  // 
        tty.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
        cfmakeraw(&tty);
        tcflush( fd, TCIFLUSH );

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        
                printf("PC: Error %d from tcsetattr  \n", errno);
                return -1;
        
        return 0;


void set_blocking(int fd, int should_block)

        struct termios tty;
        memset(&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        
                printf("PC: Error %d from tggetattr  \n", errno);
                return;
        

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = 10;            // 0.5 seconds read timeout

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
                printf("PC: Error %d setting term attributes  \n", errno);



void OpenSerialPort()

    char *portname = "/dev/ttyACM0";

    printf("PC: Opening port to table \n");

    int fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);

    usleep(2000000);
    if (fd < 0)
    
        printf("PC: Error %d opening %s: %s  \n", errno, portname, strerror(errno));
        return;
    

    set_interface_attribs(fd, B19200, 0);  // set speed to 19,200 bps, 8n1 (no parity)
    set_blocking(fd, 0);                // set no blocking
    printf("PC: Connected\n");
    connected = true;

void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands])

    if(connected) //check if arduino still connected
    
        for(int i = 0; i<numberOfCommands; i++) //go through commands 
        
            int bufferSize = strlen(commands[i]); //get the buffer size needed for this command
            char charArray[bufferSize]; //helper char array
            memcpy(charArray,commands[i],bufferSize);//copy command to the char array
            charArray[bufferSize]=0; //make sure there is a stop symbok at the end
            WriteSerialPort(charArray); //command is ready to be sent, send it.
        
    

int WriteSerialPort(const char *buffer)

    printf("PC: Now writing: ");
    int n_written = 0; //how many bytes were written

    n_written = write(fd, buffer, strlen(buffer)); //write the command and return how many bytes were written

    printf("\n");

    //check bytes send and return ouput (error, nothing or x bytes sent)
    if(n_written<0)
    
        printf("PC: Error %d from %s \n",errno, strerror(errno));
    
    else if(n_written == 0)
    
        printf("PC: Nothing was written  \n");
    
    else
    
        printf("PC: Written %i bytes  \n", n_written);
    



int ReadSerialPort(char *buffer, unsigned int buff_size)

    //check if arduino still connected
    if(connected)
    
        //read the serial data
        if(read(fd,buffer,buff_size))
            return sizeof(buffer); //return how much bytes were read
        else
        
            //else print nothing received
            printf("PC: Arduino not Connected (ReadSerialPort) \n");
        
    

OpenSerialPort我基本上是打开一个新的fd,然后调用设置通讯设置的函数。

我使用PrepareWriteCommand 确保用户输入的命令带有停止符号,并将它们发送到WriteSerialPort,我使用write() 并打印发送了多少字节。

H 文件:

#include <errno.h>
#include <fcntl.h> 
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>


#define MAX_DATA_LENGTH 256

int set_interface_attribs (int fd, int speed, int parity);
void set_blocking(int fd, int should_block);
void OpenSerialPort();
void PrepareWriteCommand(int numberOfCommands, const char *commands[numberOfCommands]);
int WriteSerialPort(const char *buffer);
int ReadSerialPort(char *buffer, unsigned int buff_size);

主要:

    #include "TableFunctions.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
    
        char output[MAX_DATA_LENGTH]; //char array to hold arduino output
        int received = 0; // check if read() got any bytes
        const char* commands[]="test"; //test command

        OpenSerialPort(); // open serial port

        PrepareWriteCommand((sizeof(commands)/sizeof(commands[1])),commands); //prepare command for sending

        usleep(500000); //wait for arduino response

        while(true)

    received = ReadSerialPort(output,MAX_DATA_LENGTH);//check serial port for response
    switch(received)
    
        case -1:
        
            printf("PC: Error %d from %s \n",errno, strerror(errno));
            break;
        
        case 0:
        
            printf("PC: Nothing received\n");
            usleep(500000);
            break;
        
        default:
        
             printf("PC: received %i\n",received); //if yes, how many bytes
            printf("PC: %s\n",output); //and what was received
            usleep(500000);
        
    

return 0; //finish program

我尝试调整 TTY 标志设置,但没有成功。每次我运行 C 代码时,我都会看到 Arduino 重置(在打开新的 fd 后,我给它一些引导加载时间)但两者之间没有通信。

输出:

PC: Opening port to table 
PC: Connected
testPC: Now writing: 
PC: Written 4 bytes  

PC: received 0
PC: 

对于理解 C 代码为何无法与 Arduino 通信的任何帮助,我们将不胜感激!

【问题讨论】:

您的 received 变量永远不会被分配。此外,您没有正确检查 read() 的返回值:它是读取的字节数或 -1 如果错误。而sizeof(buffer) 将返回指针的大小,而不是数组的大小或读取的字节数。 @rodrigo 谢谢,从未注意到收到未分配。现在 linux 的输入是: PC:收到 8 PC:所以 PC 得到 8 个字节(但发送 4,也许 arduino 设法发送数据两次),但什么也不打印。只是为了确保 read() 将读取的数据放入其参数中的缓冲区,对吗?关于 sizeof - 我看了看,似乎没有什么简单的事情要做:***.com/questions/492384/… 傻我,8个字节是指针的大小,不是吗? 是的,sizeof(pointer) 在 64 位系统中将是 8。 read 将读取的数据放入作为参数传递的数组中,并返回实际读取的字节数。第二个参数是缓冲区的大小,即读取的最大字节数。 【参考方案1】:

问题出在OpenSerialPort()。我设置了另一个变量fd,它是本地的,因此具有优先权。然后当OpenSerialPort() 完成时,它被删除,并且全局fd 保持未设置。这就是为什么我无法从 PC 发送任何内容或向 PC 发送任何内容。

谢谢。

【讨论】:

以上是关于没有与连接的串行端口通信?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Qt 的 C++ 中的线程串行端口通信

如何自动检测串行 COM 端口 c# 的连接

以编程方式与 OS X 或 Linux 中的串行端口通信

重启后Pyserial的串行连接问题

使用 C# 通过“USB 虚拟串行端口”与 USB 设备通信?

从客户端 Web 浏览器与串行端口通信。