本帖最后由 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等几个外设,可以给大家体验下面向对象的强大,提供一些封装函数的思路,更具体的代码可以下载附件的工程。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
一周热门 更多>