从零到一STM32第一个程序使用库函数点亮一个LED灯并使其闪烁(江协科技)

概要

谈起STM32必然离不开点灯,本文将从新手的角度学习库函数编程使用GPIO引脚配置点亮LED小灯,本文中使用到的部分资料来源于B站up江协科技,如有需要可以去B站自取

LED电路分析与GPIO模式选择

LED灯:发光二极管具有单向导通性,正向导通点亮,反向不亮,正常使用时需要在LED电路上接入一个限流电阻,本次使用面包板接线使用STM32核心板供电,单引脚电流较小。

发光二极管作为比较基本的电子元件其内部电路较为简单,将其与核心板连接时既可以直接使用GPIO引脚与正极相接,也可以与负极相接。理论上开漏输出和推挽输出都能实现,但如果使用开漏输出引脚与正极相接时需要外部电路提供上拉能力,所以此处选择推挽输出(即能输出高电平也能输出低电平)。

库函数编程实现与思路分析

电路连接

此接线图来源江协科技视频课程资料,也可以根据个人需要接入任一GPIO引脚

 模块化编程

为了方便管理和修改代码通常在编写STM32程序会引入模块化编程,将各个模块功能单独实现,函数生命和宏定义整理成头文件,这样主程序只需要负责整体逻辑处理即可,那么我们可以在项目根目录下建立一个文件夹Hardware来存储硬件功能模块并在keil5软件添加对应分组和头文件路径配置然后在该分组下创建本次需要使用的LED.c和LED.h文件

下面是固定步骤在LED.c文件下导入固件库头文件。

#include "stm32f10x.h"                  // Device header

在LED.h文件下写入配置文件它的作用是 防止头文件被重复包含,也就是所谓的 "include guard"(头文件保护)

#ifndef __LED_H
#define __LED_H


#endif

首先让我们在LED.c编写一个GPIO的初始化函数

GPIO作为STM32的外部引脚要想让其工作首先让给他分配系统时钟(内核模块不需要)

另外我们要知道GPIO外设在STM32的AHB总线桥接一APB2上,我们要通过这个对其进行使能。

最后才是GPIO的配置(引脚选择,工作模式,响应速度)

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE );//使能rcc时钟,使用各个外设前必须开启时钟,否则对外设的操作无效
    GPIO_InitTypeDef GPIO_InitStucture;//定义结构体
	GPIO_InitStucture.GPIO_Mode= GPIO_Mode_Out_PP;//工作模式设置为推挽输出
	GPIO_InitStucture.GPIO_Pin=GPIO_Pin_0;//选择PA0引脚
	GPIO_InitStucture.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStucture);//使用结构体的形式初始化gpio,函数内部会自己根据结构体的赋值配置gpio
	
	
}

看起来很复杂,其实很多步骤都是从库函数Ctrl cv的过程,首先使能时钟是当在键盘敲下RCC_APB2P后就会给出自动填充选择,鼠标放在该函数上右键就可以跳转到函数定义,

在函数定义界面可以看到这个函数功能就是开启或关闭APB2 (High Speed APB)外设时钟开关

并给出了参数的选择,这里默认接线GPIOA的PA0引脚,第二参数是使能与不使能即开启还是关闭时钟,这里参数选择(RCC_APB2Periph_GPIOA,ENABLE )

然后是GPIO_Init函数同样的方法调到函数定义可以看到它的功能是根据指定初始化GPIOx外设

可以看到第一个参数是选择GPIOA到GPIOG哪一个,第二个参数是一个指向GPIO_InitTypeDef定义的结构体的指针,并根据这个结构体的赋值配置GPIO

所以我们需要使用GPIO_InitTypeDef定义一个结构体,并对其包含的元素进行赋值,不同于前面的函数这里的取值都是宏定义没法直接跳转,那么我们可以使用Ctrl+F进行查找手动跳转

引脚选择GPIO_Pin_0 工作模式选择  GPIO_Mode_Out_PP(推挽输出)速度不做要求

 这么一来GPIO的引脚的配置工作就已经完成了,下面进行小灯点灯和闪烁,所谓闪烁就是小灯在亮与灭之间交换,其本质就是调节GPIO引脚输出高低电平之间变换,中间加上延时,所以这里直接进行小灯闪烁操作

