linux串口应用开发

linux串口应用开发
2009年10月20日 星期二 14:16

1、串口概述
    用户常见的数据通信的基本方式有两种:并行通信和串行通信。
    串行通信是计算机常用的接口,如:RS-232-C接口。该标准规定采用一个DB25芯引脚连接器或DB9芯引脚连接器。芯片内部常具有UART控制器,其可工作于Interrupt(中断模式)或DMA(直接内存访问)模式。
     UART的操作主要包括以下几个部分:
数据发送;数据接收;产生中断;产生波特率;Loopback模式;红外模式;自动流控模式。
    串口参数的配置主要包括:波特率、数据位、停止位、流控协议

    linux中的串口设备文件存放于/dev目录下,其中串口一,串口二对应设备名依次为“/dev/ttyS0”、“/dev/ttyS1”。在linux下操作串口与操作文件相同。


2、串口详细配置
   在使用串口之前必须设置相关配置,包括:波特率、数据位、校验位、停止位等。

串口设置由下面结构体实现:

Struct termios {
tcflag_t c_iflag; /*input flags */
tcflag_t c_oflag; /*output flags */
tcflag_t c_cflag; /*control flags */
tcflag_t c_lflag; /*local flags */
cc_t   c_cc[NCCS]; /*control characters */
};

    该结构中c_cflag最为重要,可设置波特率、数据位、校验位、停止位。在设置波特率时需在数字前加上‘B’,如B9600或B19200。使用其需通过“与”“或”操作方式。

输入模式c_iflag成员控制端口接收端的字符输入处理。


串口控制函数:

Tcgetattr                      取属性(termios结构)
Tcsetattr                    设置属性(termios结构)
cfgetispeed                  得到输入速度
Cfgetospeed                得到输出速度
Cfsetispeed                 设置输入速度
Cfsetospeed                设置输出速度
Tcdrain                      等待所有输出都被传输
tcflow                         挂起传输或接收
tcflush                        刷清未决输入和/或输出
Tcsendbreak              送BREAK字符
tcgetpgrp                    得到前台进程组ID
tcsetpgrp                    设置前台进程组ID

2.1 串口配置流程
1. 保存原先串口配置使用tcgetattr(fd,&oldtio)函数

            struct termios newtio,oldtio;
            tcgetattr( fd,&oldtio );

2. 激活选项有CLOCAL和CREAD,用于本地连接和接收使能。

             newtio.c_cflag | = CLOCAL | CREAD;

3. 设置波特率,使用cfsetispeed和cfsetospeed函数。

             cfsetispeed(&newtio, B115200);
             cfsetospeed(&newtio, B115200);

4. 设置数据位,需使用掩码设置。

             newtio.c_cflag &= ~CSIZE;
             newtio.c_cflag |= CS8;

5. 设置奇偶校验位,使用c_cflag和c_iflag。
    设置奇校验:

             newtio.c_cflag |= PARENB;
             newtio.c_cflag |= PARODD;
             newtio.c_iflag |= (INPCK | ISTRIP);

    设置偶校验:

              newtio.c_iflag |= (INPCK | ISTRIP);
              newtio.c_cflag |= PARENB;
              newtio.c_cflag &= ~PARODD;

6. 设置停止位,通过激活c_cflag中的CSTOPB实现。若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。

             newtio.c_cflag &= ~CSTOPB;

7. 设置最少字符和等待时间,对于接收字符和等待时间没有特别要求时,可设为0。

              newtio.c_cc[VTIME] = 0;
              newtio.c_cc[VMIN] = 0;


8. 处理要写入的引用对象

    tcflush函数刷清输入缓存(终端驱动程序已接收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。

             int tcflush(int filedes, int queue )

queue参数应当是下列三个常数之一:

• TCIFLUSH    刷清输入队列。
• TCOFLUSH   刷清输出队列。
• TCIOFLUSH 刷清输入和输出队列。

9. 激活配置。在完成配置后,需激活配置使其生效。使用tcsettattr()函数。原型:

int tcgetattr(int filedes, struct termios * termptr);
int tcsetattr(int filedes, int opt, const struct termios * termptr);

tcsetattr的参数opt使我们可以指定在什么时候新的终端属性才起作用。opt可以指定为下列常数中的一个:

• TCSANOW    更改立即发生。
• TCSADRAIN 发送了所有输出后更改才发生。若更改输出参数则应使用此选择项。
• TCSAFLUSH 发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被删除。


3. 串口使用详解

     在配置完串口的相关属性后,就可对串口进行打开,读写操作了。其使用方式与文件操作一样,区别在于串口是一个终端设备。

3.1 打开串口

      fd = open( "/dev/ttyS0",O_RDWR|O_NOCTTY|O_NDELAY);
      Open函数中除普通参数外,另有两个参数O_NOCTTY和O_NDELAY。
      O_NOCTTY: 通知linix系统,这个程序不会成为这个端口的控制终端。
      O_NDELAY: 通知linux系统不关心DCD信号线所处的状态(端口的另一端是否激活或者停止)。
      然后,恢复串口的状态为阻塞状态,用于等待串口数据的读入。用fcntl函数:

            fcntl(fd, F_SETFL, 0);

      接着,测试打开的文件描述府是否引用一个终端设备,以进一步确认串口是否正确打开。

            isatty(STDIN_FILENO);


3.2 读写串口
      串口的读写与普通文件一样,使用read,write函数。

            read(fd,buff,8);
            write(fd,buff,8);

 

 

Example:seri.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>

 

 

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;

}

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");

return -1;

}

printf("set done!/n");

return 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");

}

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;

}

 

int main(void)

{

int fd;

int nread,i;

char buff[]="Hello/n";

 

if((fd=open_port(fd,1))<0){

perror("open_port error");

return;

}

if((i=set_opt(fd,115200,8,'N',1))<0){

perror("set_opt error");

return;

}

printf("fd=%d/n",fd);

// fd=3;

nread=read(fd,buff,8);

printf("nread=%d,%s/n",nread,buff);

close(fd);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值