我正在创建一个类,用于嵌入式系统和在Linux环境中运行的C ++应用程序之间的串行通信。因此,我使用了适用于Linux的termios API,其描述为here。
构造函数将打开设备的串行端口。在我的情况下,这是我使用的arduino微控制器的“ ttyUSB0”。接下来,它将设置波特率和其他端口选项。
我还添加了用于在串行端口上读取或写入数据的功能。因为read是一个阻塞函数(直到收到数据或超时才返回),所以我添加了一个函数来检查是否有可用的字节,在调用“ Read()”之前可以这样做。
制作完测试用例后,阅读似乎可以正常工作。实际上,函数“ Available()”确实返回了可用的字节数。阅读它们后将它们打印到控制台。
但是,由于某些未知原因,即使我“相信”我正确地遵循了指南中的步骤,我的写入功能也无法正常工作。我为写功能创建了一个测试用例:arduino收到正确的消息后应闪烁其内置的led。一条消息以开始标记“#”开始并以结束标记“ $”结束时是正确的。
当我使用腻子测试工具或arduino的串行监视器发送正确的消息时,指示灯将闪烁。但是,当我通过自己的write函数发送消息时,不会发生这种情况。
arduino具有其他内置的LED,用于指示RX和TX引脚上的数据。一旦我从自己的写入功能发送数据,这些指示灯实际上就会亮起,但是从不调用测试用例中的闪烁功能。然后,我检查了是否读取了所有字节,但是当从我自己的写入函数发送数据时,arduino的“ Serial.available()”从不返回大于0的值。
我认为该错误可能在写函数本身或在串行端口的配置中。到目前为止,我还没弄清楚。是否有人对此有任何经验或知识,或者对我应该如何解决此问题有任何提示?
预先感谢
德克
Linux代码:
main.cpp
#include "serial.h"
#include <iostream>
using namespace std;
int main()
{
//TEST CASE FOR WRITING DATA
Serial serial("/dev/ttyUSB0");
serial.Write("#TEST$");
//TEST CASE FOR READING DATA
/*while (true)
{
char message[100];
char * ptr = NULL;
while (serial.Available() > 0)
{
char c;
serial.Read(&c);
switch(c)
{
case '#':
ptr = message;
break;
case '$':
if (ptr != NULL)
{
*ptr = '\0';
}
std::cout << "received: " << message << std::endl;
ptr = NULL;
break;
default:
if (ptr != NULL)
{
*ptr = c;
ptr++;
}
break;
}
}
}*/
return EXIT_SUCCESS;
}
Serial.h
#ifndef SERIAL_H
#define SERIAL_H
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
class Serial
{
private:
int fd;
public:
Serial(std::string device);
~Serial()
{
close(fd);
};
int Available();
void Read(char * buffer, int amountOfBytes);
void Read(char * bytePtr);
int Write(std::string message);
};
#endif
Serial.cpp
#include "serial.h"
#include <stdexcept>
#include <string.h>
Serial::Serial(std::string device)
{
// Open port
fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
throw std::runtime_error("Failed to open port!");
}
// Config
struct termios config;
tcgetattr(fd, &config);
// Set baudrate
cfsetispeed(&config, B9600);
cfsetospeed(&config, B9600);
// 9600 8N1
config.c_cflag &= ~PARENB;
config.c_cflag &= ~CSTOPB;
config.c_cflag &= ~CSIZE;
config.c_cflag |= CS8;
// Disable hardware based flow control
config.c_cflag &= ~CRTSCTS;
// Enable receiver
config.c_cflag |= CREAD | CLOCAL;
// Disable software based flow control
config.c_iflag &= ~(IXON | IXOFF | IXANY);
// Termois Non Cannoincal Mode
config.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// Minimum number of characters for non cannoincal read
config.c_cc[VMIN] = 1;
// Timeout in deciseconds for read
config.c_cc[VTIME] = 0;
// Save config
if (tcsetattr(fd, TCSANOW, &config) < 0)
{
close(fd);
throw std::runtime_error("Failed to configure port!");
}
// Flush RX Buffer
if (tcflush(fd, TCIFLUSH) < 0)
{
close(fd);
throw std::runtime_error("Failed to flush buffer!");
}
}
int Serial::Available()
{
int bytes = 0;
if (ioctl(fd, TIOCINQ, &bytes) < 0)
{
close(fd);
throw std::runtime_error("Failed to check buffer!");
}
return bytes;
}
void Serial::Read(char * buffer, int amountOfBytes)
{
if (read(fd, buffer, amountOfBytes) < 0)
{
close(fd);
throw std::runtime_error("Failed to read bytes!");
}
}
void Serial::Read(char * bytePtr)
{
return Serial::Read(bytePtr, 1);
}
int Serial::Write(std::string message)
{
int length = message.size();
if (length > 100)
{
throw std::invalid_argument("Message may not be longer than 100 bytes!");
}
char msg[101];
strcpy(msg, message.c_str());
int bytesWritten = write(fd, msg, length);
if (bytesWritten < 0)
{
close(fd);
throw std::runtime_error("Failed to write bytes!");
}
return bytesWritten;
}
Arduino代码
void setup()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
//TEST-CASE FOR WRITING DATA
/*Serial.print("#TEST$");
delay(1000);*/
//TEST-CASE FOR READING DATA
char message[100];
char * ptr = NULL;
while (Serial.available() > 0)
{
char c = Serial.read();
switch(c)
{
case '#':
ptr = message;
break;
case '$':
if (ptr != NULL)
{
*ptr = '\0';
}
ptr = NULL;
int messageLength = strlen(message);
Blink();
break;
default:
if (ptr != NULL)
{
*ptr = c;
ptr++;
}
break;
}
}
}
void Blink()
{
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
答案 0 :(得分:0)
已解决。 “打开”功能在串行端口上发送信号,arduino将其解释为重启信号。我通过disabling auto-reset解决了这个问题。
或者,您可以在保存配置后添加两秒钟的延迟。
此问题专门适用于arduino微控制器。