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

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

有一天我突发奇想,用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程序

时间: 2024-10-10 00:50:05

疯狂单片机--用C++写STM32程序的相关文章

[51单片机] SPI nRF24L01 无线简单程序 1

main.c 1 #include <reg51.h> 2 #include <api.h> 3 4 #define uchar unsigned char 5 6 /***************************************************/ 7 #define TX_ADR_WIDTH 5 // 5字节宽度的发送/接收地址 8 #define TX_PLOAD_WIDTH 4 // 数据通道有效数据宽度 9 #define LED P2 10 11

PIC12F629帮我用C语言写个程序,控制三个LED亮灭

http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控制三个LED亮灭! 2014-12-31 16:05DINZEYU  分类:C/C++ | 浏览 87 次 C语言VC++ 按键按一次LED1低亮,按两次高亮,按三次2HZ闪,按三次关,按键长按3秒松开LED2亮,长按3秒松开LED2灭,按键长按5秒松开LED3亮,长按5秒松开LED3灭,每个功能独

单片机中C语言的程序与数据存储

单片机中C语言的程序与数据存储 一.五大内存分区: 内存分成5个区,它们分别是堆.栈.自由存储区.全局/静态存储区和常量存储区. 1.栈区(stack):FIFO就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等. 2.堆区(heap):就是那些由new分配的内存块,它们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收. 3.自由存储区:就是那些

代写Servlet、代写JSP、代写JavaBean程序作业

代写Servlet.代写JSP.代写JavaBean程序作业Servlet+JSP+JavaBean模式适合开发复杂的web应用,在这种模式下,Servlet负责处理用户请求,JSP负责数据收集和显示,JavaBean封装数据操作的相关功能.请以Servlet+JSP+JavaBean模式开发新闻发布系统,主要包括用户添加.用户登录.用户信息修改.新闻发表.新闻修改和新闻查看功能.具体要求如下:1.完成数据库设计,要求记录管理员信息和新闻信息,其中管理员信息包括:用户名.密码.性别.QQ号.em

代写二叉查找树程序作业、代写BST 作业、代写Data Structures

代写二叉查找树程序作业.代写BST 作业.代写Data StructuresKIT205 Data Structures and AlgorithmsAssignment 1: Data StructuresDue: 27th April, 11:55pmIntroductionYou work for an education company that develops and runs Massive Open Online Courses(MOOCs). You have been ask

代写DNN程序作业、代作DNN的资源分配框架

代写DNN程序作业.代作DNN的资源分配框架我们提出了一种基于DNN的资源分配框架,来优化CRN的性能,而不管CRN的EE如何.它由三层组成,即输入层,多个隐藏层和输出层.输入是具有连续概率密度函数的瞬时信道功率增益 . 和 ,输出是 或 ,隐藏层和输出层的激活函数是ReLU,即 ,其中 和 分别表示神经单元的输入和输出,后面给出了网络结构的详细参数,为了获得每个神经元的权重,需要对DNN进行训练,训练数据通过[6]提出的传统资源分配策略或[5]给出的节能资源分配策略获得,瞬时信道功率增益 .

嵌入式Linux之旅——环境搭建篇之烧写裸机程序

本小节将介绍如何使用oflash和openjtag烧写裸机程序.oflash也支持并口烧写,方法与openjtag类似.如果你想使用jlink烧写,需要安装SEGGER的J-Flash的工具,这里我们就不多介绍. 首先需要先安装oflash,oflash由开发板厂商提供或者从网上下载.将oflash加上可执行权限,拷贝到“/usr/bin”目录下即可.命令如下: sudo cp oflash /usr/bin/ && sudo chmod +x /usr/bin/oflash 下面就是具体

[C++] 用Xcode来写C++程序[7] Class

用Xcode来写C++程序[7] Class 不带构造函数的Rectangle类 // // Rectangle.h // Plus // // Created by YouXianMing on 15/3/12. // Copyright (c) 2015年 YouXianMing. All rights reserved. // #ifndef __Plus__Rectangle__ #define __Plus__Rectangle__ #include <stdio.h> class

[C++] 用Xcode来写C++程序[4] 函数

用Xcode来写C++程序[4] 函数 此节包括引用函数,内联函数,防止修改函数入参,函数自身带有默认值. 引用函数:防止复制对象,减少系统开销 内联函数:编译的时候根据具体情形将代码嵌入进去,成不成功编译器说了算,减少系统开销提升性能 引用函数(防止篡改初始值的入参声明方式):防止修改数据源 函数参数带有默认值:函数的某个参数可以给定默认值,精简函数的使用 最简单的函数 #include <iostream> using namespace std; int addition (int a,