STM32学习笔记2——GPIO点灯

  学会了建立建立工程,接下来一定是迫不及待的想用自己的开发板大显身手了吧。别急,慢慢来。在C语言学习时,你最先编译的一定是那条永恒经典的代码,对,就是Hello World——简单、明了,而且能直观的看见现象。在STM32上也有一个简单、明了,而且能直观的看见现象的程序——点灯。这就是我们现在的hello world,让我们从他开始学习吧!!!

学习

  点灯我们要用到的就是控制我们需要的I/O口,所以,让我们先来看一下STM32F的GPIO端口。在STM32F0系列微控制器的每个GPIO端口有:两个32位配置寄存器(GPIOx_OTYPER和GPIOx_MODER)、两个32位数据寄存器(GPIOx_IDR和GPIOx_ODR)、一个32位置位/复位寄存器(GPIOx_BSRR)、一个16位复位寄存器(GPIOx_BRR)和一个32位锁定寄存器(GPIOx_LCKR)。根据数据手册中列出的每个I/O口的特定硬件特性,GPIO的端口的每个位可以软件分别配置成:输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、推挽复用和开漏复用功能等多种模式。具体见表
STM32学习笔记2——GPIO点灯_第1张图片
STM32学习笔记2——GPIO点灯_第2张图片
每个I/O口可以自由编程,然而I/O口的寄存器必须按32位字节进行访问。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器的读/写的独立访问;
由此,我们可以编程对寄存器进行操作,使I/O口产生方波对灯进行亮灭控制。但首先我们要找到开发板上的LED在哪个I/O口上:找到开发板的原理图你会发现
STM32学习笔记2——GPIO点灯_第3张图片
LED接在PA5端口,高电平点亮。(由于板子不一样,大家自行寻找自己的LED挂在哪个口上,是在找不到,可外接)
下面就开始对我们的开发板进行点灯的编程了

  1. 按照昨天的工程建立一个工程,Lib组里继续添加gpio.c和rcc.c。
  2. 来到main.c下进行程序的编写。

程序

1.包含头文件

#include"stm32f0xx.h"

2.延时函数

void Delay(volatile unsigned int ncount)
{
    while(ncount--);
}

3.定义GPIO初始化结构体

GPIO_InitTypeDef        GPIO_InitStructure;

4.进入主函数

int main(void)
{
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //enable the clock
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_P;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  while (1)
  {
     GPIO_SetBits(GPIOA,GPIO_Pin_5);
     Delay(0xfffff);
     GPIO_ResetBits(GPIOA,GPIO_Pin_5);
     Delay(0xfffff);
  }
}

接下来把程序按照昨天写的下到开发板上,看到LED灯开始闪烁,好了。一切都完工了没?早着呢,这才开始,下面我们开始分析为什么这么写。知其然,还要知其所以然。

分析

  • 延时函数没问题(但还要注意volatile的应用,在KEIL中无所谓,但如果你使用GCC进行编程,没有volatile的地方就会被优化掉,从而使延时函数无意义)
  • 那么接下来的GPIO_InitTypeDef GPIO_InitStructure;是什么意思呢?

在GPIO.h中还有如下代码

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

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

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

  GPIOOType_TypeDef GPIO_OType;   /*!< Specifies the operating output type for the selected pins.
                                       This parameter can be a value of @ref GPIOOType_TypeDef  */

  GPIOPuPd_TypeDef GPIO_PuPd;     /*!< Specifies the operating Pull-up/Pull down for the selected pins.
                                       This parameter can be a value of @ref GPIOPuPd_TypeDef   */
}GPIO_InitTypeDef;

两段代码合起来就是我们要找的了,先定义GPIO_InitTypeDef,然后根据这个结构定义了GPIO_InitStructure,这个结构体在后面的GPIO的设置中会用到。

  • 主函数中的第一句RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);又是什么呢?我不是配置GPIO么,这是什么东西?
    在STM32中,上电后默认所有的时钟都是关的,需要手动打开,所以这一部是先进行时钟打开,在M0内核中控制GPIOPA的时钟在AHB上
    STM32学习笔记2——GPIO点灯_第4张图片
    所以要打开PA5上的时钟,必须对AHB使能,在函数中
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState != DISABLE)
  {
    RCC->AHBENR |= RCC_AHBPeriph;
  }
  else
  {
    RCC->AHBENR &= ~RCC_AHBPeriph;
  }
}

变量uint32_t RCC_AHBPeriph在库中有如下定义#define RCC_AHBPeriph_GPIOA RCC_AHBENR_GPIOAEN #define RCC_AHBENR_GPIOAEN ((uint32_t)0x00020000)将0x00020000与寄存器按位或后进行赋值正好对应GPIOA进行使能。

  • GPIO设置
    先对结构体内的变量赋值,设置PA5口,设置端口为输出、推挽输出(模电的知识,我也是一知半解),设置输出速度为50MHz.
    然后进入让LED亮灭的程序,对GPIO_SetBits(GPIOA,GPIO_Pin_5);我们看他的原函数:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));

  GPIOx->BSRR = GPIO_Pin;
}

他传递了两个参数:*GPIOx,GPIO_Pin。在stm32f0xx.h中有

typedef struct
{
  __IO uint32_t MODER;        
  __IO uint16_t OTYPER;       
  uint16_t RESERVED0;       
  __IO uint32_t OSPEEDR;     
  __IO uint32_t PUPDR;       
  __IO uint16_t IDR;         
  uint16_t RESERVED1;      
  __IO uint16_t ODR;          
  uint16_t RESERVED2;         
  __IO uint32_t BSRR;        
  __IO uint32_t LCKR;         
  __IO uint32_t AFR[2];       
  __IO uint16_t BRR;         
  uint16_t RESERVED3;       
}GPIO_TypeDef;

对__IO的定义volatile,大家可以去看这篇文章这里写链接内容谢谢作者。通过这个结构体大家也该明白为什么能对BSRR寄存器进行操作了吧。在BSRR寄存器
STM32学习笔记2——GPIO点灯_第5张图片

#define GPIO_Pin_5                 ((uint16_t)0x0020) 

所以该函数就是对第五位ODR置位。之后延时,GPIO_ResetBits(GPIOA,GPIO_Pin_5);和上面的差不多,就不一一讲了。
至此点灯程序就差不多了,做出来不一定能写出来,写的过程是一个升华提升的过程,能扎实自己的能力,再把自己的想一想,把以前认为理所当然的过一遍,能收获很多。。。
PS:库里的*.c文件添加后,如编译时提示找不到头文件,要去stm32f0xx_cof.h中使能相应的.h 文件(就是把前面的注释去掉)。

你可能感兴趣的:(stm32)