疯狂单片机--用C++写STM32程序-STM32PIN

现单片机已经白菜价了,可用的资源也不断丰富起来.

有一天我突发奇想,用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++);
		 }
}


未完待续....

 

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
单片机面试主要是围绕单片机的基础知识、应用能力和解决问题的能力展开的。首先,面试官会问一些关于单片机的基础知识,如单片机的定义、特点、工作原理、常用的单片机有哪些等等。应聘者需要对这些基础知识有清晰的理解和掌握。 接下来,面试官可能会让应聘者解决一些简单的编程问题或是设计一些基本的电路图。这要求应聘者能够熟练使用单片机集成开发环境(IDE)进行编程,并能够应用各种编程语言(如C语言、汇编语言等)来编单片机程序,实现一些基本的功能。同时,应聘者还要能够根据给定的要求画出相应的电路图并进行调试。 此外,面试官还可能针对应聘者的工作经验和项目经历进行提问。应聘者需要能够清楚地解释自己在该领域的工作经验,并能够详细说明自己参与的项目及承担的任务,以及在项目中遇到的问题和解决方案。 最后,面试官还可能询问应聘者对未来单片机发展的看法和对该岗位的职业规划等问题。这要求应聘者对单片机相关的最新技术和趋势保持关注,并能够展示自己对该领域的热情和学习能力。 综上所述,单片机面试主要考察应聘者对单片机基础知识的掌握程度、编程能力和解决问题的能力,以及对该领域的了解和学习能力。应聘者需要准备好相关的知识和项目经验,并能够清晰地回答面试官的问题,展示自己的能力和潜力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值