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