打开上一节新建的库函数版本工程模板,直接点击工程下面的 USER 目录下面的 Template.uvproj。
跑马灯实验我们主要用到的固件库文件是:
stm32f4xx_gpio.c /stm32f4xx_gpio.h
stm32f4xx_rcc.c/stm32f4xx_rcc.h//每个实验中都要引入,因为系统时钟配置函数以及相关的外设时钟使能函数
misc.c/ misc.h //SYSTEM 文件夹中都需要使用到
stm32f4xx_usart .c/stm32f4xx_usart.h//SYSTEM 文件夹中都需要使用到
stm32f4xx_syscfg.c/stm32f4xx_syscfg.h//后面很多实验都要使用到
在FWLIB文件夹中有多余的源文件,使得编译速度变慢,可以去掉多余的源文件,留下上面使用的5个源文件,右击 Template,选择“Manage project Items”,进入这个选项卡
选中“FWLIB”分组,然后选中不需要的源文件点击删除按钮删掉,剩下上述5个源文件
然后我们进入我们工程的目录,在工程根目录文件夹下面新建一HARDWARE 的文件夹,用来存储以后与硬件相关的代码。然后在 HARDWARE 文件夹下新建一个 LED 文件夹,用来存放与 LED 相关的代码。
新建一个文件,然后保存在 HARDWARE->LED 文件夹下面,保存为 led.c
然后在 led.c 文件中输入如下代码,点击保存
#include "stm32f4xx.h"
//LED IO初始化
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//配置GPIO所用的结构体
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//时钟使能函数,PF9和PF10为输出口,所以使能这两个口的时钟,GPIOF又在AHB1总线下,所以调用AHB1函数
//GPIOF9,F10初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED所对应的两个IO口,两个IO口的功能一样才能这么设置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉,在硬件原理图中看出上拉led熄灭
GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIO
GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//GPIOF9,F10拉高
}
用同样的方法新建一个 led.h 文件,也保存在 LED 文件夹下面。在 led.h 中输入如下代码:
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
接着,我们在 Manage Project Itmes 管理里面新建一个 HARDWARE的组,并把 led.c 加入到这个组里面。这样就把led.c文件添加到工程中了
然后将 led.h 头文件的路径加入到工程里面
最后在main.c中输入如下代码,烧录进开发板,使两个led间隔500ms闪烁
#include "stm32f4xx.h"//顶层头文件
#include "led.h"
#include "delay.h"
int main ()
{
delay_init(168);//此模板默认设置是168
LED_Init();//初始化led
while(1)
{
GPIO_SetBits(GPIOF,GPIO_Pin_9);
GPIO_SetBits(GPIOF,GPIO_Pin_10);//输出高电平,熄灭
delay_ms(500);
GPIO_ResetBits(GPIOF,GPIO_Pin_9);
GPIO_ResetBits(GPIOF,GPIO_Pin_10);//输出高电平,点亮
delay_ms(500);
}
}
函数快速跳转:双击函数,右键点击Go To Definition Of ’ ’
操作步骤与库函数版本一致,在led.h输入如下代码:
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
在led.c中写寄存器的led初始化函数
配置相关寄存器寄存器RCC->AHB1ENR,打开STM32F4XX中文参考手册的6.3.12 小节RCC AHB1 外设时钟使能寄存器,可以看到GPIOF在标号的第5位,设置为1使能IO端口F时钟,其他位不变
RCC->AHB1ENR |= 1<<5;
配置四个配置寄存器 GPIOx_MODER/ GPIOx_OTYPER/ GPIOx_OSPEEDR/ GPIOx_PUPDR;打开STM32F4XX中文参考手册的7.4.1小节可以看到控制IO口的9和10,设置为01:通用输出模式
GPIOF->MODER &= ~(3<<2*9);//第18和19位的MODE寄存器清零其他位不变,11左移18位然后取反按位与
GPIOF->MODER |= 1<<(2*9);//清零的18和19位置为 01其他位不变,01左移18位后按位或
OSPEEDR和PUPDR寄存器同MODER寄存器一样都是32位寄存器,配置方式相同,OTYPER是16位寄存器,有一点不同
设置0为输出推挽
配置寄存器GPIOX_ODR或者BSRRL/BSRRH。
1拉高,0拉低
GPIOF->ODR |= 1<<9;//拉高
GPIOF->ODR &= ~(1<<9);//拉低.用&
在led.c文件中的代码:
#include "stm32f4xx.h"
//LED IO初始化
void LED_Init(void)
{
RCC->AHB1ENR |= 1<<5;//通过寄存器使能GPIOF时钟,GPIOF在寄存器的第六位,所以将1左移5位,其他不变
//PF9
GPIOF->MODER &= ~(3<<2*9);//第18和19位的MODE寄存器清零其他位不变,11左移18位然后取反按位与
GPIOF->MODER |= 1<<(2*9);//清零的18和19位置为 01其他位不变,01左移18位后按位或
GPIOF->OSPEEDR &= ~(3<<2*9);//清零
GPIOF->OSPEEDR |= 2<<(2*9);//10,50HZ
GPIOF->PUPDR &= ~(3<<2*9);//清零
GPIOF->PUPDR |= 1<<(2*9);//01,上拉
GPIOF->OTYPER &= ~(1<<9);//清零
GPIOF->OTYPER |= 0<<9;//输出推挽
GPIOF->ODR |= 1<<9;//拉高
//GPIOF->ODR &= ~(1<<9);//拉低.用&
//PF10
GPIOF->MODER &= ~(3<<2*10);//第18和19位的MODE寄存器清零其他位不变,11左移18位然后取反按位与
GPIOF->MODER |= 1<<(2*10);//清零的18和19位置为 01其他位不变,01左移18位后按位或
GPIOF->OSPEEDR &= ~(3<<2*10);//清零
GPIOF->OSPEEDR |= 2<<(2*10);//10,50HZ
GPIOF->PUPDR &= ~(3<<2*10);//清零
GPIOF->PUPDR |= 1<<(2*10);//01,上拉
GPIOF->OTYPER &= ~(1<<10);//清零
GPIOF->OTYPER |= 0<<10;//输出推挽
GPIOF->ODR |= 1<<10;//拉高
}
主函数的代码为:
#include "stm32f4xx.h"//顶层头文件
#include "led.h"
#include "delay.h"
int main ()
{
delay_init(168);//初始化时钟,此模板默认设置是168
LED_Init();//初始化led
while(1)
{
GPIOF->ODR &= ~(1<<9);//拉低
GPIOF->ODR |= 1<<10;//拉高
delay_ms(500);
GPIOF->ODR |= 1<<9;//拉高
GPIOF->ODR &= ~(1<<10);//拉低
delay_ms(500);
}
}
烧录进开发板后看到两个LED交替闪烁
前两步使能IO口时钟和初始化IO口模式操作跟前面一样,只是在操作IO口,输出高低电平时使用位带操作。
只需要修改主函数:
#include "stm32f4xx.h"//顶层头文件
#include "led.h"
#include "delay.h"
int main ()
{
delay_init(168);//初始化延时函数,此模板默认设置是168
LED_Init();//初始化led
while(1)
{
PFout(9) = 1;//拉高
PFout(10) = 1;//拉高
delay_ms(500);
PFout(9) = 0;//拉低
PFout(10) = 0;//拉低
delay_ms(500);
}
}
这里的PFout(9)和PFout(10)可以简单理解为GPIOF寄存器第9和10端口的另一个地址,与寄存器上32个地址一一对应,他们之间是映射关系中间通过进行转换。
关于如何转换可看工程代码SYSTEM文件夹下的sys.h头文件查看宏定义