Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1264631
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2008-12-16 14:37:20

这个例子是在网上找的,修改一下就可以用到实际的项目中(后面给出在DVS中的实际应用)
应用程序——串口编程
#include           /*标准输入输出定义*/
#include          /*标准函数库定义*/
#include          /*Unix标准函数定义*/
#include       /**/
#include        /**/
#include           /*文件控制定义*/
#include         /*PPSIX终端控制定义*/
#include           /*错误号定义*/
/*
  设置串口通信速率
  fd     类型 int  打开串口的文件句柄
  speed  类型 int  串口速度
  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, };
void set_speed(int fd, int speed)
{
  int   i;
  int   status;
  struct termios   Opt;
  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);
      if  (status != 0)
             perror("tcsetattr fd1");
       return;
      }
   tcflush(fd,TCIOFLUSH);
   }
}
/**
   设置串口数据位,停止位和效验位
  fd       类型  int  打开的串口文件句柄*
  databits 类型  int  数据位   取值 为 7 或者8*
  stopbits 类型  int  停止位   取值为 1 或者2*
  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)
  {
   perror("SetupSerial 1");
   return(FALSE);
  }
  options.c_cflag &= ~CSIZE;
  switch (databits) /*设置数据位数*/
  {
   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;   /* Clear parity enable */
   options.c_iflag &= ~INPCK;     /* Enable parity checking */
   break;
  case 'o':
  case 'O':
   options.c_cflag |= (PARODD | PARENB);  /* 设置为奇效验*/
   options.c_iflag |= INPCK;             /* Disnable parity checking */
   break;
  case 'e':
  case 'E':
   options.c_cflag |= PARENB;     /* Enable parity */
   options.c_cflag &= ~PARODD;   /* 转换为偶效验*/ 
   options.c_iflag |= INPCK;       /* Disnable parity checking */
   break;
  case 'S':
  case 's':  /*as no parity*/
   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);
  }
   /* Set input parity option */
   if (parity != 'n')
     options.c_iflag |= INPCK;
     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);
 }
/**
打开串口
*/
int OpenDev(char *Dev)
{
int fd = open( Dev, O_RDWR );         //| O_NOCTTY | O_NDELAY
 if (-1 == fd)
  { /*设置数据位数*/
   perror("Can't Open Serial Port");
   return -1;
  }
 else
 return fd;
}

/*
 main()
*/
int main(int argc, char **argv)
{
 int fd;
 int nread;
 char buff[512];
 char *dev ="/dev/ttyS1";
 fd = OpenDev(dev);
 if (fd>0)
    set_speed(fd,19200);
 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);
  }
  while(1)
   {
     while((nread = read(fd,buff,512))>0)
     {
        printf("\nLen %d\n",nread);
        buff[nread+1]='\0';
        printf("\n%s",buff);
      }
   }
    //close(fd);
    //exit(0);
}
 
 
 
 
 
