上一篇介绍了UART的简单通信实现,不太了解通信过程的可以先参考上一篇文章《最简单的一个UART通信实例》。上一篇的《最简单的一个UART通信实例》是面向过程编程,本编将介绍UART通信的面向对象编程。
1、抽象接口定义
#ifndef MYUART_HARDINTERFACE_H
#define MYUART_HARDINTERFACE_H
#include <fcntl.h>
#include <utils/threads.h>
#define INVALID_IO_TYPE -1
class HardInterface
{
private:
/* data */
public:
enum MCUIOTYPE { INVALIDIOTYPE = -1, EUARTIO, I2CIO };
HardInterface(/* args */) : miotype(MCUIOTYPE::INVALIDIOTYPE), fd(INVALIDIOTYPE)
{
fd = init_dev();
}
virtual ~HardInterface(){}
virtual int init_dev()
{
return INVALID_IO_TYPE;
}
virtual int txdata(unsigned char* txbuf, unsigned int txcount) = 0;//纯虚函数
virtual int rxdata(unsigned char* rxbuf, unsigned int rxcount) = 0;//纯虚函数
MCUIOTYPE miotype;
int fd;
};
#endif
2、HardInterface.h头文件里面主要定义了虚函数init_dev跟纯虚函数txdata、rxdata。接下来在UartInterface.h头文件里面定义类UartInterface实现HardInterface抽象类,这样类UartInterface就可以进行实例化了。
#ifndef MYUART_UARTINTERFACE_H
#define MYUART_UARTINTERFACE_H
#include <termios.h>
#include "HardInterface.h"
#define MCUUARTPORT "/dev/ttyLP3"
#define BAUDRATEINDEXMAX 9
#define BAUDRATEINDEX 8
#define GET_BAUDRATEINDEX(index) ( (BAUDRATEINDEXMAX - 1) & index)
#define TIMEOUT_SEC(buflen, baudrate) ((buflen)*20/(baudrate) + 2)
#define TIMEOUT_USEC 0
//波特率数组
static const int speed_arr[] = { B300, B1200, B2400, B4800, B9600, B19200,
B38400, B57600, B115200 };
//根据枚举钟不同的值设置不同的串口属性
enum UARTPROPERTI{ SERIAL_STOPBITS_ONE, SERIAL_STOPBITS_TWO, SERIAL_DATABITS_SEVEN, \
SERIAL_DATABITS_EIGHT, SERIAL_HARDWARE_UNCTRL, SERIAL_HARDWARE_XONXOFF, \
SERIAL_HARDWARE_CTRL, SERIAL_PARITY_NONE, SERIAL_PARITY_ODD, SERIAL_PARITY_EVEN, \
SERIAL_PARITY_MARK, SERIAL_PARITY_SPACE };
static const int name_arr[] = { 300, 1200, 2400, 4800, 9600, 19200, 38400,
57600, 115200 };
class UartInterface : public HardInterface
{
private:
bool uart_error;/* data */
public:
UartInterface(/* args */)
{
init_dev();
}
~UartInterface(){
uart_close(this->fd);
}
int init_dev();//设备初始化
int txdata(unsigned char* txbuf, unsigned int txcount);//向串口发送数据
int rxdata(unsigned char* rxbuf, unsigned int rxcount);//接收来自串口端的数据
int uart_sest_baudrate(int handle, int baudrateindex);//设置波特率
//设置串口属性
int uart_set_properties(int handle, unsigned char databits, unsigned char stopbits, \
unsigned char parity, unsigned char flow_control);
//关闭对应的文件描述符
int uart_close(int handle);
};
#endif
3、接下来需要实现每个函数里面的具体内容,如下:
#include <errno.h>
#include <linux/fb.h>
#include <unistd.h>
#include "UartInterface.h"
//初始化设备
int UartInterface::init_dev()
{
int ret = 0;
this->uart_error = false;
printf("UartInterface--> init dev start--\n");
this->fd = open(MCUUARTPORT, O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
if (-1 == this->fd)
{
printf("UartInterface--> open serial port %s fail %d--\n", MCUUARTPORT, this->fd);
this->uart_error = true;
return this->fd;
}
fcntl(fd, F_SETFL, 0);//设置文件状态标志值为0,阻塞模式
//设置波特率
ret = uart_sest_baudrate(this->fd, GET_BAUDRATEINDEX(BAUDRATEINDEX));
if (ret == -1)
{
printf("UartInterface--> uart_sest_baudrate %s fail %d\n", MCUUARTPORT, ret);
this->uart_error = true;
return ret;
}
//串口属性配置
ret = uart_set_properties(this->fd, SERIAL_DATABITS_EIGHT, SERIAL_STOPBITS_ONE, \
SERIAL_PARITY_NONE, SERIAL_HARDWARE_UNCTRL);
if (ret == -1)
{
printf("UartInterface--> uart_set_properties %s fail %d\n", MCUUARTPORT, ret);
this->uart_error = true;
return ret;
}
printf("UartInterface--> init dev end--\n");
return 0;
}
//向串口发送数据
int UartInterface::txdata(unsigned char* txbuf, unsigned int txcount)
{
unsigned char* write_data = txbuf;
unsigned int total_len = 0;
int len =0;
unsigned int size = txcount;
if ( this->fd <= 0)
{
printf("UartInterface-->txdata fd = %d litter zero\n", this->fd);
return this->fd;
}
for (total_len = 0; total_len < size;)
{
len = write(this->fd, &write_data[total_len], size - total_len);
if (len > 0)
{
total_len += len;
}
else if (len < 0)
{
if (total_len == 0)
{
tcflush(this->fd, TCOFLUSH);//清除正写入的数据,且不会发送至终端。
return -1;
}
return total_len;
}else
{
printf("UartInterface-->txdata len = %d \n", len);
break;
}
}//for
return 0;
}
//从串口读取数据
int UartInterface::rxdata(unsigned char* rxbuf, unsigned int rxcount)
{
if (this->fd <= 0)
{
printf("UartInterface-->rxdata fd = %d \n", this->fd);
return -1;
}
int len = read(this->fd, rxbuf, rxcount);
if (len < 0)
{
printf("UartInterface-->rxdata len = %d \n", len);
return -1;
}
return len;
}
//设置波特率
int UartInterface::uart_sest_baudrate(int handle, int baudrateindex)
{
struct termios options;
memset(&options, 0x00, sizeof(options));
if (baudrateindex >= BAUDRATEINDEXMAX)
{
printf("UartInterface--> ot support BAUDRATEINDEXMAX %d", BAUDRATEINDEXMAX);
return -1;
}
if (tcgetattr(handle, &options) != 0)
{
printf("UartInterface--> tcgetattr error\n");
return -1;
}
tcflush(this->fd, TCIOFLUSH);//刷新输入输出缓冲区
cfsetispeed(&options, speed_arr[baudrateindex]);//设置输入速度
cfsetospeed(&options, speed_arr[baudrateindex]);//设置输出速度
if (tcsetattr(handle, TCSANOW, &options) != 0)//设置串口属性,TCSANOW:不等数据传输完毕就立即改变属性
{
printf("UartInterface--> tcsetattr \n");
return -1;
}
tcflush(this->fd, TCIOFLUSH);//刷新输入输出缓冲区
return 0;
}
//设置串口属性
int UartInterface::uart_set_properties(int handle, unsigned char databits, unsigned char stopbits, \
unsigned char parity, unsigned char flow_control)
{
struct termios options;
if (this->fd <= 0)
{
printf("UartInterface--> fd litter zero \n");
return -1;
}
memset(&options, 0x00, sizeof(options));
if (tcgetattr(handle, &options) != 0)
{
printf("UartInterface--> tcgetattr error \n");
return -1;
}
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CSIZE;
switch (stopbits)
{
case SERIAL_STOPBITS_ONE:
options.c_cflag &= ~CSTOPB;
break;
case SERIAL_STOPBITS_TWO:
options.c_cflag |= CSTOPB;
break;
default:
return -1;
}
switch (databits)
{
case SERIAL_DATABITS_SEVEN:
options.c_cflag |= CS7;
break;
case SERIAL_DATABITS_EIGHT:
options.c_cflag |= CS8;
break;
default:
return -1;
}
switch (flow_control)
{
case SERIAL_HARDWARE_UNCTRL:
options.c_cflag &= ~CRTSCTS;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
case SERIAL_HARDWARE_XONXOFF:
options.c_iflag |= IXON | IXOFF | IXANY;
break;
case SERIAL_HARDWARE_CTRL:
options.c_cflag |= CRTSCTS;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
break;
default:
return -1;
}
options.c_iflag &= IGNCR;
switch (parity)
{
case SERIAL_PARITY_NONE:
options.c_cflag &= ~PARENB;
break;
case SERIAL_PARITY_ODD:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
break;
case SERIAL_PARITY_EVEN:
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
break;
case SERIAL_PARITY_MARK:
options.c_cflag &= ~PARENB;
options.c_cflag |= CSTOPB;
break;
case SERIAL_PARITY_SPACE:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
return -1;
}
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;//VTIME和VMIN都取0,即使读取不到任何数据,函数read也会立即返回
tcflush(this->fd, TCIFLUSH);//刷新输入缓冲区
if (0 != tcsetattr(handle, TCSANOW, &options)) //设置串口属性
{
printf("UartInterface--> tcsetattr error \n");
return -1;
}
return 0;
}
int UartInterface::uart_close(int handle)
{
printf("UartInterface--> uart_close \n");
close(handle);
return 0;
}
到目前为止UART通信的面向对象编程就完了,接下来是要编写测试接口函数的测试类。
4、测试类
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "UartInterface.h"
//向串口写数据
static void mcu_reboot() {
printf("mcu_reboot start\n");
unsigned char write_data[] = { 1, 4, 2, 2, 1, 3, 133, 232, 0 };
UartInterface *u = new UartInterface();
int tx = u->txdata(write_data, 9);
sleep(3);
printf("mcu_reboot tx = %d\n", tx);
}
//向串口读数据
static void mcu_read_data() {
printf("mcu_read_data start\n");
static uint8_t recv_buf[512];
UartInterface *u = new UartInterface();
int j = 1;
while(1){//由于不是每次都能读取到数据,所以要在循环中不断去读取
int readLen = u->rxdata(recv_buf, 512);
if (readLen < 0)
{
printf("read failed\n");
return ;
}
if(readLen == -1 || readLen == 0)
{
continue;//读取不到数据,就结束本次循环,进入下一次循环进行重新读取
}
printf("readLen = %d\n", readLen);
for(int i =0; i <readLen; i++)
{
printf("%02x ",recv_buf[i]);//打印从串口端读取到的数据
}
j++;
printf("\n");
usleep(10 * 1000);//睡眠10毫秒
if (j > 10)break;//读取完10条数据就跳出while循环
}
printf("mcu_read_data tr\n");
}
int main(int argc, char **argv)
{
printf("main start ---> \n");
if (argc > 1)
{
printf("argv[1] = %s\n", argv[1]);
if (strncmp(argv[1], "w", 1) == 0)
{
printf("main write data\n");
mcu_reboot();//执行后mcu会重启
}
else if (strncmp(argv[1], "r", 1) == 0)
{
printf("main read data\n");
mcu_read_data();//执行后会打印接收到的数据
}
printf("\n");
}
printf("main start ---> \n");
return 0;
}
5、运行结果如下:
代码参考:https://github.com/gunder1129/android-tool/tree/master/myuartOOP