打开串口设备:首先需要打开串口设备文件,通常是/dev/ttyX(如/dev/ttyUSB0,/dev/ttyS0等)。可以使用open()系统调用打开串口设备文件,获取一个文件描述符。
配置串口属性:打开串口后,需要配置串口的属性,例如波特率、数据位、奇偶校验、停止位等。可以使用termios库来设置串口属性。
读写数据:串口配置完成后,可以使用read()和write()系统调用来进行串口数据的读取和写入。
此外,还可以通过select()或poll()等系统调用进行多路复用,实现同时监听串口和其他文件描述符上的事件
在打开串口设备时,可以使用一些标志位(flags)来设置打开模式和行为。下面是常见的一些标志位及其含义:
O_RDWR
:以读写模式打开设备。允许读取和写入设备数据。
O_NOCTTY
:如果设备是终端设备(例如串口),不将它作为进程的控制终端。这通常用于防止串口设备接管终端特性(如终端窗口)。一般在打开串口设备时使用这个标志位。
O_NDELAY
(也叫O_NONBLOCK
):将文件描述符设置为非阻塞模式。在非阻塞模式下,读取和写入文件描述符将立即返回。如果没有数据可读取,读取操作将返回-1,并将errno
设置为EAGAIN
。如果写入操作无法立即完成,将返回-1,并将errno
设置为EAGAIN
。不建议在打开串口时使用此标志位,因为在阻塞式读取串口数据时,我们希望等待数据的到达。
O_RDONLY
:以只读模式打开设备。只允许读取设备数据。
O_WRONLY
:以只写模式打开设备。只允许写入设备数据。
O_CREAT
:如果设备不存在,创建设备。在使用此标志位时,需要提供另外的参数,如文件权限。
O_EXCL
:与O_CREAT
一起使用,确保创建新设备而不是打开现有设备。
O_APPEND
:以追加模式打开设备。每次写入操作都将数据追加到文件末尾。
O_TRUNC
:打开设备之前,先将其内容截断为零长度。
/**
******************************************************************************
* @file bsp_uart.c
* @author cj
* @version V1.0
* @date 2019/4
* @brief
******************************************************************************
* @attention
******************************************************************************
*/
#include "bsp_uart.h"
#include "typedef.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
static UartStatus initComm(const char *ttyDir, const int stop, const unsigned speed)
{
UartStatus uartStatus;
uartStatus.fd = -1;
uartStatus.isEnabled = false;
int retry = 60;
uartStatus.fd = open(ttyDir, O_RDWR | O_NOCTTY /*| O_NDELAY*/);
if (uartStatus.fd < 0)
{
CJdebug("can not open this driver\n");
return uartStatus;
}
while (lockf(uartStatus.fd, F_TLOCK, 0) < 0)
{
sleep(1);
retry--;
if (retry <= 0)
{
CJdebug("Devcie %s locked.\n", ttyDir);
close(uartStatus.fd);
return uartStatus;
}
}
unsigned currentSpeed = B9600;
switch (speed)
{
case 9600:
currentSpeed = B9600;
break;
case 38400:
currentSpeed = B38400;
break;
case 57600:
currentSpeed = B57600;
break;
case 115200:
currentSpeed = B115200;
break;
default:
CJdebug("speed error\n");
return uartStatus;
}
struct termios Opt;
tcgetattr(uartStatus.fd, &Opt);
cfsetispeed(&Opt, currentSpeed);
cfsetospeed(&Opt, currentSpeed);
tcsetattr(uartStatus.fd, TCSANOW, &Opt);
tcflush(uartStatus.fd, TCIOFLUSH);
tcgetattr(uartStatus.fd, &Opt);
/* Set data bit 8bit */
Opt.c_cflag &= ~CSIZE;
Opt.c_cflag |= CS8;
Opt.c_cflag |= IXON | IXOFF | IXANY;
/* Set parity bit: None parity bit */
Opt.c_cflag &= ~PARENB;
/* stop bit */
switch (stop)
{
case 1:
Opt.c_cflag &= ~CSTOPB;
break;
case 2:
Opt.c_cflag |= CSTOPB;
break;
default:
Opt.c_cflag &= ~CSTOPB;
break;
}
Opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
Opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
Opt.c_oflag &= ~OPOST;
/* set timeout in deciseconds for non-canonical read */
Opt.c_cc[VTIME] = 150; //over time
Opt.c_cc[VMIN] = 0; //DATA_LEN;
if (tcsetattr(uartStatus.fd, TCSANOW, &Opt) < 0)
{
perror(ttyDir);
close(uartStatus.fd);
return uartStatus;
}
tcflush(uartStatus.fd, TCIOFLUSH);
uartStatus.isEnabled = true;
return uartStatus;
}
/**
* @brief Uart_init
* @param speed
* @param stop
* @param name
* @return
*/
UartStatus uartInit(const unsigned speed, const int stop, const char *name)
{
char dev[64] = {0};
memset(dev, 0, sizeof(dev));
sprintf(dev, "/dev/%s", name);
UartStatus status = initComm(dev, stop, speed);
return status;
}
int uart_readComm(UartStatus *uart, char *data, int dataLen)
{
return read(uart->fd, data, dataLen);
}
bool uart_writeComm(UartStatus *uart, unsigned char *data, int dataLen)
{
if(write(uart->fd, data, dataLen) < dataLen)
{
CJdebug("uartComm write error !\n");
return false;
}
return true;
}
#ifndef BSP_UART_H
#define BSP_UART_H
#ifdef __cplusplus
extern "C" {
#endif
#include "typedef.h"
typedef struct _UartStatus
{
int fd;
bool isEnabled;
} UartStatus;
UartStatus uartInit(const unsigned speed, const int stop, const char *name);
bool uart_writeComm(UartStatus *uart, unsigned char *data, int dataLen);
int uart_readComm(UartStatus *uart, char *data, int dataLen);
#ifdef __cplusplus
}
#endif
#endif