1..
用户常见的数据通信的基本方式有两种:
并行通信;
串行通信;
串行通信是计算机常用的接口,如:
RS-232-C
接口。该标准规定采用一个
DB25
芯引脚连接器或
DB9
芯引脚连接器。
芯片内部常具有
UART
控制器,其可工作于
Interrupt(
中断模式
)
或
DMA
(直接内存访问)模式。
2.
UART
的操作主要包括以下几个部分:
数据发送;
数据接收;
产生中断;
产生波特率;
Loopback
模式;
红外模式;
自动流控模式
串口参数的配置主要包括:波特率、数据位、停止位、流控协议。
3.
linux
中的串口设备文件存放于
/dev
目录下,其中串口一,串口二对应设备名依次为“
/dev/ttyS0
”、“
/dev/ttyS1
”。在
linux
下操作串口与操作文件相同。
4.
在使用串口之前必须设置相关配置,包括:波特率、数据位、校验位、停止位等。串口设置由下面结构体实现:
4.1
该结构中
c_cflag
最为重要,可设置波特率、数据位、校验位、停止位。在设置波特率时需在数字前加上‘
B
’,如
B9600
。
B19200
。使用其需通过“与”“或”操作方式。
4.2
输入模式
c_iflag
成员控制端口接收端的字符输入处理。
5.
串口控制函数
Tcgetattr
取属性
(termios
结构
)
Tcsetattr
设置属性
(termios
结构
)
cfgetispeed
得到输入速度
Cfgetospeed
得到输出速度
Cfsetispeed
设置输入速度
Cfsetospeed
设置输出速度
Tcdrain
等待所有输出都被传输
tcflow
挂起传输或接收
tcflush
刷清未决输入和
/
或输出
Tcsendbreak
送
BREAK
字符
tcgetpgrp
得到前台进程组
ID
tcsetpgrp
设置前台进程组
ID
6.
串口配置流程
6.1
保存原先串口配置使用
tcgetattr(fd,&oldtio)
函数
struct termios newtio,oldtio;
tcgetattr( fd,&oldtio
);
6.2
激活选项有
CLOCAL
和
CREAD,
用于本地连接和接收使能。
newtio.c_cflag | = CLOCAL | CREAD;
以下是我自己写的一个串口,仅供参考
/*****************************************************************************/
#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;
}
memset( &newtio, sizeof( newtio ) );//
将串口配置的结构体清零
newtio.c_cflag |= CLOCAL | CREAD; //
激活选项有
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;//
设置停止位为
1
位
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;//
设置停止位为
2
位
newtio.c_cc[VTIME] = 1;//read
调用读到数据则立即返回,否则将为每个字符最多等待
1
个时间
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","/dev/ttyS3"};
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;
while(1)
{
完成文件的读写操作
}
close(fd);
return;
}
/*****************************************************************************/