由於自己需要,封裝了一個串口的方案,單例模式
1.頭文件 uart.h
#ifndef ___UART_H___ #define ___UART_H___ #include <stdio.h> /*標准輸入輸出定義*/ #include <stdlib.h> /*標准函數庫定義*/ #include <iostream> #include <termios.h> #include <errno.h> #include <time.h> #include <pthread.h> #include <string.h> #include <dirent.h> #include <unistd.h> #include <fcntl.h> #include <unistd.h> #include <fcntl.h> #define DEFAULT_UART_COM "/dev/ttyS3" //環境探測器 #define DEFAULT_VMIN 5 #define DEFAULT_VTIME 6 class SerialPort { private: SerialPort(); //構造方法 public: // 串口打開關閉與讀寫 int openUart(const char* path); //設置串口波特率 int setSpeed(int fd, int speed); //設置串口的數據位、停止位、校驗位。 int setParity(int fd, int databits, int stopbits, char parity); //串口寫入數據 int writeUart(int fd, const void* data, size_t size); //讀取串口數據 int readUart(int fd, void* data, size_t size); //關閉串口 int closeUart(int fd); private: static SerialPort* m_instance_ptr; //單例變量 public: static pthread_mutex_t mutex; static SerialPort* getInstance(); //單例實例化函數 }; #endif // !___UART_H___
2.uarh.cpp 文件
#include "uart.h" //默認構造方法 SerialPort::SerialPort() { } /****************************************************************************** * Name : SerialPort::close * Author : cqnews * Version : V1.0.0 * Data : 2021.10.22 * Describe : 串口打開關閉與讀寫 * @path : 串口名稱 * @speed : 串口波特率 * @ospeed : 等待時間,單位百毫秒(讀) * *****************************************************************************/ int SerialPort::openUart(const char* path) { if (path == NULL) { return -1; } int fd = -1; fd = open(path, O_RDWR | O_NOCTTY); if (fd < 0) //串口打開失敗 { perror(path); return -2; } struct termios opt; tcgetattr(fd, &opt); tcflush(fd, TCIOFLUSH);//設置前flush cfsetispeed(&opt, B9600); //設置的輸入波特率 cfsetospeed(&opt, B9600); //設置的輸出波特率 //raw mode opt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); opt.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); opt.c_oflag &= ~(OPOST); opt.c_cflag &= ~(CSIZE | PARENB); opt.c_cflag |= CS8; //opt.c_cc[VMIN] = DEFAULT_VMIN; //最小字節數 //opt.c_cc[VTIME] = DEFAULT_VTIME; //等待時間,單位百毫秒 (讀) if (tcsetattr(fd, TCSANOW, &opt) != 0) //配置發生錯誤 { return -3; } tcflush(fd, TCIOFLUSH); //設置后flush return fd; } int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300, B38400, B19200, B9600, B4800, B2400, B1200, B300, }; int name_arr[] = { 38400, 19200, 9600, 4800, 2400, 1200, 300, 38400, 19200, 9600, 4800, 2400, 1200, 300, }; /****************************************************************************** * Name : SerialPort::setSpeed 串口波特率 * Author : cqnews * Version : V1.0.0 * Date : 2021.10.22 * Describe : 設置串口模特率,可以是下面的一個值 * 921600, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200, 300 * 返回值: 成功 0 ; 失敗 錯誤碼 ******************************************************************************/ int SerialPort::setSpeed(int fd, int speed) { if (speed < 300 || speed > 921600) { return -1; //參數異常 } int i; int length = sizeof(speed_arr) / sizeof(int); for (i = 0; i < length; i++) { if (speed == name_arr[i]) { tcflush(fd, TCIOFLUSH); termios opt; tcgetattr(fd, &opt); cfsetispeed(&opt, speed_arr[i]); cfsetospeed(&opt, speed_arr[i]); if (tcsetattr(fd, TCSANOW, &opt) != 0) //配置發生錯誤 { return -2; //配置異常 } tcflush(fd, TCIOFLUSH); //設置后flush return 0; } } return -2; } /****************************************************************************** * Name : SerialPort::setParity 串口波特率 * Author : cqnews * Version : V1.0.0 * Date : 2021.10.22 * Describe : 設置串口的數據位、停止位、校驗位。 * databit : 數據位 * stopbit : 停止位 * paritybit : 校驗位* * 返回值: 成功 0 ; 失敗 錯誤碼 ******************************************************************************/ int SerialPort::setParity(int fd, int databit, int stopbit, char paritybit) { termios opt; tcgetattr(fd, &opt); tcflush(fd, TCIOFLUSH);//設置前flush switch (databit) //數據位 { case 7: opt.c_cflag |= CS7; break; case 8: opt.c_cflag |= CS8; break; default: fprintf(stderr, "Unsupported data size\n"); return -1; } switch (stopbit) //停止位 { case 1: opt.c_cflag &= ~CSTOPB; break; //1 位停止位 case 2: opt.c_cflag |= CSTOPB; break; //2 位停止位,否則為 1 位 default: fprintf(stderr, "Unsupported stop bit\n"); return -2; } switch (paritybit) //校驗位 { case 'n': case 'N': opt.c_cflag &= ~PARENB; // 不校驗 opt.c_iflag &= ~INPCK; //關閉輸入奇偶校驗 opt.c_iflag &= ~(ICRNL | IGNCR); opt.c_lflag &= ~(ICANON); //不規范輸入 break; case 'o': //奇校驗 case 'O': opt.c_cflag |= PARENB; //進行奇偶校驗 opt.c_cflag |= PARODD; //奇校驗,否則為偶校驗 opt.c_iflag |= INPCK; //打開輸入奇偶校驗 break; case 'e': //偶校驗 case 'E': opt.c_cflag |= PARENB; // 進行奇偶校驗 opt.c_cflag &= ~PARODD; //偶校驗 opt.c_iflag |= INPCK; //打開輸入奇偶校驗 break; case 'S': case 's': /*as no parity*/ opt.c_cflag &= ~PARENB; //不進行奇偶校驗 opt.c_cflag &= ~CSTOPB; //1 位停止位 break; default: fprintf(stderr, "Unsupported parity bit\n"); return -3; } if (tcsetattr(fd, TCSANOW, &opt) != 0) //配置發生錯誤 { return -4; } tcflush(fd, TCIOFLUSH); //設置后flush return 0; } /****************************************************************************** * Name : SerialPort::close * Author : cqnews * Version : V1.0.0 * Date : 2021.10.22 * Describe : 串口寫入數據 ******************************************************************************/ int SerialPort::writeUart(int fd, const void* buff, size_t size) { if (buff == NULL || size <= 0) { return -1; } return write(fd, buff, size); } /****************************************************************************** * Name : SerialPort::close * Author : cqnews * Version : V1.0.0 * Date : 2021.10.22 * Describe : 讀取串口數據 ******************************************************************************/ int SerialPort::readUart(int fd, void* buff, size_t size) { if (buff == NULL || size <= 0) { return -1; } return read(fd, buff, size); } /****************************************************************************** * Name : SerialPort::close * Author : cqnews * Version : V1.0.0 * Date : 2021.10.22 * Describe : 關閉串口 ******************************************************************************/ int SerialPort::closeUart(int fd) { close(fd); return 0; } /****************************************************************************** * Name : Logger::Logger * Author : cqnews * Version : V1.0.0 * Date : 2021.07.28 * Describe : 串口單例函數 ******************************************************************************/ SerialPort* SerialPort::getInstance() { if (m_instance_ptr == NULL) { pthread_mutex_lock(&mutex); if (m_instance_ptr == NULL) { m_instance_ptr = new SerialPort(); } pthread_mutex_unlock(&mutex); } return m_instance_ptr; } pthread_mutex_t SerialPort::mutex; SerialPort* SerialPort::m_instance_ptr = NULL;
3.測試方法
LINK = @echo linking $@ && arm-linux-gnueabihf-g++ GCC = @echo compiling $@ && arm-linux-gnueabihf-g++ GC = @echo compiling $@ && arm-linux-gnueabihf-gcc AR = @echo generating static library $@ && ar crv FLAGS = -g -DDEBUG -W -Wall -fPIC -std=c++11 GCCFLAGS = DEFINES = HEADER = -I./ -I/usr/arm32/include LIBS = -L./ -L/usr/arm32/lib LINKFLAGS = LIBS += -pthread -lm SOURCE_FILES :=\ main.cpp\ app/uart/uart.cpp\ PROJECTNAME = UartDemo.out TARGET = main all: $(SOURCE_FILES) $(LINK) $(FLAGS) $(LINKFLAGS) -o ${PROJECTNAME} $^ $(LIBS) ${HEADER} clean: rm -rf *.o ${PROJECTNAME}
