使用固件库函数点亮LED

使用固件库函数点亮LED

新建固件库工程里面都有哪些文件:
1-汇编编写的启动文件
startup_stm32f10x_hd.s:设置堆栈指针、设置PC指针、初始化中断向量表、配置系统时钟、对用C库函数_main最终去到C的世界

2-时钟配置文件
system_stm32f10x.c:把外部时钟HSE=8M,经过PLL倍频为72M。

3-外设相关的
stm32f10x.h:实现了内核之外的外设的寄存器映射
xxx:GPIO、USRAT、I2C、SPI、FSMC
stm32f10x_xx.c:外设的驱动函数库文件
stm32f10x_xx.h:存放外设的初始化结构体,外设初始化结构体成员的参数列表,外设固件库函数的声明

4-内核相关的
CMSIS - Cortex 微控制器软件接口标准
core_cm3.h:实现了内核里面外设的寄存器映射
core_cm3.c:内核外设的驱动固件库

NVIC(嵌套向量中断控制器)、SysTick(系统滴答定时器)
misc.h
misc.c

5-头文件的配置文件
stm32f10x_conf.h:头文件的头文件
//stm32f10x_usart.h
//stm32f10x_i2c.h
//stm32f10x_spi.h
//stm32f10x_adc.h
//stm32f10x_fsmc.h

新建固件库工程模板:网上有视频教程,跟着做就可以了
如何使用固件库点亮LED呢?
1、找一个固件库工程模板,在USER文件夹中,新建本工程的.c和.h文件
2、.c文件用来存放函数代码,.h文件用来存放宏定义,函数声明
3、在魔术棒中指定头文件的路径,这样的话我们而定编译器才会找到这个头文件
4、我们在自己写头文件的时候,为了避免头文件在被调用的时候出现重复定义的错误,我们给每一个头文件都加上条件编译

#ifndef _BSP_LED_H
#define _BSP_LED_H

#endif /*_BSP_LED_H*/

5、GPIO的映射在stm32f10x.h这个头文件中,我们将其包含进来。后续我们会在bsp_led.c文件中编写一些驱动LED的函数,函数的声明都放到这个头文件中。

#ifndef _BSP_LED_H
#define _BSP_LED_H

#include “stm32f10x.h”

#endif /*_BSP_LED_H*/

6、我们的主函数会调用LED的驱动函数,我们将bsp_led.h包含到mian.c文件中。

#include "stm32f10x.h"
#include "bsp_led.h"

int main(void)
{
    
    
	//
}

在这里我们可以看到,因为主函数中已经声明了stm32f10x.h这个头文件,然后在进行到第二步,bsp_led.h的时候,又有一个stm32f10x.h的文件在这里,如果不在头文件中进行条件编译的操作,那么就会产生重复编译的问题。
7、回到bsp_led.c文件,先对GPIO进行初始化,先新建一个函数LED_GPIO_Config().

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	
}

8、我们要操作GPIO就要先找到GPIO的固件库函数,stm32f10x_gpio.c,他的所有函数的成名以及初始化结构体都在他的头文件里面。要想初始化一个外设,他的头文件里都会有一个XXX_InitTypeDef的结构体函数,我们只要往结构体里面的成员写相对应的值就可以初始化了,而且所有结构体成员的值,都已经在这个头文件里面定义好了。那么我们先新建一个初始化结构体:

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 
}

9、然后我们往这个结构体内部的成员添加我们要控制的参数:引脚,模式,速度,模式选择推挽输出即可,速度跟功率成正比

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 

	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;
}

10、为了提高程序的可移植性,我们将硬件相关的我们都定义成宏,在bsp_led.h中

#ifndef _BSP_LED_H
#define _BSP_LED_H
#include “stm32f10x.h”

#define LED_G_GPIO_Pin 				GPIO_Pin_0
#define LED_G_GPIO_PART				GPIOB

#endif /*_BSP_LED_H*/

11、然后我们的代码就成了这样,后续修改只要在宏定义里面修改一下引脚,就可以点亮任意LED

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 

	GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;
}

12、然后我们需要一个初始化函数,来对外设进行初始化操作,

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 

	GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;

	GPIO_Init(LED_G_GPIO_PART, &GPIO_InitStruct);//第二个变量是一个指针,我们对变量取地址就变成指针了
}

