【发布时间】:2016-08-03 11:40:51
【问题描述】:
我正在尝试编写一个函数来读取通过 UART 发送的一大块数据。我正在使用在 RaspberryPi 模型 B 上运行的 Raspbian Jessie,但我想在 openwrt 上使用这个 C 代码(带有任何必要的修订)。到目前为止,这就是我写的。
标题:
#ifndef __UART_LIB__
#define __UART_LIB__
#include <stdlib.h> //Errors, etc
#include <unistd.h> //Used for UART
#include <fcntl.h> //Used for UART
#include <termios.h> //Used for UART
#include <sys/types.h> //These includes are for timeout
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h> //
#include <sys/ioctl.h>
#define BITS_PER_PACKAGE_ 11
#define WAIT_PROLONGATION_CONSTANT_ 1.1f
//Some values used by default, left for the user to change if needed
unsigned int BAUD_ ;
unsigned int NUM_BITS_ ;
char *UART_PATH_ ;
unsigned int MAX_SIZE_ ;
unsigned int OPEN_FLAG_ ;
time_t TIMEOUT_SEC_ ;
suseconds_t TIMEOUT_USEC_ ;
struct timeval WAIT_CONSTANT_ ;
int open_conf_UART_() ;
int read_UART_(int uart_filestream, char** dest, int max_len) ;
#endif
.c 文件:
#include "uartlib.h"
unsigned int BAUD_ = B115200 ;
unsigned int NUM_BITS_ = CS8 ;
char *UART_PATH_ = "/dev/ttyAMA0" ;
unsigned int MAX_SIZE_ = 128 ;
unsigned int OPEN_FLAG_ = O_RDWR ;
time_t TIMEOUT_SEC_ = 5 ;
suseconds_t TIMEOUT_USEC_ = 0 ;
int open_conf_UART_()
{
int indicator, old_fl;
int uart_filestream ;
struct termios options ;
// Opening the port in a read/write mode
uart_filestream = open(UART_PATH_, OPEN_FLAG_ | O_NOCTTY );
if (uart_filestream < 0)
{
// Unable to open the serial port, so produce an error and halt
return -1;
}
// Configuring the options for UART
// Retrieve the options and modify them.
indicator = tcgetattr(uart_filestream, &options);
if(indicator < 0)
{
// Unable to get the attributes
close(uart_filestream);
return -1;
}
// I found a question on stackoverlow where the answer said that VTIME and VMIN will be ignored unless I
// switch the FNDELAY flag off
old_fl = fcntl(uart_filestream, F_GETFL);
if(old_fl < 0)
{
return -1;
}
old_fl &= ~FNDELAY;
fcntl(uart_filestream, old_fl);
//Setting the options
options.c_cflag = CRTSCTS | BAUD_ | NUM_BITS_ | CLOCAL | CREAD ;
options.c_iflag = 0;
options.c_oflag = 0;
options.c_lflag = 0;
//I want the uart to wait 1/10 of a second between bytes at most
options.c_cc[VTIME] = 1;
options.c_cc[VMIN] = 0;
// Flushing the file stream (the input and the output area)
indicator = tcflush(uart_filestream, TCIOFLUSH);
if(indicator < 0)
{
// Unable to flush
close(uart_filestream);
return -1;
}
// Setting the options for the file stream.
indicator = tcsetattr(uart_filestream, TCSANOW, &options);
if(indicator < 0)
{
// Unable to set the attributes
close(uart_filestream);
return -1;
}
return uart_filestream;
}
int read_UART_(int uart_filestream, char** dest, int max_len)
{
int indicator;
int buffer_length;
indicator = tcflush(uart_filestream, TCIFLUSH);
if(indicator < 0)
{
// Unable to flush
return -1;
}
//Do the actual reading
buffer_length = read(uart_filestream, (void*)(*dest), max_len);
if(indicator < 0)
{
return -1;
}
else
{
// Returning number of read bytes
return buffer_length;
}
// Both branches of the if statement above have return, so this will not be reached
}
所以,当我尝试读取超过 8 个字节时,消息会被截断为 8 个字节。 正如我所读到的,将 VTIME 设置为某个值允许两个字节之间的时间间隔最多那么长。 我不确定发生了什么,但我怀疑 read() 调用在数据接收完成之前读取了缓冲区。 我的愿望是读取一块未定义大小的数据。我还在读取之前使用了带有超时的 select() 以确保程序不会完全阻塞。 我阅读了很多关于这个主题的论坛主题、stackoverflow 问题、指南等,但似乎没有一个对我的解决方案有帮助。 那么,谁能解释这里发生了什么?有没有可能做我想做的事?
请注意,我删除了一些代码(我还编写了一个写入 UART 端口的函数),所以这里可能有一些多余的包含、全局变量等。
【问题讨论】:
-
So, when I try to read more than 8 bytes, the message gets truncated to 8 bytesUART 有一个固定大小的接收缓冲区(如果需要,还有流量控制)。你应该在你的程序中做你自己的缓冲。 -
发布的代码显示没有调用
int read_UART_(int uart_filestream, char** dest, int max_len),因此没有正确调用的证据。 -
你确定数据是整块发送的吗?你用示波器测试过传输吗?旁注:传递给函数的
max_len值是什么? -
第二个
if(indicator < 0)inread_UART_()没有任何作用。 -
IIRC raspberryPi 有一个 3 线(模拟)uart,所以不能有硬件流控制。 (不过,XON/XOFF 可能是可能的)