单独创立分组存放延时函数模块,这里直接使用江协科技写好的Delay模块,如有需要可以去江协科技视频课程自取(【STM32入门教程-2023版 细致讲解 中文字幕】 https://www.bilibili.com/video/BV1th411z7sn/?p=12&share_source=copy_web&vd_source=72d6fbd140630f04643517c4f28f0180),不要忘了魔法棒配置头文件路径和头文件引用

进入固件库中gpio.h文件可以看到这里有已经封装好的所有gpio操作函数,其中对输出电平进行设置的函数主要有以下四种,其中GPIO_Write函数是对整个GPIO组的16个引脚进行统一配置

void LED_Blink(void)  // LED 闪烁函数
{
	//方法一:使用ResetBits设置低电平,SetBits设置高电平
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为低电平
	Delay_ms(500);										//延时500ms
	GPIO_SetBits(GPIOA, GPIO_Pin_0);					//将PA0引脚设置为高电平
	Delay_ms(500);										//延时500ms
		
	/*方法2:GPIO_WriteBit设置低/高电平,由Bit_RESET/Bit_SET指定*/
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);		//将PA0引脚设置为低电平
	Delay_ms(500);										//延时500ms
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);			//将PA0引脚设置为高电平
	Delay_ms(500);										//延时500ms
		
	//方法三:使用GPIO_Write和与或运算实现高低电平配置
	uint16_t port_state = GPIO_ReadOutputData(GPIOA);
    port_state &= ~0x0001;                              // bit0 清 0,设置为低电平	
    GPIO_Write(GPIOA, port_state);
	Delay_ms(500);                                      //延时500ms
    port_state |= 0x0001;                               // bit0 置 1,设置为高电平
    GPIO_Write(GPIOA, port_state);      
    Delay_ms(500);		                                //延时500ms

}

 前两种方法使用的三个函数调用比较简单

 GPIO_SetBits设置指定的端口位,置为高电平

 GPIO_ResetBits清除指定的端口位,置为低电平

 GPIO_WriteBit可以认为是前两个函数的结合,具体是高电平还是低电平由第三个参数决定

GPIO_Write对整个输出寄存器的16位同时进行操作,查看定义可以知道,第一个参数选择哪个GPIO外设组,第二个参数是对输出寄存器指定的值且需要是一个无符号的16位整形,其每一位对应 GPIO 端口的一个引脚(Pin0~Pin15),本次只对PA0进行操作就需要消除对其他15个端口输出电平的影响,因此需要先读取GPIOA输出寄存器各个端口的电平状态,这里使用的是GPIO_ReadOutputData读取整个输出寄存器各个端口的值,也是使用一个无符号十六位整形数存储

 

uint16_t port_state = GPIO_ReadOutputData(GPIOA);

 接下来要对PA0引脚进行置0或置1操作,我们知道在逻辑运算中0 | 任意数 = 任意数 1 & 任意数 = 任意数

那么我们在对PA0进行置0操作时就可以让整个输出寄存器的16位&0b1111 1111 1111 1110

同理我们在对PA0进行置1操作时就可以让整个输出寄存器的16位|0b0000 0000 0000 0001

值得注意的是在并不是所有的编译器都支持直接使用0b表示二进制,所以这里选择使用十六进制表示此时0b0000 0000 0000 0001可以表示为0x0 0 0 1

0b1111 1111 1111 1110可以表示为0xF F F E也就是~0x0 0 0 1(非运算取反)

这样就也可以在不影响其他15个引脚的情况下改变PA0的引脚

//方法三:使用GPIO_Write和与或运算实现高低电平配置
	uint16_t port_state = GPIO_ReadOutputData(GPIOA);
    port_state &= ~0x0001;                              // bit0 清 0,设置为低电平	
    GPIO_Write(GPIOA, port_state);
	Delay_ms(500);                                      //延时500ms
    port_state |= 0x0001;                               // bit0 置 1,设置为高电平
    GPIO_Write(GPIOA, port_state);      
    Delay_ms(500);		                                //延时500ms

这么一来LED.c需要编写的函数就全部实现了,不要忘记在LED.h声明这些函数 

#ifndef __LED_H
#define __LED_H
/*功能:实现对LED连接的GPIO引脚PA0的初始化
参数:void(无参数)
返回值:void(无返回值)*/

 void LED_Init(void);
 /*功能:实现对LED连接的GPIO引脚PA0的电平高低变化
参数:void(无参数)
返回值:void(无返回值)*/
 void LED_Blink(void) ;
#endif

编写的闪烁函数并没有进行循环,只对引脚电平进行高低变化, 因此要实现闪烁功能需要把

LED_Blink放入main.c的循环中

#include "stm32f10x.h"                  // Device header
#include "LED.h"
#include "Delay.h"
int main(void)
{
	LED_Init();//初始化

	while(1)
	{
		LED_Blink();//LED闪烁
	}
	
}

接下来就可以编译下载到开发板查看LED闪烁现象,本处不做演示。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值