STM32 C++开发

2019-07-20 18:30发布

本帖最后由 mzwhhwj 于 2016-4-17 12:39 编辑

    每次写代码的时候,写外设的初始化都要去复制已经写好的或者是官方的例程,再根据自己的需求来修改,重复性的工作太多,就想到用C++来封装下STM32的库函数,顺便学习下C++,感受下面向对象的强大。
    硬件平台:STM32F4-Discovery
    开发平台:MDK5.14(本来是用VS2013 +VisualGDB的,想到坛友基本都是用MDK的,又改成MDK)
   先看Main
   [mw_shl_code=cpp,true]#include "system.h"

System *stm32f407;//系统接口指针

void btnhandle(void *arg)  //按键回调处理函数
{
         delay->delay_ms(20);
        if (stm32f407->btn->ReadData() == true)
                stm32f407->led2->Toggle();
}

void tim6handle(void *arg)  //定时器中断处理函数
{
        stm32f407->led2->Toggle();
}

int main()
{
        stm32f407 = new System;//构建系统接口类
        stm32f407->tim2->startIT((void*)tim6handle, NULL);//调用TIM类的中断启动函数,只要传入中断回调函数实现自己的功能,并不需要知道中断是要怎么处理的
        uint8_t recvdata[100];
  for (;;)
  {
          stm32f407->led1->Toggle();//在system中初始化,就可以直接调用类函数
          if (true == stm32f407->Debug->IsGetRecv)//串口自动接收标志
          {
                  stm32f407->Debug->RecvData(recvdata);//串口接收函数,传入Buffer,得到接收的数据
                  stm32f407->Debug->SendData(recvdata, stm32f407->Debug->RecvDataLen, 100);
          }
          delay->delay_ms(500);
  }
}[/mw_shl_code]
    再看System类的初始化
[mw_shl_code=cpp,true]void System::init()
{
        HAL_Init();
        SystemClock_Config();
//外设初始化
  delay = new timerdelay;                //系统延时初始
        Debug = new Usart(USART3, 115200, Usart::USART_IT, 200); //Debug 串口输出初始化,只要传入用的串口号,跟波特率,传输的模式,还有接收Buffer的大小,就可以完成初始化
        led1 = new LED(GPIOD, GPIO_PIN_14, true, LED::highlevel);//LED类,继承OutputPort类,只要传入LED对应的GPIO,跟Pin,还有LED电平控制,就可以完成初始化
        led2 = new LED(GPIOD, GPIO_PIN_12, false, LED::highlevel);
        btn = new InputPort(GPIOA, GPIO_PIN_0, GPIO_MODE_IT_RISING, (void*)btnhandle, NULL); //输入类,传入GPIO,PIN,中断触发模式,回调指针,回调参数,完成初始化
        tim2 = new Timer_base(TIM2, 16800, 10000);
        BoardInfo();
}[/mw_shl_code]

OutputPort类:
[mw_shl_code=cpp,true]class OutputPort
{
public:
        OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState);//OutputPort类构建函数,简单传入三个参数
        OutputPort(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, uint32_t GPIO_Speed, uint32_t GPIO_PuPd, bool initialState);//构建函数重载,可以传入更多的参数
        ~OutputPort();
        void H(void);//类函数,构建的类都是调用同函数就可以实现,减少代码的重复
        void L(void);
        inline void  RegH(){PORT->BSRR |= GPIO_PIN;        }//内联函数,直接代码替换成寄存器操作,提高执行效率
        inline void  RegL(){ PORT->BSRR |= GPIO_PIN << 16; }
        GPIO_TypeDef* PORT;
        uint16_t GPIO_PIN;
private:
protected:

};

LED类:
class LED :public OutputPort
{
public:
        LED(GPIO_TypeDef* mPORT, uint16_t mGPIO_PIN, bool initialState, uint8_t mCtlVolLev) : OutputPort(mPORT, mGPIO_PIN, initialState), CtlVolLev(mCtlVolLev){};//继承OutputPort类,并增加新的参数
         ~LED();
         void ON();
         void OFF();
         void Toggle();
         enum{ lowlevel, highlevel };
private:
protected:
        uint8_t CtlVolLev;    //LED 1为高电平  0为低电平
};
[/mw_shl_code]    UART类:
[mw_shl_code=cpp,true]extern uint8_t UART_Recv_Timeout[5];//Time Tick

class Usart
{
public:
        enum tranmode
        {
                USART_Normal, //普通发送
                USART_IT,    //中断发送接收,接收自动判断超时完成接收
                USART_DMA    //DMA发送接收,UART闲时中断自动接收DMA接收完成
        };//类构建时传入,类函数根据输入的类别发送接收
        Usart(USART_TypeDef *USARTx, uint32_t BaudRate, tranmode mmode,uint16_t mRecvBuffSize);
        void SendData(uint8_t data);
        void SendData(uint8_t *pData, uint16_t Size, uint32_t Timeout);
        uint16_t RecvData(uint8_t *pData);
        uint16_t RecvDataLen; //接收到数据长度
        UART_HandleTypeDef UartHandle;
        uint8_t IsGetRecv;   //接收标志
        uint8_t isSendOk ;  //发送完成标志
        tranmode mode;
        void Printf(const char* fmt, ...);
        ~Usart();

private:
        uint16_t RecvBuffSize;
        uint8_t *RecvBuff;
        uint8_t SendBuff[100];
        void USART_DMA_Config(UART_HandleTypeDef *UartHandle);
};

void Do_UART_Recv(uint8_t i);//接收超时处理函数[/mw_shl_code]

     C++面向对象最大的好处是,只要定义一个类,相同的外设只要传入参数构建类,就可以调用类函数来实现功能,不需要为每个外设再重新写代码。而且封装好了类,只需要知道传入什么参数,可以调用什么接口来实现自己的功能就可以了,不需要再去了解类里面是怎么来实现的。目前就封装了GPIO,UART,TIM Base,SPI等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。