Linux下的串列埠程式設計例項
阿新 • • 發佈:2019-01-06
親測可用,移植時根據需求修改即可,轉載自:http://blog.csdn.net/w282529350/article/details/7378388
//串列埠相關的標頭檔案 #include<stdio.h> /*標準輸入輸出定義*/ #include<stdlib.h> /*標準函式庫定義*/ #include<unistd.h> /*Unix 標準函式定義*/ #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> /*檔案控制定義*/ #include<termios.h> /*PPSIX 終端控制定義*/ #include<errno.h> /*錯誤號定義*/ #include<string.h> //巨集定義 #define FALSE -1 #define TRUE 0 /******************************************************************* * 名稱: UART0_Open * 功能: 開啟串列埠並返回串列埠裝置檔案描述 * 入口引數: fd :檔案描述符 port :串列埠號(ttyS0,ttyS1,ttyS2) * 出口引數: 正確返回為1,錯誤返回為0 *******************************************************************/ int UART0_Open(int fd,char* port) { fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY); if (FALSE == fd) { perror("Can't Open Serial Port"); return(FALSE); } //恢復串列埠為阻塞狀態 if(fcntl(fd, F_SETFL, 0) < 0) { printf("fcntl failed!\n"); return(FALSE); } else { printf("fcntl=%d\n",fcntl(fd, F_SETFL,0)); } //測試是否為終端裝置 if(0 == isatty(STDIN_FILENO)) { printf("standard input is not a terminal device\n"); return(FALSE); } else { printf("isatty success!\n"); } printf("fd->open=%d\n",fd); return fd; } /******************************************************************* * 名稱: UART0_Close * 功能: 關閉串列埠並返回串列埠裝置檔案描述 * 入口引數: fd :檔案描述符 port :串列埠號(ttyS0,ttyS1,ttyS2) * 出口引數: void *******************************************************************/ void UART0_Close(int fd) { close(fd); } /******************************************************************* * 名稱: UART0_Set * 功能: 設定串列埠資料位,停止位和效驗位 * 入口引數: fd 串列埠檔案描述符 * speed 串列埠速度 * flow_ctrl 資料流控制 * databits 資料位 取值為 7 或者8 * stopbits 停止位 取值為 1 或者2 * parity 效驗型別 取值為N,E,O,,S *出口引數: 正確返回為1,錯誤返回為0 *******************************************************************/ int UART0_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; 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_oflag &= ~OPOST; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //options.c_lflag &= ~(ISIG | ICANON); //設定等待時間和最小接收字元 options.c_cc[VTIME] = 1; /* 讀取一個字元等待1*(1/10)s */ options.c_cc[VMIN] = 1; /* 讀取字元的最少個數為1 */ //如果發生資料溢位,接收資料,但是不再讀取 重新整理收到的資料但是不讀 tcflush(fd,TCIFLUSH); //啟用配置 (將修改後的termios資料設定到串列埠中) if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("com set error!\n"); return (FALSE); } return (TRUE); } /******************************************************************* * 名稱: UART0_Init() * 功能: 串列埠初始化 * 入口引數: fd : 檔案描述符 * speed : 串列埠速度 * flow_ctrl 資料流控制 * databits 資料位 取值為 7 或者8 * stopbits 停止位 取值為 1 或者2 * parity 效驗型別 取值為N,E,O,,S * * 出口引數: 正確返回為1,錯誤返回為0 *******************************************************************/ int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity) { int err; //設定串列埠資料幀格式 if (UART0_Set(fd,19200,0,8,1,'N') == FALSE) { return FALSE; } else { return TRUE; } } /******************************************************************* * 名稱: UART0_Recv * 功能: 接收串列埠資料 * 入口引數: fd :檔案描述符 * rcv_buf :接收串列埠中資料存入rcv_buf緩衝區中 * data_len :一幀資料的長度 * 出口引數: 正確返回為1,錯誤返回為0 *******************************************************************/ int UART0_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); printf("fs_sel = %d\n",fs_sel); if(fs_sel) { len = read(fd,rcv_buf,data_len); printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel); return len; } else { printf("Sorry,I am wrong!"); return FALSE; } } /******************************************************************** * 名稱: UART0_Send * 功能: 傳送資料 * 入口引數: fd :檔案描述符 * send_buf :存放串列埠傳送資料 * data_len :一幀資料的個數 * 出口引數: 正確返回為1,錯誤返回為0 *******************************************************************/ int UART0_Send(int fd, char *send_buf,int data_len) { int len = 0; len = write(fd,send_buf,data_len); if (len == data_len ) { printf("send data is %s\n",send_buf); return len; } else { tcflush(fd,TCOFLUSH); return FALSE; } } int main(int argc, char **argv) { int fd; //檔案描述符 int err; //返回呼叫函式的狀態 int len; int i; char rcv_buf[100]; //char send_buf[20]="tiger john"; char send_buf[20]="tiger john"; if(argc != 3) { printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]); return FALSE; } fd = UART0_Open(fd,argv[1]); //開啟串列埠,返回檔案描述符 do { err = UART0_Init(fd,19200,0,8,1,'N'); printf("Set Port Exactly!\n"); }while(FALSE == err || FALSE == fd); if(0 == strcmp(argv[2],"0")) { for(i = 0;i < 10;i++) { len = UART0_Send(fd,send_buf,10); if(len > 0) printf(" %d time send %d data successful\n",i,len); else printf("send data failed!\n"); sleep(2); } UART0_Close(fd); } else { while (1) //迴圈讀取資料 { len = UART0_Recv(fd, rcv_buf,99); if(len > 0) { rcv_buf[len] = '\0'; printf("receive data is %s\n",rcv_buf); printf("len = %d\n",len); } else { printf("cannot receive data\n"); } sleep(2); } UART0_Close(fd); } }