DVS:
/*********************************************************************************
* 系统头文件  *.h
**********************************************************************************/
#include
#include
#include
#include
#include  
#include      
#include
#include
#include  
#include
#include  
#include  
#include  
#include       
#include      
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "def_type.h"
#include "app.h"
#include "Comapi.h"
//=======================================================================//
// 功能: 完成串口设备的打开,与底层交互设备状态
// 参数: void
// 返回: -1 打开失败 >0 打开成功
// 说明: 打开串口1
//=======================================================================//
int baudrate = 9600;
int databit = 8;
int stopbit = 1;
int parity = 0;
int flowcontrol = 0;
int OpenCom()
{
 char dev[]="/dev/ttyAMA1";
 int fdcom = open(dev, O_RDWR);
 fcntl(fdcom,F_SETFL,O_NONBLOCK);
 if (-1 == fdcom)
 {
  perror("Can't Open Serial Port");
  return -1;
 }
 else
  return fdcom;
}
//=======================================================================//
// 功能: 设置串口设备的波特率,与底层交互设备状态,完成波特率的设置
// 参数: int fd 文件描述符,int speed 串口速率
// 返回: 无
// 说明: 完成串口设备的波特率设置
//=======================================================================//
void Set_Speed(int fd, int speed)
{
 app_SetSysValue(dbserialbaudrate,speed);
 int speed_arr[] = { B115200, B57600, B38400, B19200, B9600,B4800,B2400,B1200,B600,B300,B150,B110,B75,B50,
      B115200, B57600, B38400, B19200, B9600,B4800,B2400,B1200,B600,B300,B150,B110,B75,B50,};
 int name_arr[] =  { 115200, 57600, 38400, 19200, 9600,4800,2400,1200,600,300,150,110,75,50,
      115200, 57600, 38400, 19200, 9600,4800,2400,1200,600,300,150,110,75,50};
    unsigned int i;
 int   status;
 struct termios   Opt;
 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);
   if  (status != 0)
    perror("tcsetattr fd");
   return;
  }
  tcflush(fd,TCIOFLUSH);
 }
}
//=======================================================================//
// 功能: 设置串口设备属性,与底层交互设备状态,完成数据位,停止位,奇偶校验,流控位的设置
// 参数: int fd 文件描述符,int databit 数据位,int parity  奇偶校验,int flowctrl 流控位
// 返回: 无
// 说明: 完成串口设备属性,与底层交互设备状态,完成数据位,停止位,奇偶校验,流控位的设置
//=======================================================================//
int Set_Com(int fd,int databit,int stopbit,int parity, int flowctrl)
{
 struct termios options;
 if( tcgetattr( fd,&options)  !=  0)
 {
  perror("SetupSerial 1");
  return -1;
 }
 options.c_cflag &= ~CSIZE;
 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
 options.c_oflag &= ~OPOST;   /*OutPUT*/
 switch (databit)  /* 设置数据位数 */
 {
 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");
  break;
 }
 switch (stopbit)     /* 设置停止位*/  
 {
 case 1:
  options.c_cflag &= ~CSTOPB;
  break;
 case 2:
  options.c_cflag |= CSTOPB;
  break;
 default:
  fprintf(stderr,"Unsupported stop bits\n");
  break;
 }
 switch (parity)   /* 设置奇偶校验位 */
 {
 case 0:
  options.c_cflag &= ~PARENB;     /* no parity check */
  options.c_cflag &= ~CSTOPB;
  break;
 case 1:
  options.c_cflag |= PARENB;  /* odd check */
  options.c_cflag &=~PARODD;
  options.c_iflag |=INPCK;
  break;
 case 2:
  options.c_cflag |= PARENB;  /* even check */
  options.c_cflag |= PARODD;
  options.c_iflag |= INPCK;
  break; 
 }
 switch (flowctrl)              /* 设置流控制*/
 {
 case 0:
  options.c_cflag &= ~CRTSCTS;   /*no flow control*/
  break;
 case 1:
  options.c_cflag |= CRTSCTS;    /*hardware flow control*/
  break;
 case 2:
  options.c_cflag |= IXON|IXOFF|IXANY; /*software flow control*/
  break;
 }
 /* Set input parity option */
 if (parity != 0)
  options.c_iflag |= INPCK;
  options.c_oflag &=~OPOST;      //输出模式原始数据输出
  options.c_cc[VTIME] = 150;      // 150    15 seconds 控制字符,读取第一个字符的等待时间
  options.c_cc[VMIN] = 0;       // 0     控制字符,所要读取的字符的最小数量
  tcflush(fd,TCIFLUSH);          //溢出的数据可以接收,但不读
 if (tcsetattr(fd,TCSANOW,&options) != 0)   /* Update the options and do it NOW 设置新属性,所有改变立即生效*/
 {
  perror("SetupSerial 3");
  return -1;
 }
 return 0;
}

//=======================================================================//
// 功能: 把需要传输的数据写入到串口输出
// 参数: int fd 文件描述符,char *buf 需要写入的数据指针, int length写入的数据长度
// 返回: 写入的数据长度
// 说明: 完成数据写入到串口输出
//=======================================================================//
int WriteToCom(int fd, char *buf, int length)
{
 //app_GetSysValue(dbserialbaudrate, &baudrate);
 //app_GetSysValue(dbserialdatabit, &databit);
 //app_GetSysValue(dbserialstopbit, &stopbit);
 //app_GetSysValue(dbserialparity, &parity);
 //app_GetSysValue(dbserialflowcontrol, &flowcontrol);
 Set_Speed(fd,baudrate);
 Set_Com(fd,databit,stopbit,parity,flowcontrol);
 int len = 0;
 len = write(fd,buf,length);
 return len;
}

//=======================================================================//
// 功能: 关闭串口
// 参数: int fd 文件描述符
// 返回: 0 关闭成功
// 说明: 关闭串口
//=======================================================================//
int CloseCom(int fd)
{
 close(fd);
 return 0;
}
void  Modify_Com(PUSERIALPORT *pu)
{
 baudrate = pu->baudRate;
 databit = pu->dataBit;
 stopbit = pu->stopBit;
 parity = pu->parity;
 flowcontrol = pu->flowControl;
}

#if 0
int main()
{
 daemon(1,1);
 int fd = OpenCom();
 Set_Speed(fd,9600);
 Set_Com(fd,8,1,0,0);
 int i=100;
 while(i--)
 {
  char wbuf[]=",.?";
  WriteToCom(fd, wbuf, 36);
  usleep(100*1000);
  if (i == 10)
   CloseCom(fd);
 }
}
#endif

 
 
建议参考Unix环境高级编程一书的10和11章,有详细的讲述!

Linux 下串口编程入门

developerWorks
文档选项
将此页作为电子邮件发送

将此页作为电子邮件发送

将此页作为电子邮件发送

将此页作为电子邮件发送


级别: 初级

左锦 (), 副总裁, 南沙资讯科技园

2003 年 7 月 03 日

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍。

串 行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用。常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换 接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定。传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺。

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍,如果要非常深入了解,建议看看本文所参考的

