GPIO:通用输入输出模块
操作STM32的GPIO三步骤:
- 使用RCC开启GPIO的时钟
- 使用GPIO_Init函数初始化GPIO(需要先定义一个结构体变量,再给结构体变量赋值)
- 使用输出或输入的函数控制GPIO口
我使用的开发板的硬件原理图是这样的
由图可知,我只要给LED灯的右边输出高电压,就会点亮LED灯
所以根据这个我们就可以设置点亮LED灯实验。
首先我们要先创好这样的目录文件夹
doc存放说明文档,在Libraries里存放一些stm32的库函数代码方便调用,Project里存放自己的工程文件,User存放自己写的代码。
首先打开Kile5建立工程进Project,然后进行一下环境配置。
配置好后先创建bsp_led.c放入User-bsp-src里,创建bsp_led.h放入User-bsp-inc里
然后将main.c放入User里
在bsp_led.c里开头写入源文件模板
/*
*********************************************************************************************************
*
* 模块名称 : LED指示灯驱动模块
* 文件名称 : bsp_led.c
* 版 本 : V1.0
* 说 明 : 驱动LED指示灯,配合新建工程使用,非完整文件
*
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2019-08-02 waroyal 正式发布
*
* Copyright (C), 2014-2019, 德致伦电子
*
*********************************************************************************************************
*/
///
/* 头文件包含区 */
#include "bsp.h"
#include "sys.h"
///
/* 变量定义区 */
///
/* 外部变量申明区 */
///
/* 函数申明区 */
///
/* 函数实体区 */
///
/***************************** 德致伦电子 DeZLinc (END OF FILE) *********************************/
这里我已经写好,并且改好了开头说明,以后的练习都是按照这个模板更改。
在头文件包含区域写了
#include "bsp.h"用于在bsp里调用led.c,
#include "sys.h"用于使用位带操作。
在bsp_led.h里写入头文件模板,
/*
*********************************************************************************************************
*
* 模块名称 : LED指示灯驱动模块
* 文件名称 : bsp_led.h
* 版 本 : V1.0
* 说 明 : 头文件,配合新建工程使用,非完整文件
*
* Copyright (C), 2014-2025, 德致伦电子
*
*********************************************************************************************************
*/
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "sys.h"
#include "bsp.h"
///
//移植修改区
//按照实际端口修改
//较前版本更加容易移植(注意,端口仅仅适用于非JTAG/SWD引脚,如果是JTAG引脚,需要打开AFIO时钟,并失能JTAG)
在这个基础上,我加入了一些宏定义,后面进行解释。
#ifdef WSNEP_V01
#define RCC_ALL_LED ( LED0_GPIO_CLK | LED1_GPIO_CLK)
#define LED0_GPIO_PIN GPIO_Pin_5 //LED0引脚号
#define LED0_PIN_ID 5 //LED0引脚序号
#define LED0_GPIO_PORT GPIOB //LED0端口号
#define LED0_GPIO_CLK RCC_APB2Periph_GPIOB //LED0时钟
#define LED0_FUN_OUT PBout //LED0输出端口配置函数
//#define LED0_FUN_IN PBin //LED0输入端口配置函数
#define LED1_GPIO_PIN GPIO_Pin_5 //LED1引脚号
#define LED1_PIN_ID 5 //LED1引脚序号
#define LED1_GPIO_PORT GPIOE //LED1端口号
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOE //LED1时钟
#define LED1_FUN_OUT PEout //LED1输出端口配置函数
//#define LED0_FUN_IN PEin //LED1输入端口配置函数
#endif
/
我们在Led.c里先写一下Led的初始化函数,
void bsp_InitLed(void){
}
函数写完,里面的框架怎么写呢,根据我第一天的学习,任何设备调用都要先去使能他的时钟,所以第一行代码是使能时钟,RCC文件里存放的是时钟的函数,我们在RCC.h函数里找关于使能APB2总线的函数(.h的文件最下面都放着这些函数的声明,在最下面找就行)
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
我们找到后可以看到里面有两个关于参数,现在我们并不知道填什么,所以我们右击函数GO TO定义转到rcc.c里看一下,可以看到转过来是这样的
第一个参数存放的可选择范围在上面的@param后面都是,我们需要的是PB和PE端口的,第二个参数是使能或者失能,我们这里要选择ENABLE。
分别给两个端口使能就需要写两行,并且每次更改都需要在.c文件里更改,所以我在.h里加了宏定义,用RCC_ALL_LED代表了RCC_APB2Periph_GPIOE 和RCC_APB2Periph_GPIOB。
所以.c文件里时钟使能只需要写
RCC_APB2PeriphClockCmd(RCC_ALL_LED, ENABLE);即可完成。
下一步就是使用GPIO_Init函数初始化GPIO(需要先定义一个结构体变量,再给结构体变量赋值)
关于GPIO的函数,我们要去gpio.h的下面去找声明。
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
同样的,我们不知道里面参数添什么,所以GO TO一下看看都是填写什么
可以看到@param后面GPIOx和一个结构体GPIO_InitStruct,那个结构体我们不太懂,所以点击GPIO_InitTypeDef*再次右击GO TO一下就可以看到这个结构体都有什么了
这都是我们昨天学习过的引脚号,速度和模式,所以我们先定义一个结构体在该函数里,上下也写了这些参数的范围。即
GPIO_InitTypeDef GPIO_InitStructure;然后我们配置一下这个结构体的数据
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 推挽输出模式 */
GPIO_InitStructure.GPIO_Pin = LED0_GPIO_PIN;
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
Speed一般我们默认是使用最高的,就是GPIO_Speed_50MHz;Mode我们这里用推挽输出GPIO_Mode_Out_PP;引脚我们是PE5和PB5,都是5,所以都是GPIO_Pin_5,我们这里依旧使用的是宏定义LED0_GPIO_PIN和LED1_GPIO_PIN;,(如果用GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5 这一句也是对的;),最后是这个函数的初始化GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);第一个参数的端口号使用了宏定义,是GPIOE和GPIOB。,第二个参数是一个结构体的指针,所以我们使用 &GPIO_InitStructure;
通过之前的分析,我们知道,这两个LED都是高电平熄灭,低电平点亮。,所以我们先都给置高电平熄灭LED灯,在GPIO.h里找到GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);将电平设置为高电平。
所以Led初始化的最终代码是这样的:
void bsp_InitLed(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 打开GPIO时钟 */
RCC_APB2PeriphClockCmd(RCC_ALL_LED, ENABLE);
GPIO_SetBits(GPIOB, LED1_GPIO_PIN);
GPIO_SetBits(GPIOE,LED0_GPIO_PIN);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 推挽输出模式 */
GPIO_InitStructure.GPIO_Pin = LED0_GPIO_PIN;
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
}
然后我们先写一个LED灯的点亮函数和熄灭函数
void bsp_LedOn(uint8_t _no)
{
if( _no == 1)
{
GPIO_ResetBits(GPIOB,LED1_GPIO_PIN);
}
else if(_no == 2)
{
GPIO_ResetBits(GPIOE,LED0_GPIO_PIN);
}
}
void bsp_LedOff(uint8_t _no)
{
if(_no == 1)
{
GPIO_SetBits(GPIOB, LED1_GPIO_PIN);
}
else if( _no == 2)
{
GPIO_SetBits(GPIOE,LED0_GPIO_PIN);
}
}
还有个翻转函数,翻转库函数里是没有的,所以这里翻转函数是使用寄存器的方式
void bsp_LedToggle(uint8_t _no)
{
if (_no == 1)
{
LED0_GPIO_PORT->ODR ^= LED0_GPI其中O_PIN;
}
if (_no == 2)
{
LED1_GPIO_PORT->ODR ^= LED1_GPIO_PIN;
}
}
其中ODR是端口输出寄存器,LED0_GPIO_PORT是输出端口,加上^=就是取反。所以这句话就是对寄存器的电平进行取反,从而达到翻转的作用。
最后在led.h最下面声明一下函数
/* 供外部调用的函数声明 */
void bsp_InitLed(void);
void bsp_LedOn(uint8_t _no);
void bsp_LedOff(uint8_t _no);
void bsp_LedToggle(uint8_t _no);
#endif
在bsp.c里的bsp_Init(void)里加入LED的初始化函数bsp_InitLed();保证上电就初始化。
后面可以在main里操作led灯了
下面是我的main函数,实现LED0和LED1的翻转(中间间隔1m)
/*
*********************************************************************************************************
*
* 模块名称 : 主程序入口
* 文件名称 : main.c
* 版 本 : V1.0
* 说 明 : 跑马灯例子。使用了systick中断实现精确定时,控制LED指示灯闪烁频率。
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2019-08-02 waroyal 首发
*
* Copyright (C), 2014-2019, 天津德致伦电子
*
*********************************************************************************************************
*/
#include "bsp.h" /* 底层硬件驱动 */
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参:无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
bsp_Init(); /* 硬件初始化 */
while(1)
{
bsp_LedToggle(1);
delay_ms(1000);
bsp_LedToggle(2);
delay_ms(1000);
}
}
/***************************** 德致伦电子 DeZLinc (END OF FILE) *********************************/