野火霸天虎STM32F407笔记(二)——定义外设寄存器的结构体、编写复位置位函数、定义外设初始化结构体和编写外设初始化函数

野火霸天虎STM32F407笔记(二)——定义外设寄存器的结构体、编写复位置位函数、定义外设初始化结构体和编写外设初始化函数

一、定义外设寄存器的结构体

  • 部分头文件stm32f4xx.h

#include <stdint.h>


//要访问这些成员,只需要知道结构体的地址就可以了
typedef struct
{
	uint32_t MODER;
	uint32_t OTYPR;
	uint32_t OSPEEDR;
	uint32_t PUPDR;
	uint32_t IDR;
	uint32_t ODR;
	uint16_t BASSL;
	uint16_t BASSH;
	uint32_t LCKR;
	uint32_t AFRL;
	uint32_t AFRH;
}GPIO_TypeDef;


#define GPIOF       ((GPIO_TypeDef*)GPIOF_BASE)   //定义GPIO地址与结构体基地址一致,就可以通过寄存器结构体进行访问了



#endif    //
  • main.c
#include "stm32f4xx.h"

//软件延迟函数
void delay(unsigned int count)
{
	for( ; count !=0;count--);
	
}



int main()
{
#if 0
	//第一步:开GPIO端口时钟
	RCC_AHBIENR |= (1<<5);
	
	//第二步:配置GPIO为输出
	GPIOF->MODER &= ~(3<<(2*6));   //清除
	GPIOF->MODER |= (1<<(2*6));
	
	//第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器
	GPIOF->ODR |= (1<<6);     //输出1,关灯
	
	
	while(1)
	{
		GPIOF->ODR &= ~(1<<6);   //输出0,开灯
		delay(0x0fffff);          //软件延时函数
		GPIOF->ODR |= (1<<6);     //输出1,关灯
		
		delay(0x0fffff);
		
	}
#elif 1
	//第一步:开GPIO端口时钟
	RCC_AHBIENR |= (1<<5);
	
	//第二步:配置GPIO为输出
	GPIOF->MODER &= ~(3<<(2*6));   //清除
	GPIOF->MODER |= (1<<(2*6));
	
	//第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器
	GPIOF->ODR |= (1<<6);     //输出1,关灯
	
	
	while(1)
	{
		GPIOF->ODR &= ~(1<<6);   //输出0,开灯
		delay(0x0fffff);          //软件延时函数
		GPIOF->ODR |= (1<<6);     //输出1,关灯
		
		delay(0x0fffff);
		
	}
	
#endif
	
	
}

void SystemInit(void)
{
	
}

  • 定义的结构体怎样和端口的寄存器对应上呢,需要将GPIOF的基地址强制类型转换,类型为该结构体的指针类型。

二、编写复位置位函数

  • 编写驱动,必定会用到寄存器,我们所有的外设寄存器都要在头文件“stm32f4xx_gpio”中,所以需要在该头文件里包含头文件“stm32f4xx.h”

  • 函数体

//置位函数,替换GPIOF->ODR |= (1<<6);
void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRRL= GPIO_Pin;
	
}


//复位函数,替换GPIOF->ODR &= ~(1<<6);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRRH= GPIO_Pin;
	
}
  • 头文件
#ifndef _STM32F4XX_GPIO_H
#define _STM32F4XX_GPIO_H

#include "stm32f4xx.h"

#define   GPIO_Pin_0    ((uint16_t)(1<<0))
#define   GPIO_Pin_1    ((uint16_t)(1<<1))
#define   GPIO_Pin_2    ((uint16_t)(1<<2))
#define   GPIO_Pin_3    ((uint16_t)(1<<3))
#define   GPIO_Pin_4    ((uint16_t)(1<<4))
#define   GPIO_Pin_5    ((uint16_t)(1<<5))
#define   GPIO_Pin_6    ((uint16_t)(1<<6))
#define   GPIO_Pin_7    ((uint16_t)(1<<7))
#define   GPIO_Pin_8    ((uint16_t)(1<<8))
#define   GPIO_Pin_9    ((uint16_t)(1<<9))
#define   GPIO_Pin_10    ((uint16_t)(1<<10))
#define   GPIO_Pin_11   ((uint16_t)(1<<11))
#define   GPIO_Pin_12    ((uint16_t)(1<<12))
#define   GPIO_Pin_13    ((uint16_t)(1<<13))
#define   GPIO_Pin_14    ((uint16_t)(1<<14))
#define   GPIO_Pin_15    ((uint16_t)(1<<15))
#define   GPIO_Pin_ALL    ((uint16_t)(1<<0xffff))



void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);


#endif   //
  • 加入函数后的部分main.c
