Linux串口编程


参考网上各种资料啊!

1.串口简介

1.1基础知识

电脑与单片机串口通信是一种异步串行通信方式,将传输数据的每个字符一位接一位地传送。数据的各不同位可以分时使用同一传输通道,因此串行I/O可以减少信号连线,最少用一对线即可进行。
串口时序图
开始前,线路处于空闲状态,送出连续“1”。传送开始时首先发一个“0”作为起始位,然后出现在通信线上的是字符的二进制编码数据。每个字符的数据位长可以约定为5 位、6 位、7 位或8 位,一般采用ASCII 编码。后面是奇偶校验位,根据约定,用奇偶校验位将所传字符中为“1”的位数凑成奇数个或偶数个也可以约定不要奇偶校验,这样就取消奇偶校验位。最后是表示停止位的“1”信号,这个停止位可以约定持续1 位、1.5 位或2 位的时间宽度。至此一个字符传送完毕,线路又进入空闲,持续为“1”(高电平)。

1.2引脚定义

参考:

http://book.51cto.com/art/201308/408900.htm

2.串口操作

UART的操作主要包括以下几个部分:

  • 数据发送;
  • 数据接收;
  • 产生中断;
  • 产生波特率;
  • Loopback模式;
  • 红外模式;
  • 自动流控模式。

串口参数的配置主要包括:波特率、数据位、停止位、流控协议。

串口操作需要的头文件:

#include <stdio.h> ``标准输入输出定义*/ 
#include <stdlib.h> /*标准函数库定义*/ 
#include <unistd.h> /*Unix 标准函数定义*/ 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h> /*错误号定义*/ 

2.1打开串口

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

  • 串口0为:/dev/ttyS0
  • 串口1为:/dev/ttyS1
  • 串口2为:/dev/ttyS2

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

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

2.2设置串口

2.2.1重要成员

串口的设置主要通过设置struct termios 结构体的各成员值,来设置波特率,效验位和停止位等。在设置波特率时需在数字前加上‘B’,如B9600。B19200。使用其需通过“与”“或”操作方式。

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 */
};

其中,c_cflag成员

输入模式c_iflag成员

2.2.2重要控制函数

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

3.设置串口的流程

  • 保存原先串口配置使用tcgetattr(fd,&oldtio)函数

      struct termios newtio,oldtio; 
      tcgetattr( fd,&oldtio );
    
  • 激活选项有CLOCAL和CREAD,用于本地连接和接收使能。

      newtio.c_cflag | = CLOCAL | CREAD; 
    
  • 设置波特率,使用函数cfsetispeed、 cfsetospeed

      cfsetispeed(&newtio, B115200);
      cfsetospeed(&newtio, B115200);
    
  • 设置数据位,需使用掩码设置。

      newtio.c_cflag &= ~CSIZE;
      newtio.c_cflag |= CS8; 
    
  • 设置奇偶校验位,使用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;

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

      newtio.c_cflag &= ~CSTOPB;
    
  • 设置最少字符和等待时间,对于接收字符和等待时间 没有特别要求时,可设为0。

      newtio.c_cc[VTIME] = 0; 
      newtio.c_cc[VMIN] = 0;
    
  • 处理要写入的引用对象
    tcflush函数刷清(抛弃)输入缓存(终端驱动程序已接 收到,但用户程序尚未读)或输出缓存(用户程序已经写,但尚未发送)。

      int tcflush(int filedes, int queue)
      queue数应当是下列三个常数之一: 
      TCIFLUSH 刷清输入队列。
      TCOFLUSH 刷清输出队列。
      TCIOFLUSH 刷清输入、输出队列。
    
  • 激活配置。在完成配置后,需激活配置使其生效。使用tsettattr()函数。

tsettattr()函数原型:

int tcgetattr(int filedes, struct termios *termptr);
int tcsetattr(int filedes, int opt, const struct termios * termptr); 
tcsetattr的参数opt使我们可以指定在什么时候新的终端属性才起作用。opt可以指定为下列常数中的一个:
TCSANOW 更改立即发生。
TCSADRAIN 发送了所有输出后更改才发生。若更改输出参数则应使用此选择项。
TCSAFLUSH 发送了所有输出后更改才发生。更进一步,在更改发生时未读的所有输入数据都被删除(刷清) 
使用如:tcsetattr(fd,TCSANOW,&newtio)

4.代码范例

4.1初始化串口

void init_tty(int fd) 
{
	 struct termios newtio;
	 struct termios oldtio; 
	 bzero(&newtio,sizeof(struct termios));
	 tcgetattr(fd,&oldtio);
	 newtio.c_cflag |= CLOCAL | CREAD;
	 cfsetispeed(&newtio,B115200);    //设置输入速度 
	 cfsetospeed(&newtio,B115200);    //设置输出速度 
	 //设置数据位为8位
	 newtio.c_cflag &= ~CSIZE;       //对应比特位清零 
	 newtio.c_cflag |= CS8;          //对应比特位置位
	 //设置无校验 
	 newtio.c_cflag &= ~PARENB; 
	 newtio.c_iflag &= ~INPCK;
	 //设置1位停止位 
	 newtio.c_cflag &= ~CSTOPB; 
	 //设置最少字符与时间 
	 newtio.c_cc[VTIME] = 0; 
	 newtio.c_cc[VMIN] = 0; 
	 //刷清串口缓存 
	 tcflush(fd,TCIOFLUSH); 
	 //设置新的属性到串口文件 
	 tcsetattr(fd,TCSANOW,&newtio);
 }

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

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

4.2读写串口

读写串口时,把把串口当作文件进行读写。

//写
char buffer[1024];
int Length;
int nByte;
nByte = write(fd, buffer ,Length) 
//读
char buff[1024];
int Len;
int readByte = read(fd,buff,Len);

4.3关闭串口

close(fd);

4.4例程

#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"; //串口1 
	fd = OpenDev(dev);
	init_tty(fd);
	//循环读取数据
	while (1) {
	while((nread = read(fd, buff, 512))>0){ 
			printf("
Len %d
",nread); buff[nread+1]= '';
			printf( "
%s", buff);
		}
	}
//close(fd);
}

参考资料:

http://www.cnblogs.com/chengmin/p/3818133.html
http://blog.csdn.net/zhoutaopower/article/details/35785023
http://blog.csdn.net/zhoutaopower/article/details/42400965
http://blog.csdn.net/hwmt2012/article/details/17148331


原文地址:https://www.cnblogs.com/boyiliushui/p/6675825.html