测试:
测试源码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<termios.h>
#include<errno.h>
#include<string.h>
#include<pthread.h>
#include<time.h>
#include<linux/serial.h>
#include<sys/ioctl.h>
#define SEND_SLEEP
#define FALSE -1
#define TRUE 0
#define RS485 0
static char port_name[32];
static char log_name[100];
static int save_log_flag;
static int test_data_len; //测试数据量 M
static int test_finish = 0;
enum rx_status {
HEAD1,/*0xFE*/
HEAD2,/*0xAB*/
DATA,
XOR,
};
static void Sleep(int iSec,int iUsec)
{
struct timeval tv;
tv.tv_sec=iSec;
tv.tv_usec=iUsec;
select(0,NULL,NULL,NULL,&tv);
}
int uart_open(char* port)
{
int fd;
fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);
if (fd < 0)
{
printf("can't open serial port:%s\n",port);
return(FALSE);
}
if(fcntl(fd, F_SETFL, 0) < 0)
{
printf("fcntl failed!\n");
return(FALSE);
}
if(0 == isatty(STDIN_FILENO))
{
printf("standard input is not a terminal device\n");
return(FALSE);
}
printf("now set rs485 config \n");
#if RS485
struct serial_rs485 rs485conf;
memset(&rs485conf,0,sizeof(rs485conf));
rs485conf.padding[0] = 17;
rs485conf.delay_rts_after_send = 2000;
rs485conf.delay_rts_before_send = 2000;
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
rs485conf.flags |= SER_RS485_ENABLED;
ioctl(fd, TIOCSRS485, &rs485conf);
int ret = ioctl(fd, TIOCSRS485, &rs485conf);
perror("ioctl");
printf("ioctrl back:%d\n", ret);
#endif
return fd;
}
void uart_close(int fd)
{
close(fd);
}
int uart_set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
int i;
int status;
int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300};
struct termios options;
/*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为-1.
*/
if ( tcgetattr( fd,&options) != 0)
{
perror("setupSerial 1");
return FALSE;
}
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
if (speed == name_arr[i])
{
cfsetispeed(&options, speed_arr[i]);
cfsetospeed(&options, speed_arr[i]);
}
}
options.c_cflag |= CLOCAL; //修改控制模式,保证程序不会占用串口
options.c_cflag |= CREAD; //修改控制模式,使得能够从串口中读取输入数据
switch(flow_ctrl) //设置数据流控制
{
case 0 :
options.c_cflag &= ~CRTSCTS; //不使用流控制
options.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case 1 :
options.c_cflag |= CRTSCTS; //使用硬件流控制
break;
case 2 :
options.c_cflag |= IXON | IXOFF | IXANY;//使用软件流控制
break;
}
options.c_cflag &= ~CSIZE;//设置数据位 //屏蔽其他标志位
switch (databits)
{
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n");
return FALSE;
}
switch (parity) //设置校验位
{
case 'n':
case 'N': //无奇偶校验位。
options.c_cflag &= ~PARENB;
//options.c_iflag &= ~INPCK;
break;
case 'o':
case 'O'://设置为奇校验
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E'://设置为偶校验
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
case 's':
case 'S': //设置为空格
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr,"Unsupported parity\n");
return FALSE;
}
switch (stopbits) // 设置停止位
{
case 1:
options.c_cflag &= ~CSTOPB; break;
case 2:
options.c_cflag |= CSTOPB; break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return FALSE;
}
options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP);
//修改输出模式,原始数据输出
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//设置等待时间和最小接收字符
options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */
options.c_cc[VMIN] = 0; /* 读取字符的最少个数为1 */
//如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
// tcflush(fd,TCIFLUSH);
//激活配置 (将修改后的termios数据设置到串口中)
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("com set error!\n");
return FALSE;
}
return TRUE;
}
int uart_init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
int err;
if (uart_set(fd,speed,flow_ctrl,databits,stopbits,parity) == FALSE) //设置串口数据帧格式
{
return FALSE;
} else {
return TRUE;
}
}
int uart_recv(int fd, char *rcv_buf,int data_len)
{
int len,fs_sel;
fd_set fs_read;
struct timeval time;
FD_ZERO(&fs_read);
FD_SET(fd,&fs_read);
time.tv_sec = 10;
time.tv_usec = 0;
//使用select实现串口的多路通信
fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
if(fs_sel)
{
len = read(fd,rcv_buf,data_len);
return len;
} else {
return FALSE;
}
}
int uart_send(int fd, char *send_buf,int data_len)
{
int len = 0;
len = write(fd,send_buf,data_len);
if (len == data_len )
{
return len;
} else {
tcflush(fd,TCOFLUSH);
return FALSE;
}
}
void getNowTime(char *cur_time)
{
struct timespec time;
clock_gettime(CLOCK_REALTIME, &time); //获取相对于1970到现在的秒数
struct tm nowTime;
localtime_r(&time.tv_sec, &nowTime);
sprintf(cur_time, "%04d%02d%02d%02d:%02d:%02d", nowTime.tm_year + 1900, nowTime.tm_mon+1, nowTime.tm_mday,
nowTime.tm_hour, nowTime.tm_min, nowTime.tm_sec);
}
static void * uart_tx_pthread(void *arg)
{
int ret;
char ch = 1;
int count = 0;
int nM = 0;
sleep(3);
while(1){
ret = uart_send(*(int*)arg, &ch, 1);
if (ret == 1){
printf("**send %02x\n", ch);
if (!(++count % 1048576)){
printf("send %dM data\n", ++nM);
if (!--test_data_len){
printf("***************** tx finish *****************\n");
pthread_exit(NULL);
}
}
//printf("tx: %02x\n", ch);
//usleep(10000);
sleep(1);
++ch;
}else{
printf("tx error\n");
}
}
}
/*head(0xfe+0xab) + data(1(0-0xff)+6(random)) + xor*/
static void * uart_rx_pthread(void *arg)
{
char ch;
int len;
char pre_ch = 0;
int count;
char logstr[128];
int nM = 0;
while (1) {
len = uart_recv(*(int*)arg, &ch, 1);
if(len == 1)
{
printf("rx:0x%02x\n", ch);
if (!(++count % 1048576)){
printf("*********************** recv %dM data **********************\n", ++nM);
}
} else {
printf("%s:rx 10s timeout!\n",port_name);
//sprintf(logstr,"echo \"recv %dByte\" >> %s", count, log_name);
//system(logstr);
//pthread_exit(NULL);
}
}
}
int main(int argc, char **argv)
{
int fd;
int err;
int baud;
int databit;
int stopbit;
char parity;
printf("usage: ./rs232_test /dev/ttyS1 115200 8 1 N ./uart1.log 2M\n");
printf("格式 : 程序 设备节点 波特率 数据位 停止位 校验 日志 测试发送数据量\n");
printf("波特率:300 1200 2400 4800 9600 19200 115200\n");
printf("数据位: 7 8\n");
printf("停止位: 1 2\n");
printf("校验: N O E S\n");
if (argc != 8){
return -1;
}
fd = uart_open(argv[1]);
if (fd < 0) {
printf("open %s fail!",argv[1]);
return fd;
}
baud = atoi(argv[2]);
databit = atoi(argv[3]);
stopbit = atoi(argv[4]);
parity = argv[5][0];
strncpy(log_name, argv[6], 100);
test_data_len = atoi(argv[7]);
printf("baud:%d databit:%d stopbit:%d parity:%c log_name:%s test_data_len:%dM\n", baud, databit, stopbit, parity, log_name, test_data_len);
err = uart_init(fd,baud,0,databit, stopbit, parity);
//create two pthread, one send , another recv
pthread_t pt1, pt2;
if (pthread_create(&pt1, NULL, uart_rx_pthread, (void *)&fd) == -1){
printf("pthread_create failed\n");
return -1;
}
if (pthread_create(&pt2, NULL, uart_tx_pthread, (void *)&fd) == -1){
printf("pthread_create failed\n");
return -1;
}
sleep(1);
if (pthread_join(pt1, NULL))
{
printf("thread is not exit...\n");
return -2;
}
if (pthread_join(pt2, NULL))
{
printf("thread is not exit...\n");
return -2;
}
return 0;
}
将源码拷贝到Ubuntu,下进行编译,生成执行文件uart_test。
#arm-linux-gnueabihf-gcc uart_test.c -o uart_test -lpthread
使用跳线帽短接开发板UART1的TX-RX。
1.把编译出来的可执行文件拷贝到开发板
可以看到能正常收发数据。
文档更新时间: 2022-06-23 16:27 作者:Aeeditor