use*_*939 5 c++ linux serialization
我正在开发一个项目,需要一台 Linux PC 从 UART 上的微控制器获取数据,为此我使用了一个已经可用的开源代码,用于 Linux 的 C++ 串行端口。(基于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;
}
Run Code Online (Sandbox Code Playgroud)
你可以把ROS部分放在一边,但问题出在串口代码上。
当我运行此代码时,我正确地从控制器接收数据,但即使控制器停止发送数据,我也会看到相同的数据printf连续出现在 s 上。这是不刷新输入缓冲区的问题吗?
但是我无法将数据从Linux PC发送到控制器,不知道发生了什么,在linux的串行端口上可以同时进行读写吗?
奇怪的观察,当我在 H-term(类似于超级终端的 uART 可视化工具)中打开端口并在后端运行我的串行端口代码时,H-term 仍然不会给出任何错误,但理想情况下 H- term 应该给出一个错误,说“端口无法打开,它已被锁定”,但这并没有发生,是我的代码没有获取串行端口上的锁定吗?
当我使用运行 mu 串口代码的 H-term 连接端口时,我可以看到 UART 上从 linux-PC 到微控制器的数据?
任何人都可以对我在这里面临的问题有任何见解吗?
提前致谢。
这里有一个问题:
BufPos = fread((void*)ucResponse,1,10,fpSerial);
Run Code Online (Sandbox Code Playgroud)
因为没有检查 BufPos 是否为零或小于 10
使用 feof()(接收到 0 字节后)来检查关闭的连接,而不是使用 ros::ok,并使用 Ferr() 来检查错误。或者当您知道(根据协议)已收到数据包时,停止调用 fread。
可以不完全“同时”而是交替地以全双工模式(即读和写)使用串行端口。合作伙伴必须遵守协议以避免误解。
不要混合使用 fprintf 和 fread/fwrite。对于发送,指示fwrite。
| 归档时间: |
|
| 查看次数: |
3977 次 |
| 最近记录: |