Re:从零开始的stm32(1、32第一个程序,点亮led灯)

鸽了这么久终于又想起了CSDN的密码
今天大家一起来学习stm32,对于32如何建工程,网络上已经有很多例子,包括文件也有很多,如果需要的话可以在文末找到群号,我会在群文件里面分享,这里就不再浪费口舌。

32对于51单片机来说,无论是I/O口还是寄存器都有特别大的变化,举个很简单的例子:51单片机的I/O一般是不需要配置的,而32的I/O口需要使能,需要选择模式。(模拟输入、浮空输入、上、下拉输入、开漏输出、推挽输出、复用开漏/推挽输出共计八个模式),所以,想要学好32就必须了解32的库函数定义。

typedef struct
{
    
    
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

这就是一段GPIO初始化的结构体,结构体里面仍然是结构体,比如mode这个

typedef enum
{
    
     GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

真正初始化的函数是

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

相信大家看到这里已经懵逼了,这到底该**怎么才能初始化啊,一个I/O口怎么这么麻烦!

不要炸鸡,听我给大家讲解

首先看到前两个函数框,大家估计已经明白了,32的库函数几乎有一半都是结构体,所以大家C语言功底一定要扎实,咱们写单片机的不像搞程序的那个复杂深入,但是基本功一定不要落下。

大家看到入口参数其实就俩GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct
我们先看看GPIO_TypeDef* GPIOx,从名字上就能看出这是找I/O口的,就和51单片机是一样的,比如51叫P1那么32就叫GPIOA,第二个是初始化I/O口的,我们右键进入定义看看

typedef struct
{
    
    
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

这里也就是刚刚那一段,我们可以看到这个结构体里面有三个东西

uint16_t GPIO_Pin;   GPIOSpeed_TypeDef GPIO_Speed;  GPIOMode_TypeDef GPIO_Mode;

看后面的注释可以知道uint16_t GPIO_Pin;是定义引脚的,也就是51中的P1^1一样

GPIOSpeed_TypeDef GPIO_Speed;这是定义I/O口频率的,我们右键进去看看

typedef enum
{
    
     
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

这里我们有三个选择10 2 50,根据需要自行决定
我们看下一个

GPIOMode_TypeDef GPIO_Mode;这是对IO口模式的选择,继续右键

typedef enum
{
    
     GPIO_Mode_AIN = 0x0,
  GPIO_Mode_IN_FLOATING = 0x04,
  GPIO_Mode_IPD = 0x28,
  GPIO_Mode_IPU = 0x48,
  GPIO_Mode_Out_OD = 0x14,
  GPIO_Mode_Out_PP = 0x10,
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;

可以看到这里也就是我最开始说的八种模式
好了了解这些之后我们就开始第一步,初始化一个I/O口吧,那么因为我的LED在B5和E5,那我就以这两个I/O口为例子。

void LED_Init(void)
{
    
    
 
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
 GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高

 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5 端口配置, 推挽输出
 GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
 GPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
}

我知道大家又懵了,我来依次为大家解答
Q:第一行干什么的?
A:第一行相当于是定义一个GPIO_InitStructure结构体来初始化I/O口

Q:RCC_APB2PeriphClockCmd是什么东西?
A:这是使能B E这两个I/O口的函数。因为GPIOB和BPIOE在APB2总线上(可以在中文参考手册查到其他GPIO的总线,群里有),所以我们需要用这个函数,大家记住即可。

接下来的三行就是一个规范的结构体使用方法,根据定义中的数据,依次录入。那么因为我们是要点灯,所以我们用推挽输出。接着GPIO_Init来根据参数初始化GPIOB。

GPIO_SetBits是输出高电平的函数,使用方法看我例程也就明白了
这里补充一下:低电平是GPIO_ResetBits

Q:为什么GPIOE你只设置了Pin脚的参数,其他参数都不设置呢?
A:因为其他的和GPIOB一样,都是推挽输出和50MHz所以不需要另外设置。

LED_Init写完了之后我们就可以写主函数了

int main(void)
{
    
    
	delay_init();
	LED_Init();
	while(1)
	{
    
    
		LED0 = 0;
		LED1 = 1;
		delay_ms(300);
		LED0 = 1;
		LED1 = 0;
		delay_ms(300);
	}
}

学过51的同学应该都能看懂吧?
不过还是得说明一下

delay_init();这个函数在delay.h里面已经定义过了,不需要自己写。(群里有工程文件)
LED0 和LED1需要我们自己在led.h头文件中宏定义

#define LED0 PBout(5)
#define LED1 PEout(5)

赶快将代码编译到stm32开发板上试试吧!

下一篇我将会更新STC51的PWM,然后更新STC12的PWM,为更新STM32的PWM做好准备

交流群号:1033131250

猜你喜欢

转载自blog.csdn.net/qq_18242623/article/details/115348384