计算机串口的引脚说明

序号 信号名称 符号 流向 功能
2 发送数据 TXD DTE→DCE DTE发送串行数据
3 接收数据 RXD DTE←DCE DTE 接收串行数据
4 请求发送 RTS DTE→DCE DTE 请求 DCE 将线路切换到发送方式
5 允许发送 CTS DTE←DCE DCE 告诉 DTE 线路已接通可以发送数据
6 数据设备准备好 DSR DTE←DCE DCE 准备好
7 信号地        信号公共地
8 载波检测 DCD DTE←DCE 表示 DCE 接收到远程载波
20 数据终端准备好 DTR DTE→DCE DTE 准备好
22 振铃指示 RI DTE←DCE 表示 DCE 与线路接通,出现振铃




回页首


串口操作需要的头文件

#include           /*标准输入输出定义*/
#include /*标准函数库定义*/
#include /*Unix 标准函数定义*/
#include
#include
#include /*文件控制定义*/
#include /*PPSIX 终端控制定义*/
#include /*错误号定义*/





回页首


在 Linux 下串口文件是位于 /dev 下的

串口一 为 /dev/ttyS0

串口二 为 /dev/ttyS1

打开串口是通过使用标准的文件打开函数操作:

int fd;
/*以读写方式打开串口*/
fd = open( "/dev/ttyS0", O_RDWR);
if (-1 == fd){
/* 不能打开串口一*/
perror(" 提示错误!");
}





回页首


最基本的设置串口包括波特率设置,效验位和停止位设置。

串口的设置主要是设置 struct termios 结构体的各成员值。

struct termio
{ unsigned short c_iflag; /* 输入模式标志 */
unsigned short c_oflag; /* 输出模式标志 */
unsigned short c_cflag; /* 控制模式标志*/
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};

设置这个结构体很复杂,我这里就只说说常见的一些设置:

波特率设置

下面是修改波特率的代码:

struct  termios Opt;
tcgetattr(fd, &Opt);
cfsetispeed(&Opt,B19200); /*设置为19200Bps*/
cfsetospeed(&Opt,B19200);
tcsetattr(fd,TCANOW,&Opt);

设置波特率的例子函数:

/**
*@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, };
void set_speed(int fd, int speed){
int i;
int status;
struct termios Opt;
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(fd1, TCSANOW, &Opt);
if (status != 0) {
perror("tcsetattr fd1");
return;
}
tcflush(fd,TCIOFLUSH);
}
}
}

效验位和停止位的设置:

无效验 8位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS8;
奇效验(Odd) 7位 Option.c_cflag |= ~PARENB;
Option.c_cflag &= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
偶效验(Even) 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag |= ~PARODD;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= ~CSIZE;
Option.c_cflag |= ~CS7;
Space效验 7位 Option.c_cflag &= ~PARENB;
Option.c_cflag &= ~CSTOPB;
Option.c_cflag &= &~CSIZE;
Option.c_cflag |= CS8;

设置效验的函数:

/**
*@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) {
perror("SetupSerial 1");
return(FALSE);
}
options.c_cflag &= ~CSIZE;
switch (databits) /*设置数据位数*/
{
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; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
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);
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/
options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return (FALSE);
}
return (TRUE);
}

需要注意的是:

如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:

options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
options.c_oflag &= ~OPOST; /*Output*/





回页首


设置好串口之后,读写串口就很容易了,把串口当作文件读写就是。

  • 发送数据
    char  buffer[1024];int    Length;int    nByte;nByte = write(fd, buffer ,Length)

  • 读取串口数据

    使用文件操作read函数读取,如果设置为原始模式(Raw Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数。

    可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作。

    char  buff[1024];int    Len;int  readByte = read(fd,buff,Len);





回页首


关闭串口就是关闭文件。

close(fd);





回页首


下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件

/**********************************************************************代码说明:使用串口二测试的,发送的数据是字符,
但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。我测试使用的是单片机发送数据到第二个串口,测试通过。
**********************************************************************/
#define FALSE -1
#define TRUE 0
/*********************************************************************/
int OpenDev(char *Dev)
{
int fd = open( Dev, O_RDWR ); //| O_NOCTTY | O_NDELAY
if (-1 == fd)
{
perror("Can't Open Serial Port");
return -1;
}
else
return fd;
}
int main(int argc, char **argv){
int fd;
int nread;
char buff[512];
char *dev = "/dev/ttyS1"; //串口二
fd = OpenDev(dev);
set_speed(fd,19200);
if (set_Parity(fd,8,1,'N') == FALSE) {
printf("Set Parity Error\n");
exit (0);
}
while (1) //循环读取数据
{
while((nread = read(fd, buff, 512))>0)
{
printf("\nLen %d\n",nread);
buff[nread+1] = '\0';
printf( "\n%s", buff);
}
}
//close(fd);
// exit (0);
}





  • Linux 的源代码

  • 代码下载: 代码
阅读(1596) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~