[置顶] Linux 串口编程中遇到的问题

    今年年初,工作闲暇之时在江西网上发布了做一些小程序的帖子,后面有一个公司老板跟我说有个项目:XXX需要用到串口编程,我那时一个是确实也有点忙,自己就只是抽了点空闲时间写了下linux的一个小串口程序,其实网上的大多程序都还是能用,我的就是稍微的改进了点,网上多数都只是能够设置串口的属性,然后读取这个串口上的消息并显示,我就改进了下,还可以自己手动输入...

     现在就贴下代码了:

.h文件

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <signal.h>
#include <sys/select.h>

#define STA_IN 0

int openSerial(int port);
int setSerialAtr(int fd,long bitRate,int dataBit,int stopBit,char Parity);
int writeSerial(int fd,char *write_buf);

int writeSerial2(int fd,unsigned char *write_buf);
int readSerial(int fd,char *read_buf,int bufLen);
int closeSerial(int fd);

。cpp文件

 

    #include "serial.h"


int openSerial(int port)
{
 int fd;
 char fileName[64] = {0};
 sprintf(fileName,"/dev/ttyS%d",port);
#ifdef DEBUG
 printf("%s %d fileName:%s/n",__FILE__,__LINE__,fileName);
#endif
 if((fd = open(fileName,O_RDWR)) < 0)
 {
  perror("fopen error!");
  return -1;
 }
 return fd;
}

int setSerialAtr(int fd,long bitRate,int dataBit,int stopBit,char Parity)
{
 struct termios opt;

 if(tcgetattr(fd,&opt) != 0)
 {
  perror("tcgetattr error!");
  return -1;
 }
 //设置比特率 
 opt.c_oflag &= ~ONOCR;
 opt.c_lflag &= ICANON;

 switch(bitRate)
 {
  case 0:
   cfsetispeed(&opt,B0);
   cfsetospeed(&opt,B0);
   break;
  case 50:
   cfsetispeed(&opt,B50);
   cfsetospeed(&opt,B50);
   break;
  case 75:
   cfsetispeed(&opt,B75);
   cfsetospeed(&opt,B75);
   break;
  case 110:
   cfsetispeed(&opt,B110);
   cfsetospeed(&opt,B110);
   break;
  case 134:
   cfsetispeed(&opt,B134);
   cfsetospeed(&opt,B134);
   break;
  case 150:
   cfsetispeed(&opt,B150);
   cfsetospeed(&opt,B150);
   break;
  case 200:
   cfsetispeed(&opt,B200);
   cfsetospeed(&opt,B200);
   break;
  case 300:
   cfsetispeed(&opt,B300);
   cfsetospeed(&opt,B300);
   break;
  case 600:
   cfsetispeed(&opt,B600);
   cfsetospeed(&opt,B600);
   break;
  case 1200:
   cfsetispeed(&opt,B1200);
   cfsetospeed(&opt,B1200);
   break;
  case 1800:
   cfsetispeed(&opt,B1800);
   cfsetospeed(&opt,B1800);
   break;
  case 2400:
   cfsetispeed(&opt,B2400);
   cfsetospeed(&opt,B2400);
   break;
  case 4800:
   cfsetispeed(&opt,B4800);
   cfsetospeed(&opt,B4800);
   break;
  case 9600:
   cfsetispeed(&opt,B9600);
   cfsetospeed(&opt,B9600);
   break;
  case 19200:
   cfsetispeed(&opt,B19200);
   cfsetospeed(&opt,B19200);
   break;
  case 38400:
   cfsetispeed(&opt,B38400);
   //printf("38400/n");
   cfsetospeed(&opt,B38400);
   break;
  case 57600:
   cfsetispeed(&opt,B57600);
   cfsetospeed(&opt,B57600);
   break;
  default:
   printf("wafeaef");
   break;
 }
 if(tcsetattr(fd,TCSANOW,&opt) != 0)
 {
  perror("tcsetattr error!");
  return -1;
 }
 tcflush(fd, TCIOFLUSH);
 //设置比特率结束
 
 //设置数据位开始
 opt.c_cflag &=~CSIZE;
 switch(dataBit)
 {
  case 5:
   opt.c_cflag |= CS5;
   break;
  case 6:
   opt.c_cflag |= CS6;
   break;
  case 7:
   opt.c_cflag |= CS7;
   break;
  case 8:
   opt.c_cflag |= CS8;
   break;
  default:
   perror("no support dataBit!");
   return -1;
 }
 //设置数据位结束
 tcflush(fd, TCIOFLUSH);
 //设置停止位开始
 switch (stopBit)
 {  
  case 1:   
   opt.c_cflag &= ~CSTOPB; 
   break; 
  case 2:   
   opt.c_cflag |= CSTOPB; 
      break;
  default:   
   fprintf(stderr,"Unsupported stop bits/n"); 
    return -1;
 }
 //设置停止位结束
 tcflush(fd, TCIOFLUSH); 
 //设置校验位
 switch(Parity)
 {
  case 'n':
  case 'N':
   opt.c_cflag &= ~PARENB;   /* Clear parity enable */
   opt.c_iflag &= ~INPCK;    /* Enable parity checking */
   opt.c_iflag &= IGNCR;     //忽略回车
   opt.c_iflag &= INLCR;
//   printf("set parity N ok!/n");
   break;
  case 'o':  
  case 'O':    
   opt.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ 
   opt.c_iflag |= INPCK;             /* Disnable parity checking */
   printf("set parity O ok!/n");
   break; 
  case 'e': 
  case 'E':  
   opt.c_cflag |= PARENB;     /* Enable parity */   
   opt.c_cflag &= ~PARODD;   /* 转换为偶效验*/    
   opt.c_iflag |= INPCK;       /* Disnable parity checking */
   printf("set parity E ok!/n");
   break;
  case 's':
  case 'S':
       opt.c_cflag &= ~PARENB;
   opt.c_cflag &= ~CSTOPB;
   printf("set parity s ok!/n");
   break;
  default:  
   fprintf(stderr,"Unsupported parity/n");   
   return -1; 
 }
 if (Parity != 'n')  
  opt.c_iflag |= INPCK;
 tcflush(fd,TCIFLUSH);
 opt.c_cc[VTIME] = 150; /* 设置超时15 seconds*/  
 opt.c_cc[VMIN] = 0; /* Update the options and do it NOW */
 if (tcsetattr(fd,TCSANOW,&opt) != 0)  
 {
  perror("SetupSerial 3");  
  return -1; 
 }
 //设置结束 
 return 0;
}

