SAM

用C++做开单片机开发

0
阅读(2024)

做了多年的单片机开发,我们早已习惯了C语言+库函数的方式,偶尔在需要的地方加入几句汇编。然而我们还不知足,大部分编译器已经支持汇编、C语言和C++编译了,这次让我们体验一下用C++开发。当然,前提是牺牲那么一点效率。


在这里我们先介绍一下作者使用的开发环境(发一点小广告):单片机是ELMOS公司的E703.15,内核类似于MSP430(兼容MSP430指令),仿真器为MAZ JTAG,集成开发环境为IAR for MSP430 6.4,PC采用Windows7 32位旗舰版。接下来主要介绍用C++实现2个串口,并利用C++的封装、集成和多态的特性,复用代码。


1.1 串口类设计分析

当然,用上了C++,我们先用封装特性,把串口的数据和操作封装为类(class)。


设计前我们分析一下,E703.15有2个串口,2个串口有相同的操作,但是有不同的硬件寄存器如引脚等。设计串口类的时候,我们采用基类和派生类的方式设计。


✦  基类:封装串口变量并定义串口的操作;

✦  派生类:根据串口硬件特性重载硬件相关操作。

1.2 串口基类设计

✦  数据:串口号;

✦  操作:串口初始化(不同串口不同,虚函数);

✦  操作:串口发送一个字节;

✦  操作:串口接收一个字节;

✦  操作:串口发送字符串。

class CUartBase {

public:

    CUartBase(uart_num_t eUart);

   ~CUartBase(void);

   

public:

    void     uartByteSend(uint8_t ucData);

    uint8_t uartByteRecv(void);

    void     uartStrWrite(char *pcStr);

    

public:

    virtual void uartInit(void) = 0;

    

protected:

    uart_num_t  eUartNum;

};



1.2.1 串口基类定义

在介绍定义之前,先说明一下,具体的实现是调用了ELMOS提供的E703.15的外设库,如uart_transmit_byte函数。由于操作都比较简单,所以不进行详细介绍。

CUartBase::CUartBase(uart_num_t eUart)

{

    eUartNum = eUart;

}


CUartBase::~CUartBase(void)

{

}


void CUartBase::uartByteSend(uint8_t ucData)

{

    uart_transmit_byte( eUartNum, ucData, true );

}


uint8_t CUartBase::uartByteRecv(void)

{

    uint8_t ucData;

    

    uart_receive_byte( eUartNum, &ucData, true );               

    

    return ucData;

}


void CUartBase::uartStrWrite(char *pcStr)

{

    while ( '\0' != *pcStr ) {

        uartByteSend( *pcStr++ );

    }

}



1.3 串口0派生类

定义了基类之后,我们用上C++继承的特性,派生出串口0和串口1,由于串口0和串口1除了硬件初始化不同之外,其他操作相同,所以只介绍串口0派生类。同样先介绍原型,再介绍定义。更多学习交流可以加Q3472880374,嵌入式实训就来信盈达,单片机,LINUX,免费试听。


1.3.1 串口0原型

由于已经设计了基类,代码复用程度很高,所以派生类设计非常方便,只需重载硬件初始化虚函数即可(uartInit函数)。需要注意:构造函数使用了默认参数UART0。

class CUart0 : public CUartBase {

    

public:

    CUart0(uart_num_t eUart = UART0);

   ~CUart0(void);


public:

    void uartInit(void);

};



1.3.2串口0定义

只要重载硬件初始化函数即可,其他操作集成自基类,具体定义如下。uartInit函数在派生类实现(基类定义为虚函数),即利用C++的多态

CUart0::CUart0(uart_num_t eUart) : CUartBase(eUart)

{

    uartInit();

}


CUart0::~CUart0(void)

{

}


void CUart0::uartInit(void)

{

    sys_state_module_enable( SYS_STATE_MODULE_UART0, false );   /* 禁用串口         */

    sys_state_module_enable( SYS_STATE_MODULE_UART0, true );   /* 使能串口           */


    uart_init( eUartNum, UART_SPEED_115200, UART_FRAC_115200, UART_DATA_LEN_8, UART_PARITY_EVEN, UART_ONE_STOP );

    uart_fifo_clear( eUartNum, true, true );

    

    sys_state_module_enable( SYS_STATE_MODULE_IOMUX_CTRL, true ); /* 使能串口        */

    iomux_ctrl_select( IOMUX_IO_0, IOMUX_FUNC_2ND );               /* 使能发送引脚      */

}



1.4 主函数测试

定义了串口基类和派生类之后,在主函数new出2个串口进行测试,测试代码如下(定义基类指针,用来存放派生类,可以利用多态的特性,为了简化,这里并没有体现出多态)。

#include "uart0.h"

#include "uart1.h"


int main (void)

{

    CUartBase *phUart0 = new CUart0();

    CUartBase *phUart1 = new CUart1();

    

    phUart0->uartStrWrite( "Uart0: Hello world\r\n" );

    phUart1->uartStrWrite( "Uart1  Hello world\r\n" );

    

    while(1);

}



1.5 温馨提示

虽然IAR for MSP430 6.4支持C++开发,但是并不完全支持C++的所有特性,大致支持特性和不支持特性如下,具体可参考编译器帮助文档。

支持特性:

✦   类(class);

✦   多态(Polymorphism);

✦   重载(Overloading);

✦   new和delete;

✦   模板(Templates);

✦   名字空间(namespace)。


不支持特性:

✦   异常(Exception);

✦   运行时类型识别(RTTI)。


1.6 结束语

根据以上介绍,是否发现用C++开发单片机,利用封装、集成和多态特性,可以增加代码的复用率,提高系统的稳定性呢。有兴趣的童鞋可以在自己的开发环境中试一下C++开发,换个角度看待单片机。