1.驱动类函数
uart.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <errno.h>
#include "uart.h"
#define UART_PRINTF_INFO_EN 1 // 串口打印日志
#define SERIAL_BAUDRATE B115200 // 串口波特率
#define READ_BUF_SIZE 256 // 读取缓冲区大小
/**
* @brief TCP 监听线程
* @param func
* @return
*/
static void *recive_data(void *func)
{
HardwareUart *sm = (HardwareUart *)func;
sm->do_epoll();
return 0;
}
HardwareUart::HardwareUart()
{
#if UART_PRINTF_INFO_EN
printf("[%s]:> Add a serial device!\n", __func__);
#endif
}
HardwareUart::~HardwareUart()
{
this->Close();
}
/**
* @brief 设置回调接口
* @param callback 回调接口
*/
void HardwareUart::setCallback(UartCallback *callback)
{
m_UartCallback = callback;
}
/**
* @brief 串口打开
* @param port 端口
* @param baudrate 波特率
* @return 1 成功 other 失败
*/
int HardwareUart::Open(const char *port, speed_t baudrate)
{
if(GetState()){
printf("[%s]:> Open error, Uart is ENable!\n", __func__);
return -1;
}
_serialFd = open(port, O_RDWR | O_NOCTTY); // 打开串口设备文件
if (_serialFd == -1) {
perror("open_port: Unable to open serial port"); // 输出错误信息
return -1;
}
struct termios tty;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(_serialFd, &tty) != 0) { // 获取串口属性
perror("tcgetattr");
close(_serialFd);
return -1;
}
cfsetispeed(&tty, baudrate); // 设置输入波特率
cfsetospeed(&tty, baudrate); // 设置输出波特率
tty.c_cflag &= ~PARENB; // 禁用奇偶校验
tty.c_cflag &= ~CSTOPB; // 设置停止位为1
tty.c_cflag &= ~CSIZE; // 清除数据位设置
tty.c_cflag |= CS8; // 设置数据位为8位
tty.c_cflag &= ~CRTSCTS; // 禁用硬件流控
tty.c_cflag |= CREAD | CLOCAL; // 启用接收器,本地连接
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 设置输入模式
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控
tty.c_oflag &= ~OPOST; // 设置输出模式
tty.c_cc[VMIN] = 1; // 读取一个字符
tty.c_cc[VTIME] = 0; // 无超时
if (tcsetattr(_serialFd, TCSANOW, &tty) != 0) { // 设置串口属性
perror("tcsetattr");
close(_serialFd);
return -1;
}
tcflush(_serialFd, TCIFLUSH); // 刷新输入缓冲区
_deviceState = true;
// 启动线程
int res = pthread_create(&m_thread, NULL, recive_data, (void*)this);
if (res) {
printf("[%s]:> Create thread fail!\n", __func__);
_deviceState = false;
return -1;
}
#if UART_PRINTF_INFO_EN
printf("[%s]:> Open %s Successful!\n", __func__, port);
#endif
return _serialFd;
}
/**
* @brief 串口发送数据
* @param data 数据
* @param length 长度
* @return -1 失败 正常返回写入的长度
*/
int HardwareUart::Write(const unsigned char* data, int length)
{
int written = write(_serialFd, data, length); // 写入数据到串口
if (written == -1) {
#if UART_PRINTF_INFO_EN
perror("write");
#endif
return -1;
}
return written;
}
/**
* @brief 关闭串口
*/
void HardwareUart::Close()
{
#if UART_PRINTF_INFO_EN
printf("[%s]:> Close Uart!\n", __func__);
#endif
_deviceState = false;
close(_serialFd); // 关闭串口
pthread_exit(&m_thread);
}
/**
* @brief 获取设备状态
* @return 设备状态 true 打开 false 关闭
*/
bool HardwareUart::GetState()
{
return _deviceState;
}
/**
* @brief 处理串口数据
*/
void HardwareUart::do_epoll()
{
fd_set readfds;
unsigned char read_buffer[READ_BUF_SIZE];
int ret;
int bytes_read;
struct timeval tv;
#if UART_PRINTF_INFO_EN
printf("[%s]:> Start epoll!\n", __func__);
#endif
while (GetState()) {
// 将服务器套接字加入文件描述符集合
FD_ZERO(&readfds);
FD_SET(_serialFd, &readfds);
// 设置超时时间
tv.tv_sec = 5;
tv.tv_usec = 0;
// 使用select函数等待串口数据
ret = select(_serialFd + 1, &readfds, NULL, NULL, &tv);
if (ret == -1) {
perror("uart select");
break;
} else if (ret > 0) {
if (FD_ISSET(_serialFd, &readfds)) {
memset(read_buffer, 0, sizeof(read_buffer));
bytes_read = read(_serialFd, read_buffer, sizeof(read_buffer)); // 从串口读取数据
if (bytes_read == -1) {
perror("read uart");
// break;
} else {
read_buffer[bytes_read] = '\0'; // 添加字符串结束符
// printf("Received: %s\n", read_buffer); // 打印接收到的数据
m_UartCallback->onUartData(read_buffer, bytes_read);
}
}
}
}
#if UART_PRINTF_INFO_EN
printf("[%s]:> End epoll!\n", __func__);
#endif
}
uart.h
#ifndef __UART_H__
#define __UART_H__
#include <termios.h>
#include <pthread.h>
class UartCallback
{
public:
virtual void onUartData(unsigned char* buffer, int length) = 0;
};
class HardwareUart
{
public:
HardwareUart();
~HardwareUart();
/**
* @brief 串口打开
* @param port 端口
× @param baudrate 波特率
× @return 1 成功 other 失败
*/
int Open(const char *port, speed_t baudrate);
/**
* @brief 串口发送数据
* @param data 数据
× @param length 长度
× @return -1 失败 正常返回写入的长度
*/
int Write(const unsigned char* data, int length);
/**
* @brief 关闭串口
*/
void Close();
/**
* @brief 获取设备状态
*/
bool GetState();
/**
* @brief 处理串口数据
*/
void do_epoll();
/**
* @brief 设置回调接口
* @param callback 回调接口
*/
void setCallback(UartCallback *callback);
protected:
private:
// 串口的文件符
int _serialFd = 0;
// 设备的状态
bool _deviceState = false;
// 线程
pthread_t m_thread;
// 回调接口
UartCallback *m_UartCallback;
};
#endif // __UART_H__
2.使用例子
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "uart.h"
// Uaret1
class Uart1 : public UartCallback
{
public:
Uart1(){
m_HardwareUart = new HardwareUart;
m_HardwareUart->setCallback(this);
}
~Uart1(){
Close();
}
int Open(){
return m_HardwareUart->Open("/dev/ttyUSB0", B115200);
}
void Close(){
m_HardwareUart->Close();
}
int Write(const unsigned char* data, int length){
return m_HardwareUart->Write(data, length);
}
void onUartData(unsigned char* buffer, int length){
printf("[%s]:> Received: %s\n", __func__, buffer); // 打印接收到的数据
}
private:
HardwareUart *m_HardwareUart;
};
int main()
{
Uart1 *m_Uart1 = new Uart1;
if(m_Uart1->Open() == -1)
return -1;
m_Uart1->Write(data, 3);
while(1){
scanf("%s", (char*)data);
if(strstr((char*)data, "exit") != NULL)
break;
m_Uart1->Write(data, strlen((char*)data));
}
m_Uart1->Close();
printf("UART test!\n");
return 0;
}