Linux 使用C++驱动串口设备


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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值