固件库编程点亮LED小灯

在STM32F407上固件库编程点亮LED小灯的主要步骤

第一步 外设寄存器结构体定义

条件编译:如果没有定义某个宏,就定义这个宏,并且可以防止重复编译
用结构体进行GPIO寄存器映射:外设寄存器结构体定义
GPIO_TypeDef

typedef struct
{
	__IO	uint32_t MODER;    /*GPIO模式寄存器				    地址偏移: 0x00    */
	__IO	uint32_t OTYPER;   /*GPIO输出类型寄存器				地址偏移: 0x04    */
	__IO	uint32_t OSPEEDR;  /*GPIO输出速度寄存器				地址偏移: 0x08    */
	__IO	uint32_t PUPDR;    /*GPIO上拉/下拉寄存器			地址偏移: 0x0C    */
	__IO	uint32_t IDR;      /*GPIO输入数据寄存器				地址偏移: 0x10    */
	__IO	uint32_t ODR;      /*GPIO输出数据寄存器				地址偏移: 0x14    */
	__IO	uint16_t BSRRL;    /*GPIO置位/复位寄存器 低16位部分	地址偏移: 0x18 	   */
	__IO	uint16_t BSRRH;    /*GPIO置位/复位寄存器 高16位部分	地址偏移: 0x1A     */
	__IO	uint32_t LCKR;     /*GPIO配置锁定寄存器				地址偏移: 0x1C     */
	__IO	uint32_t AFR[2];   /*GPIO复用功能配置寄存器		    地址偏移: 0x20-0x24 */
} GPIO_TypeDef;

定义 GPIOA 寄存器结构体指针

/*定义 GPIOA 寄存器结构体指针*/
#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

第二步 编写端口的置位复位函数

新建stm32f4xx_gpio.c文件和stm32f4xx_gpio.h文件 (外设驱动文件)
条件编译
在stm32f4xx_gpio.c文件中定义置位复位函数,并在stm32f4xx_gpio.h文件中声明

/**
  *函数功能:设置引脚为高电平
  *参数说明:GPIOx,该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
  * 			  GPIO_Pin:选择要设置的GPIO端口引脚,可输入宏GPIO_Pin_0-15,
	*										表示GPIOx端口的0-15号引脚。
  */
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
	/*设置GPIOx端口BSRRL寄存器的第GPIO_Pin位,使其输出高电平*/
	/*因为BSRR寄存器写0不影响,
	  GPIO_Pin只是对应位为1,其它位均为0,所以可以直接赋值*/
	
  GPIOx->BSRRL = GPIO_Pin;
}

在调用GPIO_SetBits时,调用格式为
GPIO_SetBits(GPIOF,GPIO_Pin_6);
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< 选择Pin6 */的意思其实就是 1<<6

另外还有一些小细节,可参考开发指南

参考文献
《1-STM32F4xx中文参考手册》
[野火EmbedFire]《STM32库开发实战指南——基于野火霸天虎开发板》—20210107

第三步 定义外设初始化结构体和编写外设初始化函数

  1. 定义外设初始化结构体
typedef struct 
{
  uint32_t GPIO_Pin;              /*!< 选择要配置的GPIO引脚
                                        可输入 GPIO_Pin_ 定义的宏 */

  GPIOMode_TypeDef GPIO_Mode;     /*!< 选择GPIO引脚的工作模式
                                       可输入 GPIOMode_TypeDef 定义的枚举值*/

  GPIOSpeed_TypeDef GPIO_Speed;   /*!< 选择GPIO引脚的速率
                                       可输入 GPIOSpeed_TypeDef 定义的枚举值 */

  GPIOOType_TypeDef GPIO_OType;   /*!< 选择GPIO引脚输出类型
                                       可输入 GPIOOType_TypeDef 定义的枚举值*/

  GPIOPuPd_TypeDef GPIO_PuPd;     /*!<选择GPIO引脚的上/下拉模式
                                       可输入 GPIOPuPd_TypeDef 定义的枚举值*/
}GPIO_InitTypeDef;

用枚举类型定义MODER寄存器结构体,其他寄存器(PUPDR,OTYPER…)类似

typedef enum
{ 
  GPIO_Mode_IN   = 0x00, /*!< 输入模式 */
  GPIO_Mode_OUT  = 0x01, /*!< 输出模式 */
  GPIO_Mode_AF   = 0x02, /*!< 复用模式 */
  GPIO_Mode_AN   = 0x03  /*!< 模拟模式 */
}GPIOMode_TypeDef;

2.定义GPIO_Init(函数)

注意理解这一块为什么要这么写(稍微难理解一点):

for (pinpos = 0x00; pinpos < 16; pinpos++)
  {
		/*以下运算是为了通过 GPIO_InitStruct->GPIO_Pin 算出引脚号0-15*/
		
		/*经过运算后pos的pinpos位为1,其余为0,与GPIO_Pin_x宏对应。pinpos变量每次循环加1,*/
		pos = ((uint32_t)0x01) << pinpos;
   
		/* pos与GPIO_InitStruct->GPIO_Pin做 & 运算,若运算结果currentpin == pos,
		则表示GPIO_InitStruct->GPIO_Pin的pinpos位也为1,
		从而可知pinpos就是GPIO_InitStruct->GPIO_Pin对应的引脚号:0-15*/
    currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;

其实这句if (currentpin==pos){...}也可以写成`if (currentpin){…}
因为

currentpin=(GPIO_InitStruct->GPIO_Pin) & pos;

的结果只可能为0000000000000000(16位)或者00…1…00(引脚号对应位为1)
注:有人认为上面这段求引脚号的代码多此一举,认为GPIOx->MODER &= ~(3 << (2 *pinpos));可以直接写成GPIOx->MODER &= ~(3 << (2 *GPIO_Pin));这是错误的,因为虽然InitStruct.GPIO_Pin = GPIO_Pin_6=((uint16_t)0x0040)=(0000000001000000)2;,但它不等于引脚号,点亮红灯时引脚号为6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值