//编写端口的复位和置位函数
	//第一步:开GPIO端口时钟
	RCC_AHBIENR |= (1<<5);
	
	//第二步:配置GPIO为输出
	GPIOF->MODER &= ~(3<<(2*6));   //清除
	GPIOF->MODER |= (1<<(2*6));
	
	//第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器
	GPIOF->ODR |= (1<<6);     //输出1,关灯
	
	
	while(1)
	{
		//GPIOF->ODR &= ~(1<<6);   //输出0,开灯
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);   //复位函数
		delay(0x0fffff);          //软件延时函数
		
		
		//GPIOF->ODR |= (1<<6);     //输出1,关灯
		 GPIO_SetBits(GPIOF,GPIO_Pin_6);  //置位函数
		delay(0x0fffff);
		
	}

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

  1. 在使用固件库函数复位函数,置位函数替换原来代码后,可读性提高,在程序中我们的第一步,第二步的初始化端口配置的是输入还是输出,是通用输出还是对外输出,这些代码的实现可以将操作寄存器实现的转化为库函数实现。下面是完整的代码。
  • main.c
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"



//软件延迟函数
void delay(unsigned int count)
{
	for( ; count !=0;count--);
	
}



int main()
{
#if 0
	//第一步:开GPIO端口时钟
	RCC_AHBIENR |= (1<<5);
	
	//第二步:配置GPIO为输出
	GPIOF->MODER &= ~(3<<(2*6));   //清除
	GPIOF->MODER |= (1<<(2*6));
	
	//第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器
	GPIOF->ODR |= (1<<6);     //输出1,关灯
	
	
	while(1)
	{
		GPIOF->ODR &= ~(1<<6);   //输出0,开灯
		delay(0x0fffff);          //软件延时函数
		GPIOF->ODR |= (1<<6);     //输出1,关灯
		
		delay(0x0fffff);
		
	}
#elif 1                         //定义外设初始化结构体,编写外设初始化函数
	//第一步:开GPIO端口时钟
	RCC_AHBIENR |= (1<<5);
	
//	//第二步:配置GPIO为输出
//	GPIOF->MODER &= ~(3<<(2*6));   //清除
//	GPIOF->MODER |= (1<<(2*6));
	GPIO_InitTypeDef GPIO_InitStruct;
	/*初始化PF6引脚*/
/*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
/*设置引脚模式为输出模式*/
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
/*设置引脚的输出类型为推挽输出*/
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
/*设置引脚为上拉模式*/
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
/*设置引脚速率为2MHz */   
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOF, &GPIO_InitStruct);
	
	
	
	//第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器
	GPIOF->ODR |= (1<<6);     //输出1,关灯
	
	
	while(1)
	{
		//GPIOF->ODR &= ~(1<<6);   //输出0,开灯
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);   //固件库函数:复位函数
		delay(0x0fffff);          //软件延时函数
		
		
		//GPIOF->ODR |= (1<<6);     //输出1,关灯
		 GPIO_SetBits(GPIOF,GPIO_Pin_6);  //置位函数
		delay(0x0fffff);
		
	}
	
#endif
	
	
}

void SystemInit(void)
{
	
}


  • stm32f4xx.h
#ifndef _STM32F4XX_H
#define _STM32F4XX_H

#include <stdint.h>

#define GPIOF_BASE  ((unsigned int)0x40021400)
#define RCC_BASE    ((unsigned int)0x40023800)
	

#define GPIO_MODER  *(unsigned int*)(GPIOF_BASE + 0x00)
#define GPIO_OTYPER *(unsigned int*)(GPIOF_BASE + 0x04)
#define GPIOF_ODR   *(unsigned int*)(GPIOF_BASE + 0x14)

#define RCC_AHBIENR *(unsigned int*)(RCC_BASE + 0x30)
	

//外设寄存器结构体定义

//typedef unsigned int uint32_t;
//typedef unsigned short int uint16_t;

//要访问这些成员,只需要知道结构体的地址就可以了
typedef struct
{
	uint32_t MODER;
	uint32_t OTYPER;
	uint32_t OSPEEDR;
	uint32_t PUPDR;
	uint32_t IDR;
	uint32_t ODR;
	uint16_t BSRRL;
	uint16_t BSRRH;
	uint32_t LCKR;
	uint32_t AFRL;
	uint32_t AFRH;
}GPIO_TypeDef;


#define GPIOF       ((GPIO_TypeDef*)GPIOF_BASE)   //定义GPIO地址与结构体基地址一致,就可以通过寄存器结构体进行访问了



#endif    //



  • stm32f4xx_gpio.c

#include "stm32f4xx_gpio.h"
#include "stm32f4xx.h"
//写函数要有可读性,一看这个函数名就知道这个函数是干嘛的

