STM32学习第二天:点灯

GPIO:通用输入输出模块

操作STM32的GPIO三步骤:

  1. 使用RCC开启GPIO的时钟
  2. 使用GPIO_Init函数初始化GPIO(需要先定义一个结构体变量,再给结构体变量赋值)
  3. 使用输出或输入的函数控制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) *********************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值