在使用串口的时候要遵循以下的顺序才能使用。
1、打开串口设备
2、设置串口的波特率,数据位,校验位,停止位以及其它设置
3、写数据
4、读出数据
5、关闭串口。
在编写Linux串口的C程序之前,需要包含以下头文件:
#include
在Linux系统中,一切皆文件,所以串口设备也是一类文件,学习过Linux驱动程序的学员都知道,Linux有三类设备:字符设备,块设备,网络设备。那么串口设备属于字符设备。
所以串口设备的命名一般为/dev/ttySn(n = 0、1、2…),如果该串口为USB转串口,可能名称为/dev/ttyUSBn(n = 0、1、2…),不同的平台下串口的名称是不同的,
且串口的名称也是可以更改的。如何更改?在板卡对应的Linux驱动中更改。
在Linux下操作串口,那么也就是跟操作一个文件一样,既然是文件,也就可以使用标准的文件操作API来操作。
1、打开串口
int fd;
fd = open("/dev/ttyS0", O_RDWR|O_NOCTTY);
if(fd<0){
perror(“open uart device error\n”);
}
2、关闭串口
close(fd);
fd为文件描述符。
如果不设置串口的波特率,数据位,停止位,校验位的情况下,Linux下默认设置的属性值为:
波特率:9600
数据位:8
校验位:n(表示无)
停止位:1
在不设置串口属性值的情况下,也可以读写串口值。
3、读、写串口
使用read,write函数即可,例如:
len = write(fd, buf, sizeof(buf));
if (len < 0) {
printf(“write data error \n”);
}
len = read(fd, buf, sizeof(buf));
if (len < 0) {
printf(“read error \n”);
return -1;
}
以下例程是往串口写入一个数据,串口就会回复一个数据,也就是自发自收。
完整例程:
#include
#include
#include
#include
#include
#define DEV_NAME “/dev/ttyS1”
int main (int argc, char *argv[])
{
int fd;
int len, i,ret;
char buf[] = “hello ZLG!”;
fd = open(DEV_NAME, O_RDWR | O_NOCTTY);
if(fd < 0) {
perror(DEV_NAME);
return -1;
}
len = write(fd, buf, sizeof(buf));
if (len < 0) {
printf(“write data error \n”);
}
len = read(fd, buf, sizeof(buf));
if (len < 0) {
printf(“read error \n”);
return -1;
}
printf("%s", buf);
return(0);
}
上面给出的例程是串口驱动的默认属性值(9600,8n1,无流控),在实际产品开发过程中,还是会根据不同的应用场景来设置串口的属性。操作串口属性需要设置对应的标志,
在POSIX终端已经帮我们实现了若干结构体以及相应的标志位,我们只要熟练使用它即可,非常简单。
最重要的struct termios 结构体
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 */
};
1、设置串口波特率
struct termios opt;
if (tcgetattr(fd, &opt)< 0) {
return ERROR;
}
cfsetispeed(&opt, B9600); /设置为9600bps/
cfsetospeed(&opt, B9600);
if (tcsetattr(fd, TCSANOW, &opt)<0) {
return ERROR;
}
或者按以下用法:
struct termios opt;
tcgetattr(fd, &opt);
cfsetispeed(&opt,B19200); /设置为19200bps/
cfsetospeed(&opt,B19200);
tcsetattr(fd,TCANOW,&opt);
一般来说,输入、输出的波特率应该是一致的。
2、设置数据位
设置数据位不需要专用的函数,只需要在设置数据位之前用数据位屏蔽标志(CSIZE)把对应数据位清零,然后再设置新的数据位即可,如下所示:
options.c_cflag &= ~CSIZE;/* 先把数据位清零*/
options.c_cflag |= CS8;/* 把数据位设置为8位*/
3、设置校验位
正如设置数据位一样,设置奇偶校验是在直接在cflag成员上设置。下面是各种类型的校验设置方法。
1)无奇偶校验(8N1):
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
2)7位数据位奇偶校验(7E1):
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
3)奇校验(7O1):
options.c_cflag|= PARENB;
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
4、设置停止位
通过激活c_cflag中的CSTOPB而实现的。若停止位为1,则清除CSTOPB,若停止位为0,则激活CSTOPB。下面是停止位为1时的代码(CSTOPB表示2个停止位(清除该标志表示1个停止位):
options.c_cflag &= ~CSTOPB;