0
点赞
收藏
分享

微信扫一扫

STM32 IO 简介


STM32 IO 简介

  • ​​1.IO介绍​​
  • ​​2.仿真与下载​​

1.IO介绍

STM32 的 IO 口可以由软件配置成如下 8 种模式:
1、 输入浮空
2、 输入上拉
3、 输入下拉
4、 模拟输入
5、 开漏输出
6、 推挽输出
7、 推挽式复用功能
8、 开漏复用功能
每个 IO 口可以自由编程, 但 IO 口寄存器必须要按 32 位字被访问。 STM32 的很多 IO 口都
是 5V 兼容的,这些 IO 口在与 5V 电平的外设连接的时候很有优势,具体哪些 IO 口是 5V 兼容
的,可以从该芯片的数据手册管脚描述章节查到(I/O Level 标 FT 的就是 5V 电平兼容的)。
STM32 的每个 IO 端口都有 7 个寄存器来控制。
他们分别是:
配置模式的 2 个 32 位的端口配置寄存器 CRL 和 CRH;
2 个 32 位的数据寄存器 IDR 和 ODR;
1 个 32 位的置位/复位寄存器BSRR;
一个 16 位的复位寄存器 BRR;
1 个 32 位的锁存寄存器 LCKR;

typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;

这里我们仅介绍常用 的
几个寄存器,我们常用的 IO 端口寄存器只有 4 个: CRL、 CRH、 IDR、 ODR。
CRL 和 CRH 控制着每个 IO 口的模式及输出速率。
STM32 的 IO 口位配置表如表 6.1.1 所示:
STM32 IO 简介_#define
STM32 IO 简介_STM32 IO 简介_02
接下来我们看看端口低配置寄存器 CRL 的描述,如图 6.1.1 所示:

STM32 IO 简介_#include_03
STM32 IO 简介_#define_04
该寄存器的复位值为 0X4444 4444,从图 6.1.1 可以看到,复位值其实就是配置端口为浮空输入模式。从上图还可以得出: STM32 的 CRL 控制着每组 IO 端口(A~G)的低 8 位的模式。每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。这里我们可以记住几个常用的配置,比如 0X0 表示模拟输入模式(ADC 用)、 0X3 表示推挽输出模式(做输出口用,50M 速率)、 0X8 表示上/下拉输入模式(做输入口用)、 0XB 表示复用输出(使用 IO 口的第二功能, 50M 速率)。
CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8
位输出口。这里我们对 CRH 就不做详细介绍了。
给个实例,比如我们要设置 PORTC 的 11 位为上拉输入, 12 位为推挽输出。代码如下:

GPIOC->CRH&=0XFFF00FFF;//清掉这 2 个位原来的设置,同时也不影响其他位的设置
GPIOC->CRH|=0X00038000; //PC11 输入, PC12 输出
GPIOC->ODR=1<<11; //PC11 上拉

通过这 3 句话的配置,我们就设置了 PC11 为上拉输入, PC12 为推挽输出。
IDR 是一个端口输入数据寄存器,只用了低 16 位。该寄存器为只读寄存器,并且只能以
16 位的形式读出。该寄存器各位的描述如图 6.1.2 所示:
STM32 IO 简介_STM32流水灯原理_05
要想知道某个 IO 口的状态, 你只要读这个寄存器,再看某个位的状态就可以了。使用起
来是比较简单的。
ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平。该寄存器的各位描述如图 6.1.3 所示:
STM32 IO 简介_#include_06
流水灯实验

#include "led.h"
//初始化 PB5 和 PE5 为输出口.并使能这两个口的时钟
//LED IO 初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<3; //使能 PORTB 时钟
RCC->APB2ENR|=1<<6; //使能 PORTE 时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000;//PE.5 推挽输出
GPIOE->ODR|=1<<5; //PE.5 输出高
}

该代码里面就包含了一个函数 void LED_Init(void),该函数的功能就是用来实现配置 PB5
和 PE5 为推挽输出。 这里需要注意的是: 在配置 STM32 外设的时候,任何时候都要先使能该外设的时钟!APB2ENR 是 APB2 总线上的外设时钟使能寄存器,其各位的描述如图 6.3.2 所示:
STM32 IO 简介_寄存器_07
我们要使能的 PORTB 和 PORTE 的时钟使能位,分别在 bit3 和 bit6,只要将这两位置 1 就可以使能 PORTA 和 PORTD 的时钟了。该寄存器还包括了很多其他外设的时钟使能。大家在以后会慢慢使用到的。关于这个寄存器的详细说明在《STM32 参考手册》的第 70 页。
在设置完时钟之后就是配置完时钟之后, LED_Init 配置了 PB5 和 PE5 的模式为推挽输出,并且默认输出 1。这样就完成了对这两个 IO 口的初始化。
保存 led.c 代码,然后我们按同样的方法,新建一个 led.h 文件,也保存在 LED 文件夹下面。在 led.h 中输入如下代码:

#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义
#define LED0 PBout(5)// DS0 #define LED0 (1<<5) //led0 PB5
#define LED1 PEout(5)// DS1 #define LED1 (1<<5) //led1 PE5
void LED_Init(void);//初始化
#endif

这里使用的是位带操作来实现操作某个 IO 口的 1 个位的,关于位带操作前面已经有介绍,
这里不再多说。需要说明的是,这里可以使用另外一种操作方式实现。如下:

#define LED0 (1<<5) //led0 PB5
#define LED1 (1<<5) //led1 PE5
#define LED0_SET(x) GPIOB->ODR=(GPIOB->ODR&~LED0)|(x ? LED0: 0)
#define LED1_SET(x) GPIOE->ODR=(GPIOE->ODR&~LED1)|(x ? LED1: 0)

后者通过 LED0_SET(0)和 LED0_SET(1)来控制 PB5 的输出 0 和 1。而前者的类似操作为:LED0=0 和 LED0=1。显然前者简单很多,从而可以看出位带操作带来的好处。以后像这样的IO 口操作,我们都使用位带操作来实现,而不使用第二种方法。

main函数

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
//ALIENTEK 战舰 STM32 开发板实验 1
//跑马灯实验
int main(void)
{
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //初始化与 LED 连接的硬件接口
while(1)
{
LED0=0;
LED1=1;
delay_ms(300);
LED0=1;
LED1=0;
delay_ms(300);
}
}

2.仿真与下载

STM32 IO 简介_寄存器_08
STM32 IO 简介_#include_09
Display Type 选择 bit,然后单击 Close 关闭该对话框,可以看到逻辑分析窗口出来了两个信号,如图 6.4.2 所示:
STM32 IO 简介_寄存器_10
STM32 IO 简介_STM32 IO 简介_11
STM32 IO 简介_STM32流水灯原理_12
STM32 IO 简介_STM32流水灯原理_13


举报

相关推荐

0 条评论