Linux环境串口程序设计.docx
《Linux环境串口程序设计.docx》由会员分享,可在线阅读,更多相关《Linux环境串口程序设计.docx(15页珍藏版)》请在冰点文库上搜索。
Linux环境串口程序设计
Linux环境串口程序设计
串口是计算机上一种非常通用设备通信的协议,常用PC机上包含的是RS232规格的串口,具有连接线少,通讯简单,得到广泛的使用。
Linux对所有设备的访问是通过设备文件来进行的,串口也是这样,为了访问串口,只需打开其设备文件即可操作串口设备。
在linux系统下面,每一个串口设备都有设备文件与其关联,设备文件位于系统的/dev目录下面。
如linux下的/ttyS0,/ttyS1分别表示的是串口1和串口2。
在串口编程中,比较重要的是串口的设置,我们要设置的部分包括:
波特率,数据位,停止位,奇偶校验位;要注意的是,每台机器的串口默认设置可能是不同的,如果你没设置这些,仅仅按照默认设置进行发送数据,很可能出现n多异想不到而又查不出来的情况。
1)设置波特率
#include
#include
intcfsetispeed(structtermios*termios_p,speed_tspeed);
intcfsetospeed(structtermios*termios_p,speed_tspeed);
2)设置属性:
奇偶校验位、数据位、停止位。
主要设置中的termios结构体即可:
#defineNCCS19
structtermios{
tcflag_tc_iflag;/*inputmodeflags*/
tcflag_tc_oflag;/*outputmodeflags*/
tcflag_tc_cflag;/*controlmodeflags*/
tcflag_tc_lflag;/*localmodeflags*/
cc_tc_line;/*linediscipline*/
cc_tc_cc[NCCS];/*controlcharacters*/
};
有相应的函数供获取和设置属性:
inttcgetattr(intfd,structtermios*termios_p);
inttcsetattr(intfd,intoptional_actions,structtermios*termios_p);
3)打开、关闭和读写串口。
串口作为设备文件,可以直接用文件描述符来进行操作。
#include
#include
#include
intopen(constchar*pathname,intflags);
#include
intclose(intfd);
ssize_twrite(intfd,constvoid*buf,size_tcount);
ssize_tread(intfd,void*buf,size_tcount);
网上的一个例子:
/*串口设备无论是在工控领域,还是在嵌入式设备领域,应用都非常广泛。
而串口编程也就显得必不可少。
偶然的一次机会,需要使用串口,而且操作系统还要求是Linux,因此,趁着这次机会,综合别人的代码,
进行了一次整理和封装。
具体的封装格式为C代码,这样做是为了很好的移植性,使它可以在C和C++环境下,
都可以编译和使用。
代码的头文件如下:
*/
///////////////////////////////////////////////////////////////////////////////
//filename:
stty.h
#ifndef__STTY_H__
#define__STTY_H__
//包含头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
//串口设备信息结构
typedefstructtty_info_t
{
intfd;//串口设备ID
pthread_mutex_tmt;//线程同步互斥对象
charname[24];//串口设备名称,例:
"/dev/ttyS0"
structtermiosntm;//新的串口设备选项
structtermiosotm;//旧的串口设备选项
}TTY_INFO;
//
//串口操作函数
TTY_INFO*readyTTY(intid);
intsetTTYSpeed(TTY_INFO*ptty,intspeed);
intsetTTYParity(TTY_INFO*ptty,intdatabits,intparity,intstopbits);
intcleanTTY(TTY_INFO*ptty);
intsendnTTY(TTY_INFO*ptty,char*pbuf,intsize);
intrecvnTTY(TTY_INFO*ptty,char*pbuf,intsize);
intlockTTY(TTY_INFO*ptty);
intunlockTTY(TTY_INFO*ptty);
#endif
/*从头文件中的函数定义不难看出,函数的功能,使用过程如下:
(1)打开串口设备,调用函数setTTYSpeed();
(2)设置串口读写的波特率,调用函数setTTYSpeed();
(3)设置串口的属性,包括停止位、校验位、数据位等,调用函数setTTYParity();
(4)向串口写入数据,调用函数sendnTTY();
(5)从串口读出数据,调用函数recvnTTY();
(6)操作完成后,需要调用函数cleanTTY()来释放申请的串口信息接口;
其中,lockTTY()和unlockTTY()是为了能够在多线程中使用。
在读写操作的前后,需要锁定和释放串口资源。
具体的使用方法,在代码实现的原文件中,main()函数中进行了演示。
下面就是源代码文件:
*/
////////////////////////////////////////////////////////////////////////////////
//stty.c
#include
#include
#include"stty.h"
///////////////////////////////////////////////////////////////////////////////
//初始化串口设备并进行原有设置的保存
TTY_INFO*readyTTY(intid)
{
TTY_INFO*ptty;
ptty=(TTY_INFO*)malloc(sizeof(TTY_INFO));
if(ptty==NULL)
returnNULL;
memset(ptty,0,sizeof(TTY_INFO));
pthread_mutex_init(&ptty->mt,NULL);
sprintf(ptty->name,"/dev/ttyS%d",id);
//
//打开并且设置串口
ptty->fd=open(ptty->name,O_RDWR|O_NOCTTY|O_NDELAY);
if(ptty->fd<0)
{
free(ptty);
returnNULL;
}
//
//取得并且保存原来的设置
tcgetattr(ptty->fd,&ptty->otm);
returnptty;
}
///////////////////////////////////////////////////////////////////////////////
//清理串口设备资源
intcleanTTY(TTY_INFO*ptty)
{
//
//关闭打开的串口设备
if(ptty->fd>0)
{
tcsetattr(ptty->fd,TCSANOW,&ptty->otm);
close(ptty->fd);
ptty->fd=-1;
free(ptty);
ptty=NULL;
}
return0;
}
///////////////////////////////////////////////////////////////////////////////
//设置串口通信速率
//ptty参数类型(TTY_INFO*),已经初始化的串口设备信息结构指针
//speed参数类型(int),用来设置串口的波特率
//return返回值类型(int),函数执行成功返回零值,否则返回大于零的值
///////////////////////////////////////////////////////////////////////////////
intsetTTYSpeed(TTY_INFO*ptty,intspeed)
{
inti;
//
//进行新的串口设置,数据位为8位
bzero(&ptty->ntm,sizeof(ptty->ntm));
tcgetattr(ptty->fd,&ptty->ntm);
ptty->ntm.c_cflag=/*CS8|*/CLOCAL|CREAD;
switch(speed)
{
case300:
ptty->ntm.c_cflag|=B300;
break;
case1200:
ptty->ntm.c_cflag|=B1200;
break;
case2400:
ptty->ntm.c_cflag|=B2400;
break;
case4800:
ptty->ntm.c_cflag|=B4800;
break;
case9600:
ptty->ntm.c_cflag|=B9600;
break;
case19200:
ptty->ntm.c_cflag|=B19200;
break;
case38400:
ptty->ntm.c_cflag|=B38400;
break;
case115200:
ptty->ntm.c_cflag|=B115200;
break;
}
ptty->ntm.c_iflag=IGNPAR;
ptty->ntm.c_oflag=0;
//
//
tcflush(ptty->fd,TCIFLUSH);
tcsetattr(ptty->fd,TCSANOW,&ptty->ntm);
//
//
return0;
}
//设置串口数据位,停止位和效验位
//ptty参数类型(TTY_INFO*),已经初始化的串口设备信息结构指针
//databits参数类型(int),数据位,取值为7或者8
//stopbits参数类型(int),停止位,取值为1或者2
//parity参数类型(int),效验类型取值为N,E,O,,S
//return返回值类型(int),函数执行成功返回零值,否则返回大于零的值
///////////////////////////////////////////////////////////////////////////////
intsetTTYParity(TTY_INFO*ptty,intdatabits,intparity,intstopbits)
{
//
//取得串口设置
if(tcgetattr(ptty->fd,&ptty->ntm)!
=0)
{
printf("SetupSerial[%s]\n",ptty->name);
return1;
}
bzero(&ptty->ntm,sizeof(ptty->ntm));
ptty->ntm.c_cflag=CS8|CLOCAL|CREAD;
ptty->ntm.c_iflag=IGNPAR;
ptty->ntm.c_oflag=0;
//
//设置串口的各种参数
ptty->ntm.c_cflag&=~CSIZE;
switch(databits)
{//设置数据位数
case7:
ptty->ntm.c_cflag|=CS7;
break;
case8:
ptty->ntm.c_cflag|=CS8;
break;
default:
printf("Unsupporteddatasize\n");
return5;
}
//
//
switch(parity)
{//设置奇偶校验位数
casen:
caseN:
ptty->ntm.c_cflag&=~PARENB;/*Clearparityenable*/
ptty->ntm.c_iflag&=~INPCK;/*Enableparitychecking*/
break;
caseo:
caseO:
ptty->ntm.c_cflag|=(PARODD|PARENB);/*设置为奇效验*/
ptty->ntm.c_iflag|=INPCK;/*Disnableparitychecking*/
break;
casee:
caseE:
ptty->ntm.c_cflag|=PARENB;/*Enableparity*/
ptty->ntm.c_cflag&=~PARODD;/*转换为偶效验*/
ptty->ntm.c_iflag|=INPCK;/*Disnableparitychecking*/
break;
caseS:
cases:
/*asnoparity*/
ptty->ntm.c_cflag&=~PARENB;
ptty->ntm.c_cflag&=~CSTOPB;
break;
default:
printf("Unsupportedparity\n");
return2;
}
//
//设置停止位
switch(stopbits)
{
case1:
ptty->ntm.c_cflag&=~CSTOPB;
break;
case2:
ptty->ntm.c_cflag|=CSTOPB;
break;
default:
printf("Unsupportedstopbits\n");
return3;
}
//
//
ptty->ntm.c_lflag=0;
ptty->ntm.c_cc[VTIME]=0;//inter-charactertimerunused
ptty->ntm.c_cc[VMIN]=1;//blockingreaduntil1charsreceived
tcflush(ptty->fd,TCIFLUSH);
if(tcsetattr(ptty->fd,TCSANOW,&ptty->ntm)!
=0)
{
printf("SetupSerial\n");
return4;
}
return0;
}
intrecvnTTY(TTY_INFO*ptty,char*pbuf,intsize)
{
intret,left,bytes;
left=size;
while(left>0)
{
ret=0;
bytes=0;
pthread_mutex_lock(&ptty->mt);
ioctl(ptty->fd,FIONREAD,&bytes);
if(bytes>0)
{
ret=read(ptty->fd,pbuf,left);
}
pthread_mutex_unlock(&ptty->mt);
if(ret>0)
{
left-=ret;
pbuf+=ret;
}
usleep(100);
}
returnsize-left;
}
intsendnTTY(TTY_INFO*ptty,char*pbuf,intsize)
{
intret,nleft;
char*ptmp;
ret=0;
nleft=size;
ptmp=pbuf;
while(nleft>0)
{
pthread_mutex_lock(&ptty->mt);
ret=write(ptty->fd,ptmp,nleft);
pthread_mutex_unlock(&ptty->mt);
if(ret>0)
{
nleft-=ret;
ptmp+=ret;
}
//usleep(100);
}
returnsize-nleft;
}
intlockTTY(TTY_INFO*ptty)
{
if(ptty->fd<0)
{
return1;
}
returnflock(ptty->fd,LOCK_EX);
}
intunlockTTY(TTY_INFO*ptty)
{
if(ptty->fd<0)
{
return1;
}
returnflock(ptty->fd,LOCK_UN);
}
#ifdefLEAF_TTY_TEST
///////////////////////////////////////////////////////////////////////////////
//接口测试
intmain(intargc,char**argv)
{
TTY_INFO*ptty;
intnbyte,idx;
unsignedcharcc[16];
ptty=readyTTY(0);
if(ptty==NULL)
{
printf("readyTTY(0)error\n");
return1;
}
//
//
lockTTY(ptty);
if(setTTYSpeed(ptty,9600)>0)
{
printf("setTTYSpeed()error\n");
return-1;
}
if(setTTYParity(ptty,8,N,1)>0)
{
printf("setTTYParity()error\n");
return-1;
}
//
idx=0;
while
(1)
{
cc[0]=0xFA;
sendnTTY(ptty,&cc[0],1);
nbyte=recvnTTY(ptty,cc,1);
printf("%d:
%02X\n",idx++,cc[0]);
}
cleanTTY(ptty);
}
#endif