目录
点亮RGB LED
RGB LED原理图
根据原理图可知,LED低电平有效。上图中为了保护引脚,避免输入电流过大,所以加入了3个限流电阻。
寄存器点亮RGB
点亮前须知
要想实现LED点亮,需要三个步骤(以PB0为实验引脚):
1)打开GPIOB端口的时钟(RCC_APB2ENR寄存器)。
2)配置IO口为输出(GPIOx_CRL寄存器)。
3)控制ORD寄存器(GPIOx_ODR寄存器)。
翻阅STM32F103参考手册存储器映射,可发现:
代码段
//打开GPIOB端口的时钟
* (unsigned int *)0x40021018 |= ( (1) << 3 );
//配置IO口为推挽输出,最大速度10MHz
* (unsigned int *)0x40010C00 &=~ ( (0x0f) << (4*0) ); //先清零
* (unsigned int *)0x40010C00 |= ( (1) << (4*0) ); //再取值
//控制ODR寄存器
* (unsigned int *)0x40010C0C &=~ (1<<0); //低电平有效
标准库点亮RGB(演变过程)
代码段1
对程序进行改进,引入stm32f10x.h,描述的是寄存器映射。
stm32f10x.h文件
//用来存放STM32寄存器映射的代码
//外设 perirhral
#define PERIRH_BASE ((unsigned int)0x40000000)
#define APB1PERIRH_BASE PERIRH_BASE
#define APB2PERIRH_BASE (APB1PERIRH_BASE + 0x10000)
#define AHBPERIRH_BASE (APB1PERIRH_BASE + 0x20000)
#define RCC_BASE (AHBPERIRH_BASE + 0x1000)
#define GPIOB_BASE (APB2PERIRH_BASE + 0x0C00)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE + 0x0C)
main函数下
//打开GPIOB端口的时钟
RCC_APB2ENR |= ( (1) << 3 );
//配置IO口为推挽输出,最大速度10MHz
GPIOB_CRL &=~ ( (0x0f) << (4*0) );
GPIOB_CRL |= ( (1) << (4*0) );
//控制ODR寄存器
GPIOB_ODR &=~ (1<<0); //看原理图,高电平不亮。所以要输出低电平
代码段2
再进行改进。增加stm32f10x_gpio的文件。
stm32f10x.h文件
//用来存放STM32寄存器映射的代码
//外设 perirhral
#define PERIRH_BASE ((unsigned int)0x40000000)
#define APB1PERIRH_BASE PERIRH_BASE
#define APB2PERIRH_BASE (APB1PERIRH_BASE + 0x10000)
#define AHBPERIRH_BASE (APB1PERIRH_BASE + 0x20000)
#define RCC_BASE (AHBPERIRH_BASE + 0x1000)
#define GPIOB_BASE (APB2PERIRH_BASE + 0x0C00)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE + 0x0C)
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef struct
{
uint32_t CRL;
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
typedef struct
{
uint32_t CR;
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2RSTR;
uint32_t APB1RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
uint32_t DBCR;
uint32_t CSR;
}RCC_TypeDef;
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
#define RCC ((RCC_TypeDef *)RCC_BASE)
stm32f10x_gpio.h文件
#ifndef _STM32F10X_GPIO_H
#define _STM32F10X_GPIO_H
#include "stm32f10x.h"
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!<选择Pin1 */ //(00000000 00000001)b
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!<选择Pin2 */ //(00000000 00000010)b
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!<选择Pin3 */ //(00000000 00000100)b
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!<选择Pin4 */ //(00000000 00001000)b
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!<选择Pin5 */ //(00000000 00010000)b
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!<选择Pin6 */ //(00000000 00100000)b
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!<选择Pin7 */ //(00000000 01000000)b
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!<选择Pin8 */ //(00000000 10000000)b
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!<选择Pin9 */ //(00000001 00000000)b
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!<选择Pin10 */ //(00000010 00000000)b
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!<选择Pin11 */ //(00000100 00000000)b
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!<选择Pin12 */ //(00001000 00000000)b
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!<选择Pin13 */ //(00010000 00000000)b
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!<选择Pin14 */ //(00100000 00000000)b
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!<选择Pin15 */ //(01000000 00000000)b
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!<选择Pin16 */ //(10000000 00000000)b
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!<选择全部引脚 */ //(11111111 11111111)b
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
#endif /*_STM32F10X_GPIO_H*/
stm32f10x_gpio.c文件
#include "stm32f10x_gpio.h"
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BSRR |= GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BRR |= GPIO_Pin;
//GPIOx->BSRR |= GPIO_Pin<<16; 和上行意思一样
}
main函数下
//打开GPIOB端口的时钟
RCC->APB2ENR |= ( (1) << 3 );
//配置IO口为输出,控制CRL寄存器
GPIOB->CRL &=~ ( (0x0f) << (4*0) );
GPIOB->CRL |= ( (1) << (4*0) );
GPIO_SetBits(GPIOB,GPIO_Pin_0); //高电平,灭
//GPIO_ResetBits(GPIOB,GPIO_Pin_0); //低电平,亮
代码段3
最后进行改进。对于GPIO的初始化函数和GPIOMode结构体的枚举,可以通过下图来解释。
stm32f10x.h文件
照旧
stm32f10x_gpio.h文件
#ifndef _STM32F10X_GPIO_H
#define _STM32F10X_GPIO_H
#include "stm32f10x.h"
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!<选择Pin1 */ //(00000000 00000001)b
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!<选择Pin2 */ //(00000000 00000010)b
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!<选择Pin3 */ //(00000000 00000100)b
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!<选择Pin4 */ //(00000000 00001000)b
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!<选择Pin5 */ //(00000000 00010000)b
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!<选择Pin6 */ //(00000000 00100000)b
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!<选择Pin7 */ //(00000000 01000000)b
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!<选择Pin8 */ //(00000000 10000000)b
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!<选择Pin9 */ //(00000001 00000000)b
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!<选择Pin10 */ //(00000010 00000000)b
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!<选择Pin11 */ //(00000100 00000000)b
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!<选择Pin12 */ //(00001000 00000000)b
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!<选择Pin13 */ //(00010000 00000000)b
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!<选择Pin14 */ //(00100000 00000000)b
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!<选择Pin15 */ //(01000000 00000000)b
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!<选择Pin16 */ //(10000000 00000000)b
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!<选择全部引脚 */ //(11111111 11111111)b
typedef enum
{
GPIO_Speed_10MHz = 1, //10MHz (01)b
GPIO_Speed_2MHz, // 2MHz (10)b
GPIO_Speed_50MHz //50MHz (11)b
}GPIOSpeed_TypeDef;
typedef enum
{
GPIO_Mode_AIN = 0x0, //模拟输入 (0000 0000)b
GPIO_Mode_IN_FLOATING = 0x04, //浮空输入 (0000 0100)b
GPIO_Mode_IPD = 0x28, //下拉输入 (0010 1000)b
GPIO_Mode_IPU = 0x48, //上拉输入 (0100 1000)b
GPIO_Mode_OUT_OD = 0x14, //开漏输出 (0001 0100)b
GPIO_Mode_OUT_PP = 0x10, //推挽输出 (0001 0000)b
GPIO_Mode_AF_OD = 0x1C, //复用开漏输出 (0001 1100)b
GPIO_Mode_AF_PP = 0x18 //复用推挽输出 (0001 1000)b
}GPIOMode_TypeDef;
typedef struct
{
uint16_t GPIO_Pin;
uint16_t GPIO_Speed;
uint16_t GPIO_Mode;
}GPIO_InitTypeDef;
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
#endif /*_STM32F10X_GPIO_H*/
stm32f10x_gpio.c文件
#include "stm32f10x_gpio.h"
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BSRR |= GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
GPIOx->BRR |= GPIO_Pin;
//GPIOx->BSRR |= GPIO_Pin<<16; 和上行意思一样
}
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/*---------------------- GPIO 模式配置 --------------------------*/
// 把输入参数GPIO_Mode的低四位暂存在currentmode
currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
// bit4是1表示输出,bit4是0则是输入
// 判断bit4是1还是0,即首选判断是输入还是输出模式
if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
{
// 输出模式则要设置输出速度
currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
}
/*-------------GPIO CRL 寄存器配置 CRL寄存器控制着低8位IO- -------*/
// 配置端口低8位,即Pin0~Pin7
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
{
// 先备份CRL寄存器的值
tmpreg = GPIOx->CRL;
// 循环,从Pin0开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
// pos的值为1左移pinpos位
pos = ((uint32_t)0x01) << pinpos;
// 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
// pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << pinpos);
}
else
{
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
}
}
}
}
// 把前面处理后的暂存值写入到CRL寄存器之中
GPIOx->CRL = tmpreg;
}
/*-------------GPIO CRH 寄存器配置 CRH寄存器控制着高8位IO- -----------*/
// 配置端口高8位,即Pin8~Pin15
if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
{
// 先备份CRH寄存器的值
tmpreg = GPIOx->CRH;
// 循环,从Pin8开始配对,找出具体的Pin
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = (((uint32_t)0x01) << (pinpos + 0x08));
// pos与输入参数GPIO_PIN作位与运算
currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
//若currentpin=pos,则找到使用的引脚
if (currentpin == pos)
{
//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
pos = pinpos << 2;
//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
// 向寄存器写入将要配置的引脚的模式
tmpreg |= (currentmode << pos);
// 判断是否为下拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
// 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
// 判断是否为上拉输入模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
{
// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
}
}
}
// 把前面处理后的暂存值写入到CRH寄存器之中
GPIOx->CRH = tmpreg;
}
}
main函数下
#define LED_G_GPIO_PORT GPIOB
#define LED_G_GPIO_CLK_ENABLE (RCC_APB2ENR |= ( (1) << 3 ))
#define LED_G_GPIO_PIN GPIO_Pin_0
#define LED_B_GPIO_PORT GPIOB
#define LED_B_GPIO_CLK_ENABLE (RCC_APB2ENR |= ( (1) << 3 ))
#define LED_B_GPIO_PIN GPIO_Pin_1
#define LED_R_GPIO_PORT GPIOB
#define LED_R_GPIO_CLK_ENABLE (RCC_APB2ENR |= ( (1) << 3 ))
#define LED_R_GPIO_PIN GPIO_Pin_5
void Delay(uint32_t count)
{
for( ; count != 0 ; count--)
{}
}
int main()
{
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOB端口的时钟
LED_G_GPIO_CLK_ENABLE;
GPIO_InitStructure.GPIO_Pin = LED_B_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED_G_GPIO_PORT,&GPIO_InitStructure);
while(1)
{
GPIO_SetBits(LED_G_GPIO_PORT, LED_B_GPIO_PIN); //高电平,灭
Delay(0xF5FF);
GPIO_ResetBits(LED_G_GPIO_PORT, LED_B_GPIO_PIN); //低电平,亮
Delay(0xF5FF);
}
}
HAL库点亮rgb
利用STM32CubeMX对RGB LED引脚进行推挽输出配置生成HAL库。
MX_GPIO_Init函数(总IO初始化)
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pins : PB0 PB1 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
GPIO_InitTypeDef初始化结构体
typedef struct
{
uint32_t Pin; //GPIO_pins_define中选择
uint32_t Mode; //GPIO_mode_define中选择
uint32_t Pull; //GPIO_pull_define中选择
uint32_t Speed; //GPIO_speed_define中选择
} GPIO_InitTypeDef; //stm32f1x_hal_gpio.h
4个32位的配置寄存器共同决定了I/O的功能配置选择,GPIO_InitTypeDef结构体的功能是选择GPIO的引脚号、模式、上下拉、最大速度。
打开时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
#define __HAL_RCC_GPIOB_CLK_ENABLE() do { \
__IO uint32_t tmpreg; \
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
/* Delay after an RCC peripheral clock enabling */\
tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
UNUSED(tmpreg); \
} while(0U)
宏定义中do...while(0) 的目的是为了确保宏定义在使用时与函数调用一样的语法,同时避免一些潜在的问题。
1、语法正确性:在C语言中,条件语句if、while等后面通常跟着一个代码块({}内语句),而宏定义展开后的代码会被直接替换到宏调用的地方。如果宏定义不适用do...while(0)包裹,当我们在使用if、while等语句调用宏时,可能会导致语法错误。使用do...while(0)可以确保宏定义展开后的代码成为一个完整的代码块,避免了这种问题。
2、语义正确性:使用do...while(0)可以确保宏定义在调用时作为一个整体,不会被其他语句的控制流程所影响。例如,如果没有do...while(0),在宏定义中使用的变量可能会与外部变量冲突,导致逻辑错误。
3、错误检查:使用do...while(0)可以让编辑器检查宏定义中的语法错误。如果宏定义中出现了语法错误,编译器会在编译时报错,而不是在运行时才发现。
4、代码规范性:使用do...while(0)可以使代码更具可读性和一致性。它使得宏定义的调用方法与函数调用相似,提高了代码的可读性和可维护性。
HAL_GPIO_Init()初始化函数
/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position = 0x00u;
uint32_t ioposition;
uint32_t iocurrent;
uint32_t temp;
uint32_t config = 0x00u;
__IO uint32_t *configregister; /* Store the address of CRL or CRH register based on pin number */
uint32_t registeroffset; /* offset used during computation of CNF and MODE bits placement inside CRL or CRH register */
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
/* Configure the port pins */
while (((GPIO_Init->Pin) >> position) != 0x00u)
{
/* Get the IO position */
ioposition = (0x01uL << position);
/* Get the current IO position */
iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
if (iocurrent == ioposition)
{
/* Check the Alternate function parameters */
assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
/* Based on the required mode, filling config variable with MODEy[1:0] and CNFy[3:2] corresponding bits */
switch (GPIO_Init->Mode)
{
/* If we are configuring the pin in OUTPUT push-pull mode */
case GPIO_MODE_OUTPUT_PP:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_PP;
break;
/* If we are configuring the pin in OUTPUT open-drain mode */
case GPIO_MODE_OUTPUT_OD:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_OD;
break;
/* If we are configuring the pin in ALTERNATE FUNCTION push-pull mode */
case GPIO_MODE_AF_PP:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_PP;
break;
/* If we are configuring the pin in ALTERNATE FUNCTION open-drain mode */
case GPIO_MODE_AF_OD:
/* Check the GPIO speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_OD;
break;
/* If we are configuring the pin in INPUT (also applicable to EVENT and IT mode) */
case GPIO_MODE_INPUT:
case GPIO_MODE_IT_RISING:
case GPIO_MODE_IT_FALLING:
case GPIO_MODE_IT_RISING_FALLING:
case GPIO_MODE_EVT_RISING:
case GPIO_MODE_EVT_FALLING:
case GPIO_MODE_EVT_RISING_FALLING:
/* Check the GPIO pull parameter */
assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
if (GPIO_Init->Pull == GPIO_NOPULL)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_FLOATING;
}
else if (GPIO_Init->Pull == GPIO_PULLUP)
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
/* Set the corresponding ODR bit */
GPIOx->BSRR = ioposition;
}
else /* GPIO_PULLDOWN */
{
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;
/* Reset the corresponding ODR bit */
GPIOx->BRR = ioposition;
}
break;
/* If we are configuring the pin in INPUT analog mode */
case GPIO_MODE_ANALOG:
config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_ANALOG;
break;
/* Parameters are checked with assert_param */
default:
break;
}
/* Check if the current bit belongs to first half or last half of the pin count number
in order to address CRH or CRL register*/
configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL : &GPIOx->CRH;
registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position - 8u) << 2u);
/* Apply the new configuration of the pin to the register */
MODIFY_REG((*configregister), ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), (config << registeroffset));
/*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable AFIO Clock */
__HAL_RCC_AFIO_CLK_ENABLE();
temp = AFIO->EXTICR[position >> 2u];
CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
AFIO->EXTICR[position >> 2u] = temp;
/* Enable or disable the rising trigger */
if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
SET_BIT(EXTI->RTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->RTSR, iocurrent);
}
/* Enable or disable the falling trigger */
if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
SET_BIT(EXTI->FTSR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->FTSR, iocurrent);
}
/* Configure the event mask */
if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
SET_BIT(EXTI->EMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->EMR, iocurrent);
}
/* Configure the interrupt mask */
if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
SET_BIT(EXTI->IMR, iocurrent);
}
else
{
CLEAR_BIT(EXTI->IMR, iocurrent);
}
}
}
position++;
}
}
HAL_GPIO接口函数
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
点亮RGB LED
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);