linux 串口初始化
基于FL2440开发板
串口设置说明:数据位8位,停止位1位,没有校验位,串口输入输出波特率为9600.
一、打开串口
1. 在linux系统下,串口的设备名为ttyS0,ttyS1,ttyS3,位于dev目录下。
2. 打开文件的模式采用O_RDWR | O_NOCTTY | O_NONBLOCK 。
O_NOCTTY 当打开文件为tty(终端设备)时,不将此设备分配作为进程的控制终端,
O_NONBLOCK 当打开的设备是FIFO、一个块特殊文件或一个字符特殊文件,设置设备的打开和后续 I/O操作设置为非阻塞方式。
二、设置串口
1. 串口的配置是通过struct termios进行配置的
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
};
2.串口设置函数
tcgetattr 取属性(termios结构)
tcsetattr 设置属性(termios结构)
cfgetispeed 得到输入速度
cfgetospeed 得到输出速度
cfsetispeed 设置输入速度
cfsetospeed 设置输出速度
tcdrain 等待所有输出都被传输
tcflow 挂起传输或接收
tcflush 刷清未决输入和/或输出
tcsendbreak 送BREAK字符
tcgetpgrp 得到前台进程组ID
tcsetpgrp 设置前台进程组ID
三、配置串口
1. struct termios new_termios;
2. 设置串口数据位
new_termios.c_cflag &= ~CSIZE; //字符大小屏蔽,以便设置数据位大小
new_termios.c_cflag |= CS8; //设置数据位为8位
3. 设置停止位
new_termios.c_cflag &= ~CSTOPB; //设置一位停止位
new_termios.c_cflag |= CSTOPB; //设置两位停止位
4. 设置奇偶校验位
设置奇校验:
newtio.c_cflag |= PARENB; //进行奇偶校验
newtio.c_cflag |= PARODD; //设置为奇校验
newtio.c_iflag |= (INPCK | ISTRIP);//打开输入校验,剥除数据的第8位
设置偶校验:
newtio.c_iflag |= (INPCK|ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag |= ~PARODD; //设置为偶校验
没有奇偶校验
newtio.c_cflag &= ~PARENB;
5. 设置最少字符和等待时间
new_termios.c_cc[VTIME] = 0;
new_termios.c_cc[VMIN] = 0;
6. 硬件流控设置
new_termios.c_cflag &= ~(CRTSCTS); //关闭硬件流控制
options.c_cflag |= CNEW_RTSCTS;//打开硬件流控 7. 本地设置成员变量c_lflag可以使用的常量
Flag | Description |
ISIG | 当接收到字符INTR,QUIT,SUSP或DSUSP时,产生相应的信号 |
XCASE | (不属于POSIX;LINUX下不支持)如果同时设置了ICANON,终端只有大写。输入被转换为小写,除了以\前缀的字符。输出时,大写字符被前缀\,小写字符被转换成大写 |
ECHO | 回显输入字符 |
ECHOE | 如果同时设置了ICANON,字符ERASE擦除前一个输入字符,WERASE擦除前一个词 |
ECHOK | 如果同时设置了ICANON,字符KILL删除当前行 |
ECHONL | 如果同时设置了ICANON,回显字符NL,即使没有设置ECHO |
ECHOCTL | (不属于POSIX)如果同时设置了ECHO,除了TAB,NL,START和STOP之外的ASCII控制信号被回显为x,这里X是比控制信号大0x40的ASCII码。例如字符0x08(BS)被回显为H |
ECHOPRT | (不属于POSIX)如果同时设置了ICANON和IECHO,字符在删除的同时被打印 |
ECHOKE | (不属于POSIX)如果同时设置了ICANON,回显KILL时将删除一行中的每个字符,如同指定了ECHOE和ECHORPT一样 |
DEFECHO | (不属于POSIX)只在一个进程读的时候回显 |
FLUSHO | (不属于POSIX;LINUX不支持)输出被刷新。这个标志可以通过键入字符DISCARD来打开和关闭 |
NOFLSH | 禁止产生SIGINT,SIGQUIT和SIGSUSP信号时刷新输入和输出队列 |
TOSTOP | 向试图写控制终端的后台进程组发送SIGTTOU信号 |
PENDIN | (不属于POSIX;LINUX不支持)在读入一个字符时,输入队列中的所有字符被重新输出。(bash用他来处理typeahead) |
IEXTEN | 启用实现自定义的输入处理。这个标志必须与ICANON同时使用,才能解释特殊字符EOL2,LNEXT,REPRINT和WERASE,IUCLC标志才有效 |
选择经典输入
经典输入是以面向行设计的。在经典输入模式中输入字符会被放入一个缓冲之中, 这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符。 选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:new_termios.c_lflag |= (ICANON | ECHO | ECHOE);
原始输入根本不会被处理。输入字符只是被原封不动的接收。一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:
new_termios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
8.输入模式
Flag | Description |
IGNBRK | 忽略输入中的BREAK状态 |
BRKINT | 如果设置了IGNBRK,将忽略BREAK。如果没有设置,但是设置了 BRKINT,那么BREAK将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到SIGINT信号。如果既未设置IGNBRK也未设置BRKINT,BREAK将视为NUL同义字符,除非设置了PARMRK,这种情况下被视为序列\377 |
IGNPAR | 忽略桢错误和奇偶校验错误 |
PARMRK | 如果没有设置IGNPAR,在有奇偶校验错误或者桢错误的字符前插入\377。如果既没有设置IGNPAR也没有设置PARMRK,将所有奇偶校验错误或者桢错误的字符视为 |
INPCK | 启用输入奇偶校验检测 |
ISTRIP | 去掉第八位 |
INLCR | 将输入的NL翻译为CR |
IGNCR | 忽略输入中的回车 |
ICRNL | 将输入中的回车翻译为新行字符(除非设置了IGNCR) |
IUCLC | (不属于POSIX)将输入中的大写字母映射为小写字母 |
IXON | 启用输出的XON/XOFF流控制 |
IXANY | (不属于POSIX。1;XSI)允许任何字符来重新开始输出 |
IXOFF | 启用输入的XON/XOFF流控制 |
IMAXBEL | (不属于POSIX)当输入队列满时响铃。LINUX没有实现该位,总是将其视为已设置 |
9. 输出模式标志 c_oflag的常量
IGNBRK | 忽略输入中的BREAK状态 |
BRKINT | 如果设置了IGNBRK,将忽略BREAK。如果没有设置,但是设置了 BRKINT,那么BREAK将使得输入和输出队列被刷新,如果终端是一个前台进程组的控制终端,这个进程组中所有进程将收到SIGINT信号。如果既未设置IGNBRK也未设置BRKINT,BREAK将视为NUL同义字符,除非设置了PARMRK,这种情况下被视为序列\377 |
IGNPAR | 忽略桢错误和奇偶校验错误 |
PARMRK | 如果没有设置IGNPAR,在有奇偶校验错误或者桢错误的字符前插入\377。如果既没有设置IGNPAR也没有设置PARMRK,将所有奇偶校验错误或者桢错误的字符视为 |
INPCK | 启用输入奇偶校验检测 |
ISTRIP | 去掉第八位 |
INLCR | 将输入的NL翻译为CR |
IGNCR | 忽略输入中的回车 |
ICRNL | 将输入中的回车翻译为新行字符(除非设置了IGNCR) |
IUCLC | (不属于POSIX)将输入中的大写字母映射为小写字母 |
IXON | 启用输出的XON/XOFF流控制 |
IXANY | (不属于POSIX。1;XSI)允许任何字符来重新开始输出 |
IXOFF | 启用输入的XON/XOFF流控制 |
IMAXBEL | (不属于POSIX)当输入队列满时响铃。LINUX没有实现该位,总是将其视为已设置 |
10. 控制模式标志 c_cflag常量
Flag | Description |
CBAUD | (不属于POSIX)波特率掩码(4+1位) |
CBAUDEX | (不属于POSIX)扩展的波特率掩码(1位),包含在CBAUD中 |
CSIZE | 字符长度掩码。取值为CS5,CS6,CS7或CS8 |
CSTOPB | 设置两个停止位 |
CREAD | 打开接受者 |
PARENB | 允许输出产生奇偶信息以及输入的奇偶校验 |
PARODD | 输入和输出是奇校验 |
HUPCL | 在最后一个进程关闭设备后,降低MODEM控制线(挂断) |
CLOCAL | 忽略MODEM控制线 |
LOBLK | (不属于POSIX)从非当前SHELL层阻塞输出(用于sh1) |
CIBAUD | (不属于POSIX)输入速度的掩码。CIBAUD各位的值与CBAUD各位相同,左移了IBSHIFT位 |
CRTSCTS | (不属于POSIX)启用RTS/CTS(硬件)控制流 |
11.设置串口输入输出波特率
cfsetispeed(&new_termios, B9600);
cfsetospeed(&new_termios,B9600);
12.设置串口,使配置生效
tcsetattr(fd, TCSANOW, &new_termios); //成功返回0
四、串口设置函数
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include "at.h"
#define SERIAL "/dev/ttyS1"
#define MODE O_RDWR | O_NOCTTY | O_NONBLOCK
int init_serial()
{
int retval;
int fd;
fd=open(SERIAL,MODE);
if(fd<0)
{
printf("open file error,%s\n",strerror(errno));
return -1;
}
else
{
printf("open file successful\n");
}
struct termios old_cfg, new_cfg;
if(tcflush(fd, TCIOFLUSH)<0)
{
retval=-1;
goto error;
}
if (0 != tcgetattr(fd, &old_cfg))
{
retval = -2; // Failed to get Com settings
goto error;
}
memset(&new_cfg, 0, sizeof(new_cfg));
new_cfg.c_cflag &= ~CSIZE;
new_cfg.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
new_cfg.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
new_cfg.c_oflag &= ~(OPOST);
new_cfg.c_cflag |= CS8;
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_cflag &= ~CSTOPB;
new_cfg.c_cflag &= ~(CRTSCTS);
new_cfg.c_iflag &= ~(IXON | IXOFF);
cfsetispeed(&new_cfg, B9600);
cfsetospeed(&new_cfg,B9600);
new_cfg.c_cc[VMIN] = 0;
new_cfg.c_cc[VTIME] = 0;
if (0 != tcsetattr(fd, TCSANOW, &new_cfg))
{
retval = -3; // Failed to set device com port settings
goto error;
}
printf("init successful\n");
return 0;
error:
printf("error\n");
return retval;
}
参考文章:
http://blog.chinaunix.net/uid-28458801-id-4243864.html
http://www.cnblogs.com/wblyuyang/archive/2011/11/21/2257544.html