我正在开发一个项目,需要一台Linux PC从UART上的微控制器获取数据,我已经在C ++ for Linux中使用了已经可用的串口开源代码。 (基于Ros(机器人操作系统)的代码)
代码如下:
#define DEFAULT_BAUDRATE 115200
#define DEFAULT_SERIALPORT "/dev/ttyUSB0"
//Global data
FILE *fpSerial = NULL; //serial port file pointer
ros::Publisher ucResponseMsg;
ros::Subscriber ucCommandMsg;
int ucIndex; //ucontroller index number
int FileDesc;
unsigned char crc_sum=0;
//Initialize serial port, return file descriptor
FILE *serialInit(char * port, int baud)
{
int BAUD = 0;
int fd = -1;
struct termios newtio, oldtio;
FILE *fp = NULL;
//Open the serial port as a file descriptor for low level configuration
// read/write, not controlling terminal for process,
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
ROS_INFO("FileDesc : %d",fd);
if ( fd<0 )
{
ROS_ERROR("serialInit: Could not open serial device %s",port);
return fp;
}
// save current serial port settings
tcgetattr(fd,&oldtio);
// clear the struct for new port settings
bzero(&newtio, sizeof(newtio));
//Look up appropriate baud rate constant
switch (baud)
{
case 38400:
default:
BAUD = B38400;
break;
case 19200:
BAUD = B19200;
break;
case 115200:
BAUD = B115200;
break;
case 9600:
BAUD = B9600;
break;
case 4800:
BAUD = B4800;
break;
case 2400:
BAUD = B2400;
break;
case 1800:
BAUD = B1800;
break;
case 1200:
BAUD = B1200;
break;
} //end of switch baud_rate
if (cfsetispeed(&newtio, BAUD) < 0 || cfsetospeed(&newtio, BAUD) < 0)
{
ROS_ERROR("serialInit: Failed to set serial baud rate: %d", baud);
close(fd);
return NULL;
}
// set baud rate, (8bit,noparity, 1 stopbit), local control, enable receiving characters.
newtio.c_cflag = BAUD | CRTSCTS | CS8 | CLOCAL | CREAD;
// ignore bytes with parity errors
newtio.c_iflag = IGNPAR;
// raw output
newtio.c_oflag = 0;
// set input mode to non - canonical
newtio.c_lflag = 0;
// inter-charcter timer
newtio.c_cc[VTIME] = 0;
// blocking read (blocks the read until the no.of charcters are read
newtio.c_cc[VMIN] = 0;
// clean the line and activate the settings for the port
tcflush(fd, TCIFLUSH);
tcsetattr (fd, TCSANOW,&newtio);
//Open file as a standard I/O stream
fp = fdopen(fd, "r+");
if (!fp) {
ROS_ERROR("serialInit: Failed to open serial stream %s", port);
fp = NULL;
}
ROS_INFO("FileStandard I/O stream: %d",fp);
return fp;
} //serialInit
//Process ROS command message, send to uController
void ucCommandCallback(const geometry_msgs::TwistConstPtr& cmd_vel)
{
unsigned char msg[14];
float test1,test2;
unsigned long i;
// build the message packet to be sent
msg = packet to be sent;
msg[13] = crc_sum;
for (i=0;i<14;i++)
{
fprintf(fpSerial, "%c", msg[i]);
}
tcflush(FileDesc, TCOFLUSH);
} //ucCommandCallback
//Receive command responses from robot uController
//and publish as a ROS message
void *rcvThread(void *arg)
{
int rcvBufSize = 200;
char ucResponse[10];//[rcvBufSize]; //response string from uController
char *bufPos;
std_msgs::String msg;
std::stringstream ss;
int BufPos,i;
unsigned char crc_rx_sum =0;
while (ros::ok()) {
BufPos = fread((void*)ucResponse,1,10,fpSerial);
for (i=0;i<10;i++)
{
ROS_INFO("T: %x ",(unsigned char)ucResponse[i]);
ROS_INFO("NT: %x ",ucResponse[i]);
}
msg.data = ucResponse;
ucResponseMsg.publish(msg);
}
return NULL;
} //rcvThread
int main(int argc, char **argv)
{
char port[20]; //port name
int baud; //baud rate
char topicSubscribe[20];
char topicPublish[20];
pthread_t rcvThrID; //receive thread ID
int err;
//Initialize ROS
ros::init(argc, argv, "r2SerialDriver");
ros::NodeHandle rosNode;
ROS_INFO("r2Serial starting");
//Open and initialize the serial port to the uController
if (argc > 1) {
if(sscanf(argv[1],"%d", &ucIndex)==1) {
sprintf(topicSubscribe, "uc%dCommand",ucIndex);
sprintf(topicPublish, "uc%dResponse",ucIndex);
}
else {
ROS_ERROR("ucontroller index parameter invalid");
return 1;
}
}
else {
strcpy(topicSubscribe, "uc0Command");
strcpy(topicPublish, "uc0Response");
}
strcpy(port, DEFAULT_SERIALPORT);
if (argc > 2)
strcpy(port, argv[2]);
baud = DEFAULT_BAUDRATE;
if (argc > 3) {
if(sscanf(argv[3],"%d", &baud)!=1) {
ROS_ERROR("ucontroller baud rate parameter invalid");
return 1;
}
}
ROS_INFO("connection initializing (%s) at %d baud", port, baud);
fpSerial = serialInit(port, baud);
if (!fpSerial )
{
ROS_ERROR("unable to create a new serial port");
return 1;
}
ROS_INFO("serial connection successful");
//Subscribe to ROS messages
ucCommandMsg = rosNode.subscribe("cmd_vel" /*topicSubscribe*/, 100, ucCommandCallback);
//Setup to publish ROS messages
ucResponseMsg = rosNode.advertise<std_msgs::String>(topicPublish, 100);
//Create receive thread
err = pthread_create(&rcvThrID, NULL, rcvThread, NULL);
if (err != 0) {
ROS_ERROR("unable to create receive thread");
return 1;
}
//Process ROS messages and send serial commands to uController
ros::spin();
fclose(fpSerial);
ROS_INFO("r2Serial stopping");
return 0;
}
您可以将ROS部分放在一边,但问题出在串口代码上。
当我运行此代码时,我正确地从控制器接收数据,但即使控制器停止发送数据,我也会看到printf
上连续出现的相同数据。这是不刷新输入缓冲区的问题吗?
但我无法将数据从Linux PC发送到控制器,不知道发生了什么,可以在linux的串口上同时读写吗?
奇怪的是,当我用H-term打开端口(类似于超级终端的uART可视化器),我的串口代码在后端运行时,H-term仍然没有给出任何错误,但理想情况下,H-term应该给出一个错误说&#34;端口无法打开它被锁定&#34;,但这没有发生,我的代码是不是在串口上锁定了? / p>
当我使用H-term连接端口并运行mu串口代码时,我可以看到UART上的数据从linux-PC到微控制器?
任何人都可以对我在这里遇到的问题有任何见解吗?
提前致谢。
答案 0 :(得分:0)
这里有一个问题:
BufPos = fread((void*)ucResponse,1,10,fpSerial);
因为没有检查BufPos是零还是小于10
而不是ros :: ok,使用feof()(在接收0字节后)检查关闭连接,并使用ferror()检查错误。或者当您知道(根据协议)已收到数据包时停止呼叫fread。
可以在全双工模式下使用串行端口(即,读和写),而不是完全&#34;同时&#34;但也可以。合作伙伴必须遵守协议以避免误解。
不要混合fprintf和fread / fwrite。对于发送,指示fwrite。