C++:串口

  • cm_uart_mcu.h文件:
#ifndef CM_UTILS_UART_H_
#define CM_UTILS_UART_H_

#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>

/* 返回成功 */
#define SUCCESS 0
/* 返回失败 */
#define FAILURE -1
/* 设备未找到 */
#define DEV_NOT_FOUND -1
/* 接收缓存区大小 */
#define MAX_RECV_BUF 1024


typedef unsigned char BYTE;
typedef unsigned int DWORD;
typedef unsigned short WORD;


/* 串口类 */
class CM_Serial
{
public:
	CM_Serial();

	virtual ~CM_Serial();
	
	//串口设备文件描述符
	int fd;

	int open(const char* com_port);

	/* 设置串口参数 */
	int set_uart_config(int fd, int baud,int dataBits,int parityMode,int stopBits);

	int close(int fd);

	int write(int fd, char* buf,int len);
	
	/* 创建线程函数 */
	virtual int PCreate();
	
	/* 等待接收线程结束 */
	virtual void wait_thread_end();
	
	/* 打印十六进制数据 --- 调试用*/
	void pri_hex( const BYTE *buf, const DWORD len, const char *pname);

private:
	//接收线程描述符
	pthread_t tid;

	//接收线程函数
	friend void *RecThread(void* arg);
};

#endif

  • cm_uart_mcu.cpp文件:
#include "../include/cm_uart_mcu.h"

/*************************************************************** (线程函数)友元函数 ***************/

/*******************************************************************************************
函数名称: receiveThread
描   述 : 读取串口信息     ------------------------线程 (友元函数)
输入参数:
输出参数: 无
返   回 : 实际读取长度
********************************************************************************************/
void* RecThread(void* arg)
{
	CM_Serial* tmp_serial=(CM_Serial*)arg;
	int len = -1;
	char buf[MAX_RECV_BUF];
	memset(buf, 0, sizeof(buf));

	/* 设置线程取消使能 */
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	while(true)
		{
			/* 回收线程。线程取消点 */
			pthread_testcancel();
			/* 设置异步取消(收到信号,马上回收) */
			pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
			len=read(tmp_serial->fd,buf,sizeof(buf));
			if(len>0)
				{
					tmp_serial->pri_hex((BYTE *)buf, len , __FUNCTION__);
				}
		}
}

/*************************************************************** (线程函数)友元函数 ***************/

/*************************************************************** CM_Serial类函数 ********************/

/* 构造函数 */
CM_Serial::CM_Serial()
{

}
/* 析构函数 */
CM_Serial::~CM_Serial()
{
	::close(fd);
}

/*******************************************************************************************
函数名称: CM_Serial::open
描   述 : 打开串口
输入参数: 设备节点名称
输出参数: 无
返   回 : 串口设备文件描述符
********************************************************************************************/
int CM_Serial::open(const char* dev)
{
	int fd;
	int Ret;
	if(dev == NULL)
		return FAILURE;

	/* 以阻塞的方式打开 */
	fd=::open(dev,O_RDWR|O_NOCTTY);
	if(fd < 0)
		return DEV_NOT_FOUND;

	//测试是否为终端设备
	Ret = isatty(STDIN_FILENO);
	if(Ret ==0 )
		printf("isatty error \n");

	this->fd  = fd;

	return fd;

}

