新建led文件夹和bsp_led.c和bsp_led.h的板级支持包。
在bsp_led.c中,函数LED_GPIO_Config(void)提供了gpio的初始化过程:
- 定义GPIO初始化结构体;
- 开启RCC时钟,这一步非常重要,要找到对应的总线和外设时钟;
- 给初始化结构体成员赋值,由于和硬件相关,都在bsp_led.h中定义成宏,提高可移植性。
bsp_led.c
// bsp: board support package 板级支持包
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
// 定义GPIO初始化结构体
GPIO_InitTypeDef GPIO_InitStruct;
// 开启RCC时钟,非常关键
RCC_APB2PeriphClockCmd(LED_R_GPIO_CLK | LED_G_GPIO_CLK | LED_B_GPIO_CLK, ENABLE);
// 配置初始化结构体,传入具体参数
GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
// 初始化3个LED灯的GPIO
GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = LED_R_GPIO_PIN;
GPIO_Init(LED_R_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = LED_B_GPIO_PIN;
GPIO_Init(LED_B_GPIO_PORT, &GPIO_InitStruct);
// 初始状态关闭所有LED灯
GPIO_SetBits(LED_R_GPIO_PORT, LED_R_GPIO_PIN);
GPIO_SetBits(LED_G_GPIO_PORT, LED_G_GPIO_PIN);
GPIO_SetBits(LED_B_GPIO_PORT, LED_B_GPIO_PIN);
}
在bsp_led.h中,大量使用了宏定义,来封装硬件相关的函数
bsp_led.h
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "stm32f10x.h"
// 硬件封装宏
#define LED_R_GPIO_PIN GPIO_Pin_5
#define LED_R_GPIO_PORT GPIOB
#define LED_R_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED_G_GPIO_PIN GPIO_Pin_0
#define LED_G_GPIO_PORT GPIOB
#define LED_G_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED_B_GPIO_PIN GPIO_Pin_1
#define LED_B_GPIO_PORT GPIOB
#define LED_B_GPIO_CLK RCC_APB2Periph_GPIOB
// 直接操作寄存器的方法控制IO
#define digitalHi(port, pin) do {port->BSRR |= pin;} while (0) // 置位
#define digitalLo(port, pin) do {port->BRR |= pin;} while (0) // 复位
#define digitalToggle(port, pin) do {port->ODR ^= pin;} while (0) // 反转
// 定义控制IO的宏
#define LED_R_TOGGLE digitalToggle(LED_R_GPIO_PORT, LED_R_GPIO_PIN)
#define LED_R_ON digitalLo(LED_R_GPIO_PORT, LED_R_GPIO_PIN)
#define LED_R_OFF digitalHi(LED_R_GPIO_PORT, LED_R_GPIO_PIN)
#define LED_G_TOGGLE digitalToggle(LED_G_GPIO_PORT, LED_G_GPIO_PIN)
#define LED_G_ON digitalLo(LED_G_GPIO_PORT, LED_G_GPIO_PIN)
#define LED_G_OFF digitalHi(LED_G_GPIO_PORT, LED_G_GPIO_PIN)
#define LED_B_TOGGLE digitalToggle(LED_B_GPIO_PORT, LED_B_GPIO_PIN)
#define LED_B_ON digitalLo(LED_B_GPIO_PORT, LED_B_GPIO_PIN)
#define LED_B_OFF digitalHi(LED_B_GPIO_PORT, LED_B_GPIO_PIN)
// 颜色设置
#define LED_RED do {LED_R_ON; LED_G_OFF; LED_B_OFF;} while (0)
#define LED_GREEN do {LED_R_OFF; LED_G_ON; LED_B_OFF;} while (0)
#define LED_BLUE do {LED_R_OFF; LED_G_OFF; LED_B_ON;} while (0)
#define LED_YELLOW do {LED_R_ON; LED_G_ON; LED_B_OFF;} while (0)
#define LED_PURPLE do {LED_R_ON; LED_G_OFF; LED_B_ON;} while (0)
#define LED_CYAN do {LED_R_OFF; LED_G_ON; LED_B_ON;} while (0)
#define LED_ALL_ON do {LED_R_ON; LED_G_ON; LED_B_ON;} while (0)
#define LED_ALL_OFF do {LED_R_OFF; LED_G_OFF; LED_B_OFF;} while (0)
void LED_GPIO_Config(void);
#endif /* __BSP_LED_H */
然后在主函数中进行调用
main.c
#include "stm32f10x.h"
#include "bsp_led.h"
void delay(uint32_t count);
int main(void)
{
LED_GPIO_Config();
while (1)
{
LED_CYAN;
delay(0XFFFFF);
LED_ALL_OFF;
delay(0XFFFFF);
}
}
void delay(uint32_t count)
{
for (; count != 0; count--);
}
GPIO具有锁定机制,可以冻结该GPIO的配置,即在下次复位前,不能更改GPIO的配置。
锁定操作的寄存器为GPIOx_LCKR,具体描述如下
上面的说明起始我感觉挺难理解的,于是找到了标准库里面的源码,发现写的非常清晰,具体如下
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint32_t tmp = 0x00010000;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
tmp |= GPIO_Pin;
/* Set LCKK bit */
GPIOx->LCKR = tmp;
/* Reset LCKK bit */
GPIOx->LCKR = GPIO_Pin;
/* Set LCKK bit */
GPIOx->LCKR = tmp;
/* Read LCKK bit*/
tmp = GPIOx->LCKR;
/* Read LCKK bit*/
tmp = GPIOx->LCKR;
}
tmp为LCCK位置1,然后把GPIO_Pin的相应值也置1。接下来就是对相应的位执行写入序列操作。
首先是写1,即写入带LCCK和GPIO_Pin的位;
然后写0,写只带GPIO_Pin的位;
然后重复写1;
接下来读GPIOx_LCKR的值到tmp,连续读取两次,完成操作。