为什么使用C++?
以面向对象的方式思考,把Stm32的硬件模块当作对象。
在没有C++的情况下,我们作如下调用:
USART1->SR=0;
HAL_UART_Transmit(&huart1,"Hello",5,HAL_MAX_DELAY);
//这是ST官方HAL库
有了C++,我们可以这样:
USART1->SR=0;
USART1->Print("Hello");
//USART1是对象的指针,指向一个Usart对象
C的USART1
指向一个结构体,其中的数据对应相应的寄存器,考虑下面这个结构体:
typedef struct
{
__IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */
__IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */
__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */
__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */
__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */
__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */
__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */
} USART_TypeDef;
#define USART1 ((USART_TypeDef *) 0x40011000U)
USART1
指向地址0x40011000U
,结构体里的数据是按照顺序,连续储存的,
USART1->SR
表示0x40011000U
位置的一个无符号整型
USART1->DR
表示0x40011000U+4
位置的一个无符号整型
USART1->BRR
表示0x40011000U+8
位置的一个无符号整型
…
通过这种方式,可以访问串口1的实际寄存器。
C++的USART1
应当指向一个对象,其对应的类的成员变量应当和上述USART_TypeDef
结构体的数据一致:
class Usart
{
public:
__IO u32 SR; /*!< USART Status register, Address offset: 0x00 */
__IO u32 DR; /*!< USART Data register, Address offset: 0x04 */
__IO u32 BRR; /*!< USART Baud rate register, Address offset: 0x08 */
__IO u32 CR1; /*!< USART Control register 1, Address offset: 0x0C */
__IO u32 CR2; /*!< USART Control register 2, Address offset: 0x10 */
__IO u32 CR3; /*!< USART Control register 3, Address offset: 0x14 */
__IO u32 GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */
void Baud(u32 b);
void Reset();
void Enable(Use_Mode mode);
void PrintLn(const char *s);
void PrintLn(u8 *s);
void Clean(Usart_Status s);
void SendHex(u8 *hex, u32 len);
void Push(char c);
};
#define USART1 ((Usart *) 0x40011000U)
现在的USART1
,每个成员变量对应实际寄存器,
USART1->SR
表示0x40011000U
位置的一个无符号整型
USART1->DR
表示0x40011000U+4
位置的一个无符号整型
USART1->BRR
表示0x40011000U+8
位置的一个无符号整型
…
这和C里面使用结构体没什么区别,但是,后面多了一堆成员函数,其储存位置在哪呢,如果是紧跟着最后一个成员变量那可不妙,因为这块区域是其它外设的寄存器。
成员变量是属于对象的,而成员函数属于类,也就是说,成员函数不占用内存空间,其储存位置还是在Flash,如果你尝试sizeof(Usart)
,会得到28,与sizeof(USART_TypeDef)
一致。
C++的函数调用是一种怎样的机制呢?请看如下代码:
USART1->PrintLn("Hello");
USART2->PrintLn("Hello");
函数PrintLn
是属于类的,只有一份拷贝,USART1
和USART2
是两个对象的指针,指向两块内存区域,PrintLn
是如何区分它们呢?事实上编译器做了一系列操作,可以理解为编译器多传递了一个参数给PrintLn
,相当于:
PrintLn(USART1,"Hello");
PrintLn(USART2,"Hello");
只不过这个参数由编译器隐藏了,我们看不到。
使用C++还有很多好处,可以重载函数:
USART1->PrintLn("Hello");//发送字符串
USART1->PrintLn(256);//发送int
USART1->PrintLn(25.8f);//发送float
重载操作符:
*USART1<<"Hello";//发送字符串
值得注意,用来定义外设寄存器的类不能有虚函数,因为含有虚函数的类,实例化为对象的时候,除了给成员变量分配空间,还要额外的空间来储存虚函数指针表。
有兴趣的小伙伴请移步码云