//如果你是新手,请按时间顺序查看我的[STM32从0开始]文章,跟着我的步骤入门,因为我也是新手,这是我写给我自己的新手向入门教程,阅读本问需要C语言基础
工程创建
如果你是新手,请从工程创建这一片博文开始看[STM32从0开始]STM32F10x系列工程创建 ,在这里,我们直接复制之前创建并备份的原工程。
GPIO的基本知识
STM32单片机的基本输入输出大致可分为开漏和推挽两种模式,开楼又因涉及到上拉电阻,又可细分为强上拉与弱上拉,按照手册上的描述,推挽模式0激活N管,1激活P管,而开漏0与推挽是一样的,区别在于开漏1的时候是高阻态,P管不会被激活,请各位根据自己的单片机查看对应手册。
我们的目的主要是了解输出部分的代码,所以我们主要看输出部分,更详细的原理这里不再赘述。
开漏本身是无法输出逻辑高电频的,如果需要开漏模式点亮led需要外接一个上拉电阻
按照我的理解简单来说,如果使用推挽模式点亮led灯,可直接连接,否则需要增加一个电阻。关于这方面我不是很理解,如果有错请大佬纠正。
推挽控制LED灯,LED文件编写
将GPIO设置成推挽的方式,在任意IO口连接上任意数量的LED灯,我们将学习如何初始化并控制其亮灭。
在工具栏点击该图标或者按住Ctrl+N创建新的文件,点击保存按钮或者使用Ctrl+S保存文件并命名为led.c与led.h,将其存在工程的User目录下。
在工程左侧右键单击User文件夹,选择Add Existing...将刚刚创建的led.c文件导入到工程中,
双击打开编辑led.c,加入头文件
#include "stm32f10x.h"
#include "led.h"
创建LED灯初始化函数
void LED_Init(void)
{
}
STM32是一款非常强大的芯片,大部分功能默认是关闭的以便于节省功耗,所以我们需要打开相应的时钟阀门以使得需要的功能正常运行,通过stm32f10x_rcc.c中的我们可以看到,如果我们想要使用GPIOA~G,就需要使用RCC_APB2PeriphClockCmd来开启相应的时钟阀门。
为了方便大家理解,我这里使用3个led灯,分别放置在ABC3组,其中C组是最小系统板板载LED灯PC13,我们初始化GPIOA、GPIOB、GPIOC的时钟阀门为开启。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| \
RCC_APB2Periph_GPIOB| \
RCC_APB2Periph_GPIOC,ENABLE);
对led的操作本质上是对GPIO的操作,在基础库中找到相应的函数即可 stm32f10x_gpio.c,可以看到GPIO函数需要两个参数,一个是GPIO的所属分组,一个是结构体,GPIO的模式配置,包括引脚、模式、频率三个部分。
根据需要,我们初始化GPIOA、GPIOB、GPIOC的具体引脚,为了方便大家少走弯路,我这里初始化每个组的所有引脚。
下表为你可以操作的所有引脚,每组16个,在复杂的工程中要考虑端口复用的问题,这里不需要。
这个引脚怎么来的呢?在上图中的注释中有@ref样式,说明你可以通过搜索搜索到相对应的资源,按Ctrl+F调出搜索,搜索GPIO_pins_define,即可得到下图。
同理,结构体中所需要的其他数据也可通过搜索得到。下图为mode表与speed表,参数具体含义请自行百度,这里调用推挽输出模式,最高速度。
结构体完整配置如下
GPIO_InitTypeDef GPIO_InitType; //GPIO配置结构体声明
GPIO_InitType.GPIO_Mode = GPIO_Mode_Out_PP;//设置为输出模式
GPIO_InitType.GPIO_Pin = GPIO_Pin_All;//所有引脚
GPIO_InitType.GPIO_Speed = GPIO_Speed_50MHz;//最高速度
在配置完成后,我们需要将其初始化,提交给初始化函数让系统知道我们要什么模式。还记得这张图吗?可以看到我们需要的两个参数都已经整理完毕。
GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_Init(GPIOC,&GPIO_InitType);
到此,LED初始化完成,在STM32中,1高电平熄灭,0低电平点亮,我是将led灯正级接到3.3,负极接io口的。如果你要初始化状态灯全灭请在初始化函数最后加入。
GPIO_SetBits(GPIOA,GPIO_Pin_All);
GPIO_SetBits(GPIOB,GPIO_Pin_All);
GPIO_SetBits(GPIOC,GPIO_Pin_All);
led.c完整初始化代码
#include "stm32f10x.h"
#include "led.h"
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| \
RCC_APB2Periph_GPIOB| \
RCC_APB2Periph_GPIOC,ENABLE); //开启GPIO分组的时钟阀门
GPIO_InitTypeDef GPIO_InitType; //GPIO配置结构体声明
GPIO_InitType.GPIO_Mode = GPIO_Mode_Out_PP;//设置为输出模式
GPIO_InitType.GPIO_Pin = GPIO_Pin_All;//所有引脚
GPIO_InitType.GPIO_Speed = GPIO_Speed_50MHz;//最高速度
//初始化组A、B、C所有引脚为输出模式
GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_Init(GPIOC,&GPIO_InitType);
//默认关闭LED灯
GPIO_SetBits(GPIOA,GPIO_Pin_All);
GPIO_SetBits(GPIOB,GPIO_Pin_All);
GPIO_SetBits(GPIOC,GPIO_Pin_All);
}
为了在main.c中能正常调用,请在led.h文件中填入以下代码
#ifndef __LED_H
#define __LED_H
#endif
void LED_Init(void);
推挽控制LED灯,MAIN文件编写
C语言运行是从main函数开始的,你的main函数所在的.c文件无论是什么名字都是主文件,一个程序只能有一个main函数。
在main函数中如果想使用别的文件的函数,需要他在.h文件中有声明,就像我们刚刚的led.h一样,将其引用到main中
#include "stm32f10x.h"
#include "led.h"
要做闪烁效果,我们还需要自己编写一个延时函数
void delay(int t)
{
int i;
while(t--)
{
for(i=0;i<120;i++);
}
}
在main中初始化调用LED初始化函数,系统时钟默认初始化函数
RCC_DeInit();
LED_Init();
在main.c中完整代码如下。其中if之内的函数是系统自带的库函数,功能是对led灯进行翻转,如果亮就灭,如果灭就亮,每隔一段时间判断一次,以达到闪烁效果。
#include "stm32f10x.h"
#include "led.h"
void delay(int t)
{
int i;
while(t--)
{
for(i=0;i<120;i++);
}
}
int main()
{
RCC_DeInit();
LED_Init();
while(1)
{
if(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_All))
{
GPIO_ResetBits(GPIOB,GPIO_Pin_All);
GPIO_ResetBits(GPIOA,GPIO_Pin_All);
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
else
{
GPIO_SetBits(GPIOB,GPIO_Pin_All);
GPIO_ResetBits(GPIOA,GPIO_Pin_All);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
delay(555);
}
}
最后
如果你看到了这里,恭喜你耐下心来看了3000多字,有人可能觉得话多又麻烦,我这个是自己记录学习历程并分享给仅有C语言的0单片机基础的人的,尽量做到每一步都详细且简单,到这里初步入门了STM32GPIO操作篇,本来想写个按钮控制的,但是身边没有按钮用,而且按钮也很简单,同样的初始化步骤,将io口输出改为输入罢了,不管是hal库还是什么,都可以在基库中找到类似的文件,这篇文章所用到的有stm32f10x_rcc.c、stm32f10x_gpio.c,所用到的函数都有具体且详细的注释解释,有良好的C语言基础基本只要理清他们的关系就会一通百通。
如果你是看我的文章从0开始,那么恭喜你迈出了从0到1的第一步,下一篇我将加上按钮,写按钮控制LED灯的基本写法。
红GPIOA、绿GPIOB、板载GPIOC。灯长正短负。
多用脑,多思考