嵌入式学习——STM32F4系列GPIO口理论以及跑马灯实验

文章介绍了STM32F4开发板中使用库函数实现GPIO控制LED跑马灯实验的过程,涉及GPIO推挽输出的原理及在LED_Init中的应用,同时讨论了如何通过`delay_ms()`和`delay_init()`进行延时控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    本文章主要以库函数出发,因为本人以智能车硬件出身主要以硬件去理解STM32.本章节主要从GPIO的硬件出发理解为什么跑马灯实验为什么使用推挽输出。本人的所有文章会随着本人理解逐步更新,若有不足之处请各位大神指出。

以下代码为使用正点原子stm32F4开发板库函数指南。
跑马灯实验
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
int main(void)
{
delay_init(168);
//初始化延时函数
LED_Init();
//初始化 LED 端口
/**下面是通过直接操作库函数的方式实现 IO 控制**/
while(1)
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //LED0 对应引脚 GPIOF.9 拉低,亮 等同 LED0=0;
GPIO_SetBits(GPIOF,GPIO_Pin_10); //LED1 对应引脚 GPIOF.10 拉高,灭 等同 LED1=1;
delay_ms(500);
//延时 500ms
GPIO_SetBits(GPIOF,GPIO_Pin_9); //LED0对应引脚GPIOF.0拉高,灭 等同LED0=1;
GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED1 对应引脚 GPIOF.10 拉低,亮 等同 LED1=0;
delay_ms(500); //延时 500ms
}
}
 
以上代码为3部分;LED_Init()初始化;while(1)里面的GPIO_SetBites()与GPIO_ReseBits;delay_ms()与delay_init()延迟
先从简单的入手
部分一:delay_ms()与delay_int()
delay_ms()
根据代码所示delay_ms() delay_init() 在delay.c文件中
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	u32 reload;
#endif
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;						//不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	reload=SYSCLK/8;						//每秒钟的计数次数 单位为M	   
	reload*=1000000/delay_ostickspersec;	//根据delay_ostickspersec设定溢出时间
											//reload为24位寄存器,最大值:16777216,在168M下,约合0.7989s左右	
	fac_ms=1000/delay_ostickspersec;		//代表OS可以延时的最少单位	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//开启SYSTICK中断
	SysTick->LOAD=reload; 					//每1/delay_ostickspersec秒中断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; 	//开启SYSTICK    
#else
	fac_ms=(u16)fac_us*1000;				//非OS下,代表每个ms需要的systick时钟数   
#endif
}								    
void delay_ms(u16 nms)
{	 	 
	u8 repeat=nms/540;						//这里用540,是考虑到某些客户可能超频使用,
											//比如超频到248M的时候,delay_xms最大只能延时541ms左右了
	u16 remain=nms%540;
	while(repeat)
	{
		delay_xms(540);
		repeat--;
	}
	if(remain)delay_xms(remain);
} 

STM32F4-正点原子探索者-SYSTEM文件夹下的delay.c文件内延时函数详解_if (!sys_support_os)_Archimedes' boat的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_62722416/article/details/126181663对于这两个函数使用os的讲解请看以上博客的理解,本人正在学习原理中。理解后会在本文更新

部分二:LED_Init()初始化 

LED_Init存储在led.h和led.c 

//led.c

void LED_Init(void)
{    	 
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

  //GPIOF9,F10初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0和LED1对应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;//上拉
  GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIO
	
	GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//GPIOF9,F10设置高,灯灭

}
//led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"

//LED端口定义
#define LED0 PFout(9)	// DS0
#define LED1 PFout(10)	// DS1	 

void LED_Init(void);//初始化		 				    
#endif

下面进行对LED.Init初始化函数的分解

第一句GPIO_InitTypeDef GPIO_InitStructure创建GPIO的结构体 ;

GPIO_InitTypeDef GPIO_InitStructure ;
/*
GPIO_InitTypeDef结构体变量
ypedef struct
{
  uint16_t GPIO_Pin;                         

  GPIOSpeed_TypeDef GPIO_Speed; 

  GPIOMode_TypeDef GPIO_Mode;  
                                     
}GPIO_InitTypeDef
将GPIO_InitStructure定义成GPIO_InitTypeDef结构体类似于 int char

ypedef struct
{
  uint16_t GPIO_Pin;                         

  GPIOSpeed_TypeDef GPIO_Speed; 

  GPIOMode_TypeDef GPIO_Mode;  
                                     
}GPIO_InitStructure
*/

第二句 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟

主要是打开GPIO的开关,在一个给GPIO的频率信号。因为GPIO是以D触发器为启动,STM32F4全部为低功耗模式D触法器全部没有开启所以要进行始能赋值启动.这也是为什么是STM32的功耗如此低的原因。

第三句 

//GPIOF9,F10初始化设置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0和LED1对应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;//上拉

ypedef struct
{
  uint16_t GPIO_Pin;                         

  GPIOSpeed_TypeDef GPIO_Speed; 

  GPIOMode_TypeDef GPIO_Mode;  
                                     
}GPIO_InitStructure
*/

在前面我们进行了GPIO_InitStructure这个结构体的建立

但是我们并没有完成内部的设置

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0和LED1对应IO口
对uint16_t GPIO_Pin;    进行定义

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

对GPIO的频率进行定义,但是正点原子的100MHz我个人不认可,首先这个GPIO所使用的只是一个led完全用不上这个频率,是对资源的浪费建议改成2MHz。后面会出对于不同频率之间EMI EMC的分析。100MHz的EMI干扰是非会对IIC通信会有影响还需要尝试

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式 

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

将GPIO_Mode设置成普通输出模式,只是STM32F4的gpio.h的定义与是stm32f1的gpio.h有所不同。f1可以直接GPIO_InitStructure.GPIO_Mode=GPIO_MODE_OUT_PP;在使用各类单片机时候需要看清楚.h的定义。

       以下的内容是介绍为什么要使用推挽输出和下拉。从硬件角度分析,我们在使用gpio时我们需要怎样的信号输入和输出。以及我们的输出需不需要在进行一定提升驱动能力例如使用一些外设是的运放和驱动电路,并且我们需要清楚的知道,各类单片机对数字电平的范围是不同的。
     从输出出发一共有4类

准确的来说只有两类 推挽与开漏。复用只是延伸。
推挽输出
      推挽输出的结构是由两个三极管或者MOS管受到互补信号的控制,两个管子始终保持一个处于截止,另一个处于导通的状态。如图 2部分所示。
      其实学习过拉扎维的会感受到推挽输出有一点像反向器,其实工作原理是一样都是两个管子始终保持一个处于截止,另一个处于导通的状态。只是输入与反向器不同。
推挽输出的最大特点是可以真正能真正的输出高电平和低电平,在两种电平下都具有驱动能力。
  
      推挽输出最大的作用是提高GPIO的输出能力和负载能力。但是推挽输出的一个缺点是无法线与,如果当两个推挽输出结构相连在一起,一个输出高电平,即上面的MOS导通,下面的MOS闭合;同时另一个输出低电平,即上面的MOS闭合,下面的MOS导通时会直接短路。所以我们要使用开漏。
     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值