STM32F4_跑马灯实验

目录

1.硬件分析

2.软件分析

2.1 GPIO重要函数

2.1.1 1个初始化函数:

2.1.2 2个读取输入电平函数:

2.1.3 4个设置输出电平函数:

2.1.4 2个读取输出电平函数:

2.2 跑马灯_库函数

2.2.1 书写步骤

2.2.2 实验代码


1.硬件分析

         如图为STM32F407ZG有关LED的原理图;在此需要特别注意,不同板子对应的引脚不同;STM32F4xx系列LED0对应到MCU_PF9引脚,LED1对应MCU_PF10引脚

        LED模块的原理图通过VCC3.3V进行供电,模块最下边的LED_PWR左侧接地,右侧接上510R的上拉电阻(LED_PWR右侧直接呈现高电平),此时LED_PWR天生具有电势差,即VCC3.3V一旦供电,PWR就会亮,所以LED_PWR作为电源灯,STM32F4xx板子一旦供电,LED_PWR就会亮;

        LED0 和 LED1 左侧接MCU微控制器的PF9 和 PF10 引脚,右侧接上拉电阻呈现高电平,所以只要给到LED0 和 LED1 低电平,LED0 和 LED1就会亮;反之,就不会亮;

2.软件分析

GPIO使用输出模式为推挽输出原因在于推挽输出可以控制输出高低电平

跑马灯实验的库函数操作IO口必须引入源文件和头文件:源文件---stm32f4xx_gpio.c;头文件---stm32f4xx_gpio.h;

控制LED必须引用stm32f4xx_rcc.c(时钟使能,任何程序的运行都需要)、misc.c、stm32f4xx_usart.c(串口);

补充(该部分参考他人博客总结如下):

什么是推挽输出?什么又是开漏输出?

        首先先来了解一下32单片机GPIO口的三种输出状态:输出高电平、输出低电平、呈现高阻态

å¨è¿éæå¥å¾çæè¿°

上图是STM32的GPIO口的内部逻辑电路图,通过上图可以知道:GPIO口的输出状态完全取决于Q1和Q2两个MOS管的导通状态

        Q1导通,Q2关断,此时上半部分逻辑电路导通,输出接VCC,GPIO输出高电平

        Q1关断,Q2导通,此时下半部分逻辑电路导通,输出接地,GPIO输出低电平

        Q1关断,Q2关断,此时输出处于浮空状态,相对于其他点电阻无穷大,GPIO口呈现高阻态

        Q1导通,Q2导通,VCC直接对地短路,这样会烧坏MOS管,单片机不允许这种情况出现;

综上所述:GPIO配置输出时,只会呈现三种状态:高电平、低电平、高阻态

推挽输出:

        我们将GPIO输出高电平和输出低电平两种状态拿出来单独分析(这也是我们最初对引脚的认识,GPIO引脚要么输出高电平,要么输出低电平

当输出高电平时,电流如下图箭头流出去,我们称之为,简单来说就是把电流推出去。

å¨è¿éæå¥å¾çæè¿°

当输入高电平时,电流按下图所示方向流进来,我们称之为,意思就是说把电流挽回来。

å¨è¿éæå¥å¾çæè¿°

所谓了推挽,实际上就是GPIO输出高低电平时电流的一个动作而已;

开漏输出:

        我们把GPIO输出低电平和高阻态两种状态拿出来单独分析;在低电平和高阻态两种状态下,两种状态的MOS管Q1都是关断的,可以认为MOS管Q1不存在;

å¨è¿éæå¥å¾çæè¿°

此时,MOS管的漏极等于什么也没有接,处于一个开路状态,这个模式我们称之为开漏模式

开漏模式的用处?

        1. 改变高电平的电压

        如下图,现在我们想要通过一个GPIO引脚去控制芯片的使能引脚EN;

å¨è¿éæå¥å¾çæè¿°

        通过上图可以发现,芯片的使能引脚EN只支持3.3V输入,而GPIO输出的高电平却有5V,如果此时采用推挽输出,将微控制的5V高电平输出到芯片,可能就会把芯片烧毁。

        所以此时我们需要选择开漏输出(开漏输出模式下默认MOS管Q1不存在),同时外接一个上拉电阻;此时,当Q2关断时(即高阻态),EN引脚就被上拉电阻拉到了3.3V,芯片的使能引脚就会呈现高电平;

å¨è¿éæå¥å¾çæè¿°

        同理,当Q2导通时,芯片的使能引脚EN就会接地,从而呈现低电平;

        这样就可以实现5V单片机对3.3V芯片的控制作用;

        2. 多个GPIO控制一个输入

å¨è¿éæå¥å¾çæè¿°

        如果此时考虑推挽模式的话,当上面的GPIO输出高电平,下面的GPIO输出低电平,两个GPIO之间就会短路,从而烧毁MOS管。

        我们将两个GPIO设置为开漏模式,再外接一个上拉电阻,如图,

å¨è¿éæå¥å¾çæè¿°

        此时注意:只要有任意一个GPIO输出低电平,芯片的使能引脚EN就会被拉低。(之所以只要有任意一个GPIO输出低电平,芯片的使能引脚EN就会被拉低;是因为开漏模式下,引脚GPIO只会出现低电平和高阻态两种状态,不会出现高电平这种情况)。只有两个GPIO都呈现高阻态时,两个GPIO相当于断路,上拉电阻将芯片使能引脚EN拉高至3.3V,呈现高电平;

2.1 GPIO重要函数

GPIO重要函数包括1个初始化函数:void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);

2个读取输入电平函数:uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

2个读取输出电平函数:uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

4个设置输出电平函数:void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

void GPIO_WriteBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin,BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx,uint16_t PortVal);

2.1.1 1个初始化函数:

void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);是用来设置4个32位配置寄存器的,设置IO口的模式(速度、输出方式、上下拉);注意:外设(包括GPIO)在使用之前,几乎都要先使能对应的时钟

GPIOx:GPIOA~GPIOK(最多11组,11*16=176个IO口)

void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct)函数用结构体指针来接收;

 用结构体来初始化端口:typedef结构体重命名为GPIO_InitTypeDef;

GPIO初始化样例:

2.1.2 2个读取输入电平函数:

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);参数(指定哪一种IO,指定哪一个IO);作用:读取某个GPIO输入电平;ag. GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)读取GPIOA5的输入电平;

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);作用:读取某组GPIO输入电平;ag. GPIO_ReadInputData(GPIOA)读取GPIOA组的所有输入电平;

实际上操作的都是GPIOx_IDR输入寄存器

补充:uint8_t的意思是unsigned char uint8_t;_t 的意思是通过typedef重定义,它是我们已知的类型;

2.1.3 4个设置输出电平函数:

void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);实际操作BSRRL寄存器;设置某个IO口输出为高电平1;

void GPIO_Re(取反)setBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);实际操作BSRRH寄存器;设置某个IO口输出为低电平0;

void GPIO_WriteBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin,BitAction BitVal);

void GPIO_Write(GPIO_TypeDef* GPIOx,uint16_t PortVal);后面两个并不常用;

2.1.4 2个读取输出电平函数:

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);读取某个GPIO口输出电平;

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);读取某组GPIO口输出电平;

实际上操作的都是GPIOx_ODR输入寄存器

2.2 跑马灯_库函数

2.2.1 书写步骤

1. 使能IO口时钟。调用函数  RCC_AHB1PeriphClockCmd();不同的外设调用的时钟使能函数可能不同;同时使用GPIO必须先使能相应的GPIO时钟;

2. 初始化IO口模式。调用函数GPIO_Init();

3. 操作IO口,输出高低电平;GPIO_SetBits();GPIO_ResetBits();

2.2.2 实验代码

实现LED流水灯:(切记相应的GPIO时钟使能)

#include "stm32f4xx.h"
#include "delay.h"




int main()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //LED连接微控制器引脚PF9和PF10,所以先使能GPIOF时钟
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10; //设置GPIO引脚,PF9和PF10
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //设置GPIO引脚输出模式
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //设置推挽输出,更方便的去设置GPIO引脚的高低电平
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz; //设置GPIO速度-100MHz
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //GPIO引脚设置为上拉
	GPIO_Init(GPIOF,&GPIO_InitStructure);
	GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10); //初始化时  默认设置PF9个PF10引脚为高电平,默认LED不亮;
	delay_init(168); //初始化延迟函数
	while(1)
	{
		
		GPIO_ResetBits(GPIOF,GPIO_Pin_9); //LED0对应引脚低电平,LED0 亮
		delay_ms(200);
		GPIO_SetBits(GPIOF,GPIO_Pin_9); //LED0对应引脚高电平,LED0 灭
		delay_ms(200);
		GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED1对应引脚低电平,LED1 亮
		delay_ms(200);
		GPIO_SetBits(GPIOF,GPIO_Pin_10); LED1对应引脚高电平,LED1 灭
		delay_ms(200);
	}
}

         如果想要LED0 和 LED1 同时闪烁,只需要把GPIO_SetBits(GPIOF,GPIO_Pin_9)和GPIO_ResetBits(GPIOF,GPIO_Pin_9)改为GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10)和 GPIO_ResetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10)即可;

        此程序需要注意:本人第一次敲代码时,将结构体(下图所示结构体)一并敲出,系统报错;很懵?为什么不用定义结构体而直接用,后来学习发现gpio头文件中已经定义结构体,直接定义结构体变量,通过结构体变量+  访问结构体成员变量即可;另外需要注意:任何实验程序使用前都需要进行相应GPIO口的时钟使能;delay延迟函数默认168;系统配置;注意:因为初始化GPIO函数的参数是用指针接收的,所以定义GPIO初始化函数时需要取地址GPIO_InitStructure;

区别51单片机的地方在于:初始化时需要初始化输出电平函数到引脚为高电平,即未给LED引脚低电平时LED不能亮;

typedef struct
{
	uint32_t GPIO_Pin;
	GPIOMode_TypeDef GPIO_Mode;
	GPIOSpeed_TypeDef GPIO_Speed;
	GPIOOType_TypeDef GPIO_OType;
	GPIOPuPd_TypeDef GPIO_PuPd;
}GPIO_InitTypeDef;

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值