13、接下来我们还要对时钟进行设置,开时钟,对于这个部分要注意在更改控制IO的时候,特别是在控制串口的时候,要注意对应的时钟,不然光改串口不改时钟就无法运行。时钟是由RCC这个外设控制的,RCC开时钟是通过总线来控制,使用的时候要找准外设挂载的总线是哪一个。我们找到RCC的固件库,然后找到他的头文件,在头文件里找到相应的函数,这里需要的是RCC_APB2PeriphClockCmd(),Cmd就是使能的意思,看一下这个函数的原型,看看他的输入都是什么数据。上面有输入数据的所有形参的类型和格式。最终我们可以看到这个函数操作的是RCC_APB2ENR这个寄存器。大家在编程的时候最好养成这个习惯,虽然调用的是固件库的函数,但是我们也要了解一下,他这个函数到底操作的是什么寄存器。

#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 
	void RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE)

	GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;

	GPIO_Init(LED_G_GPIO_PART, &GPIO_InitStruct);//第二个变量是一个指针,我们对变量取地址就变成指针了
}

14、还是老规矩,RCC_APB2periph_GPIOB我们将其定义成一个宏,方便后续的代码移植,然后代码就变成下面的样子:

#ifndef _BSP_LED_H
#define _BSP_LED_H
#include “stm32f10x.h”

#define LED_G_GPIO_Pin 				GPIO_Pin_0
#define LED_G_GPIO_PART				GPIOB
#define LED_G_GPIO_CLK				RCC_APB2Periph_GPIOB

void LED_GPIO_Config(void);

#endif /*_BSP_LED_H*/
#include "bsp_led.h"

void LED_GPIO_Config()
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct; 
	RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK, ENABLE)

	GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_Pin;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz ;

	GPIO_Init(LED_G_GPIO_PART, &GPIO_InitStruct);//第二个变量是一个指针,我们对变量取地址就变成指针了
}

15、接下来我们就可以将LED初始化的函数写进mian.c然后看一下有什么效果,我们会发现由于板载的LED灯是低电平点亮,而我们的ODR数据输出寄存器它的默认值为0,就正好让我们的LED灯点亮了。固件库中也有专门的函数,来对位进行高低位的操作,我么将其找到,写入函数中。

/*main函数*/
#include "stm32f10x.h"
#include "bsp_led.h"
/*软件延时函数*/
void Delay(uint32_t count)
{
    
    
	for(;count!=0;count--);
}

int main()
{
    
    
	LED_GPIO_Config();

	while(1)
	{
    
    
		GPIO_SetBits(LED_G_GPIO_PART,LED_G_PIN);
		Delay(0xFFFFF);
		GPIO_ResetBits(LED_G_GPIO_PART,LED_G_PIN);
		Delay(0xFFFFF);
	}

}

16、最后呢,为大家再展示一下更加简洁的版本:

#ifndef _BSP_LED_H
#define _BSP_LED_H
#include “stm32f10x.h”

#define LED_G_GPIO_Pin 				GPIO_Pin_0
#define LED_G_GPIO_PART				GPIOB
#define LED_G_GPIO_CLK				RCC_APB2periph_GPIOB

#define ON				1
#define OFF				0
#define LED_G(a)		if(a) \
							 GPIO_ResetBits(LED_G_GPIO_PART,LED_G_PIN);\
						else GPIO_SetBits(LED_G_GPIO_PART,LED_G_PIN);

void LED_GPIO_Config(void);

#endif /*_BSP_LED_H*/
/*main函数*/
#include "stm32f10x.h"
#include "bsp_led.h"
/*软件延时函数*/
void Delay(uint32_t count)
{
    
    
	for(;count!=0;count--);
}

int main()
{
    
    
	LED_GPIO_Config();

	while(1)
	{
    
    
		//GPIO_SetBits(LED_G_GPIO_PART,LED_G_PIN);
		Delay(0xFFFFF);
		LED_G(ON);
		//GPIO_ResetBits(LED_G_GPIO_PART,LED_G_PIN);
		LED_G(OFF);
		Delay(0xFFFFF);
	}

}

注意事项:

1、Delay函数中赋值是16进制的0xFFFF,不要写成FFFF
2、声明函数时,如果void LED_GPIO_Config(void);中括号里的那个void没有加进去会Warning
3、调用函数时,不要直接拷贝过来把前面那个声明void也带上,那个是声明的时候用的,调用函数就直接用函数。

猜你喜欢

转载自blog.csdn.net/qq_36535414/article/details/115603182