int writeSerial(int fd,unsigned char *write_buf)
{
 //int totalLen = strlen(write_buf);
 int writeLen = 0;
 if((writeLen = write(fd,write_buf,1)) < 0)
 {
  perror("write error!");
  return -1;
 }
 //printf("%s %d %d %d/n",__FILE__,__LINE__,*write_buf,writeLen);
 return 0;
}

int writeSerial2(int fd,unsigned char *write_buf)
{
 int totalLen = strlen(write_buf);
 int writeLen = 0;
 if((writeLen = write(fd,write_buf,totalLen)) < 0)
 {
  perror("write error!");
  return -1;
 }
 //printf("%s %d %d %d/n",__FILE__,__LINE__,*write_buf,writeLen);
 return 0;
}

int readSerial(int fd,char *read_buf,int bufLen)
{
 int readLen = 0;
 if((readLen = read(fd,read_buf,bufLen-1)) <= 0)
 {
  perror("read error!");
  return -1;
 }
 read_buf[readLen] = '/0';
 return readLen;
}

int closeSerial(int fd)
{
 close(fd);
}

unsigned char analyzeArgs(char *args)
{
 unsigned char sub = 0;
 
 if(2 != strlen(args))
 {
  return -1;
 }
 if((args[0] >= '0' && args[0] <= '9'))
 {
  sub += (args[0]-'0')*16;
 }
 else if(args[0] >= 'a' && args[0] <= 'f')
 {
  sub += (args[0] - 'a'+10)*16;
 }
 else if(args[0] >= 'A' && args[0] <= 'F')
 {
  sub += (args[0]-'A'+10)*16;
 }
 else
 {
  return -1;
 }
 
 if((args[1] >= '0' && args[1] <= '9'))
 {
  sub += args[1]-'0';
 }
 else if(args[1] >= 'a' && args[1] <= 'f')
 {
  sub += args[1] - 'a'+10;
 }
 else if(args[1] >= 'A' && args[1] <= 'F')
 {
  sub += args[1]-'A'+10;
 }
 else
 {
  return -1;
 }
 return sub;
}

