我有一个带FPGA的设备,它通过简单的UART发送数据。数据是一个32字节的数据包,波特率是115200.我通过UART-TTL / USB适配器将它们连接到我的笔记本电脑,因此在系统(Ubuntu 14.04)中,我可以从ttyUSB
读取数据。我在GTK / C中创建了一个简单的应用程序来接收数据,进行数学运算并将结果保存在文本文件中。一切都工作正常,直到我增加了从每秒5次发送32字节数据包到每秒100次的频率。问题是十几个或几十个中的一个包具有错误的字节顺序。我已经用逻辑分析仪检查过我的FPGA每次都能正确发送数据。
例如,FPGA发送数据包:
1 2 3 4 5 6 7 8 9
但我的申请有时会收到:
1 2 7 3 4 5 6 8 9
我正在使用此功能打开串口:
int rs232_open(char *com_name, int baudrate, int databits, char *parity, int stopbits)
{
serial_fd = open(com_name, O_RDWR | O_NOCTTY | O_NDELAY); //open port
if(serial_fd==-1)
{
perror("unable to open comport ");
return 1;
}
error = tcgetattr(serial_fd, &old_settings); //save actual port settings
if(error==-1)
{
close(serial_fd);
perror("unable to read portsettings ");
return 2;
}
memset(&new_settings, 0, sizeof(new_settings));
new_settings.c_iflag = 0; //without in processing
new_settings.c_oflag = 0; //without out processing
new_settings.c_lflag = 0; //without line processing
new_settings.c_cflag = CLOCAL | CREAD; //without flow control, receiver active
switch(baudrate) //baudrate
{
case 9600: new_settings.c_cflag |= B9600; break;
case 19200: new_settings.c_cflag |= B19200; break;
case 38400: new_settings.c_cflag |= B38400; break;
case 115200: new_settings.c_cflag |= B115200; break;
default: return 3; break;
}
switch(databits) //number of data bits
{
case 5: new_settings.c_cflag |= CS5; break;
case 6: new_settings.c_cflag |= CS6; break;
case 7: new_settings.c_cflag |= CS7; break;
case 8: new_settings.c_cflag |= CS8; break;
default: return 3;
}
switch(parity[0]) //parity
{
case 'N': new_settings.c_iflag |= IGNPAR; break;
case 'E': new_settings.c_cflag |= PARENB; break;
case 'O': new_settings.c_cflag |= PARENB | PARODD; break;
default: return 3;
}
switch (stopbits) //stop bits
{
case 1: break; //1 bit
case 2: new_settings.c_cflag |= CSTOPB; break; //2 bits
default: return 3;
}
new_settings.c_cc[VMIN] = 1; //1 received char allows to read
new_settings.c_cc[VTIME] = 0;
tcflush(serial_fd, TCIOFLUSH); //clear port buffers
error = tcsetattr(serial_fd, TCSANOW, &new_settings); //save new settings
if(error==-1)
{
close(serial_fd);
perror("unable to set portsettings ");
return 4;
}
return 0;
}
在我的GTK / C应用程序中,单击“OPEN”按钮调用上面的函数:
rs232_open("ttyUSB0",115200,8,"N",2);
然后,我为串口创建一个通道,设置其编码并为接收事件添加处理程序:
int serial_fd; //serial port file descriptor
GIOChannel *serial_ch; //serial port channel
serial_ch = g_io_channel_unix_new(serial_fd); //attach channel to serial port
g_io_add_watch(serial_ch, G_IO_IN, read_channel, NULL); //attach read_channel handler function
函数read_channel()
看起来像这样(frame
是一个带有chars buffer
表和整数字段byte_number
)的结构:
gboolean read_channel(GIOChannel *channel, GIOCondition condition, gpointer data)
{
unsigned char i;
gsize bytes_read;
gchar chr;
GString *recdata = g_string_new(NULL);
if(g_io_channel_read_chars(channel, &chr, 1, &bytes_read, NULL) == G_IO_STATUS_NORMAL) //if reading a byte is successful
{
if(bytes_read) //1 byte received
{
//
// here I search for 0x55 0x55 sequence (start tag of 32 bytes packet)
// if start tag is received frame buffer is cleared and byte counter zeroed
//
frame.buffer[frame.byte_number++]=chr; //save received byte to buffer
if(frame.byte_number > BUFFER_SIZE-1) //frame buffer full
{
if(frame.buffer[BUFFER_SIZE-1] == 0x0D) //end tag is correct (0x0D is end tag of my 32 bytes packet)
{
//
// here I convert received data (some int16 numbers)
// and save them in readable form to text file
// also as a string of hex numbers for debugging
//
}
else //end tag not correct
{
//
// here I increase error counter
//
}
for(i=0; i<BUFFER_SIZE; i++) frame.buffer[i]=0; //clear the buffer
frame.byte_number=0; //reset byte counter
}
}
}
return TRUE;
}