//置位函数,替换GPIOF->ODR |= (1<<6);
void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRRL= GPIO_Pin;
	
}


//复位函数,替换GPIOF->ODR &= ~(1<<6);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRRH= GPIO_Pin;
	
}

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
	  uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
	
	/*-- GPIO Mode Configuration --*/
  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;

		/*currentpin == pos时执行初始化*/
    if (currentpin == pos)
		{		
			/*GPIOx端口,MODER寄存器的GPIO_InitStruct->GPIO_Pin对应的引脚,MODER位清空*/
			GPIOx->MODER  &= ~(3 << (2 *pinpos));
		
			/*GPIOx端口,MODER寄存器的GPIO_Pin引脚,MODER位设置"输入/输出/复用输出/模拟"模式*/
			GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (2 *pinpos));

			/*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,PUPDR位清空*/
			GPIOx->PUPDR &= ~(3 << ((2 *pinpos)));
		
			/*GPIOx端口,PUPDR寄存器的GPIO_Pin引脚,PUPDR位设置"上/下拉"模式*/
			GPIOx->PUPDR |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (2 *pinpos));		
		
			/*若模式为"输出/复用输出"模式,则设置速度与输出类型*/
			if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) || (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF))
			{
				/*GPIOx端口,OSPEEDR寄存器的GPIO_Pin引脚,OSPEEDR位清空*/
				GPIOx->OSPEEDR &= ~(3 << (2 *pinpos));
				/*GPIOx端口,OSPEEDR寄存器的GPIO_Pin引脚,OSPEEDR位设置输出速度*/
				GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (2 *pinpos));

				/*GPIOx端口,OTYPER寄存器的GPIO_Pin引脚,OTYPER位清空*/
				GPIOx->OTYPER  &= ~(1 << (pinpos)) ;
				/*GPIOx端口,OTYPER位寄存器的GPIO_Pin引脚,OTYPER位设置"推挽/开漏"输出类型*/
				GPIOx->OTYPER |= (uint16_t)(((uint16_t)GPIO_InitStruct->GPIO_OType) << (pinpos));
			}
		}
	}
}




  • stm32f4xx_gpio.h
#ifndef _STM32F4XX_GPIO_H
#define _STM32F4XX_GPIO_H

#include "stm32f4xx.h"

#define   GPIO_Pin_0    ((uint16_t)(1<<0))
#define   GPIO_Pin_1    ((uint16_t)(1<<1))
#define   GPIO_Pin_2    ((uint16_t)(1<<2))
#define   GPIO_Pin_3    ((uint16_t)(1<<3))
#define   GPIO_Pin_4    ((uint16_t)(1<<4))
#define   GPIO_Pin_5    ((uint16_t)(1<<5))
#define   GPIO_Pin_6    ((uint16_t)(1<<6))
#define   GPIO_Pin_7    ((uint16_t)(1<<7))
#define   GPIO_Pin_8    ((uint16_t)(1<<8))
#define   GPIO_Pin_9    ((uint16_t)(1<<9))
#define   GPIO_Pin_10    ((uint16_t)(1<<10))
#define   GPIO_Pin_11   ((uint16_t)(1<<11))
#define   GPIO_Pin_12    ((uint16_t)(1<<12))
#define   GPIO_Pin_13    ((uint16_t)(1<<13))
#define   GPIO_Pin_14    ((uint16_t)(1<<14))
#define   GPIO_Pin_15    ((uint16_t)(1<<15))
#define   GPIO_Pin_ALL    ((uint16_t)(1<<0xffff))

/** 
  * GPIO端口配置模式的枚举定义
  */   
typedef enum
{ 
  GPIO_Mode_IN   = 0x00, /*!< 输入模式 */
  GPIO_Mode_OUT  = 0x01, /*!< 输出模式 */
  GPIO_Mode_AF   = 0x02, /*!< 复用模式 */
  GPIO_Mode_AN   = 0x03  /*!< 模拟模式 */
}GPIOMode_TypeDef;

/** 
  * GPIO输出类型枚举定义
  */  
typedef enum
{ 
  GPIO_OType_PP = 0x00,	/*!< 推挽模式 */
  GPIO_OType_OD = 0x01	/*!< 开漏模式 */
}GPIOOType_TypeDef;


/** 
  * GPIO输出速率枚举定义
  */  
typedef enum
{ 
  GPIO_Speed_2MHz   = 0x00, /*!< 2MHz   */
  GPIO_Speed_25MHz  = 0x01, /*!< 25MHz  */
  GPIO_Speed_50MHz  = 0x02, /*!< 50MHz  */
  GPIO_Speed_100MHz = 0x03  /*!<100MHz  */
}GPIOSpeed_TypeDef;


  

/** 
  *GPIO上/下拉配置枚举定义
  */ 
