linux的设计思想是一切皆文件,对于串口的访问,通过/dev/ttyxx实现对串口设备的访问.
1.串口基本操作
串口最基本的操作是open/read/write. 如下所示是最基本的串口操作程序, open函数打开设备节点,read函数读取串口数据,write函数向串口写入数据.实现终端接收到串口数据,再原封不动的发送给对端.在我们的实际应用中,串口一般外接各类串口模块,比如GPS等.会涉及到配置串口波特率、数据位、停止位等参数.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <asm/termios.h>
#define DEV_UART "/dev/ttySAC0"
int main (int argc, char *argv[])
{
int fd;
int len, i,ret;
char buf[100] = {0};
fd = open(DEV_UART, O_RDWR | O_NOCTTY);
if(fd < 0) {
perror(DEV_UART);
return -1;
}
while(1){
len = read(fd, buf, sizeof(buf));
if (len > 0){
write(fd, buf, len);
}
}
return 0;
}
2.串口参数设置
串口参数涉及串口波特率、数据位、停止位、奇偶检验位.linux下使用struct termios 结构体来描述这些属性.设置串口参数的流程为,tcgetattr()获取终端属性参数,然后设置串口参数,最后调用tcsetattr()设置终端属性.
struct termios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
};
2.1. 波特率设置
cfgetispeed和cfgetospeed获取串口的输入输出波特率. cfsetispeed和cfsetospeed设置串口的输入输出波特率.
一般情况下,串口的输入输出波特率都设置为相同的值.
// 设置串口波特率
static void set_baudrate (struct termios *opt, unsigned int baudrate)
{
cfsetispeed(opt, baudrate);
cfsetospeed(opt, baudrate);
}
2.2. 数据位设置
数据位置是每个字节中的实际数据所占据的bit数.数据位通过修改struct termios结构体中的c_cflag成员变量实现.CS5、CS6、CS7和CS8分别表示数据位为5、6、7和8.设置数据位之前,先使用CSIZE做位屏蔽.
// 设置数据位.
static void set_data_bit (struct termios *opt, unsigned int databit)
{
opt->c_cflag &= ~CSIZE;
switch (databit) {
case 8:
opt->c_cflag |= CS8;
break;
case 7:
opt->c_cflag |= CS7;
break;
case 6:
opt->c_cflag |= CS6;
break;
case 5:
opt->c_cflag |= CS5;
break;
default:
opt->c_cflag |= CS8;
break;
}
}
2.3. 奇偶校验位
奇偶检验可以选择奇校验、偶检验或者不校验.
// 设置奇偶校验.
static void set_parity (struct termios *opt, char parity)
{
switch (parity) {
case 'N': /* no parity check */
opt->c_cflag &= ~PARENB;
break;
case 'E': /* even */
opt->c_cflag |= PARENB;
opt->c_cflag &= ~PARODD;
break;
case 'O': /* odd */
opt->c_cflag |= PARENB;
opt->c_cflag |= ~PARODD;
break;
default: /* no parity check */
opt->c_cflag &= ~PARENB;
break;
}
}
2.4.停止位设置
static void set_stopbit (struct termios *opt, const char *stopbit)
{
if (0 == strcmp (stopbit, "1")) {
opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
} else if (0 == strcmp (stopbit, "1")) {
opt->c_cflag &= ~CSTOPB; /* 1.5 stop bit */
} else if (0 == strcmp (stopbit, "2")) {
opt->c_cflag |= CSTOPB; /* 2 stop bits */
} else {
opt->c_cflag &= ~CSTOPB; /* 1 stop bit */
}
}
3.测试函数
int main (int argc, char *argv[])
{
int fd;
int len;
char buf[1024] = {0};
struct termios opt;
fd = open(DEV_UART, O_RDWR | O_NOCTTY);
if(fd < 0) {
perror(DEV_UART);
return -1;
}
tcgetattr(fd, &opt);
//设置波特率
set_baudrate(&opt, B115200);
opt.c_cflag |= CLOCAL | CREAD; /* | CRTSCTS */
//设置数据位
set_data_bit(&opt, 8);
//设置校验位
set_parity(&opt, 'N');
//设置停止位
set_stopbit(&opt, "1");
tcsetattr (fd, TCSANOW, &opt);
while(1){
len = read(fd, buf, sizeof(buf));
if (len > 0){
write(fd, buf, len);
}
}
return 0;
}