本文章主要以库函数出发,因为本人以智能车硬件出身主要以硬件去理解STM32.本章节主要从GPIO的硬件出发理解为什么跑马灯实验为什么使用推挽输出。本人的所有文章会随着本人理解逐步更新,若有不足之处请各位大神指出。
#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
}
}
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博客https://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的定义。

