现单片机已经白菜价了,可用的资源也不断丰富起来.
有一天我突发奇想,用C++写单片机不是更方便.(相信很多人有类似的想法,不过在网上找到的参考资料也太少了)
话说很多编译器本身是支持C++,大部分人认为C++效率C低,我想说的是当年Android刚出来的时候,也受到了很多人的抵触...
手上正好有块STM32开发板,就拿它开刀了:
一.把库中的.C文件改成.CPP
二.定义一个GPIO的类
单片机的helloworld,那就是流水灯.
要是能够简化定义成这样子就好理解了
STM32PIN DS1_N(PF,6);
STM32PIN DS2_N(PF,7);
STM32PIN DS3_N(PF,8);
STM32PIN DS4_N(PF,9);
于是我定义了下面这么一个类
//stm32pin.h #pragma once typedef struct tagGPIO_PIN { uint32_t periph;//eg:RCC_APB2Periph_GPIOF GPIO_TypeDef* port; //eg:GPIOF uint16_t pin; //eg:GPIO_Pin_10 GPIOMode_TypeDef mode; //eg.GPIO_Mode_IN_FLOATING; GPIOSpeed_TypeDef speed; //eg.GPIO_Speed_50MHz }GPIO_PIN; enum STM32_PORT_INDEX { PA=0,PB,PC,PD,PE,PF,PG }; struct { uint32_t p_periph; GPIO_TypeDef* p_port; }PERIPH_PORT[]= { RCC_APB2Periph_GPIOA,GPIOA, RCC_APB2Periph_GPIOB,GPIOB, RCC_APB2Periph_GPIOC,GPIOC, RCC_APB2Periph_GPIOD,GPIOD, RCC_APB2Periph_GPIOE,GPIOE, RCC_APB2Periph_GPIOF,GPIOF, RCC_APB2Periph_GPIOG,GPIOG, }; //简化书写 #define GM_AIN GPIO_Mode_AIN //模拟输入模式 #define GM_IN_FLOATING GPIO_Mode_IN_FLOATING //浮空输入模式 #define GM_IPD GPIO_Mode_IPD //下拉输入模式 #define GM_IPU GPIO_Mode_IPU //上拉输入模式 #define GM_OUT_OD GPIO_Mode_Out_OD //开漏输出模式 #define GM_OUT_PP GPIO_Mode_Out_PP //通用推挽输出模式 #define GM_AFOD GPIO_Mode_AF_OD //复用功能开漏输出 #define GM_AFPP GPIO_Mode_AF_PP //复用功能推挽输出 /*--------------------如何定义STM32PIN--------------------------------------*/ // //eg: // STM32PIN key1(RCC_APB2Periph_GPIOC,GPIOC,GPIO_Pin_1,GM_IN_FLOATING); // STM32PIN pins(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO,GPIOC,GPIO_Pin_1|GPIO_Pin_10); // STM32PIN EnTk(PA,0); class STM32PIN { private: GPIO_PIN m_gpio; public: ~STM32PIN() { } STM32PIN() { } STM32PIN( STM32_PORT_INDEX indexPort, uint16_t indexPin, //只能取0~15对应GPIO_Pin_0~GPIO_Pin_15 GPIOMode_TypeDef p_mode=GM_OUT_PP, GPIOSpeed_TypeDef p_speed=GPIO_Speed_50MHz ) //对于输入Speed应为0 { reset(PERIPH_PORT[indexPort].p_periph, PERIPH_PORT[indexPort].p_port, (uint16_t)1<<indexPin,//根据GPIO_Pin_x对应规则 p_mode, p_speed ); } STM32PIN( uint32_t p_periph, GPIO_TypeDef* p_port, uint16_t p_pins, //可以或上多引脚 GPIOMode_TypeDef p_mode=GPIO_Mode_Out_PP, GPIOSpeed_TypeDef p_speed=GPIO_Speed_50MHz ) //对于输入Speed应为0 { reset( p_periph, p_port, p_pins, //可以或上多引脚 p_mode, p_speed ); } void reset( GPIOMode_TypeDef p_mode=GPIO_Mode_Out_PP ) { if(m_gpio.mode==p_mode)return; reset( m_gpio.periph, m_gpio.port, m_gpio.pin, //可以或上多引脚 p_mode, m_gpio.speed ); m_gpio.mode=p_mode; } void reset( uint32_t p_periph, GPIO_TypeDef* p_port, uint16_t p_pins, //可以或上多引脚,如片外RAM扩展的定义 GPIOMode_TypeDef p_mode=GPIO_Mode_Out_PP, GPIOSpeed_TypeDef p_speed=GPIO_Speed_50MHz ) { m_gpio.periph = p_periph; m_gpio.port = p_port; m_gpio.pin = p_pins; m_gpio.mode=p_mode; m_gpio.speed=p_speed; GPIO_InitTypeDef tmp_InitType;//临时产生 tmp_InitType.GPIO_Pin= m_gpio.pin ; tmp_InitType.GPIO_Mode=m_gpio.mode; tmp_InitType.GPIO_Speed=m_gpio.speed; RCC_APB2PeriphClockCmd( m_gpio.periph, ENABLE ); GPIO_Init( m_gpio.port ,&tmp_InitType); } inline bool get(void) { if( ishigh() ) { return true; } else { return false; } } inline void set(bool bs) { if(bs) { high();//GPIO_SetBits(m_gpio.port, m_gpio.pin); } else { low();//GPIO_ResetBits(m_gpio.port, m_gpio.pin); } } inline void invert(void) { if ( ishigh() ) { low();//GPIO_ResetBits(m_gpio.port, m_gpio.pin); } else { high();//GPIO_SetBits(m_gpio.port, m_gpio.pin); } } inline void high(void) { //GPIO_SetBits(m_gpio.port, m_gpio.pin); m_gpio.port->BSRR = m_gpio.pin; } inline void low(void) { //GPIO_ResetBits(m_gpio.port, m_gpio.pin); m_gpio.port->BRR = m_gpio.pin; } inline bool ishigh() { // if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET) GPIO_ReadInputDataBit(m_gpio.port, m_gpio.pin)==Bit_SET if( m_gpio.port->IDR & m_gpio.pin) { return true; } else { return false; } } inline bool islow() { // if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET) GPIO_ReadInputDataBit(m_gpio.port, m_gpio.pin)==Bit_SET if( m_gpio.port->IDR & m_gpio.pin) { return false; } else { return true; } } void toggle(uint32_t t=1000,bool bLoop=true) { while(bLoop) { high(); for(int i=0;i<t;i++); low(); for(int i=0;i<t;i++); } } };
从上面的类,可以看到,让GPIO拉高使用high(),拉使用low(),
为了能产生高效的代码,其中大部分函数使用内联,
将 GPIO_SetBits() GPIO_ResetBits()函数调用改写成寄存器方式
//GPIO_SetBits(m_gpio.port, m_gpio.pin);
inline void high(void)
{
m_gpio.port->BSRR = m_gpio.pin;
}
//GPIO_ResetBits(m_gpio.port, m_gpio.pin);
inline void low(void)
{
m_gpio.port->BRR = m_gpio.pin;
}
于是流水灯的程序就可以写这样子:
//main.cpp #include "stm32pin.h" int main(void) { STM32PIN DS1_N(PF,6); STM32PIN DS2_N(PF,7); STM32PIN DS3_N(PF,8); STM32PIN DS4_N(PF,9); uint8_t i=0; while(true) { i++; i & 0x01 ? DS1_N.low():DS1_N.high(); i & 0x02 ? DS2_N.low():DS2_N.high(); i & 0x04 ? DS3_N.low():DS3_N.high(); i & 0x08 ? DS4_N.low():DS4_N.high(); for(uint32_t i=0;i<10000000;i++); } }
接着让USER2键按下,流水灯反过来计数,只要这样定义
STM32PIN USER2(PD,3,GM_IN_FLOATING);
使用的时候这样写
if( USER2.islow() )
{
//要执行的动作
}
#include "stm32pin.h" int main(void) { STM32PIN DS1_N(PF,6); STM32PIN DS2_N(PF,7); STM32PIN DS3_N(PF,8); STM32PIN DS4_N(PF,9); STM32PIN USER2(PD,3,GM_IN_FLOATING); uint8_t i=0; while(true) { i++; if( USER2.islow() ) { i & 0x08 ? DS1_N.low():DS1_N.high(); i & 0x04 ? DS2_N.low():DS2_N.high(); i & 0x02 ? DS3_N.low():DS3_N.high(); i & 0x01 ? DS4_N.low():DS4_N.high(); } else { i & 0x01 ? DS1_N.low():DS1_N.high(); i & 0x02 ? DS2_N.low():DS2_N.high(); i & 0x04 ? DS3_N.low():DS3_N.high(); i & 0x08 ? DS4_N.low():DS4_N.high(); } for(uint32_t i=0;i<10000000;i++); } }
未完待续....
疯狂单片机--用C++写STM32程序