int main(int argc,char* argv[])
{
 int serialNum,databit,stopbit;
 long int bitrate;
 unsigned char parity;
 int fd;
 char read_buf[1024] = {0};
 char write_buf[2] = {0};
 char c = '/0';
 unsigned char arg = 0;
 int i = 2;
 
 fd_set fds;
 int retSelect;
 struct timeval timeout;
 if(argc < 2)
 {
  printf("useage:exec bitrate(比特率) args(需要写进串口的数据,类似00 1F bF等)/n");
  return -1;
 }
 serialNum = 0;//打开/dev/stty0
 bitrate = atol(argv[1]);//波特率
 databit = 8;//数据位
 stopbit = 1;//停止位
 parity = 'n';//校验位
 
 timeout.tv_sec = 2;
 timeout.tv_usec = 0;
 
 fd = openSerial(serialNum);
// printf("args:%d %d %d %d %c/n",fd,bitrate,databit,stopbit,parity);
 if(setSerialAtr(fd,bitrate,databit,stopbit,parity) != 0)
 {
  printf("setSerialAtr error!/n");
  return -1;
 }
 

 printf("wrtie data: ");
 for(i = 2;i < argc;i++)
 {
  arg = analyzeArgs(argv[i]);
  if(-1 != arg)
  {
//   sprintf(write_buf,"%02x",arg);
   printf("%02x ",arg);
   writeSerial(fd,&arg);
  }
 }
 printf("/n");
 
 while(1)
 {
  FD_ZERO(&fds);
  FD_SET(STA_IN,&fds);
  FD_SET(fd,&fds);
  retSelect = select(fd+1,&fds,NULL,NULL,&timeout);
  switch(retSelect)
  {
   case -1:
    perror("select error!");
    return -1;
   case 0:
    //printf("no data/n");
    break;
    
   default:
    //printf("-----------/n");
    if(FD_ISSET(STA_IN,&fds))
    {
     if(read(STA_IN,write_buf,256) > 0)
     {
      writeSerial2(fd,write_buf);
      memset(write_buf,0,256);
      //while((c=getchar())!='/n'&&c!=EOF);
      //setbuf(STA_IN,NULL);
      //fflush(STA_IN);
     }     
    }
    else if(FD_ISSET(fd,&fds))
    {
     if(readSerial(fd,read_buf,1024)> 0)
     {
      printf("%s",read_buf);
      memset(read_buf,0,1024);
     }
    }
    else
    {
     printf("error!!!!/n");
    }
    break;
  }
 }
 
  
 closeSerial(fd);
}

 

makefile:

CC=gcc
export CFLAGS += -DDEBUG
all:serial

serial:serial.c serial.h
 $(CC) $(CFLAGS) -o serial serial.c

clean:
 rm -f serial.c.bak
 rm -f serial.h.bak
 rm -f Makefile.bak
 rm -f core*
 rm -f serial

 

程序就到此为止,这个我觉得写程序你可以写出来,问题是你要调试,你要保证你的程序是准确无误的,在虚拟机下有一个方法:通过添加一个串口,使用PC上的COM口,这样你就可以通过串口调试工具配合调试,用串口调试工具写(这个方法不行,串口不能被两个程序同时打开读写:虚拟机,串口调试工具;方法只有通过一个嵌入式设备接对应的COM口),你的虚拟机执行这个执行档接收写的数据,看看能不能正常接收,如果可以说明你的程序是正确的,这样你才可以放心使用。

      今天我们的板子想不到就需要这样的一个小程序,对云台的485口进行测试,呵呵,正好用到,可是我拿来那个程序都忘了怎么用,想到了原来的调试方法但是始终没有输出,后面郁闷了半天终于想到虚拟机的串口没有连接上...好郁闷...

你可能感兴趣的:(编程,linux,虚拟机,null,工具,makefile)