嵌入式学习开发野火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 */


 

<think>好的,我现在需要比较野火霸天虎开发板和霸道开发板的区别。首先,我需要收集这两款开发板的基本信息,比如处理器型号、外设配置、适用场景等。根据用户提供的引用内容,霸天虎开发板使用的是F407芯片,而霸道开发板可能使用不同的芯片,比如F103系列,但不确定,需要进一步确认。 接着,用户提到的引用[2]中提到霸天虎的外部晶振是25MHz,而原子开发板是8MHz,这说明不同开发板的外部时钟源可能不同,这可能会影响程序移植时的时钟配置。另外,霸天虎的GPIO分配如LED和蜂鸣器的引脚与原子开发板不同,这可能意味着霸道开发板的GPIO布局也有差异。 然后,我需要查找野火官方资料或用户手册,确认霸天虎和霸道开发板的具体参数。例如,处理器型号、内存大小、外设接口(如USB、以太网、CAN等)、扩展模块支持(如LCD、SD卡)、配套的学习资源等。比如,霸天虎可能针对中高级用户,带有更多高级外设,而霸道可能更基础,适合初学者。 另外,用户引用[1]提到野火的课程包含从入门到大师的内容,这可能意味着霸天虎开发板配套的教程更深入,适合系统性学习。而霸道开发板可能配套更基础的教程,适合快速上手。 还要考虑价格因素,通常功能更多的开发板价格更高。此外,扩展性和生态支持也很重要,比如是否有丰富的扩展模块和社区资源。 最后,总结出两者的主要区别,包括处理器性能、外设配置、适用人群、学习资源和价格等方面,帮助用户根据需求选择适合的开发板。</think>### 野火霸天虎开发板与霸道开发板对比分析 #### 1. **核心处理器差异** - **霸天虎(F407)**: 基于STM32F407ZGT6芯片,主频168MHz,配备1MB Flash+192KB RAM,支持浮点运算单元(FPU)和数字信号处理指令(DSP),适合复杂算法和实时控制[^1]。 - **霸道(F103)**: 通常采用STM32F103ZET6芯片(以霸道V2为例),主频72MHz,512KB Flash+64KB RAM,无FPU/DSP,定位为入门级Cortex-M3核心。 #### 2. **外设与硬件配置** | 特性 | 霸天虎F407 | 霸道F103 | |---------------------|-----------------------------|-----------------------------| | **外部晶振** | 25MHz(需注意移植时时钟树调整)[^2] | 通常8MHz | | **通信接口** | 含以太网MAC、双CAN、USB OTG | 无以太网,单CAN,USB FS | | **GPIO布局** | LED/PF6-PF7,蜂鸣器独立引脚 | 需核对具体型号引脚定义差异 | | **扩展能力** | 支持SDRAM/Camera接口 | 基础IO扩展与常用外设 | #### 3. **学习资源与定位** - **霸天虎**: 配套“大师进阶篇”课程,包含LWIP、文件系统、RTOS深度实践,适合中高级开发者或希望深入理解嵌入式系统的用户[^1]。 - **霸道**: 侧重基础外设驱动与标准库开发,教程以模块化案例为主,适合零基础快速入门。 #### 4. **典型应用场景** - **霸天虎**: 工业控制(多协议通信)、图像处理、物联网网关(需网络功能)。 - **霸道**: 传感器数据采集、简单控制系统、教学演示项目。 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值