一.库函数版本
1) 使能 IO 口时钟。调用函数为 RCC_APB2PeriphColckCmd();
2) 初始化 IO 参数。调用函数GPIO_Init();
3) 操作 IO。
GPIO_SetBits();
GPIO_ResetBits();
1.重要函数
(1)初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:初始化一个或者多个IO口(同一组)的工作方式和速度。
该函数主要是操作GPIO_CRL(CRH)[端口配置寄存器]寄存器,在上拉或者下拉的
时候有设置BSRR[置位/复位]或者BRR[复位]寄存器
这个函数有两个参数:
第一个参数是用来指定 GPIO,取值范围为 GPIOA~GPIOG。
第二个参数为初始化参数结构体指针,结构体类型为 GPIO_InitTypeDef。
可以查看结构体的定义:
typedef struct
{ uint16_t GPIO_Pin;
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
初始化实例
GPIO_InitTypeDef GPIO_InitStructure;
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;//速度 50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);//根据设定参数配置 GPIO
上面代码的意思是设置 GPIOB 的第 5 个端口为推挽输出模式,同时速度为 50M。
(2)读取输入电平函数
//实际操作的是GPIOx_IDR寄存器。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
(3)读取输出电平函数
//实际操作的是GPIO_ODR寄存器。
uint8_t GPIO_ReadOutputDataBit (GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
(4)设置输出电平函数
//实际操作BSRR寄存器
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//实际操作BRR寄存器
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin
2.软件设计
新建HARDWARE组,添加led.h,led.c文件。
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
led.c
#include"led.h"
#include"stm32f10x.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);//使能 GPIOB,GPIOE 端口时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//LED0--->GPIOB.5,端口配置
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5);//GPIOB.5 输出高
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//LED1-->GPIOE.5 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//初始化 GPIOE.5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//IO口速度为50MHz
GPIO_Init(GPIOE,&GPIO_InitStructure);//初始化GPIOE.5
GPIO_SetBits(GPIOE,GPIO_Pin_5);//GPIOE.5 输出高
}
该代码里面就包含了一个函数 void LED_Init(void),该函数的功能就是用来实现配置 PB5 和 PE5 为推挽输出。这里需要注意的是:在配置 STM32 外设的时候,任何时候都要先使能该 外设的时钟。GPIO 是挂载在 APB2 总线上的外设,在固件库中对挂载在 APB2 总线上的外设时 钟使能是通过函数 RCC_APB2PeriphClockCmd()来实现的。
main.c
#include"stm32f10x.h"
#include"led.h"
#include"delay.h"
int main(void)
{
delay_init();//延时函数初始化
LED_Init();//初始化与LED连接的硬件接口
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);//延时300ms
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);延时300ms
}
}
二.寄存器版本
1) 使能 IO 口时钟。配置寄存器 RCC_APB2ENR。
2) 初始化 IO 参数。配置寄存器 GPIOx_CRH/CRL
3) 操作 IO。配置寄存器 GPIOX_ODR或者BSRR/BRR。
1.寄存器
我们常用的 IO 端口寄存器只有 4 个:CRL、CRH、IDR、ODR。
配置模式的 2 个 32 位的端口 配置寄存器 CRL 和 CRH;
2 个 32 位的数据寄存器 IDR 和 ODR;
1 个 32 位的置位/复位寄存器 BSRR;一个 16 位的复位寄存器 BRR;
1 个 32 位的锁存寄存器 LCKR;
(1)寄存器实例
设置了 PC11 为上拉输入,PC12 为推挽输出。
GPIOC->CRH&=0XFFF00FFF; //清掉这 2 个位原来的设置,同时也不影响其他位的设置
GPIOC->CRH|=0X00038000; //PC11 输入,PC12 输出
GPIOC->ODR=1<<11; //PC11 上拉
2.软件设计
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
led.c
#include"led.h"
#include"stm32f10x.h"
void LED_Init(void)
{
RCC->APB2ENR|=1<<3;//使能 PORTB 时钟
RCC->APB2ENR|=1<<6;//使能 PORTE 时钟
//GPIOB.5
GPIOB->CRL&=0xFF0FFFFF;//清零
GPIOB->CRL|=0x00300000;//PB.5 推挽输出 (置1)
GPIOB->ODR|=1<<5;//PB.5 输出高
//GPIOE.5
GPIOE->CRL&=0xFF0FFFFF;
GPIOE->CRL|=0x00300000;//PE.5 推挽输出
GPIOE->ODR|=1<<5;//PE.5 输出高
}
在配置 STM32 外设的时候,任何时候都要先使能该外设的时钟!
APB2ENR 是 APB2 总线上的外设时钟使能寄存器
端口配置低寄存器(GPIOx_CRL) (x=A..E)
- 因PB5属于GPIO0~7之间,所以,需通过GPIOB_CRL寄存器才能实现对PB5的设置。
- 因GPIOB_CRL寄存器中每4位决定一个GPIO工作模式,所以,需通过设置GPIOB_CRL的第20~23位。
- 因PB5引脚“输出模式”,从图中2可以看出须把GPIOB_CRH寄存器的MODE5[1:0]设置为11(50MHz)。
- 根据MODE[1:0]的值为11可知,CNF11[1:0]需要选择“在输出模式(MODE[1:0]>00)”中选择需要设置的值。
- 因PB5须设置为“通用推挽输出模式”,故CNF11[1:0]需设置为00。(0011 = 3)
- 最终设置指令为:
GPIOB->CRL&=0xFF0FFFFF;//清零 GPIOB->CRL|=0x00300000;//PB.5 推挽输出 (置1)
main.c
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
int main(void)
{
delay_init(72);
LED_Init();
while(1)
{
GPIOB->ODR|=1<<5;
GPIOE->ODR|=1<<5;
delay_ms(500);
GPIOB->ODR&=~(1<<5);
GPIOE->ODR&=~(1<<5);
delay_ms(500);
}
}