typedef enum
{ 
  GPIO_PuPd_NOPULL = 0x00,/*浮空*/
  GPIO_PuPd_UP     = 0x01, /*上拉*/
  GPIO_PuPd_DOWN   = 0x02  /*下拉*/
}GPIOPuPd_TypeDef;


/** 
  * GPIO初始化结构体类型定义
  */ 
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;





void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);


#endif   //



  • 这一节是一个过渡,为了更好地学习固件库,后期学习重点在于学会并熟练调用函数,根据外设的初始化结构体在手册里面找到寄存器说明来看具体外设的功能。Persistence is victory!
  • 16
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 野火STM32F407霸天虎是一种基于STM32F407芯片的开发板,霸天虎例程是该开发板的一套示例代码。 霸天虎例程包含了多个例子,覆盖了多个功能模块。例如:LED灯的控制、按键输入的检测、蜂鸣器的控制、ADC模数转换的实验、PWM输出的实验、定时器的使用等。 在野火STM32F407霸天虎例程中,用户可以根据自己的需求,选择相应的例程进行学习和应用。每个例程都有详细的代码注释,方便用户理解和修改。 野火STM32F407霸天虎例程的优势在于其丰富的功能和简单易用的操作。用户无需从零开始编写代码,只需要按照例程的要求连接硬件,然后将对应的例程下载到开发板上即可实现相应的功能。 除了例程本身,野火还提供了丰富的资料和技术支持,如开发板原理图、用户手册、视频教程等。这些资源对于初学者来说非常重要,能够帮助他们更好地学习和应用霸天虎例程。 总之,野火STM32F407霸天虎例程是一套功能强大、简单易用的示例代码,适用于学习STM32F407芯片和开发板的人群。无论是初学者还是有一定经验的开发者,都可以从中获得很多实用的知识和经验。 ### 回答2: 野火STM32F407霸天虎例程是针对野火开发板上的STM32F407芯片编写的一段示例代码。霸天虎野火公司为该开发板设计的一款功能强大的处理器模块。 野火STM32F407霸天虎例程提供了多种实用功能的示例代码,包括LED灯控制、按键输入、串口通信、PWM输出等。这些例程可以帮助开发者快速熟悉和上手野火开发板,并且可以作为开发基础,用于次开发和调试。 例如,LED灯控制的例程可以通过修改代码中的参数来控制野火开发板上的LED灯的亮灭状态,可以用于验证开发板的硬件功能是否正常。按键输入的例程可以通过读取按键状态,实现按键事件的响应,例如控制电机的启动或停止等。串口通信的例程可以帮助开发者与外部设备进行数据交互,例如通过串口与电脑进行通信、发送调试信息等。PWM输出的例程可以生成特定的脉冲信号,用于控制伺服电机或产生PWM波形等。 野火STM32F407霸天虎例程在开发者社区中广泛使用,具有丰富的示例代码和详细的注释,方便开发者学习和理解。同时,野火还提供了相关的开发文档和技术支持,帮助开发者快速解决问题和进行开发工作。如果对例程中的代码有修改需求,开发者可以根据自己的需求进行次开发,实现更加复杂的功能。 总之,野火STM32F407霸天虎例程是一段功能丰富、易于上手的示例代码,帮助开发者快速入门STM32F407开发板,并且可以作为开发基础和参考,用于次开发和应用。 ### 回答3: 野火STM32F407霸天虎例程是针对STMicroelectronics公司推出的STM32F407核心板进行开发的一套示例程序。 该例程采用了野火提供的开发环境Keil5进行开发,可以通过野火官方网站下载源代码和相应的开发工具。 野火STM32F407霸天虎例程包含了一系列的示例程序,用于演示和说明STMicroelectronics STM32F407核心板的各种功能和特性。这些例程涵盖了从基本的GPIO控制、外部中断、定时器、PWM输出,到更复杂的USART、SPI、I2C、SD卡等外设的使用。 除了基本的外设操作示例,野火STM32F407霸天虎例程还提供了一些有趣的案例,如LED点阵显示、触摸屏控制、摄像头采集、音频播放等,帮助开发者更好地理解和应用该核心板。同时,这些案例程序也可以作为开发者学习和扩展的起点,根据自己的需求进行修改和优化。 野火STM32F407霸天虎例程是为了方便开发者快速上手STM32F407核心板而设计的,它提供了一种简单、直观的学习方式,通过代码实例的演示,帮助开发者深入了解STM32F407核心板的各项功能和使用方法。 总之,野火STM32F407霸天虎例程是一套详尽而实用的示例程序,适用于想要学习和开发STM32F407核心板的开发者,通过这些例程的学习和实践,可以更好地掌握和应用STM32F407的各种功能,提高开发效率和质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值