有关linux串口通信

来源:互联网 发布:mac如何卸载app 编辑:程序博客网 时间:2024/06/14 12:45

有关linux串口通信

Talk is cheap,show me the code.

COM_Linux.h#ifndef __COM_LINUX_H__#define __COM_LINUX_H__#define MAX_BUF 512 //串口数据缓冲最大字节数#define MIN(A,B) (A<B?A:B)int COM_open(char*);int COM_set(int,int,int,int,char,char);int COM_BufQueSize(int,int*);int COM_recv(int,char*,int);int COM_transmit(int,char*,int);#endif
#include <stdio.h>      /*开头两个头文件就不多说了*/#include <stdlib.h>#include <string.h>     /*字符串操作会用到*/#include <unistd.h>     /*Unix标准函数定义 unix std*/#include <fcntl.h>      /*文件控制定义 file control*/#include <termios.h>    /*POSIX 终端控制定义*/#include <errno.h>      /*错误号定义*/#include <sys/ioctl.h>#include "COM_Linux.h"/****************************************************** * 名称:  COM_open * 功能:  打开串口并返回串口设备文件描述 * 传参:  fd:文件描述符 port:串口号(ttyS0,ttyUSB0...) * 返回:  正确 fd 错误 -1*******************************************************/int COM_open(char* port) {    int fd=-1;     fd=open(port,O_RDWR|O_NOCTTY|O_NDELAY);     /*open函数代表打开串口设备     * 一般推荐的标志位参数如上述,通过|运算组合     *O_RDWR 以可读写方式打开文件     *O_NOCTTY 表明本程序非串口上的控制终端,不受组合键信号影响     *O_DELAY 表示忽略DCD信号线状态(另一端是否已经链接)     *否则open函数会阻塞等待DCD信号,导致程序丢失相应*/     if(-1 == fd){        perror("Unable to Open Uart\n");         return -1;     }else{        printf("fd->open=%d\n",fd);     }     //恢复串口为阻塞状态     if(fcntl(fd,F_SETFL,0)<0){         printf("set flag error!\n");             return -1;     }else{        printf("fcntl=%d\n",fcntl(fd,F_SETFL,0));     }     return fd;}/******************************************** * 名称:                  COM_close * 功能:              关闭串口 * 入口参数:            fd * 出口参数:            成功 0    错误 -1 * ******************************************/int COM_close(fd){    if(fd<0) return -1;    if(close(fd)==-1) return -1;    printf("Close Uart\n");    return 0;}/************************************************************ * 名称:      COM_set * 功能:      置串口各项参数 * 入口参数:    fd *              baud        串口速度,即波特率 4800 9600 115200 *              data_bit    数据位 一个字节的数据位个数 7、8 *              stop_bit    停止位 停止位个数 1、2 *              parity      校验类型 N:无校验 O:奇校验ODD E: 偶校验EVEN *              flow_ctrl   数据流控制 N:无 S:软件流 H:硬件流 * 出口参数:    正确0,错误-1 * ********************************************************/int COM_set(int fd,int baud,int data_bit,int stop_bit,char parity,char flow_ctrl){    struct termios options;    //tcgetattr(fd,&options)得到fd指向对象的相关参数    //保存在termios定义的结构体内    //且可测试配置是否正确,调用成功返回0,失败返回-1    if(tcgetattr(fd,&options)!=0){        perror("Set com error\n");          return -1;    }    switch(baud){    case 4800:        /*c_cflag成员用于描述串口硬件控制 用于波特率 校验 数据位 停止 控制流等         * 所有的都是位操作,通过位运算的与或非关系来设置或清楚相关标志 */        options.c_cflag=B4800;        break;    case 9600:        options.c_cflag=B9600;        break;    case 115200:        options.c_cflag=B115200;        break;    default:        options.c_cflag=B9600;        break;    }    switch(data_bit){    case 7:        options.c_cflag&=~CSIZE;        options.c_cflag|=CS7;        break;    case 8:        options.c_cflag&=~CSIZE;        options.c_cflag|=CS8;        break;    default:        options.c_cflag&=~CSIZE;        options.c_cflag|=CS8;        break;    }    switch(stop_bit){    case 1:        options.c_cflag&=~CSTOPB;        break;    case 2:        options.c_cflag|=CSTOPB;        break;    default:        options.c_cflag&=~CSTOPB;        break;    }    switch(parity){    case 'N':        options.c_cflag&=~PARENB; //无奇偶校验        //c_iflag 控制串口数据输入 如剥离输入字符为8位 奇偶校验生效等        options.c_iflag&=~(INPCK|ISTRIP); //禁用输入奇偶校验        options.c_iflag|=IGNPAR; //忽略奇偶校验错误        break;    case 'O':        options.c_cflag|=(PARENB|PARODD); //启用校验并设置为奇校验        options.c_iflag|=(INPCK|ISTRIP); //启用奇偶检查并从接受字符串中脱去奇偶位        options.c_iflag&=~IGNPAR; //不忽略奇偶校验错误        break;    case 'E':        options.c_cflag|=PARENB; //启用奇偶校验        options.c_cflag&=~PARODD; //设置为偶校验        options.c_iflag|=(INPCK|ISTRIP); //启用检查并从中脱去奇偶校验位        options.c_iflag&=~IGNPAR; //不忽略校验错误        break;    default:        options.c_cflag&=~PARENB;        options.c_iflag&=~(INPCK|ISTRIP);        options.c_iflag|=IGNPAR;        break;    }    switch(flow_ctrl){    case 'N':        options.c_cflag&=~CRTSCTS; //停用硬件流控制        options.c_iflag&=~(IXON|IXOFF|IXANY);//停用软件控制流        options.c_cflag|=CLOCAL; //不使用流控制        break;    case 'S':        options.c_cflag&=~CRTSCTS; //停用硬件流控制        options.c_iflag|=(IXON|IXOFF|IXANY);//使用软件流控制        options.c_cflag&=~CLOCAL; //使用流控制        break;    case 'H':        options.c_cflag|=CRTSCTS;        options.c_iflag&=~(IXON|IXOFF|IXANY);//使用硬件流控制        options.c_cflag&=~CLOCAL; //使用流控制        break;    default:        options.c_cflag&=~CRTSCTS;        options.c_iflag&=~(IXON|IXOFF|IXANY);        options.c_cflag|=CLOCAL;        break;    }    options.c_cflag|=CREAD; //启用接收器,能够从串口中读取数据    options.c_iflag|=IGNBRK; //忽略输入行终止条件    //c_lflag设置串口驱动与用户间界面    options.c_lflag=0;//非加工输入,即显示原始数据    options.c_oflag=0;//非加工输出    //options.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);    //options.c_oflag &= ~OPOST;    /*c_cc成员数组,索引宏常量     * 还可以设置超时参数,通过VMIN和VTIME引用     * 但只在非加工方式才有实际意义     * 分别控制等待字节数和等待时长,单位0.1s*/    //如果串口输入队列没有数据,将在read调用处阻塞    options.c_cc[VMIN] = 1;    options.c_cc[VTIME] = 0;    if(tcsetattr(fd,TCSANOW,&options)==-1){        printf("set error\n");          return -1;    }    tcflush(fd,TCIFLUSH); //刷新收到的数据,但是不读    tcflush(fd,TCOFLUSH); //刷新写入的数据,但不传送    return 0;}/***************************************************** * 名称:      COM_BufQueSize * 功能:      得到串口输入队列中的字节数 * 传参:      fd *              buf_size 字节数会保存在该指针指向内存 * 返回:      正确 0 错误 -1 ****************************************************/ int COM_BufQueSize(int fd,int* buf_size) {    int byte_count=0;    if(fd == -1)        return -1;    //使用ioctl系统调用来实现配置串口    //任何IO操作都可以交给它    //此处的FIONREAD为返回输入队列中的字节数    if(ioctl(fd,FIONREAD,&byte_count)!=-1){        *buf_size=byte_count;        return 0;    }    return -1; }/***************************************************** * 名称:      COM_recv * 功能:      接受串口数据 * 传参:      fd *              recv_buf    读出串口数据存入recv_buf字符串 *              data_len    一帧读取数据的长度 * 返回:      正确 所读字节数    错误 -1 * *****************************************************/int COM_recv(int fd,char* recv_buf,int data_len){    int rCount=0; //实际读到的字节数    int recvBytes=0; //实际接受字节数,可能大于最大缓冲    int QueSize=0; //输入队列字节数    if(fd<0){        perror("file description is valid\n");          return -1;    }    if(recv_buf==NULL){        perror("read buf is NULL\n");           return -1;    }    if(data_len>MAX_BUF) //大于最大缓冲区的分开处理        recvBytes=MAX_BUF;    else         recvBytes=data_len;    memset(recv_buf,'\0',recvBytes); //清空字符串    if(COM_BufQueSize(fd,&QueSize)!=-1){ //获取输入队列字节数        printf("Uart Queue have %d bytes\n",QueSize);           recvBytes=MIN(recvBytes,QueSize); //取其中的较小值作为接受字节数    }    if(!recvBytes) return -1;    rCount=read(fd,recv_buf,recvBytes);    if(rCount<0){        perror("read error\n");         return -1;    }    return rCount;}/************************************************* * 名称:      COM_transmit * 功能:      发送数据 * 传参:      fd   *              mit_buf 将指向缓冲区数据写入串口 *              data_len 写入的字节数长度    * 返回:      成功返回 实际写入字节数  失败 -1 * **********************************************/int COM_transmit(int fd,char* mit_buf,int data_len){    int wCount=0;  //实际写入字节数长度      int mitBytes=data_len;    if(fd<0){        perror("file description is valid\n");          return -1;    }    if((mitBytes>MAX_BUF)||!mitBytes) return -1;    wCount=write(fd,mit_buf,mitBytes);    if(wCount<0){        perror("write error\n");            return -1;    }    while(tcdrain(fd)==-1); //保证输出队列中所有数据被传送    return wCount;}
main.c#include "COM_Linux.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#define CMD_MAX_LEN 255int main(int argc,char *argv[]){    char Read_Buf[MAX_BUF+1]; //存储读取数据    char Write_Buf[MAX_BUF+1]; //存储发送数据    char CMD[CMD_MAX_LEN+1]; //命令控制字符串    int rCount=0;    int wCount=0;    int fd,com_port;    if(argc<3){        printf("please fill the parameter\n");          return -1;    }    if((fd=COM_open(argv[1]))==-1) return -1;       //if((fd=COM_open("/dev/ttyS1"))==-1) return -1;    com_port=atoi(argv[2]); //将字符串转换为int整数    if(COM_set(fd,com_port,8,1,'N','N')==-1){        COM_close(fd);          return -1;    }    while(1){        memset(CMD,'\0',CMD_MAX_LEN+1); //清空        printf("Enter Command: \n");        if(!fgets(CMD,CMD_MAX_LEN+1,stdin)){ //从stdin流,键盘获取输入            perror("fget error\n");             return -1;        }        /*fgets函数当遇到换行符和缓冲区已满,即会停止返回         *所以在不填满缓冲区的正常情况下          fgets获取的数据包括输入字符串加上回车换行符并在最后加上'\0'          如输入hello后回车,得到的strlen长度应为hello的5个字符长度          加一个\n回车以及最后的\0结束符,共7个          但strlen函数不包括结束符号,所以只有共6个          此处的CMD字符串应当将'\n'替换成'\0',便于后续比较str compare          '\n'位于strlen长度最后一位,数组索引需减1*/        //printf("111%c222%c333",CMD[strlen(CMD)],CMD[strlen(CMD)-1]);        CMD[strlen(CMD)-1]='\0';        if(strncmp(CMD,"quit",sizeof("quit"))==0) break; //退出命令         if(strncmp(CMD,"read",sizeof("read"))==0){            memset(Read_Buf,'\0',MAX_BUF+1);                rCount=COM_recv(fd,Read_Buf,MAX_BUF);            if(rCount>0){                printf("ReadBuffer: %s\n",Read_Buf); //向屏幕打印获取数据                printf("Read com char num: %d\n",rCount);            }        }        if(strncmp(CMD,"write",sizeof("write"))==0){            memset(Write_Buf,'\0',MAX_BUF+1);               strcpy(Write_Buf,"Hello");            printf("Write_Buf:%s\n",Write_Buf);            wCount=COM_transmit(fd,Write_Buf,strlen((char*)Write_Buf));            sleep(1);            memset(Read_Buf,'\0',MAX_BUF+1);        }    }    COM_close(fd);    return 0;}
原创粉丝点击