📄 main.c
字号:
#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> /*错误号定义*/#define TRUE 1#define FALSE 0/***@brief 设置串口通信速率*@param fd 类型 int 打开串口的文件句柄*@param speed 类型 int 串口速度*@return void*/int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, };int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, };/** * 为什么设置了speed_arr 和name_arr两个数组, * 这是因为在linux下,系统为波特率专门准备了一张表用B38400,B19200......代替, * 而我们实际上传进去的只能是38400,19200这些值,所以我们拿我们传进去的和name_arr进行比较, * 如果相等则从系统对照表中取出相应值进行设置, * 如果不等证明传的值在系统对照表中没有,则不进行设置。*/void set_speed(int fd, int speed){ int i; int status; struct termios Opt; //它包括了串口端所有的设置,下面还要用到。它在termios.h中被定义。 tcgetattr(fd, &Opt); //用来得到机器原端口的默认设置 for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { if (speed == name_arr[i]) //判断传进来是否相等 { tcflush(fd, TCIOFLUSH); //刷新输入输出缓冲 cfsetispeed(&Opt, speed_arr[i]);//这里分别设置 波特率 cfsetospeed(&Opt, speed_arr[i]); status = tcsetattr(fd, TCSANOW, &Opt); //这是立刻把bote rates设置真正写到串口中去 if (status != 0) perror("tcsetattr fd1"); //设置错误 return; } tcflush(fd,TCIOFLUSH); //刷新输入输出缓冲 }}/***@brief 设置串口数据位,停止位和效验位*@param fd 类型 int 打开的串口文件句柄**@param databits 类型 int 数据位 取值 为 7 或者8**@param stopbits 类型 int 停止位 取值为 1 或者2**@param parity 类型 int 效验类型 取值为N,E,O,,S*/int set_Parity(int fd,int databits,int stopbits,int parity){ struct termios options; if ( tcgetattr( fd,&options) != 0) //首先读取系统默认设置options中,必须! { perror("SetupSerial 1"); return(FALSE); } options.c_cflag &= ~CSIZE; //这是设置c_cflag选项不按位数据位掩码 switch (databits) /*设置数据位数*/ { case 7: options.c_cflag |= CS7; //设置c_cflag选项数据位为7位 break; case 8: options.c_cflag |= CS8; //设置c_cflag选项数据位为8位 break; default: fprintf(stderr,"Unsupported data size\n"); //其他的都不支持 return (FALSE); } switch (parity) //设置奇偶校验,c_cflag和c_iflag有效 { case 'n': case 'N': //无校验当然都不选 options.c_cflag &= ~PARENB; /* Clear parity enable */ options.c_iflag &= ~INPCK; /* Enable parity checking */ break; case 'o': case 'O': //奇校验 (Odd)其中PARENB校验位有效;PARODD奇校验INPCK检查校验 options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'e': case 'E': //偶校验(Even),奇校验不选就是偶校验了 options.c_cflag |= PARENB; /* Enable parity */ options.c_cflag &= ~PARODD; /* 转换为偶效验*/ options.c_iflag |= INPCK; /* Disnable parity checking */ break; case 'S': //Space(空白)效验 case 's': /*as no parity*/ options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; break; default: fprintf(stderr,"Unsupported parity\n"); return (FALSE); } /* 设置停止位*/ switch (stopbits) //这是设置停止位数,影响的标志是c_cflag { case 1: options.c_cflag &= ~CSTOPB; //不指明表示一位停止位 break; case 2: options.c_cflag |= CSTOPB; //指明CSTOPB表示两位,只有两种可能 break; default: fprintf(stderr,"Unsupported stop bits\n"); return (FALSE); } /* Set input parity option */ if (parity != 'n') //这是设置输入是否进行校验 options.c_iflag |= INPCK; /** * 这个地方是用来设置控制字符和超时参数的,一般默认即可。 * 稍微要注意的是c_cc数组的VSTART 和 VSTOP 元素被设定成DC1 和 DC3, * 代表ASCII 标准的XON和XOFF字符。所以如果在传输这两个字符的时候就传不过去, * 这时需要把软件流控制屏蔽 options.c_iflag &= ~(IXON | IXOFF | IXANY); */ options.c_cc[VTIME] = 150; // 15 seconds options.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); /* Update the options and do it NOW *///刷新和立刻写进去 if (tcsetattr(fd,TCSANOW,&options) != 0) { perror("SetupSerial 3"); return (FALSE); } return (TRUE); }/** * 串口设置框架到这里就大概结束了,对于设置了数据位校验位停止位和波特率的端口已经可以传输大多数信息。 * 在实际中的情况往往是很多特例,比如,在用write发送数据时没有键入回车,信息就将发送不出去的情况, * 这主要是因为我们在输出输入时是按照规范模式接受到回车或者换行才发送,而很多情况我们是不需要回车和换行的, * 这时,应当切换到行方式输入,设置options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); * 不经处理直接发送。又比如在我们发送字符0x0d的时候,往往接受端得到的字符是0x0a这是怎么回事, * 原因是在串口设置中c_iflag和c_oflag中存在从NL-CR 和CR-NL的映射,也就是说,串口可以把回车和换行看成一个字符, * 所以,此时我们应该屏蔽掉这些,用options.c_oflag &=~(INLCR|IGNCR|ICRNL|);和options.c_oflag &=~(ONLCR|OCRNL);进行设置。 * 总之,串口的设置是很复杂也很麻烦的东西,具体情况要具体分析,找到相应的办法,如果发现数据不能传送,不妨耐点心在串口设置上找答案吧 *//***@breif 打开串口*/int OpenDev(char *Dev){int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY 这种方式看open函数 if (-1 == fd) { /*设置数据位数*/ perror("Can't Open Serial Port"); return -1; } else return fd;}/***@breif main()*/int main(int argc, char **argv){ int fd; int nread; char buff[10]; char *dev ="/dev/ttyS0";// char *dev ="/dev/modem"; fd = OpenDev(dev); if (fd>0) set_speed(fd,9600); else { printf("Can't Open Serial Port!\n"); exit(0); } if (set_Parity(fd,8,1,'N')== FALSE) { printf("Set Parity Error\n"); exit(1); } /** * 一般读的时候一般都用read ,写的时候一般都用write,read要注意阻塞后程序停止不动, * 所以要用select 进行控制,注意tv每次循环都要设置;write 不用考虑阻塞, * 但要用循环写方式保证一定写完,其实读最好也用循环读方式保证一定能读到所有东西并且能拼接在一起, * 然后在进行其他操作。最后while (1) 是串口通讯中常用的循环就是一直执行,直到碰到break; * 这些东西挺烦琐,不过其实也没什么。这里就不详细说了,下面是个最最简单的。 */ while(1) { while((nread = read(fd,buff,10))>0) {// printf("\nLen %d\n",nread); buff[nread+1]='\0'; printf("\n%s",buff); } } //close(fd); //exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -