• stm32F407学习笔记2——GPIO操作跑马灯实验


    一、库函数版本

    1、硬件原理图

    在这里插入图片描述

    2、软件设计

    打开上一节新建的库函数版本工程模板,直接点击工程下面的 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拉高
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    用同样的方法新建一个 led.h 文件,也保存在 LED 文件夹下面。在 led.h 中输入如下代码:

    #ifndef __LED_H
    #define __LED_H
    
    void LED_Init(void); 	
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    接着,我们在 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);
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    函数快速跳转:双击函数,右键点击Go To Definition Of ’ ’

    二、寄存器版本

    操作步骤与库函数版本一致,在led.h输入如下代码:

    #ifndef __LED_H
    #define __LED_H
    
    void LED_Init(void); 	
    
    #endif
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在led.c中写寄存器的led初始化函数

    1、使能IO口时钟

    配置相关寄存器寄存器RCC->AHB1ENR,打开STM32F4XX中文参考手册的6.3.12 小节RCC AHB1 外设时钟使能寄存器,可以看到GPIOF在标号的第5位,设置为1使能IO端口F时钟,其他位不变
    在这里插入图片描述

    RCC->AHB1ENR |= 1<<5;
    
    • 1

    2、初始化IO口模式

    配置四个配置寄存器 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位后按位或
    
    • 1
    • 2

    OSPEEDR和PUPDR寄存器同MODER寄存器一样都是32位寄存器,配置方式相同,OTYPER是16位寄存器,有一点不同
    在这里插入图片描述
    设置0为输出推挽

    3、操作IO口,输出高低电平

    配置寄存器GPIOX_ODR或者BSRRL/BSRRH。
    在这里插入图片描述
    1拉高,0拉低

    GPIOF->ODR |= 1<<9;//拉高
    GPIOF->ODR &= ~(1<<9);//拉低.用&
    
    • 1
    • 2

    在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;//拉高
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    主函数的代码为:

    #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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    烧录进开发板后看到两个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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这里的PFout(9)和PFout(10)可以简单理解为GPIOF寄存器第9和10端口的另一个地址,与寄存器上32个地址一一对应,他们之间是映射关系中间通过进行转换。
    关于如何转换可看工程代码SYSTEM文件夹下的sys.h头文件查看宏定义
    在这里插入图片描述

  • 相关阅读:
    什么是迭代器,Python迭代器及其用法
    Android 10.0 Camera2退出时屏幕旋转为横屏
    概要设计:描绘软件结构的图形工具,结构图既能表示模块间的数据信息、控制信息,也能表示选择调用和循环调用关系。
    私有化+国产化,这款安全可靠的知识管理系统超赞
    决策树-分析与应用
    数据结构与算法 | 哈希表(Hash Table)
    Semantic Kernel 入门系列:🥑Memory内存
    GitHub 开源大厂缓存架构 Redis 优化的文档被警告,900 页全是宝贝
    化工行业升级进行时,数商云B2B商城系统询报价功能助力企业精确对接供求
    java培训技术通过debug调试流程
  • 原文地址:https://blog.csdn.net/weixin_48213877/article/details/127592260