基于ARM开发板的简单串口服务器

    xiaoxiao2022-06-30  56

    串口服务器是为RS-232/485/422串口到TCP/IP网络之间完成数据转换的通讯接口转换器。提供RS-232/485/422终端串口与TCP/IP网络的数据双向透明传输,提供串口转网络功能,RS-232/485/422转网络的解决方案,可以让串口设备立即联接网络。

    MOXA工业级串口服务器

    应用领域

    门禁系统、考勤系统、售饭系统、 POS 系统、楼宇自控系统、自助银行系统电信机房监控,电力监控等。

    产品特点

      ·体积小,火柴盒大小   ·支持RS232,RS485   ·10/100M以太网口 ,软件可升级   ·一个开关量输入,一个开关量输出   ·可作为TCP Server 或TCP Client ,UDP数据   ·内置WEB服务器,支持Java   ·支持多种异步串口格式   ·无需修改原有应用软件就可在网络环境下使用   ·将COM口定向至IP地址,每台计算机可同时拥有256个串口

    工作方式

    服务器方式:在该工作方式下,串口联网服务器作为TCP服务器端, 转换器在指定的TCP端口上监听平台程序的连接请求,该方式比较适合于一个转换器与多个平台程序建立连接(一个转换器不能同时与多个平台程序建立连接)。

    客户端方式:在该工作方式下,串口联网服务器 作为 TCP 客户端,转换器上电时主动向平台程序请求连接,该方式比较适合于多个转换器同时向一个平台程序建立连接。

    通讯模式

    点对点通讯模式:该模式下,转换器成对的使用,一个作为服务器端,一个作为客户端,两者之间建立连接,实现数据的双向透明传输。该模式适用于将两个串口设备之间的总线连接改造为 TCP/IP 网络连接。 使用虚拟串口通讯模式:该模式下,一个或者多个转换器与一台电脑建立连接,实现数据的双向透明传输。由电脑上的虚拟串口软件管理下面的转换器,可以实现一个虚拟串口对应多个转换器, N 个虚拟串口对应 M 个转换器( N<=M )。该模式适用于串口设备由电脑控制的 485 总线或者 232 设备连接。 基于网络通讯模式: 该模式下,电脑上的应用程序基于SOCKET 协议编写了通讯程序,在转换器设置上直接选择支持 SOCKET 协议即可。

    实现原理

    ARM开发板 一般的开发板都可使用,只要带有网口(有线/无线)、串口。

    开发板串口服务端源码

    #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <pthread.h> #include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <fcntl.h> #include <termios.h> /*PPSIX终端控制定义*/ #include <errno.h> /*错误号定义*/ #define COM_FILE "/dev/ttySAC0" //串口设备文件 #define PORT 8848 #define BACKLOG 5 #define MAXDATASIZE 128 #define BUFSIZE 512 void* net_proc(void* arg);//网络侦听服务 void* net_recv(void* arg);//接收网络客户端数据 void* net_send(void* arg);//发送数据到网络客户端数据 void* com_recv(void* arg);//串口接收处理 void* com_send(void* arg);//串口发送处理 int init_com(void);//初始化串口参数 struct ARG { int connfd; struct sockaddr_in client; }; static char net_buff[BUFSIZE]; static char com_buff[BUFSIZE]; int wr_index = 0; int re_index = 0; /********************************** 主函数 **********************************/ int main(void) { int fd = 0; pthread_t net_th, com_r,com_s; memset(net_buff,0,BUFSIZE); memset(com_buff,0,BUFSIZE); if((fd = init_com())<=0){ perror("init_com() error"); exit(1); } //网络服务器线程 if(pthread_create(&net_th, NULL, net_proc, NULL)){ perror("pthread_creat() error"); exit(1); } //串口接收线程 if(pthread_create(&com_r, NULL, com_recv, (void*)&fd)){ perror("pthread_creat() error"); exit(1); } //串口发送线程 if(pthread_create(&com_s, NULL, com_send, (void*)&fd)){ perror("pthread_creat() error"); exit(1); } pthread_join(net_th,NULL); pthread_join(com_r,NULL); pthread_join(com_s,NULL); } /********************************** 网络服务端线程 **********************************/ void* net_proc(void* arg) { int listenfd, connectfd; pthread_t thread; //id of thread struct ARG *acc_arg; struct sockaddr_in server; //server's address info struct sockaddr_in client; //client's int sin_size; // int opt = SO_REUSEADDR; //create tcp socket printf("socket.... "); if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ perror("creating socket failed."); exit(1); } // setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); bzero(&server,sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = htonl(INADDR_ANY); printf("bind.... "); if(bind(listenfd,(struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){ perror("bind error."); exit(1); } printf("listen.... "); if(listen(listenfd,BACKLOG) == -1) { perror("listen() error "); exit(1); } sin_size = sizeof(struct sockaddr_in); sleep(1); while(1){ printf("accepting....\n "); if((connectfd = accept(listenfd,(struct sockaddr *)&client,(socklen_t*)&sin_size)) == -1) { perror("accept() error "); exit(1); } acc_arg = malloc(sizeof(struct ARG)); acc_arg->connfd = connectfd; memcpy((void *)&acc_arg->client, &client, sizeof(client)); // 服务端接收客户端数据 if(pthread_create(&thread, NULL, net_recv, (void*)acc_arg)){ perror("pthread_creat() error"); exit(1); } // 服务端向客户端发送数据 if(pthread_create(&thread, NULL, net_send, (void*)acc_arg)){ perror("pthread_creat() error"); exit(1); } } close(listenfd); return (0); } /********************************** 网络数据接收线程 **********************************/ void* net_recv(void* arg) { int connectfd; int nbyte; char recvbuf[MAXDATASIZE]; struct sockaddr_in client; struct ARG * n_arg = arg; connectfd = n_arg->connfd; client = n_arg->client; printf("IP: %s. \n",inet_ntoa(client.sin_addr) ); //get client's name from client while(1){ memset(recvbuf,0,MAXDATASIZE); nbyte = recv(connectfd, recvbuf, MAXDATASIZE, 0); if(nbyte== 0 || nbyte == -1) { close(connectfd); perror("Client disconnected. "); break; } recvbuf[nbyte] = '\0'; printf("fd=%d nbyte=%d net recv: %s \n", connectfd,nbyte,recvbuf ); // send(connectfd, recvbuf, strlen(recvbuf), 0); //回传到客户端 //网络收到的数据,存到全局缓冲区 strcat(net_buff,recvbuf); } } /********************************** 网络数据发送线程 **********************************/ void* net_send(void* arg) { int connectfd; int nbyte; struct ARG * n_arg = arg; connectfd = n_arg->connfd; while(1){ //发送串口收到的数据到网络客户端 if(strlen(com_buff)>0) { nbyte = send(connectfd, com_buff, strlen(com_buff), 0); printf("net send nbyte=%d\n",nbyte); memset(com_buff, '\0', BUFSIZE); } } } /********************************** 串口初始化 **********************************/ int init_com(void) { int fd_com; struct termios initial_settings, new_settings; fd_com = open(COM_FILE, O_RDWR | O_NOCTTY ); if(-1 == fd_com) { perror("Can't Open Serial Port"); return -1; } //获取终端属性 tcgetattr(fd_com,&initial_settings); new_settings = initial_settings; //设置速度 cfsetispeed(&new_settings, B115200);//波特率115200 cfsetospeed(&new_settings, B115200); /*控制模式设置*/ // new_settings.c_cflag &= ~CSIZE; //数据位8 new_settings.c_cflag |= CS8; //数据位8 new_settings.c_cflag &= ~CSTOPB; //停止位1 new_settings.c_cflag &= ~PARENB; //无校验 /*输入模式设置*/ new_settings.c_iflag &= ~INPCK; //取消校验 new_settings.c_iflag |= IGNPAR; //忽略奇偶校验错误的字符 new_settings.c_iflag |= ICRNL; //收到的回车符转成换行符 /*输出模式设置*/ new_settings.c_oflag = 0; /*本地模式设置*/ new_settings.c_lflag &= ~ICANON; //启用非标准输入 // new_settings.c_lflag &= ~ECHO; //关闭回显功能 new_settings.c_lflag &= ~ISIG; //禁用信号 /*控制字符设置*/ new_settings.c_cc[VMIN] = 1; //有字符立即读取 new_settings.c_cc[VTIME] = 0; //启用新的终端设置 if(tcsetattr(fd_com, TCSANOW, &new_settings) != 0) { fprintf(stderr,"could not set attributes\n"); } // tcsetattr(fd_com,TCSANOW,&initial_settings); //恢复原有设置 return fd_com; } /********************************** 串口数据发送 **********************************/ void* com_send(void* arg) { int fd; int nbyte; fd = *(int*)arg; while(1) { if(strlen(net_buff)>0) { nbyte = write(fd,net_buff,strlen(net_buff)); printf("com send nbyte=%d\n",nbyte); memset(net_buff, '\0', sizeof(net_buff)); } } } /********************************** 串口数据接收 **********************************/ void* com_recv(void* arg) { int fd; int nbyte = 0; fd = *(int*)arg; char recvbuf[MAXDATASIZE]; while(1) { //读取串口数据到缓冲区 memset(recvbuf,'\0',MAXDATASIZE); nbyte = 0; nbyte = read(fd,recvbuf,MAXDATASIZE); recvbuf[nbyte] = '\0'; printf("nbyte=%d com recv:%s\n",nbyte,recvbuf); strcat(com_buff,recvbuf); } }

    PC客户端源程序

    /* cthread.c */ #include <stdio.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <netdb.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <errno.h> #include <stdlib.h> #include <pthread.h> #define PORT 8848 #define MAXDATASIZE 128 void* net_recv(void* arg); void* net_send(void* arg); int get_line(char *msg); int init_net(int argc, char *argv[]); /********************************** 主函数 **********************************/ int main(int argc, char *argv[]) { int net_fd; pthread_t recv_th,send_th; net_fd = init_net(argc,argv); pthread_create(&send_th,NULL,net_send,(void*)&net_fd); pthread_create(&recv_th,NULL,net_recv,(void*)&net_fd); pthread_join(recv_th,NULL); pthread_join(send_th,NULL); return 0; } /********************************** 网络接收线程 **********************************/ void* net_recv(void* arg) { char recvline[MAXDATASIZE]; int *sockfd; int numbytes; sockfd = (int*)arg; while(1){ printf("@\n"); if((numbytes = recv(*sockfd, recvline, MAXDATASIZE, 0)) == 0){ printf("serial not data. \n"); } //recevie message form server echo recvline[numbytes] = '\0'; printf("[com data] %s\n", recvline); //clean output buffer memset(recvline, '0', strlen(recvline)-1); } } /********************************** 网络初始化,连接到服务端 **********************************/ int init_net(int argc, char *argv[]) { int fd; struct hostent *he; struct sockaddr_in server; //server's address info char *defaultIP = "127.0.0.1"; if(argc != 2) { if((he = gethostbyname(defaultIP)) == NULL){ perror("gethostbyname() error"); exit(1); } }else{ if((he = gethostbyname(argv[1])) == NULL){ perror("gethostbyname() error"); exit(1); } } if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){ perror("socket() error"); exit(1); } bzero(&server , sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr = *((struct in_addr *)he->h_addr); if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr)) == -1){ perror("connect() error"); exit(1); } return fd; } /********************************** 网络发送数据线程 **********************************/ void* net_send(void* arg) { char sendline[MAXDATASIZE],recvline[MAXDATASIZE]; int numbytes; int len; int * sock_fd; sock_fd = (int*)arg; printf("connected to server. \n"); //send message to server //when the string is not NULL , send another! while(1){ while((len =get_line(sendline)) != 0){ sendline[len] = '\0'; send(*sock_fd, sendline, strlen(sendline), 0); } } } /********************************** 接收命令行输入的数据 **********************************/ int get_line(char *msg) { int i=0; char temp; printf("Input message:"); fflush(stdout); while (1) { temp = getchar(); if (temp == '\r' || temp == '\n') {return i ;} msg[i]=temp; if(msg[i]==13){ msg[i]=0; break; } fflush(stdout); i++; } }
    转载请注明原文地址: https://ju.6miu.com/read-1125849.html

    最新回复(0)