- 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 #