一、HardwareUART介绍
在之前的文章中介绍过了串口的c语言接口,并通过这些接口完成初始化、和串口读写功能。HardwareUART类主要基于这些接口进行封装,并且继承了outputStream和inputStream类的收发功能。在介绍outputStream和inputStream类中说过,outputStream设置了纯虚函数让子类来实现,使得不同的输出硬件可以使用相同的接口,inputStream的本质为接收缓存区的管理,所以HardwareUART类只需要完成串口的初始化函数、outputStream的纯虚函数、将inputStream的串口缓冲区指针指向串口对应的接收缓冲区,即可通过串口实现子类的收发功能,并不需要再去写许多复杂的发送/接收的代码。 以下为HardwareUART的声明:
class HardwareUART : public outputStream, public inputStream
{
UART_enum uart_x;
int baudrate;
void set_buf_ptr();
public:
HardwareUART(UART_enum uart)
{
uart_x = uart;
set_buf_ptr();
};
int begin(int buadrate_in = 115200)
{
baudrate = buadrate_in;
uart_init(uart_x, buadrate_in);
return 1;
};
int end() { return 1; };
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);
};
HardwareUART主要包含以下几个公共成员函数:
二、方法介绍
1.构造函数HardwareUART(UART_enum uart): HardwareUART构造是需要传入一个串口的枚举,告诉类这个对象是哪个串口的。每一个串口对应一个对象。 对象声明后,不同串口间的使用互不干扰。 串口的枚举在my_usart.h文件中:
typedef enum
{
#ifdef HAVE_SERIAL1
UART_1 = (uint32_t)USART1,
#endif
#ifdef HAVE_SERIAL2
UART_2 = (uint32_t)USART2,
#endif
#ifdef HAVE_SERIAL3
UART_3 = (uint32_t)USART3,
#endif
#ifdef HAVE_SERIAL4
UART_4 = (uint32_t)UART4,
#endif
#ifdef HAVE_SERIAL5
UART_5 = (uint32_t)UART5,
#endif
UART_END
} UART_enum;
示例:
HardwareUART Serial1(UART_1);
HardwareUART Serial2(UART_2);
2.初始化和释放: 初始化:int begin(int buadrate_in = 115200) 初始化一个串口并设定波特率(默认为115200),由于底层的C接口还不支持设置校验位、停止位等,所以目前还不能设置相关的参数(等以后添加了再来补充)。 释放:int end()释放串口资源 由于底层没有写释放的接口,所以暂时还没有用~ 示例:
Serial1.begin(9600);
Serial2.begin();
3.串口收发接口: 串口的收发功能继承自outputStream和inputStream类。 对于发送的函数,重写了size_t write(uint8_t); size_t write(const uint8_t *buffer, size_t size);两个来自基类的虚函数。
size_t HardwareUART::write(uint8_t data)
{
uart_write_byte(uart_x, data);
return 0;
}
size_t HardwareUART::write(const uint8_t *buffer, size_t size)
{
uart_write_buffer(uart_x, buffer, size);
return 0;
}
发送功能则是将基类的缓冲区指针指向了串口接收缓冲区。 使用示例: 收发功能的使用方法在之前介绍outputStream和inputStream类的文章中已经介绍的很详细了就,就不来凑字数了 从新建工程开始使用C++开发单片机(以STM32为例):六、C++输入输出流(附代码)
总结
从这里开始,使用设计outputStream和inputStream类的好处就已经体现出来了,可以看到只需要完成串口初始化以及覆盖基类的虚函数之后,串口类基本上不需要写很多的代码就可以完成强大的功能。而单片机中还有SPI、I2C等串行接口,以及屏幕的输出设备,都可以继承基类,只需要写很少的代码就可以实现其对应的功能。 并且由于硬件的底层操作都是在C语言层完成,所以在不同的单片机之间移植也会非常容易,只需要重写C语言的初始化、输出和接收接口就能非常轻松地移植这个类,节省大量地精力和时间。
代码
#ifndef __MCU_HARDWARE_HARDWARE_UART_H
#define __MCU_HARDWARE_HARDWARE_UART_H
#include "headfile.h"
#include "outputStream.h"
#include "inputStream.h"
class HardwareUART : public outputStream, public inputStream
{
UART_enum uart_x;
int baudrate;
void set_buf_ptr();
public:
HardwareUART(UART_enum uart)
{
uart_x = uart;
set_buf_ptr();
};
int begin(int buadrate_in = 115200)
{
baudrate = buadrate_in;
uart_init(uart_x, buadrate_in);
return 1;
};
int end() { return 1; };
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size);
};
#endif
#include "hardwareUART.h"
void HardwareUART::set_buf_ptr()
{
switch (uart_x)
{
#ifdef HAVE_SERIAL1
case UART_1:
buf = &UART1_recbuf;
return;
#endif
#ifdef HAVE_SERIAL2
case UART_2:
buf = &UART2_recbuf;
return;
#endif
#ifdef HAVE_SERIAL3
case UART_3:
buf = &UART3_recbuf;
return;
#endif
#ifdef HAVE_SERIAL4
case UART_4:
buf = &UART4_recbuf;
return;
#endif
#ifdef HAVE_SERIAL5
case UART_5:
buf = &UART5_recbuf;
return;
#endif
default:
buf = 0;
return;
}
}
size_t HardwareUART::write(uint8_t data)
{
uart_write_byte(uart_x, data);
return 0;
}
size_t HardwareUART::write(const uint8_t *buffer, size_t size)
{
uart_write_buffer(uart_x, buffer, size);
return 0;
}
|