/*******************************************************************************************
函数名称: CM_Serial::set_uart_config
描   述 : 配置串口参数
输入参数: 串口设备文件描述符、波特率、数据位数、校验模式、停止位数
输出参数: 无
返   回 : 函数执行结果
********************************************************************************************/
int CM_Serial::set_uart_config(int fd, int baud, int dataBits,int parityMode,int stopBits)
{
	struct termios new_cfg,old_cfg;
	int speed;
	int Ret;
	
	/* tcgetattr函数用于获取与终端相关的参数 */
	if(tcgetattr(fd,&old_cfg)!=0)
		{
			perror("tcgetattr");
			return -1;
		}
	tcflush(fd, TCIOFLUSH);

	new_cfg=old_cfg;
	cfmakeraw(&new_cfg);/* 配置为原始模式 */
	new_cfg.c_cflag&=~CSIZE;

	/* 设置波特率*/
	switch(baud)
		{
		case 2400:
		{
			speed = B2400;
			break;
		}
		case 4800:
		{
			speed = B4800;
			break;
		}
		case 9600:
		{
			speed = B9600;
			break;
		}
		case 19200:
		{
			speed = B19200;
			break;
		}
		case 38400:
		{
			speed = B38400;
			break;
		}
		case 115200:
		{
			speed = B115200;
			break;
		}
		}
	cfsetispeed(&new_cfg,speed);
	cfsetospeed(&new_cfg,speed);

	/* 设置数据位   */
	switch(dataBits)
		{
		case 7:
		{
			new_cfg.c_cflag|=CS7;
			break;
		}
		case 8:
		{
			new_cfg.c_cflag|=CS8;
			break;
		}
		}

	/* 设置奇偶校验位   */
	switch(parityMode)
		{
		case 'o':
		case 'O':
		{
			new_cfg.c_cflag|=(PARODD|PARENB);
			new_cfg.c_iflag|=(INPCK |ISTRIP);
			break;
		}
		case 'e':
		case 'E':
		{
			new_cfg.c_cflag |=PARENB;
			new_cfg.c_cflag &=~PARODD;
			new_cfg.c_iflag |=(INPCK | ISTRIP);
			break;
		}
		case 's':
		case 'S':
		{
			new_cfg.c_cflag &=~PARENB;
			new_cfg.c_cflag &=~CSTOPB;
			break;
		}

		case 'n':
		case 'N':
		{
			new_cfg.c_cflag &=~PARENB;
			new_cfg.c_iflag &=~INPCK;
			break;
		}

		}
	/* 设置停止位   */
	switch(stopBits)
		{
		case 1:
		{
			new_cfg.c_cflag &=~CSTOPB;
			break;
		}
		case 2:
		{
			new_cfg.c_cflag |=CSTOPB;
			break;
		}
		}
	new_cfg.c_cc[VTIME] =10;
	new_cfg.c_cc[VMIN] =5;
	//处理未接收字符
	tcflush(fd,TCIFLUSH);

	/* tcsetattr函数用于设置终端的相关参数 */
	if((tcsetattr(fd,TCSANOW,&new_cfg))!=0)
		{
			perror("tcsetattr");
			return FAILURE;
		}
		
	return SUCCESS;
}

/* 配置完成之后,创建线程,实现监听端口 */
/*******************************************************************************************
函数名称: CM_Serial::PCreate
描   述 : 创建线程
输入参数: 无
输出参数: 无
返   回 : 无
********************************************************************************************/
int CM_Serial::PCreate()
{
	int Ret = pthread_create(&(this->tid), 0, RecThread, this);
	if(Ret!=0)
		return FAILURE;
	return SUCCESS;
}

/*******************************************************************************************
函数名称: CM_Serial::write
描   述 : 发送串口信息
输入参数: 串口设备文件描述符、发送缓冲区,发送的长度
输出参数: 无
返   回 : 实际发送的长度
********************************************************************************************/
int CM_Serial::write(int fd, char* buf,int len)
{
	return ::write(fd,buf,len);
}

/*******************************************************************************************
函数名称: CM_Serial::close
描   述 : 关闭串口
输入参数: 串口设备文件描述符
输出参数: 无
返   回 : 函数执行结果
********************************************************************************************/
int CM_Serial::close(int fd)
{
	if(fd>=0)
		{
			::close(fd);
			fd=-1;
			/* 结束接收线程 */
			pthread_cancel(this->tid);
			return SUCCESS;
		}
	return FAILURE;
}

/* 等待接收线程结束 */
/*******************************************************************************************
函数名称: CM_Serial::wait_thread_end
描   述 : 等待接收线程结束
输入参数: 无
输出参数: 无
返   回 : 无
********************************************************************************************/
void CM_Serial::wait_thread_end()
{		
	if( this->tid != 0 )
		{
			int wait_thread_end= pthread_join( this->tid, NULL);					
			if( wait_thread_end != 0 )
				printf("**RecThread** pthread_join fail !\n");
			else
				printf("**RecThread** pthread_join success !\n");
		}	
}


