零、所需文件及环境 :
1、第一章建立好的LED灯闪烁程序
2、编译环境MDK5(KEIL5)
3、一个STM32F407VET6硬件
4、一个下载器j-link 或 st-link等
5.代码编辑器 Notepad++ (可以不要 用记事本也能编译 都是习惯的问题)
壹、复制LED灯闪烁程序
1.1 复制led灯闪烁程序并进行重命名
BSP_LED.h代码
2.1 仔细阅读参考手册找到GPIO寄存器地址,将一堆GPIO寄存器一层一层封装出来 方便控制 直接操作的是寄存器 可以自己写但没有必要,挨个核对寄存器地址时特别费时,所以我这里复制的 原子的sys.h里面的 将其添加进之前的BSP_LED.h里面 修改后的文件如图所示
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "stm32f4xx.h"
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414
#define GPIOC_ODR_Addr (GPIOC_BASE+20) //0x40020814
#define GPIOD_ODR_Addr (GPIOD_BASE+20) //0x40020C14
#define GPIOE_ODR_Addr (GPIOE_BASE+20) //0x40021014
#define GPIOF_ODR_Addr (GPIOF_BASE+20) //0x40021414
#define GPIOG_ODR_Addr (GPIOG_BASE+20) //0x40021814
#define GPIOH_ODR_Addr (GPIOH_BASE+20) //0x40021C14
#define GPIOI_ODR_Addr (GPIOI_BASE+20) //0x40022014#define GPIOA_IDR_Addr (GPIOA_BASE+16) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+16) //0x40020410
#define GPIOC_IDR_Addr (GPIOC_BASE+16) //0x40020810
#define GPIOD_IDR_Addr (GPIOD_BASE+16) //0x40020C10
#define GPIOE_IDR_Addr (GPIOE_BASE+16) //0x40021010
#define GPIOF_IDR_Addr (GPIOF_BASE+16) //0x40021410
#define GPIOG_IDR_Addr (GPIOG_BASE+16) //0x40021810
#define GPIOH_IDR_Addr (GPIOH_BASE+16) //0x40021C10
#define GPIOI_IDR_Addr (GPIOI_BASE+16) //0x40022010
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //输出
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //输入#define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n) //输出
#define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n) //输入#define CPU_LED PEout(1)
//定义一个宏 以后改起来方便只需要修改宏就可以
//根据实际情况选择哪一个口 我的硬件灯接的PE1
#define LED_PIN GPIO_Pin_1
#define LED_GPIO_PORT GPIOE
#define LED_GPIO_CLK RCC_APB2Periph_GPIOE
//根据自己实际硬件定义 有的是输出高亮 有的是输出低亮
//GPIO_SetBits(LED_GPIO_PORT,LED_PIN); //输出高
//GPIO_ResetBits(LED_GPIO_PORT,LED_PIN); //输出低
#define CPU_LED_ON GPIO_ResetBits(LED_GPIO_PORT,LED_PIN)
#define CPU_LED_OFF GPIO_SetBits(LED_GPIO_PORT,LED_PIN)
extern void BSP_LED_Init(void);
#endif
叁、编写BSP_TIMER.c与BSP_TIMER.h代码
3.1 进入USER/BSP文件夹下 复制BSP_LED文件夹改为BSP_TIMER
3.2 进入USER/BSP/TIMER文件夹,修改文件名
3.3 打开BSP_TIMER.h修改为
#ifndef __BSP_TIMER_H
#define __BSP_TIMER_H
#include "stm32f4xx.h"
extern void BSP_TIMER_Init(uint16_t arr,uint16_t psc);
#endif
3.4 打开BSP_TIMER.c修改为
#include "BSP_TIMER.h"
#include "BSP_LED.h"
#define BSP_TIMERx TIM3
#define BSP_TIMERx_IRQn TIM3_IRQn
#define BSP_TIMERx_Priority 5 //中断函数接口(见stm32f10x_it.c)
#define BSP_TIMERx_IRQHandler TIM3_IRQHandler
#define BSP_TIMERx_CLK RCC_APB1Periph_TIM3
//F1定时器中断时间 = (Period +1)*(Prescaler+1)/84M
//(8400 - 1+1)*(1000 - 1+1)/84M = 0.1S
//100ms定时器
void BSP_TIMER_Init(uint16_t arr,uint16_t psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(BSP_TIMERx_CLK,ENABLE); ///使能TIM3时钟
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(BSP_TIMERx,&TIM_TimeBaseInitStructure);
TIM_ITConfig(BSP_TIMERx,TIM_IT_Update,ENABLE); //允许定时器3更新中断
TIM_Cmd(BSP_TIMERx,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=BSP_TIMERx_IRQn; //定时器3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=BSP_TIMERx_Priority; //抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/* 定时器中断向量 */
void BSP_TIMERx_IRQHandler(void)
{
if(TIM_GetITStatus(BSP_TIMERx ,TIM_IT_Update)==SET) //溢出中断
{
CPU_LED = ~CPU_LED;
}
TIM_ClearITPendingBit(BSP_TIMERx ,TIM_IT_Update); //清除中断标志位
}
肆、打开工程,将BSP_TIMER.c添加入工程并添加头文件路径
伍、修改main函数
#include "stm32f4xx.h"
#include "BSP_DELAY.h"
#include "BSP_LED.h"
#include "BSP_TIMER.h"int main(void)
{
// BSP_DELAY_Init(168); //延时初始化
BSP_LED_Init(); //LED初始化
BSP_TIMER_Init(8400,1000);while(1)
{// CPU_LED_ON;
// BSP_DELAY_ms(500);
// CPU_LED_OFF;
// BSP_DELAY_ms(500);
}
}