STM32 - 2

STM32 - 2

之前我们已经了解了一些STM32的基础知识,下面就开始正式的编程了。我们主要会使用STM32的HAL库,这些库函数已经在创建工程的时候初始化好了,一般来说,直接使用即可。

GPIO

片上外设的使能时钟

首先了解一下STM32的片上外设的使能时钟。STM32几乎所有的片上设备都有使能时钟,包括输入输出GPIO。不把使能时钟打开,对应的外设就不能用。STM32这么设计是为了降低功耗。

那怎么样启动使能时钟呢?以最小系统板上面的PC13为例,这个IO实际上就是GPIOC的13号引脚,那么我们就在main.c里面使用如下代码就可以开启GPIOC的使能时钟:

1
__HAL_RCC_GPIOC_CLK_ENABLE();

初始化GPIO

在打开GPIO的使能时钟之后,就要初始化GPIO了。可以使用如下API初始化GPIO:

1
void HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

其中,GPIOC就是GPIO的类型,而后面的那个GPIO_InitStruct则是各种初始化参数,如输入输出模式、输入输出引脚等。下面是初始化设置的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void MX_GPIO_Init(void)
{
  // GPIO初始化设置
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  // 打开GPIOC的使能时钟
  __HAL_RCC_GPIOC_CLK_ENABLE();

  // 设置GPIOC的13号引脚的输出Level
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

  // 然后配置各种GPIO的设置,如引脚为13,模式为PP(推挽输出),没有上拉电阻,输出速率等等。
  GPIO_InitStruct.Pin = GPIO_PIN_13;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  // 完成GPIO的初始化
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

向GPIO写入值(输出)

在初始化完毕之后,就可以使用HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);向对应的GPIO写入值了。参数都很容易理解,最后一个参数,如果是SET,那么就是写1;如果是RESET,就是写0。

OK,到这里,一个最简单的亮灯程序就写完了。后面,我们就深入了解一下GPIO的各种设置属性。

GPIO的设置

GPIO的设置主要是使用GPIO_InitTypeDef来声明:GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitTypeDef主要包含4个设置:

  • Mode:IO引脚的模式

    我们在上面的示例代码中用到的,就是GPIO_MODE_OUTPUT_PP,即输出推挽模式(Output Push-Pull Mode)。推挽模式就是高低电平均有驱动能力的输出模式。

    此外,输出模式还有GPIO_MODE_OUTPUT_OD,即输出开漏模式。开漏输出高电平相当于高阻态,是没有驱动能力的。

    另外,还可以选择输入模式,即GPIO_MODE_INPUTGPIO_MODE_AF_INPUT。具体这些模式的区别,可以参考下 https://www.bilibili.com/video/BV1th411z7sn 15分钟左右的讲解,很详细

  • Pin:就是第几号IO引脚

    如果要设置第13号引脚,就可以使用:GPIO_InitStruct.Pin = GPIO_PIN_13;,如果要设置多个引脚,可以使用|:

    1
    2
    
    // 同时设置13和14号引脚
    GPIO_InitStruct.Pin = GPIO_PIN_13 | GPIO_PIN_14;
    
  • Pull:用在输入模式里面,即上拉/下拉电阻,用来设置输入悬空的时候,输入口是高电平(上拉电阻PULLUP)还是低电平(下拉电阻PULLDOWN)还是就把它悬空(NOPULL),详见 https://www.bilibili.com/video/BV1th411z7sn 9分钟30秒左右的讲解

  • Speed:设置IO引脚允许的最大速度

    看f411的源代码可以到这里可以设置4个级别的IO速度,分别是2M、12.5M~50M、25M~100M和50M~200M。速度越快,IO的读取频率就越高,也就越耗电。

    1
    2
    3
    4
    
    #define  GPIO_SPEED_FREQ_LOW         0x00000000U  /*!< IO works at 2 MHz, please refer to the product datasheet */
    #define  GPIO_SPEED_FREQ_MEDIUM      0x00000001U  /*!< range 12,5 MHz to 50 MHz, please refer to the product datasheet */
    #define  GPIO_SPEED_FREQ_HIGH        0x00000002U  /*!< range 25 MHz to 100 MHz, please refer to the product datasheet  */
    #define  GPIO_SPEED_FREQ_VERY_HIGH   0x00000003U  /*!< range 50 MHz to 200 MHz, please refer to the product datasheet  */
    

