linux串口编程例子

来源:互联网 发布:网络上很嚣张 现实被打 编辑:程序博客网 时间:2024/05/01 16:39
/*******************************************************************/
/*                           serial.h                              */
/*******************************************************************/
#ifndef __SERIAL_H__
#define __SERIAL_H__
extern int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);
extern int open_port(int fd,int comport);
#endif
/*******************************************************************/
/*                          serial.c                               */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include "serial.h"
/*******************************************************************
* 函数名称: set_opt
* 功能描述: 设置串口基本参数
* 输入参数: fd     打开的串口标识符 (通过open_port函数返回)
    nSpeed 波特率 2400、4800、9600、115200
    nBits  数据位 7、8
    nEvent 奇偶校验 'O' 'N' 'E'
    nStop  停止位 1、2
* 输出参数: 无
* 返 回 值: 0  设置成功
    -1 设置过程出错
* 其它说明: 无
* 修改日期   版本号     修改人     修改内容
* --------------------------------------------------------------------
* 2010/09/27      V1.0             ***     创建函数
***********************************************************************/
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
    struct termios newtio,oldtio;
//保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息
    if ( tcgetattr( fd,&oldtio) != 0)
    {
        perror("SetupSerial 1");
        return -1;
    }
//extern void bzero(void *s, int n); 置字节字符串s的前n个字节为零
    bzero( &newtio, sizeof( newtio ) );
//设置字符大小
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
//设置数据位
    switch( nBits )
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }
//设置校验位
    switch( nEvent )
    {
    case 'O':
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E':
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':
        newtio.c_cflag &= ~PARENB;
        break;
    }
//设置波特率
switch( nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }
//设置停止位
    if( nStop == 1 )
        newtio.c_cflag &= ~CSTOPB;
    else if ( nStop == 2 )
  newtio.c_cflag |= CSTOPB;
//设置等待时间和最小接收字符
    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;
//处理未接收字符
    tcflush(fd,TCIFLUSH);
//激活新配置
    if((tcsetattr(fd,TCSANOW,&newtio))!=0)
    {
        perror("com set error");//打印com set error及出错原因
        return -1;
    }
    printf("set done!\n");
    return 0;
}
/**********************************************************************
* 函数名称: open_port
* 功能描述: 打开指定串口
* 输入参数: fd 文件描述符
    comport 串口号(1、2、3)
* 输出参数: 无
* 返 回 值: 出错 返回 -1
             成功 返回 fd文件描述符
* 其它说明: 无
* 修改日期   版本号     修改人     修改内容
* --------------------------------------------------------------------
* 2010/09/27      V1.0             ***     创建函数
***********************************************************************/
int open_port(int fd,int comport)
{
    char *dev[]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2"};
    long vdisable;//没用
//打开串口
    if (comport==1)
    {   
  fd = open("/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd)
  {
            perror("Can't Open Serial Port");
            return(-1);
        }
        else
            printf("open ttyS0 .....\n");
    }
    else if(comport==2)
    {   
  fd = open("/dev/ttyS1",O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd)
  {
            perror("Can't Open Serial Port");
            return(-1);
        }
        else
            printf("open ttyS1 .....\n");
    }
    else if (comport==3)
    {
        fd = open("/dev/ttyS2",O_RDWR|O_NOCTTY|O_NDELAY);
        if (-1 == fd)
  {
            perror("Can't Open Serial Port");
            return(-1);
        }
        else
            printf("open ttyS2 .....\n");
    }
else if (comport==4)
{
  fd = open("/dev/ttyS3",O_RDWR|O_NOCTTY|O_NDELAY);
  if (-1 == fd)
  {
   perror("Can't Open Serial Port");
   return(-1);
  }
  else
   printf("open ttyS3 .....\n");
}
//恢复串口的状态为阻塞状态,用于等待串口数据的读入
    if(fcntl(fd, F_SETFL, 0) < 0)
        printf("fcntl failed!\n");
    else
        printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
//测试打开的文件描述符是否引用一个终端设备,以进一步确认串口是否正确打开
    if(isatty(STDIN_FILENO)==0)
        printf("standard input is not a terminal device\n");
    else
        printf("isatty success!\n");
    printf("fd-open=%d\n",fd);
    return fd;
}
/*******************************************************************/
/*                          main.c                                 */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
#include "serial.h"
int main(void)
{
int fd;
int nread,i;
char buff[512];
bzero(buff, 512);
if((fd=open_port(fd,4)) < 0)
{
  perror("open_port error");
  return -1;
}
if((i=set_opt(fd,115200,8,'N',1)) < 0)
{
  perror("set_opt error");
  return -1;
}
printf("fd=%d\n",fd);
while (1)
{
  sleep(2);
  //while ((nread = read(fd,buff,512)) > 0)
  {
   nread = read(fd,buff,512);
   printf("nread = %d\n",nread);
   printf("%s\n",buff);
   bzero(buff,nread);//清空
   //usleep(100000);
  }
}
close(fd);
return 0;
}
//下面为截取的一小段Makefile内容,Makefile是通过QT的qmake自动生成的,如果程序在开发板上跑,要稍加修改。
####### Compiler, tools and options
ARCH=arm
CROSS_COMPILE=arm-unknown-linux-gnu-
DEFINES =
#DEFINES += -DMASK_GATEWAY_CHECK
CC       = ${CROSS_COMPILE}gcc
CXX      = ${CROSS_COMPILE}g++
LEX      = ${CROSS_COMPILE}flex
YACC     = ${CROSS_COMPILE}yacc
CFLAGS   = -Wall -Wextra #-pipe -Wall -W -O2 -march=i386 -mcpu=i686 -g -DGLX_GLXEXT_LEGACY -fno-use-cxa-atexit -fno-exceptions  -DQT_NO_DEBUG
CFLAGS += $(DEFINES)
CXXFLAGS = -Wall -Wextra #-pipe -Wall -W -O2 -march=i386 -mcpu=i686 -g -DGLX_GLXEXT_LEGACY -fno-use-cxa-atexit -fno-exceptions  -DQT_NO_DEBUG
#LEXFLAGS =
#YACCFLAGS= -d
#INCPATH  = -I$(QTDIR)/mkspecs/default -I. -I$(QTDIR)/include -I.ui/ -I.moc/
LINK     = ${CROSS_COMPILE}gcc
LFLAGS   =
#LIBS     = $(SUBLIBS) -L$(QTDIR)/lib -L/usr/X11R6/lib -lqt-mt -lXext -lX11 -lm
LIBS =
#AR       = ar cqs
#RANLIB   =
#MOC      = $(QTDIR)/bin/moc
#UIC      = $(QTDIR)/bin/uic
#QMAKE    = qmake
#TAR      = tar -cf
#GZIP     = gzip -9f
#COPY     = cp -f
#COPY_FILE= $(COPY) -p
#COPY_DIR = $(COPY) -pR
DEL_FILE = rm -f
#SYMLINK  = ln -sf
#DEL_DIR  = rmdir
#MOVE     = mv -f
#CHK_DIR_EXISTS= test -d
#MKDIR    = mkdir -p

####### Output directory
OBJECTS_DIR = .obj/
####### Files
HEADERS = /mnt/hgfs/share/serial/serial.h
SOURCES = /mnt/hgfs/share/serial/serial.c \
  /mnt/hgfs/share/serial/main.c
OBJECTS = .obj/serial.o \
  .obj/main.o
FORMS =
UICDECLS =
UICIMPLS =
SRCMOC   =
OBJMOC =
DIST    = serial.pro
QMAKE_TARGET = serial
DESTDIR  =
TARGET   = serial
first: all
####### Implicit rules