背景
这段代码是一个简单的串口通信库的示例,用于在类Unix操作系统(如Linux)上进行基本的串口通信。它包含了串口的打开、配置、读写操作以及关闭。为了便于理解和后续扩展,代码中的所有函数和结构体都采用了统一的前缀 cm(意为“Customized Module”或“Communication Module”)。该库支持异步读取,即当串口有数据到达时,将通过回调函数处理这些数据。此外,代码中也包括了写操作,用于向串口发送数据。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
typedef void (*CM_SERIAL_CALLBACK)(const char *data, int len);
typedef struct {
int fd;
bool active;
CM_SERIAL_CALLBACK callback;
pthread_t thread_id;
} CM_SERIAL_ARGS_ST;
void *cm_serial_listener(void *args) {
CM_SERIAL_ARGS_ST *port = (CM_SERIAL_ARGS_ST *)args;
char buf[1024];
int n;
while (port->active) {
n = read(port->fd, buf, sizeof(buf));
if (n > 0) {
port->callback(buf, n);
}
}
return NULL;
}
CM_SERIAL_ARGS_ST* cm_serial_open(const char *device, int baudrate, CM_SERIAL_CALLBACK callback) {
int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
perror("Unable to open serial device");
return NULL;
}
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
perror("Error from tcgetattr");
return -1;
}
cfsetospeed(&tty, baudrate);
cfsetispeed(&tty, baudrate);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= 0;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("Error from tcsetattr");
return -1;
}
CM_SERIAL_ARGS_ST *port = malloc(sizeof(CM_SERIAL_ARGS_ST));
port->fd = fd;
port->active = true;
port->callback = callback;
if(pthread_create(&port->thread_id, NULL, &cm_serial_listener, port)) {
perror("Failed to create the serial listener thread");
close(fd);
free(port);
return NULL;
}
return port;
}
int cm_serial_write(CM_SERIAL_ARGS_ST *port, const char *data, int len) {
return write(port->fd, data, len);
}
void cm_serial_close(CM_SERIAL_ARGS_ST *port) {
if (port) {
port->active = false;
pthread_join(port->thread_id, NULL);
close(port->fd);
free(port);
}
}
void cm_callback(const char *data, int len) {
printf("Received data: ");
fwrite(data, 1, len, stdout);
printf("\n");
}
int main() {
CM_SERIAL_ARGS_ST *port = cm_serial_open("/dev/ttyS0", B9600, cm_callback);
if (port == NULL) exit(1);
// 示例写操作
const char *message = "Hello, Serial Port!";
int bytes_written = cm_serial_write(port, message, strlen(message));
if (bytes_written >= 0) {
printf("Sent: %s\n", message);
} else {
perror("Failed to write to serial port");
}
// 当需要关闭串口时
cm_serial_close(port);
return 0;
}