/* 十六进制打印 */
void CM_Serial::pri_hex( const BYTE *buf, const DWORD len, const char *pname)
{
	int idx;

	if((buf == NULL) || (len <= 0))
		{
			return ;
		}
	printf("[%s]: ", ((NULL == pname) ? "null" : pname));
	for(idx=0; idx <len; idx++)
		{
			printf("%02X",buf[idx]);
		}
	printf("\n");

}
/*************************************************************** CM_Serial类函数 ********************/

- test.cpp文件:

#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#include "../include/cm_uart_mcu.h"


/* 打印宏定义 --- 可加参数  */
#define PRI(fmt, ...) 	printf("[%s]: %d " ,__FUNCTION__,__LINE__ );\
						printf(fmt, ##__VA_ARGS__);

/* 确定函数运行位置 */
#define PRI_MARK() 	printf("[%s]: %d ********************** " ,__FUNCTION__,__LINE__ );\
						printf("\n");

int main()
{
	/* 临时函数返回值 */
	int Ret;
	
/************************************ 测试串口类 */

	CM_Serial cm_s_test;
	/* 定义一个串口文件描述符 :不同的串口会有不同描述符 */
	int fd_test;
	
	/* 要打开的串口的设备节点 */
	char com_port[16] = "/dev/ttyAMA3";
		
	/* 打开串口 */
	fd_test = cm_s_test.open(com_port);
	if(fd_test < 0)
	{
		PRI("%s cannot open!\n", com_port);
        return -1;
	}
	PRI("open success ! \n");
	
	/* 配置串口 --- 创建线程进行监听 */
	Ret = cm_s_test.set_uart_config(fd_test, 115200, 8, 'N', 1);
	if(Ret < 0)
	{
		PRI("%s cannot set_uart_config!\n", com_port);
        return -1;
	}
	
	/* 创建接收线程 */
	cm_s_test.PCreate();
	
	
	/* 通过串口发送 */
	char w_buf[64] = "okay okay this okay write test write test write test!\n";	
	printf("write[%d] : %s \n",strlen(w_buf), w_buf );
	
	Ret = cm_s_test.write(fd_test, w_buf, strlen(w_buf));
	if(Ret < 0)
	{
		PRI("%s cannot write!\n", com_port);
        return -1;
	}
	
	//等待接收线程结束
	cm_s_test.wait_thread_end();
	return 0;
}

Makefile:

# Makefile
#cc=g++
cc=aarch64-himix100-linux-g++

LDFLAGS= -lpthread

M_SRCS = ./src/test.cpp
U_SRCS = ./src/cm_uart_mcu.cpp

O_M_TARGET = test.o
O_U_TARGET = cm_uart_mcu.o

TARGET = test 

$(TARGET):$(O_M_TARGET) $(O_U_TARGET)
	$(cc)  $(O_M_TARGET) $(O_U_TARGET) -o $(TARGET) $(LDFLAGS)

$(O_M_TARGET):$(M_SRCS)
	$(cc) -c $(LDFLAGS) $(M_SRCS) -o $(O_M_TARGET)
	
$(O_U_TARGET):$(U_SRCS)
	$(cc) -c $(LDFLAGS) $(U_SRCS) -o $(O_U_TARGET)	

.PHONY:clean
clean:
	rm -r $(O_M_TARGET) $(O_U_TARGET) $(TARGET) 

编译:

root@ubuntu:/test# tree
.
├── include
│   └── cm_uart_mcu.h
├── Makefile
└── src
    ├── cm_uart_mcu.cpp
    └── test.cpp

2 directories, 4 files
root@ubuntu:/test# make 
aarch64-himix100-linux-g++ -c -lpthread ./src/test.cpp -o test.o
aarch64-himix100-linux-g++ -c -lpthread ./src/cm_uart_mcu.cpp -o cm_uart_mcu.o	
aarch64-himix100-linux-g++  test.o cm_uart_mcu.o -o test  -lpthread
root@ubuntu:/test# 

运行:

/mnt/test # ./test
[main]: 41 open success ! 
write[54] : okay okay this okay write test write test write test!
 
^C
/mnt/test # 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值