一、串口设备节点
二、访问并口1.打开并口
#include /* Standard input/output definitions */
#include /* String function definitions */
#include /* UNIX standard function definitions */
#include /* File control definitions */
#include /* Error number definitions */
#include /* POSIX terminal control definitions */
/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int open_port(void)
{
int fd; /* File descriptor for the port */
fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/ttyf1 - ");
} else {
fcntl(fd, F_SETFL, 0);
}
return (fd);
}
额外的设置标志:
2.发送数据
n = write(fd, "ATZrn", 5);
if (n < 0) {
fputs("write() of 5 bytes failed!n", stderr);
}
write函数写完后会返回发送的字节数linux下串口驱动,倘若发生错误会返回-1.
3.接收数据
(1)在原始数据模式操作并口时,使用read函数即可。
成功读取时,返回并口输入buffer中实际可用的字符数目,当并口输入buffer中没有可用字符时,会引起堵塞直至新的字符到来。
read函数也可以设置直接返回,当读取不到可用字符时linux学习,立刻返回0:
fcntl(fd, F_SETFL, FNDELAY);
假如想要恢复read函数的堵塞机制,可以再度设置:
fcntl(fd, F_SETFL, 0);
4.关掉并口
close(fd);
三、设置并口(重点)1.POSIXTerminal插口
大多数系统都支持POSIXterminal(serial)插口来改变并口参数,例如码率,数据宽度等。
首先包含头文件:
#include
该文件中和POSIX控制函数一样linux下串口驱动,定义了终端控制结构体Termios:
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 32
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 */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
#define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
#define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
};
其中每项成员的意义如下:
成员意义
c_cflag
控制设置
c_lflag
本地设置
c_iflag
输入设置
c_oflag
输出设置
c_cc
控制字符
c_ispeed
输入速度
c_ospeed
输出速度
两个最重要的POSIX函数是tcgetattr和tcsetattr,获取参数和设置参数,原型如下:
/* Put the state of FD into *TERMIOS_P. */
extern int tcgetattr (int __fd, struct termios *__termios_p) __THROW;
/* Set the state of FD to *TERMIOS_P.
Values for OPTIONAL_ACTIONS (TCSA*) are in . */
extern int tcsetattr (int __fd, int __optional_actions,
const struct termios *__termios_p) __THROW;
tcsetattr在设置参数时可选择的标志如下:
/* tcsetattr uses these */
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
2.控制设置(ControlOptions)
c_cflag成员控制码率深度linux系统,数据位、校验位、停止位的长度,和硬件流控。
2.1.可选常量
这种设置选项支持的值都早已被定义为常量,如下。
(1)码率
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
#define __MAX_BAUD B4000000
(2)数据位
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
(3)停止位
//设置该值则为2个停止位,不设置则为1个停止位
#define CSTOPB 0000100
(4)校准位
//使能校验位
#define PARENB 0000400
//设置该值则使用奇校验,否则使用偶校验
#define PARODD 0001000
2.2.建议使能的标志
还有两个选项应当始终被启用:
#define CREAD 0000200
#define CLOCAL 0004000
这两个设置确保你的程序不会变为端口的所有者而遭到影响,但是并口驱动程序将会速率传入的数据。
在设置c_cflag成员的时侯,一定不能直接形参,要使用位操作来设置或则消除对应的位。
2.3.设置示例
(1)设置码率为115200
struct termios options;
/*
* Get the current options for the port...
*/
tcgetattr(fd, &options);
/*
* Set the baud rates to 115200...
*/
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
/*
* Set the new options for the port...
*/
tcsetattr(fd, TCSANOW, &options)
(2)设置数据位为8位
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
(3)设置无校准位
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
(6)设置无硬件流控
options.c_cflag &= ~CNEW_RTSCTS;
3.本地设置(LocalOptions)
c_lflag成员控制输入的字符怎么被并口驱动管理,通常拿来设置是否使用原始数据模式即可。
开启原始数据模式:
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
四、串口回传示例
#include
#include
#include
#include
#include
#include
/* 115200, 8, N, 1 */
int uart_setup(int fd)
{
struct termios options;
// 获取原有串口配置
if (tcgetattr(fd, &options) < 0) {
return -1;
}
// 修改控制模式,保证程序不会占用串口
options.c_cflag |= CLOCAL;
// 修改控制模式,能够从串口读取数据
options.c_cflag |= CREAD;
// 不使用流控制
options.c_cflag &= ~CRTSCTS;
// 设置数据位
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// 设置奇偶校验位
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
// 设置停止位
options.c_cflag &= ~CSTOPB;
// 设置最少字符和等待时间
options.c_cc[VMIN] = 1; // 读数据的最小字节数
options.c_cc[VTIME] = 0; //等待第1个数据,单位是10s
// 修改输出模式,原始数据输出
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// 设置波特率
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
// 清空终端未完成的数据
tcflush(fd, TCIFLUSH);
// 设置新属性
if(tcsetattr(fd, TCSANOW, &options) < 0) {
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int fd;
int ret;
char ch;
if (argc != 2) {
printf("usage: ./test_uart [device]n");
return -1;
}
/* 打开串口 */
fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
printf("open dev fail!n");
return -1;
} else {
fcntl(fd, F_SETFL, 0);
}
/* 设置串口 */
ret = uart_setup(fd);
if (ret < 0) {
printf("uart setup fail!n");
close(fd);
return -1;
}
/* 串口回传实验 */
while (1) {
scanf("%c", &ch);
ret = write(fd, &ch, 1);
printf("write [%c] , ret is %d!rn", ch, ret);
ret = read(fd, &ch, 1);
if (ret < 1) {
printf("read fail, ret is %drn", ret);
} else {
printf("recv a char:[0xx][%c]rn", ch, ch);
}
}
close(fd);
}
编译:
arm-linux-gnueabihf-gcc uart_app.c -o uart_app
在开发板上执行: