嵌入式学习开发野火F407-霸天虎-入门篇

一、如何用DAP仿真器下载程序

5-初识STM32_哔哩哔哩_bilibili

在上面链接学习整理

二、 初始STM32

1.什么是STM32

2.STM32有什么

三、 什么是寄存器

四、新建工程-寄存器版

1、使用Keil新建一个工程

  • 1.设置文字

  • 2.懂太语法检测

  • 3.配置仿真器

以霸天虎为例,不是ULINK而是DAP

还有视频里的:

main.c

#include "stm32f4xx.h"

int main(void){
	
	while(1){
		/*在这里添加程序的主题代码*/
	}
	
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

 stm32f4xx.h

/*用来存放寄存器映射相关的代码*/


要多一行,不然编译报错 

2、初步入门,像51单片机一样点亮LED

main.c

#include "stm32f4xx.h"

#if 0
#include <reg51.>
void main(void)
	{
		PAO = 0XFE;
		while(1);
	}
#endif


int main(void){
	
#if 0
	/*第一步:开启GPIO端口的时钟*/
	/*打开GPIOF端口的时钟*/
	*( unsigned int * )(0x40023800+0x30) |= ( 1<<5 );
	
	/*第二步:控制GPIO的方向*/
	/*GPIO 配置为输出*/
	*( unsigned int * )(0x40021400+0x00) &=~ ( (0x03) << (2*6) );
	*( unsigned int * )(0x40021400+0x00) |= ( 1<< (2*6) );
	
	/*第三步:控制GPIO的数据输出寄存器*/
	/* PF6输出高电平 */
	*( unsigned int * )(0x40021400+0x14) |= (1<<6);
	/* PF6输出低电平 */
	*( unsigned int * )(0x40021400+0x14) &= ~(1<<6);
	
#elif 1
	/*第一步:开启GPIO端口的时钟*/
	/*打开GPIOF端口的时钟*/
	RCC_AHB1ENR |= ( 1<<5 );
	
	/*第二步:控制GPIO的方向*/
	/*GPIO 配置为输出*/
	GPIOF_MODER &=~ ( (0x03) << (2*6) );
	GPIOF_MODER |= ( 1<< (2*6) );
	
	/*第三步:控制GPIO的数据输出寄存器*/
	/* PF6输出高电平 */
	GPIOF_ODR |= (1<<6);
	/* PF6输出低电平 */
	GPIOF_ODR &= ~(1<<6);
	
#endif
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

 stm32f4xx.h

/*用来存放寄存器映射相关的代码*/

#define RCC_AHB1ENR  *(unsigned int *)(0x40023800+0x30) 
#define GPIOF_MODER  *( unsigned int * )(0x40021400+0x00)
#define GPIOF_ODR  *( unsigned int * )(0x40021400+0x14)

五、作业---1.--2.

1.把其他俩个灯也点亮

    /*作业1*/
	/*第一步:开启GPIO端口的时钟*/
	/*打开GPIOF端口的时钟*/
	RCC_AHB1ENR |= ( 1<<5 );
	
	/*第二步:控制GPIO的方向*/
	/*GPIO 配置为输出*/
	GPIOF_MODER &=~ ( (0x03) << (2*6) );
	GPIOF_MODER |= ( 1<< (2*6) );
	
	GPIOF_MODER &=~ ( (0x03) << (2*7) );
	GPIOF_MODER |= ( 1<< (2*7) );
	
	GPIOF_MODER &=~ ( (0x03) << (2*8) );
	GPIOF_MODER |= ( 1<< (2*8) );
	
	/*第三步:控制GPIO的数据输出寄存器*/
	/* PF6输出高电平 */
	GPIOF_ODR |= (1<<6);
	/* PF6输出低电平 */
	GPIOF_ODR &= ~(1<<6);
	
	/* PF7输出高电平 */
	GPIOF_ODR |= (1<<7);
	/* PF7输出低电平 */
	GPIOF_ODR &= ~(1<<7);
	
	/* PF8输出高电平 */
	GPIOF_ODR |= (1<<8);
	/* PF8输出低电平 */
	GPIOF_ODR &= ~(1<<8);

2.实现三个灯闪烁(时间的控制使用软件延迟)

    /*作业2*/

    void Delay(unsigned int count){
	for(;count!=0;count--);
    }


	/*第一步:开启GPIO端口的时钟*/
	/*打开GPIOF端口的时钟*/
	RCC_AHB1ENR |= ( 1<<5 );
	
	/*第二步:控制GPIO的方向*/
	/*GPIO 配置为输出*/
	GPIOF_MODER &=~ ( (0x03) << (2*6) );
	GPIOF_MODER |= ( 1<< (2*6) );
	
	GPIOF_MODER &=~ ( (0x03) << (2*7) );
	GPIOF_MODER |= ( 1<< (2*7) );
	
	GPIOF_MODER &=~ ( (0x03) << (2*8) );
	GPIOF_MODER |= ( 1<< (2*8) );
	
	/*第三步:控制GPIO的数据输出寄存器*/
	/* PF6输出高电平 */
	GPIOF_ODR |= (1<<6);
	/* PF6输出低电平 */
	GPIOF_ODR &= ~(1<<6);
	
	/* PF7输出高电平 */
	GPIOF_ODR |= (1<<7);
	/* PF7输出低电平 */
	GPIOF_ODR &= ~(1<<7);
	
	/* PF8输出高电平 */
	GPIOF_ODR |= (1<<8);
	/* PF8输出低电平 */
	GPIOF_ODR &= ~(1<<8);
	
	while(1){
		
		GPIOF_ODR &= ~(1<<6);
		Delay(0x0fffff);
		GPIOF_ODR |= (1<<6);
		Delay(0x0fffff);
		
		GPIOF_ODR &= ~(1<<7);
		Delay(0x0fffff);
		GPIOF_ODR |= (1<<7);
		Delay(0x0fffff);
		
		GPIOF_ODR &= ~(1<<8);
		Delay(0x0fffff);
		GPIOF_ODR |= (1<<8);
		Delay(0x0fffff);
	}

六、使用寄存器点亮LED

1、GPIO功能框图讲解

GPIO跟引脚有什么区别 

2、从0开始写代码讲解实验

main.c

#include "stm32f4xx.h"

/*
 *注意事项
 *要在 Options for target 选项里的Use MicroLIB这个勾选上
 *这样才能执行C文件里的main函数
 */
 
 /*软件延时函数*/
 void delay(unsigned int count){
	for(;count!=0;count--);
}
 

int main(void){
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF_MOOER &= ~( 3<<(2*6) );  //清零
	GPIOF_MOOER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF_ODR |= (1<<6); 
	
	while(1){
		GPIOF_ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF_ODR |= (1<<6);
		delay(0x0fffff);
	}
	
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

stm32f4xx.h

/*用来存放寄存器映射相关的代码*/

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

#define GPIOF_MOOER   *( unsigned int * )(GPIOF_BASE+0x00)
#define GPIOF_OTYPER  *( unsigned int * )(GPIOF_BASE+0x04)
#define GPIOF_ODR     *( unsigned int * )(GPIOF_BASE+0x14)
		
#define RCC_AHB1ENR  *( unsigned int * )(RCC_BASE+0x30)


七、自己写库-构建库函数雏形

1、外设寄存器结构体定义

main.c

#include "stm32f4xx.h"

/*自己写库*/
/*
 *注意事项
 *要在 Options for target 选项里的Use MicroLIB这个勾选上
 *这样才能执行C文件里的main函数
 */
 
 /*软件延时函数*/
 void delay(unsigned int count){
	for(;count!=0;count--);
}
 

int main(void){
	
#if 0
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF_MOOER &= ~( 3<<(2*6) );  //清零
	GPIOF_MOOER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF_ODR |= (1<<6); 
	
	while(1){
		GPIOF_ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF_ODR |= (1<<6);
		delay(0x0fffff);
	}
	
#elif 1    /*定义外设的寄存器结构体*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIOF->ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF->ODR |= (1<<6);
		delay(0x0fffff);
	}
	
#endif
	
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

stm32f4xx.h

//#include <stdint.h>
#ifndef _STM32F4XX_H
#define _STM32F4XX_H


/*用来存放寄存器映射相关的代码*/

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

#define GPIOF_MOOER   *( unsigned int * )(GPIOF_BASE+0x00)
#define GPIOF_OTYPER  *( unsigned int * )(GPIOF_BASE+0x04)
#define GPIOF_ODR     *( unsigned int * )(GPIOF_BASE+0x14)
		
#define RCC_AHB1ENR  *( 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)
	
#endif  /*_STM32F4XX_H*/





2、编写端口复位和置位函数

新建了stm32f4xx_gpio.c和stm32f4xx_gpio.h文件,用来编写端口的复位和置位函数 

stm32f4xx_gpio.c

#include "stm32f4xx_gpio.h"


/*置位函数*/
void GPIO_SetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin){
	GPIOx->BSRRL = GPIO_Pin;
}


/*复位函数*/
void GPIO_ResetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin){
	GPIOx->BSRRH = GPIO_Pin;
}

stm32f4xx_gpio.h

#ifndef _STM32F4XX_GPIO_H
#define _STM32F4XX_GPIO_H
#include "stm32f4xx.h"
#include <stdint.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_A11   ((uint16_t)(0xffff))


/*置位函数*/
void GPIO_SetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin);
//复位函数
void GPIO_ResetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin);
#endif  /*_STM32F4XX_GPIO_H*/

 main.c函数调用函数实现功能

#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
/*自己写库*/
/*
 *注意事项
 *要在 Options for target 选项里的Use MicroLIB这个勾选上
 *这样才能执行C文件里的main函数
 */
 
 /*软件延时函数*/
 void delay(unsigned int count){
	for(;count!=0;count--);
}
 

int main(void){
	
#if 0
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF_MOOER &= ~( 3<<(2*6) );  //清零
	GPIOF_MOOER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF_ODR |= (1<<6); 
	
	while(1){
		GPIOF_ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF_ODR |= (1<<6);
		delay(0x0fffff);
	}
	
#elif 0    /*定义外设的寄存器结构体*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIOF->ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF->ODR |= (1<<6);
		delay(0x0fffff);
	}
	
	
#elif 1    /*编写端口的置位和复位函数*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
		GPIO_SetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
	}
	
#endif
	
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

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

stm32f4xx_gpio.c

#include "stm32f4xx_gpio.h"


/*置位函数*/
void GPIO_SetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin){
	GPIOx->BSRRL = GPIO_Pin;
}


/*复位函数*/
void GPIO_ResetBits(GPIO_TypeDef * GPIOx,uint16_t GPIO_Pin){
	GPIOx->BSRRH = GPIO_Pin;
}

/**
*函数功能:初始化引脚模式
*参数说明:GPIOx,该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
*          GPIO_InitTypeDef:GPIO_InitTypeDef结构体指针,指向初始化变量
*/
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)(( GPIO_InitStruct->GPIO_OType)<< (pinpos));
            }
        }
    }
}

 stm32f4xx_gpio.h

#ifndef _STM32F4XX_GPIO_H
#define _STM32F4XX_GPIO_H
#include "stm32f4xx.h"
#include <stdint.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_A11   ((uint16_t)(0xffff))


typedef enum{
	GPIO_Mode_IN = 0X00,
	GPIO_Mode_OUT = 0X01,
	GPIO_Mode_AF = 0X02,
	GPIO_Mode_AN = 0X03
}GPIOMode_TypeDef;



typedef enum{
	GPIO_PuPd_NOPULL = 0X00,
	GPIO_PuPd_UP = 0X01,
	GPIO_PuPd_DOWN = 0X02
}GPIOPuPd_TypeDef;



typedef enum{
	GPIO_OType_PP = 0X00,
	GPIO_OType_OD = 0X01
}GPIOOType_TypeDef;



typedef enum{
	GPIO_Speed_2MHz = 0X00,
	GPIO_Speed_25MHz = 0X01,
	GPIO_Speed_20MHz = 0X02,
	GPIO_Speed_100MHz = 0X03
}GPIOSpeed_TypeDef;



/*定义GPIO的初始化结构体*/
typedef struct{
	uint16_t   GPIO_Pin;
	GPIOMode_TypeDef GPIO_Mode;
	GPIOPuPd_TypeDef GPIO_PuPd;
	GPIOOType_TypeDef GPIO_OType;
	GPIOSpeed_TypeDef GPIO_Speed;
}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  /*_STM32F4XX_GPIO_H*/



main.c

#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
/*自己写库*/
/*
 *注意事项
 *要在 Options for target 选项里的Use MicroLIB这个勾选上
 *这样才能执行C文件里的main函数
 */
 
 /*软件延时函数*/
 void delay(unsigned int count){
	for(;count!=0;count--);
}
 

int main(void){
	
#if 0
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF_MOOER &= ~( 3<<(2*6) );  //清零
	GPIOF_MOOER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF_ODR |= (1<<6); 
	
	while(1){
		GPIOF_ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF_ODR |= (1<<6);
		delay(0x0fffff);
	}
	
#elif 0    /*定义外设的寄存器结构体*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIOF->ODR &= ~(1<<6);
		delay(0x0fffff);
		GPIOF->ODR |= (1<<6);
		delay(0x0fffff);
	}
	
	
#elif 1    /*编写端口的置位和复位函数*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
//	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
//	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01



//c89的语法格式就是变量必须紧跟大括号
//c99不需要
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;

GPIO_Init(GPIOF, &GPIO_InitStruct);
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
		GPIO_SetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
	}
	
	
	
#elif 1    /*定义外设的初始化结构体和编写外设的初始化函数*/
	
	/*第一步:开GPIO端口时钟*/
	RCC_AHB1ENR |= (1<<5);
	
	/*第二步:配置GPIO为输出*/
	GPIOF->MODER &= ~( 3<<(2*6) );  //清零
	GPIOF->MODER |= ( 1<<(2*6) );   //配置成 01
	
	/*第三步:让GPIO输出0或者1,ODR寄存器或者BSRR寄存器*/
	GPIOF->ODR |= (1<<6); 
	
	while(1){
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
		GPIO_SetBits(GPIOF,GPIO_Pin_6);
		delay(0x0fffff);
	}
	
#endif
	
}


void SystemInit(void){
	/*函数体为空,目的是为了骗过编译器不报错*/
}

八、自己写库—构建库函数雏形

1、 什么是STM32固件库

固件库是指“STM32标准函数库”,它是由ST公司针对STM32提供的函数接口,即API (Application Program Interface), 开发者可调用这些函数接口来配置STM32的寄存器,使开发人员得以脱离最底层的寄存器操作,有开发快速,易于阅读,维护成本低等优点。

当我们调用库API的时候不需要挖空心思去了解库底层的寄存器操作,就像当年我们刚开始学习C语言的时候,用prinft()函数时只是学习它的使用格式, 并没有去研究它的源码实现,但需要深入研究的时候,经过千锤百炼的库源码就是最佳学习范例。

实际上,库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。 库开发方式与直接配置寄存器方式的区别见图 固件库开发与寄存器开发对比图 。

2、新建工程-库函数版 

  • 新建一个文件夹FWLIB-TEMPALTE,然后在里面新建以下几个文件夹

  • 在Libraries文件夹下拷贝过来以下俩个文件,在固件库里拷贝
  • 在这个位置拷贝的:D:\1野火嵌入式\固件库stm32f4_dsp_stdperiph_lib_V1.8.0\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries

  • 在User文件夹下拷贝以下四个文件:
  • 路径:D:\1野火嵌入式\固件库stm32f4_dsp_stdperiph_lib_V1.8.0\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Templates

  • 需要把stm32f4xx_it.c文件里的俩行删除

  • 把main.c文件全部删除,然后编写以下代码
#include "stm32f4xx.h"

int main(void){
	/*在这里添加你自己的程序*/
	while(1);
} 

  • 在D:\1野火嵌入式\FWLIB-TEMPALTE\Libraries\CMSIS  这个文件里保留俩个文件(Device、Include),其他全部删除

  • 在D:\1野火嵌入式\FWLIB-TEMPALTE\Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates  保留俩个文件,其他的全部删除

  • 在D:\1野火嵌入式\FWLIB-TEMPALTE\Project  新建RVMDK(uv5)文件夹

打开Keil,执行如下步骤新建工程:

点击保存弹出这个框:选择芯片型号

点击OK,弹出下面这个框,然后点击×,给它去掉

然后就新建好了:如下图:

然后修改名称,并添加以下文件:

在STARTUP文件里添加启动文件:路径:

D:\1野火嵌入式\FWLIB-TEMPALTE\Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm

在CMSIS下添加文件:D:\1野火嵌入式\FWLIB-TEMPALTE\Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates

在STM32F4xx_StdPeriph_Driver文件夹添加这个路径的D:\1野火嵌入式\FWLIB-TEMPALTE\Libraries\STM32F4xx_StdPeriph_Driver\src全部文件

在USER文件夹添加俩个文件:D:\1野火嵌入式\FWLIB-TEMPALTE\User

最后需要指定头文件的目录,不然报错

还需要添加这个:USE_STDPERIPH_DRIVER.STM32F40_41xxx.(这个错了

应该是:USE_STDPERIPH_DRIVER,STM32F40_41xxx,  

然后需要取消三个文件:

运行出来有错误和警告,原因是

3、固件库编程-GPIO输出-使用固件库点亮LED灯

 复制上述建立的文件FWLIB-TEMPALTE,改名为GPIO输出——使用固件库点亮LED灯

 在USER文件夹下新建LED文件夹,用来存放跟LED相关的代码,然后再在这个文件夹下新建俩个驱动文件用来存放代码(bsp_led.c、bsp_led.h)

打开程序

外设初始化分四步:bsp_led.c:

    /*以下四个步骤适合所有外设的初始化*/
	
	/*第一步:开GPIO的时钟*/
	
	
	/*第二步:定义一个GPIO初始化结构体*/
	
	
	/*第三步:配置GPIO初始化结构体的成员*/
	
	
	/*第四步:调用GPIO初始化函数,把配置好的结构体的成员的参数写入寄存器*/

bsp_led.c:

//bsp:board support package 板级支持包

#include "bsp_led.h"


/*外设初始化函数*/
void LED_GPIO_Config(void){
	
	/*以下四个步骤适合所有外设的初始化*/
	
	/*第一步:开GPIO的时钟*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	
	/*第二步:定义一个GPIO初始化结构体*/
	GPIO_InitTypeDef GPIO_InitStruct;
	
	/*第三步:配置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_Speed = GPIO_Low_Speed;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	
	/*第四步:调用GPIO初始化函数,把配置好的结构体的成员的参数写入寄存器*/
	GPIO_Init(GPIOF,&GPIO_InitStruct);
	GPIO_ResetBits(GPIOF,GPIO_Pin_6);
	
	
}

bsp_led.h: 

#ifndef _BSP_LED_H
#define _BSP_LED_H

#include "stm32f4xx.h"
void LED_GPIO_Config(void);

#endif /*_BSP_LED_H*/

main.c出现警告

#include "stm32f4xx.h"
#include "bsp_led.h"

void Delay(uint32_t count){
	for(; count!=0; count-- );
}

int main(void){
	/*在这里添加你自己的程序*/
	LED_GPIO_Config();
	
	//实现闪烁
	while(1){
		GPIO_ResetBits(GPIOF,GPIO_Pin_6);
		Delay(0xffffff);
		GPIO_SetBits(GPIOF,GPIO_Pin_6);
		Delay(0xffffff);
	}
} 


 4、GPIO输入-按键检测

 复制上述文件GPIO输出——使用固件库点亮LED灯,在USER文件夹新建KEY文件夹,然后新建俩个文件:c文件bsp_key.c和头文件bsp_key.h

需要修改以下四个文件:

​​​​​​​

bsp_key.c:

#include "bsp_key.h"

/*外设初始化函数*/
void KEY_GPIO_Config(void){
	
	/*以下四个步骤适合所有外设的初始化*/
	
	/*第一步:开GPIO的时钟*/
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);
	
	/*第二步:定义一个GPIO初始化结构体*/
	GPIO_InitTypeDef GPIO_InitStruct;
	
	/*第三步:配置GPIO初始化结构体的成员*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	/*只在输入下用到*/
	//GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	//GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	
	/*第四步:调用GPIO初始化函数,把配置好的结构体的成员的参数写入寄存器*/
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	
	/*第三步:配置GPIO初始化结构体的成员*/
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
	/*只在输入下用到*/
	//GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	//GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	
	/*第四步:调用GPIO初始化函数,把配置好的结构体的成员的参数写入寄存器*/
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	
	
	//GPIO_ResetBits(GPIOF,GPIO_Pin_6);
	
	
}


//按键扫描函数
uint8_t KEY_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin){
	if(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON ){
		while(GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON);
		return KEY_ON;
	} else {
		return KEY_OFF;
	}		
}





bsp_key.h:

#ifndef _BSP_KEY_H
#define _BSP_KEY_H


//包含所有寄存器映射的文件
#include "stm32f4xx.h"

#define KEY_ON 1
#define KEY_OFF 0



void KEY_GPIO_Config(void);
uint8_t KEY_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);

#endif /*_BSP_KEY_H*/

重点是bsp_led.h这个文件,从人家写好的文件拷贝的:​​​​​​​

#ifndef _BSP_LED_H
#define _BSP_LED_H

#include "stm32f4xx.h"

//引脚定义
/*******************************************************/
//R 红色灯
#define LED1_PIN                  GPIO_Pin_6                 
#define LED1_GPIO_PORT            GPIOF                      
#define LED1_GPIO_CLK             RCC_AHB1Periph_GPIOF

//G 绿色灯
#define LED2_PIN                  GPIO_Pin_7                 
#define LED2_GPIO_PORT            GPIOF                      
#define LED2_GPIO_CLK             RCC_AHB1Periph_GPIOF

//B 蓝色灯
#define LED3_PIN                  GPIO_Pin_8                 
#define LED3_GPIO_PORT            GPIOF                       
#define LED3_GPIO_CLK             RCC_AHB1Periph_GPIOF
/************************************************************/


/** 控制LED灯亮灭的宏,
	* LED低电平亮,设置ON=0,OFF=1
	* 若LED高电平亮,把宏设置成ON=1 ,OFF=0 即可
	*/
#define ON  0
#define OFF 1

/* 带参宏,可以像内联函数一样使用 */
#define LED1(a)	if (a)	\
					GPIO_SetBits(LED1_GPIO_PORT,LED1_PIN);\
					else		\
					GPIO_ResetBits(LED1_GPIO_PORT,LED1_PIN)

#define LED2(a)	if (a)	\
					GPIO_SetBits(LED2_GPIO_PORT,LED2_PIN);\
					else		\
					GPIO_ResetBits(LED2_GPIO_PORT,LED2_PIN)

#define LED3(a)	if (a)	\
					GPIO_SetBits(LED3_GPIO_PORT,LED3_PIN);\
					else		\
					GPIO_ResetBits(LED3_GPIO_PORT,LED3_PIN)


/* 直接操作寄存器的方法控制IO */
#define	digitalHi(p,i)			 {p->BSRRL=i;}		//设置为高电平
#define digitalLo(p,i)			 {p->BSRRH=i;}		//输出低电平
#define digitalToggle(p,i)	 {p->ODR ^=i;}		//输出反转状态

/* 定义控制IO的宏 */
#define LED1_TOGGLE		digitalToggle(LED1_GPIO_PORT,LED1_PIN)
#define LED1_OFF			digitalHi(LED1_GPIO_PORT,LED1_PIN)
#define LED1_ON				digitalLo(LED1_GPIO_PORT,LED1_PIN)

#define LED2_TOGGLE		digitalToggle(LED2_GPIO_PORT,LED2_PIN)
#define LED2_OFF			digitalHi(LED2_GPIO_PORT,LED2_PIN)
#define LED2_ON				digitalLo(LED2_GPIO_PORT,LED2_PIN)

#define LED3_TOGGLE		digitalToggle(LED3_GPIO_PORT,LED3_PIN)
#define LED3_OFF			digitalHi(LED3_GPIO_PORT,LED3_PIN)
#define LED3_ON				digitalLo(LED3_GPIO_PORT,LED3_PIN)

/* 基本混色,后面高级用法使用PWM可混出全彩颜色,且效果更好 */

//红
#define LED_RED  \
					LED1_ON;\
					LED2_OFF;\
					LED3_OFF

//绿
#define LED_GREEN		\
					LED1_OFF;\
					LED2_ON;\
					LED3_OFF

//蓝
#define LED_BLUE	\
					LED1_OFF;\
					LED2_OFF;\
					LED3_ON

					
//黄(红+绿)					
#define LED_YELLOW	\
					LED1_ON;\
					LED2_ON;\
					LED3_OFF
//紫(红+蓝)
#define LED_PURPLE	\
					LED1_ON;\
					LED2_OFF;\
					LED3_ON

//青(绿+蓝)
#define LED_CYAN \
					LED1_OFF;\
					LED2_ON;\
					LED3_ON
					
//白(红+绿+蓝)
#define LED_WHITE	\
					LED1_ON;\
					LED2_ON;\
					LED3_ON
					
//黑(全部关闭)
#define LED_RGBOFF	\
					LED1_OFF;\
					LED2_OFF;\
					LED3_OFF		




void LED_GPIO_Config(void);

#endif /* _BSP_LED_H */


 

  • 23
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答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的各种功能,提高开发效率和质量。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值