Makefile
SOURCE = $(wildcard *.c)
TARGETS = $(patsubst %.c, %, $(SOURCE))
CC = arm-linux-gcc
#CFLAGS = -Wall
LIBS = -lpthread
all:$(TARGETS)
$(TARGETS):%:%.c
$(CC) $< -o $@ $(LIBS)
.PHONY:clean all
clean:
-rm -rf $(TARGETS)
源代码rs485_test.c
#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 <signal.h>
#include <pthread.h>
#include <linux/serial.h>
#define FALSE 0
#define TRUE 1
/* Driver-specific ioctls: ...\linux-3.10.x\include\uapi\asm-generic\ioctls.h */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
int fd;
pthread_t threads[10];
char buff[95];
static struct termios newtios,oldtios; /*termianal settings */
static int saved_portfd=-1; /*serial port fd */
/* Test GCC version, this structure is consistent in GCC 4.8, thus no need to overwrite */
//printf("%s, %s\n", __GNUC__, __GNUC_MINOR__);
#if (__GNUC__ == 4 && __GNUC_MINOR__ == 3)
struct my_serial_rs485
{
unsigned long flags; /* RS485 feature flags */
#define SER_RS485_ENABLED (1 << 0) /* If enabled */
#define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for RTS pin when sending */
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for RTS pin after sent*/
#define SER_RS485_RX_DURING_TX (1 << 4)
unsigned long delay_rts_before_send; /* Delay before send (milliseconds) */
unsigned long delay_rts_after_send; /* Delay after send (milliseconds) */
unsigned long padding[5]; /* Memory is cheap, new structs are a royal PITA .. */
};
#endif
static void reset_tty_atexit(void)
{
if(saved_portfd != -1)
{
tcsetattr(saved_portfd,TCSANOW,&oldtios);
}
}
/*cheanup signal handler */
static void reset_tty_handler(int signal)
{
if(saved_portfd != -1)
{
tcsetattr(saved_portfd,TCSANOW,&oldtios);
}
_exit(EXIT_FAILURE);
}
static int open_port(const char *portname)
{
struct sigaction sa;
int portfd;
/*open serial port */
if((portfd = open(portname, O_RDWR |O_NOCTTY, 0)) < 0 )
{
printf("open serial port %s fail \n ",portname);
return portfd;
}
return portfd;
printf("opening serial port:%s\n",portname);
}
int rs485_set(int portfd,int baude,int c_flow,int bits,char parity,int stop)
{
struct termios options;
#if (__GNUC__ == 4 && __GNUC_MINOR__ == 3)
printf("used my_serial_rs485\n");
struct my_serial_rs485 rs485conf;
struct my_serial_rs485 rs485conf_bak;
#else
struct serial_rs485 rs485conf;
struct serial_rs485 rs485conf_bak;
#endif
/*获取终端属性*/
if(tcgetattr(portfd,&options) < 0)
{
perror("tcgetattr error");
return -1;
}
/*设置输入输出波特率,两者保持一致*/
switch(baude)
{
case 4800:
cfsetispeed(&options,B4800);
cfsetospeed(&options,B4800);
break;
case 9600:
cfsetispeed(&options,B9600);
cfsetospeed(&options,B9600);
break;
case 19200:
cfsetispeed(&options,B19200);
cfsetospeed(&options,B19200);
break;
case 38400:
cfsetispeed(&options,B38400);
cfsetospeed(&options,B38400);
break;
case 115200:
cfsetispeed(&options,B115200);
cfsetospeed(&options,B115200);
break;
default:
fprintf(stderr,"Unkown baude!\n");
return -1;
}
/*设置控制模式*/
options.c_cflag |= CLOCAL;//保证程序不占用串口
options.c_cflag |= CREAD;//保证程序可以从串口中读取数据,表启用字符接收器,目的是能够从串口中读取输入的数据
/*设置数据流控制*/
switch(c_flow)
{
case 0://不进行流控制
options.c_cflag &= ~CRTSCTS;
break;
case 1://进行硬件流控制
options.c_cflag |= CRTSCTS;
break;
case 2://进行软件流控制
options.c_cflag |= IXON|IXOFF|IXANY;
break;
default:
fprintf(stderr,"Unkown c_flow!\n");
return -1;
}
/*设置数据位*/
switch(bits)
{
case 5:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag &= ~CSIZE;//屏蔽其它标志位
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unkown bits!\n");
return -1;
}
/*设置校验位*/
switch(parity)
{
/*无奇偶校验位*/
case 'n':
case 'N':
options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
break;
/*设为空格,即停止位为2位*/
case 's':
case 'S':
options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag &= ~CSTOPB;//CSTOPB:使用两位停止位
break;
/*设置奇校验*/
case 'o':
case 'O':
options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag |= PARODD;//PARODD:若设置则为奇校验,否则为偶校验
options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
break;
/*设置偶校验*/
case 'e':
case 'E':
options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
options.c_cflag &= ~PARODD;//PARODD:若设置则为奇校验,否则为偶校验
options.c_cflag |= INPCK;//INPCK:使奇偶校验起作用
options.c_cflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
break;
default:
fprintf(stderr,"Unkown parity!\n");
return -1;
}
/*设置停止位*/
switch(stop)
{
case 1:
options.c_cflag &= ~CSTOPB;//CSTOPB:使用一位停止位
break;
case 2:
options.c_cflag |= CSTOPB;//CSTOPB:使用两位停止位
break;
default:
fprintf(stderr,"Unkown stop!\n");
return -1;
}
/*设置输出模式为原始输出*/
options.c_oflag &= ~(OPOST| ONLCR | OLCUC | OCRNL | ONOCR | ONLRET | OFILL);//OPOST:若设置则按定义的输出处理,否则所有c_oflag失效
/*设置本地模式为原始模式*/
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/*
*ICANON:允许规范模式进行输入处理
*ECHO:允许输入字符的本地回显
*ECHOE:在接收EPASE时执行Backspace,Space,Backspace组合
*ISIG:允许信号
*/
/*设置等待时间和最小接受字符*/
options.c_cc[VTIME] = 0;//可以在select中设置
options.c_cc[VMIN] = 1;//最少读取一个字符
/*如果发生数据溢出,只接受数据,但是不进行读操作*/
tcflush(portfd,TCIFLUSH);
/*激活配置*/
if(tcsetattr(portfd,TCSANOW,&options) < 0)
{
perror("tcsetattr failed");
return -1;
}
if (ioctl (portfd, TIOCGRS485, &rs485conf) < 0)
{
/* Error handling.*/
printf("ioctl TIOCGRS485 error.\n");
return -1;
}
/* Enable RS485 mode: */
rs485conf.flags |= SER_RS485_ENABLED;
/* Set logical level for RTS pin equal to 1 when sending: */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
//rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
/* set logical level for RTS pin equal to 0 after sending: */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
//rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
/* Set rts delay after send, if needed: */
rs485conf.delay_rts_after_send = 0x80;
if (ioctl (portfd, TIOCSRS485, &rs485conf) < 0)
{
/* Error handling.*/
printf("ioctl TIOCSRS485 error.\n");
return -1;
}
if (ioctl (portfd, TIOCGRS485, &rs485conf_bak) < 0)
{
/* Error handling.*/
printf("ioctl TIOCGRS485 error.\n");
return -1;
}
else
{
printf("rs485conf_bak.flags 0x%x.\n", rs485conf_bak.flags);
printf("rs485conf_bak.delay_rts_before_send 0x%x.\n", rs485conf_bak.delay_rts_before_send);
printf("rs485conf_bak.delay_rts_after_send 0x%x.\n", rs485conf_bak.delay_rts_after_send);
}
return portfd;
}
void * send(void* arg)
{
int portfd = (int) arg;
unsigned int i, j;
int rev1, rev2;
char RxBuffer[sizeof(buff)];
rev1 =0;
rev2 =0;
printf("send content:%s\n", buff);
while(rev2 < sizeof(buff))
{
rev1 = write(portfd,(buff+rev2),sizeof(buff));
rev2 += rev1;
}
printf("\n send %d byts\n", rev2);
}
void * receive(void* arg)
{
int portfd = (int) arg;
unsigned int i, j;
int rev1, rev2;
char RxBuffer[sizeof(buff)];
rev1 = 0;
rev2 = 0;
while(rev2 < sizeof(RxBuffer))
{
rev1 = read(portfd,(RxBuffer+rev2),sizeof(RxBuffer) - rev2);
rev2 += rev1;
if(rev1 > 0)
printf("\n receive %d bytes \n", rev2);
}
printf("receive content: %s\n", RxBuffer);
printf("\n receive %d bytes \n", rev2);
}
/**
*@breif main()
*/
int main(int argc, char **argv)
{
const char *tty = NULL;
unsigned int i;
int ret;
int baude;
int c_flow;
int bits;
char parity;
int stop;
if(argc < 1)
{
printf("please input /dev/ttySx\n");
}
tty = argv[1];
if( argc < 2)
{
printf("format uart_test /dev/ttySx baude stop data_bits parity config_stream\n");
printf("such as:./uart_test /dev/ttySx 115200 1 8 N 0\n");
exit(EXIT_FAILURE);
}
baude = atoi(argv[2]);
stop = atoi(argv[3]);
bits = atoi(argv[4]);
parity = *argv[5];
c_flow = atoi(argv[6]);
printf("%s\n", tty);
printf("%d, %d, %d, %c, %d\n", baude, stop, bits, parity, c_flow);
for(i = 0; i < sizeof(buff); i++)
{
buff[i] = (i + 0x21);
}
fd = open_port(tty);
if (fd < 0)
{
printf("open uart error\n");
return 0;
}
ret = rs485_set(fd, baude, c_flow, bits, parity, stop);
if(ret == -1)
{
fprintf(stderr,"rs485_set failed!\n");
exit(EXIT_FAILURE);
}
pthread_create(&threads[0], NULL, send, (void*)(fd));
pthread_create(&threads[1], NULL, receive, (void*)(fd));
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
close(fd);
return 0;
}