最后,需要注意传进去的GPIO_InitTypeDef是一个指针,所以需要使用&GPIO_InitStruct 传地址进去。

GPIO输入

我们就用最简单的开关来学习GPIO口的输入。

首先复习一下在配置输入模式的时候,有一个Pull字段。这个字段代表着在输入悬空的时候,默认是上拉电阻还是下拉电阻或者是悬空。这玩意有什么用呢?我们看一下下面的开关电路:

image-20220801171400974

很好理解,开关按下的时候,GPIO输入就接地,即低电平0。那这个上下拉电阻有什么关系呢?

看下左边的图,如果开关断开,这个时候PA0输入就悬空了。如果这个时候GPIO口的配置为悬空,那这个引脚就真的悬空了,其输入就不确定。而如果这个时候,GPIO口的输入配置为下拉电阻,此时PA0悬空,输入就被下拉电阻拉到了低电平,那这个按键实际上就没用了。因此,在按键一边接地的时候,如果没有手动配置上拉电阻(右边的图),那就必须把GPIO的输入设置为上拉电阻模式(PULLUP),来保证开关断开时输入为高电平

当然,如果像右边一样,外面单独配置了上拉电阻,那么PA0的输入模式配置为上拉电阻模式或者悬空时都可以的。

❗ 注意:由于STM32系列并不是所有的开关都有下拉电阻模式,因此,在习惯上,只要是开关都采用低电平触发的方式,即一边接地一边接GPIO。

输入模式

按键消抖

一般来说,按下按键之后,按键会有一个5-10ms的抖动,然后才会稳定在高电平。消除抖动的策略很简单,在检测到按键之后,延迟20ms再进入完全按下时的那个while循环。然后就只要按下就一直在这个while循环里,直到松开按键,跳出while循环,然后再delay20ms。对于按键的要求比较高的场合,可能还需要后续的滤波。

GPIO输出

上面我们已经了解了GPIO输出模式的推挽模式(PP),即输出的时候,上下两个MOS管均可以导通(同时只有一个能通),然后输出就能够被下推到0V或上拉到3.3V,这样高低电平都有强驱动能力。

除了推挽模式之外,输出还有开漏模式(OD)。其实开漏模式和推挽模式的区别就在于,开漏模式的上面接高电平的MOS管一直是断开的。这样的话,只有下面的MOS可以导通,那就低电平有强驱动能力。而在输出1的时候,上下MOS均断开,输出就是一个高阻抗状态,就相当于这个输出直接断开了(不是输出高电平)。

两个输出模式的区别:

image-20220802104324062

开漏模式的应用场景

驱动IED

PP和OD模式都能驱动LED,驱动电路略有不同:

image-20220802104639906区别是除了电路不同之外,两个模式驱动LED还有如下区别:

  1. PP模式是输出1灯亮,而OD是输出0灯亮
  2. PP模式是芯片向外供电,而OD是外面的电源供电,芯片吸电
  3. OD模式相对于PP模式,理论上能够承载的最大电流多一些
  4. OD模式能够降低芯片功耗

逻辑线与

逻辑线与最多是用在I2C通信总线上。

I2C是一种通信总线,它有两个线:一个是SDA用于传数据,一个是SCL用于传时钟。其接线如图:

image-20220802105029636

I2C的所有SDA和SCL的IO都是OD模式,这样的话,只要有一个输出是0,那么对应的SDA就会被拉到0V输出低电平。而只有所有的SDA或者SCL全是1,由于是高阻态,对应输出的SDA或SCL就会被上拉电阻拉到VDD,输出高电平。这就是逻辑线与。

匹配不同电压等级

STM32输出的高电平一般是3.3V,但是如果我们想要去驱动需要5V输入的芯片应该如何做呢?下面就是使用开漏模式驱动5V输入的原理图:

可以看到,在STM32输出0的时候,那右边芯片的DIN输入就是0V低电平。如果STM32输出1的时候,由于输出口为高阻态,那么DIN就会被外接电源拉到5V,也就是右边芯片需要的高电平。这就实现了不同电压水平的匹配。

image-20220802105423779
updatedupdated2024-05-102024-05-10