https://blog.csdn.net/tigerjibo/article/details/6179291
1 #include<stdio.h> /*标准输入输出定义*/ 2 #include<stdlib.h> /*标准函数库定义*/ 3 #include<unistd.h> /*Unix 标准函数定义*/ 4 #include<sys/types.h> 5 #include<sys/stat.h> 6 #include<fcntl.h> /*文件控制定义*/ 7 #include<termios.h> /*PPSIX 终端控制定义*/ 8 #include<errno.h> /*错误号定义*/ 9 #include<string.h> 10 11 #define FALSE -1 12 #define TRUE 0 13 14 int UART0_Open(int fd,char* port) 15 { 16 17 fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY); 18 if (FALSE == fd) 19 { 20 perror("Can't Open Serial Port"); 21 return(FALSE); 22 } 23 //恢复串口为阻塞状态 24 if(fcntl(fd, F_SETFL, 0) < 0) 25 { 26 printf("fcntl failed!\n"); 27 return(FALSE); 28 } 29 else 30 { 31 printf("fcntl=%d\n",fcntl(fd, F_SETFL,0)); 32 } 33 //测试是否为终端设备 34 if(0 == isatty(STDIN_FILENO)) 35 { 36 printf("standard input is not a terminal device\n"); 37 return(FALSE); 38 } 39 else 40 { 41 printf("isatty success!\n"); 42 } 43 printf("fd->open=%d\n",fd); 44 return fd; 45 } 46 /******************************************************************* 47 * 名称: close_uart 48 * 功能: 关闭串口并返回串口设备文件描述 49 * 入口参数: fd :文件描述符 port :串口号(ttyS0,ttyS1,ttyS2) 50 * 出口参数: void 51 *******************************************************************/ 52 53 void close_uart(int fd) 54 { 55 close(fd); 56 } 57 58 /******************************************************************* 59 * 名称: UART0_Set 60 * 功能: 设置串口数据位,停止位和效验位 61 * 入口参数: fd 串口文件描述符 62 * speed 串口速度 63 * flow_ctrl 数据流控制 64 * databits 数据位 取值为 7 或者8 65 * stopbits 停止位 取值为 1 或者2 66 * parity 效验类型 取值为N,E,O,,S 67 *出口参数: 正确返回为1,错误返回为0 68 *******************************************************************/ 69 int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity) 70 { 71 72 int i; 73 int status; 74 int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300}; 75 int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300}; 76 struct termios options; 77 78 /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1. 79 */ 80 if ( tcgetattr( fd,&options) != 0) 81 { 82 perror("SetupSerial 1"); 83 return(FALSE); 84 } 85 86 //设置串口输入波特率和输出波特率 87 for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) 88 { 89 if(speed == name_arr[i]) 90 { 91 cfsetispeed(&options, speed_arr[i]); 92 cfsetospeed(&options, speed_arr[i]); 93 } 94 } 95 96 //修改控制模式,保证程序不会占用串口 97 options.c_cflag |= CLOCAL; 98 //修改控制模式,使得能够从串口中读取输入数据 99 options.c_cflag |= CREAD; 100 101 //设置数据流控制 102 switch(flow_ctrl) 103 { 104 105 case 0 ://不使用流控制 106 options.c_cflag &= ~CRTSCTS; 107 break; 108 109 case 1 ://使用硬件流控制 110 options.c_cflag |= CRTSCTS; 111 break; 112 case 2 ://使用软件流控制 113 options.c_cflag |= IXON | IXOFF | IXANY; 114 break; 115 } 116 //设置数据位 117 //屏蔽其他标志位 118 options.c_cflag &= ~CSIZE; 119 switch (databits) 120 { 121 case 5: 122 options.c_cflag |= CS5; 123 break; 124 case 6: 125 options.c_cflag |= CS6; 126 break; 127 case 7: 128 options.c_cflag |= CS7; 129 break; 130 case 8: 131 options.c_cflag |= CS8; 132 break; 133 default: 134 fprintf(stderr,"Unsupported data size\n"); 135 return (FALSE); 136 } 137 //设置校验位 138 switch (parity) 139 { 140 case 'n': 141 case 'N': //无奇偶校验位。 142 options.c_cflag &= ~PARENB; 143 options.c_iflag &= ~INPCK; 144 break; 145 case 'o': 146 case 'O'://设置为奇校验 147 options.c_cflag |= (PARODD | PARENB); 148 options.c_iflag |= INPCK; 149 break; 150 case 'e': 151 case 'E'://设置为偶校验 152 options.c_cflag |= PARENB; 153 options.c_cflag &= ~PARODD; 154 options.c_iflag |= INPCK; 155 break; 156 case 's': 157 case 'S': //设置为空格 158 options.c_cflag &= ~PARENB; 159 options.c_cflag &= ~CSTOPB; 160 break; 161 default: 162 fprintf(stderr,"Unsupported parity\n"); 163 return (FALSE); 164 } 165 // 设置停止位 166 switch (stopbits) 167 { 168 case 1: 169 options.c_cflag &= ~CSTOPB; break; 170 case 2: 171 options.c_cflag |= CSTOPB; break; 172 default: 173 fprintf(stderr,"Unsupported stop bits\n"); 174 return (FALSE); 175 } 176 177 //修改输出模式,原始数据输出 178 options.c_oflag &= ~OPOST; 179 180 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//我加的 181 //options.c_lflag &= ~(ISIG | ICANON); 182 183 //设置等待时间和最小接收字符 184 options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */ 185 options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */ 186 187 //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读 188 tcflush(fd,TCIFLUSH); 189 190 //激活配置 (将修改后的termios数据设置到串口中) 191 if (tcsetattr(fd,TCSANOW,&options) != 0) 192 { 193 perror("com set error!\n"); 194 return (FALSE); 195 } 196 return (TRUE); 197 } 198 /******************************************************************* 199 * 名称: UART0_Init() 200 * 功能: 串口初始化 201 * 入口参数: fd : 文件描述符 202 * speed : 串口速度 203 * flow_ctrl 数据流控制 204 * databits 数据位 取值为 7 或者8 205 * stopbits 停止位 取值为 1 或者2 206 * parity 效验类型 取值为N,E,O,,S 207 * 208 * 出口参数: 正确返回为1,错误返回为0 209 *******************************************************************/ 210 int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity) 211 { 212 int err; 213 //设置串口数据帧格式 214 if (UART0_Set(fd,19200,0,8,1,'N') == FALSE) 215 { 216 return FALSE; 217 } 218 else 219 { 220 return TRUE; 221 } 222 } 223 224 /******************************************************************* 225 * 名称: UART0_Recv 226 * 功能: 接收串口数据 227 * 入口参数: fd :文件描述符 228 * rcv_buf :接收串口中数据存入rcv_buf缓冲区中 229 * data_len :一帧数据的长度 230 * 出口参数: 正确返回为1,错误返回为0 231 *******************************************************************/ 232 int UART0_Recv(int fd, char *rcv_buf,int data_len) 233 { 234 int len,fs_sel; 235 fd_set fs_read; 236 237 struct timeval time; 238 239 FD_ZERO(&fs_read); 240 FD_SET(fd,&fs_read); 241 242 time.tv_sec = 10; 243 time.tv_usec = 0; 244 245 //使用select实现串口的多路通信 246 fs_sel = select(fd+1,&fs_read,NULL,NULL,&time); 247 if(fs_sel) 248 { 249 len = read(fd,rcv_buf,data_len); 250 printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel); 251 return len; 252 } 253 else 254 { 255 printf("Sorry,I am wrong!"); 256 return FALSE; 257 } 258 } 259 /******************************************************************** 260 * 名称: UART0_Send 261 * 功能: 发送数据 262 * 入口参数: fd :文件描述符 263 * send_buf :存放串口发送数据 264 * data_len :一帧数据的个数 265 * 出口参数: 正确返回为1,错误返回为0 266 *******************************************************************/ 267 int UART0_Send(int fd, char *send_buf,int data_len) 268 { 269 int len = 0; 270 271 len = write(fd,send_buf,data_len); 272 if (len == data_len ) 273 { 274 return len; 275 } 276 else 277 { 278 279 tcflush(fd,TCOFLUSH); 280 return FALSE; 281 } 282 } 283 284 int main(int argc, char **argv) 285 { 286 int fd; //文件描述符 287 int err; //返回调用函数的状态 288 int len; 289 int i; 290 char rcv_buf[100]; 291 char send_buf[20]="tiger john"; 292 if(argc != 3) 293 { 294 printf("Usage: %s /dev/ttySn 0(send data)/1 (receive data) \n",argv[0]); 295 return FALSE; 296 } 297 fd = UART0_Open(fd,argv[1]); //打开串口,返回文件描述符 298 do{ 299 err = UART0_Init(fd,19200,0,8,1,'N'); 300 printf("Set Port Exactly!\n"); 301 }while(FALSE == err || FALSE == fd); 302 303 if(0 == strcmp(argv[2],"0")) 304 { 305 for(i = 0;i < 10;i++) 306 { 307 len = UART0_Send(fd,send_buf,10); 308 if(len > 0) 309 printf(" %d send data successful\n",i); 310 else 311 printf("send data failed!\n"); 312 313 sleep(2); 314 } 315 UART0_Close(fd); 316 } 317 else 318 { 319 while (1) //循环读取数据 320 { 321 len = UART0_Recv(fd, rcv_buf,9); 322 if(len > 0) 323 { 324 rcv_buf[len] = '\0'; 325 printf("receive data is %s\n",rcv_buf); 326 printf("len = %d\n",len); 327 } 328 else 329 { 330 printf("cannot receive data\n"); 331 } 332 sleep(2); 333 } 334 UART0_Close(fd); 335 } 336 }