如何找到串口设备号
串口之打开操作
串口之初始化
串口之发送
串口之接收
如何找到串口设备号
如果你使用的是开发板搭载Linux系统进行的串口编程,你可以通过原理图进行查看 如果你电脑安装的linux系统,那么插上串口,通过dmesg命令进行查看 本文例子使用/dev/ttyS0
串口之打开操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include
#include
#include
int main(){
int fd;
char *com = "/dev/ttyS0";
if((fd = open(com,O_RDWR|O_CREAT,0777))<0){
//fd返回-1打开失败
}else{
//打开成功
}
return 0;
}
串口之初始化
了解termio结构体
常用初始化函数
tcgetattr函数
cfgetispeed函数
cfgetospeed函数
cfsetispeed函数
cfsetospeed函数
tcflush函数
tcsetattr函数
初始化步骤
读取当前参数
修改参数
配置参数
了解termio结构体
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8struct termios
{
tcflag_t c_iflag;//输入模式
tcflag_t c_oflag;//输出模式
tcflag_t c_cflag;//控制模式
tcflag_t c_lflag;//本地模式
cc_t c_cc[NCCS];//控制字符
};
c_iflag参数如下:
键值
说明
IGNBRK
忽略BREAK键输入
BRKINT
如果设置了IGNBRK,BREAK键输入将被忽略
IGNPAR
忽略奇偶校验错误
PARMRK
标识奇偶校验错误
INPCK
允许输入奇偶校验
ISTRIP
去除字符的第8个比特
INLCR
将输入的NL(换行)转换成CR(回车)
IGNCR
忽略输入的回车
ICRNL
将输入的回车转化成换行(如果IGNCR未设置的情况下)
IUCLC
将输入的大写字符转换成小写字符(非POSIX)
IXON
允许输出时对XON/XOFF流进行控制
IXANY
输入任何字符将重启停止的输出
IXOFF
允许输入时对XON/XOFF流进行控制
IMAXBEL
当输入队列满的时候开始响铃
c_oflag参数如下:
键值
说明
OPOST
处理后输出
OLCUC
将输入的小写字符转换成大写字符(非POSIX)
ONLCR
将输入的NL(换行)转换成CR(回车)及NL(换行)
OCRNL
将输入的CR(回车)转换成NL(换行)
ONOCR
第一行不输出回车符
ONLRET
不输出回车符
OFILL
发送填充字符以延迟终端输出
OFDEL
以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符为NUL
NLDLY
换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
CRDLY
回车延迟,取值范围为:CR0、CR1、CR2和 CR3
TABDLY
水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
BSDLY
空格输出延迟,可以取BS0或BS1
VTDLY
垂直制表符输出延迟,可以取VT0或VT1
FFDLY
换页延迟,可以取FF0或FF1
c_cflag参数如下:
参数
说明
CBAUD
波特率(4+1位)(非POSIX)
CBAUDEX
附加波特率(1位)(非POSIX)
CSIZE
字符长度,取值范围为CS5、CS6、CS7或CS8
CSTOPB
设置两个停止位
CREAD
使用接收器
PARENB
使用奇偶校验
PARODD
对输入使用奇偶校验,对输出使用偶校验
HUPCL
关闭设备时挂起
CLOCAL
忽略调制解调器线路状态
CRTSCTS
使用RTS/CTS流控制
c_lflag参数如下:
参数
说明
ISIG
当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON
使用标准输入模式
XCASE
在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO
显示输入字符
ECHOE
如果ICANON同时设置,ERASE将删除输入的字符
ECHOK
如果ICANON同时设置,KILL将删除当前行
ECHONL
如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT
如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP
向后台输出发送SIGTTOU信号
c_cc[NCCS]参数如下:
宏
说明
宏
说明
VINTR
Interrupt字符
VEOL
附加的End-of-file字符
VQUIT
Quit字符
VTIME
非规范模式读取时的超时时间
VERASE
Erase字符
VSTOP
Stop字符
VKILL
Kill字符
VSTART
Start字符
VEOF
End-of-file字符
VSUSP
Suspend字符
VMIN
非规范模式读取时的最小字符数
常用初始化函数
tcgetattr函数
cfgetispeed函数
cfgetospeed函数
cfsetispeed函数
cfsetospeed函数
tcflush函数
tcsetattr函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34读取当前参数函数:
int tcgetattr(int fd,struct termios *termios_p)
fd:open操作后返回的文件句柄
*termios_p:为前面介绍的结构体
初始化开始前调用这个函数.
获取当前波特率函数:
int speed_t cfgetispeed(const struct termios *termios_p)
int speed_t cfgetospeed(const struct termios *termios_p)
*termios_p:为前面介绍的结构体
成功返回0,失败返回-1
波特率设置函数:
int cfsetispeed(struct termios *termios_p,speed_t speed)
int cfsetospeed(struct termios *termios_p,speed_t speed)
*termios_p:为前面介绍的结构体
speed:波特率,常用B2400,B4800,B9600,B115200,B460800
成功返回0,失败返回-1
清空buffer数据函数:
int tcflush(int fd,int queue_selector)
queue_selector:有三个常用宏定义
TCIFLUSH:清空正读的数据,且不会读出
TCOFLUSH:清空正写入的数据,且不会发送到终端
TCIOFLUSH:清空所有正在发生的I/O数据.
成功返回0,失败返回-1
设置串口参数函数:
int tcsetattr(int fd,int optional_actions,cons struct termios *termios_p)
optional_actions:有三个常用宏定义
TCSANOW:不等数据传输完毕,立即改变属性
TCSADRAIN:等所有数据传输完毕,再改变属性
TCSAFLUSH:清空输入输出缓冲区才改变属性
成功返回0,失败返回-1
初始化设置代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82/**
*fd:文件句柄
*nSpeed:波特率
*nBits:数据位
*nEvent:奇偶校验
*nStop:停止位
/
int set_opt(int fd,int nSpeed,int nBits,int nEvent ,int nStop){
struct termios newtio,oldtio;
if(tcgetattr(fd,&oldtio)!=0){
//错误
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;
case 460800:
cfsetispeed(&newtio,B460800);
cfsetospeed(&newtio,B460800);
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((tcsetttr(fd,TCSANOW,&newtio))!=0){
//com set error
return -1;
}
return 0;
}
串口之发送与接收
#include
#include
#include
#include
#include
#include
#include
#include
int set_opt(int,int,int,char,int);
void main()
{
int fd;
char *com= "/dev/ttyS0";
char *buffer = "hello world!\n";
if((fd = open(com, O_RDWR|O_NOCTTY|O_NDELAY))<0){
printf("open %s is failed",com);
}
else{
printf("open %s is success\n",com);
set_opt(fd, 115200, 8, 'N', 1);
wr_static = write(fd,buffer, strlen(buffer));
//读取差不多一样的这里就不介绍了
if(wr_static<0)
printf("write failed\n");
else
printf("wr_static is %d\n",wr_static);
close(fd);
}
}
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;
if ( tcgetattr( fd,&oldtio) != 0) {
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;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
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;
}
return 0;
}