电子产品世界 » 论坛首页 » 高校社团 » 坤创E-Geek/天科大新电社 » 大白带你重玩STM32系列(六) ------使用库函数法点亮LED彩灯


共15条 1/2 1 2 跳转至

大白带你重玩STM32系列(六) ------使用库函数法点亮LED彩灯

助工
2017-05-24 19:39:58    评分

各位盆友们,我们有两周没见了,这两周楼主所在的学校开始进行本科生的毕业答辩了,时间上确实有点忙,导致帖子稍有耽搁,接下来的两周我会加紧赶一赶,大家不要太心急哦。

既然说到了毕业设计,楼主就在这里给大家分享一下毕业设计过程中的一些小插曲。情况是这样的。楼主指导的几位同学的其中一个,在答辩前两天告诉我:“老师,我紧张的不行了,这两天都睡不着觉。总是做梦梦到自己会挂掉,毕不了业。害怕答辩老师会问到我不会回答的问题。”

这位同学是我所带学生里面做毕业设计不怎么用心的一位同学,而作为他的指导老师,在这个节骨眼上,我可是对他好一顿精心的安慰+鼓励,告诉他不用紧张,把论文和毕业设计多看几遍多了解了解,并站在答辩老师的角度给他提出了几个问题,让他下去提前准备。最终这位同学虽然在答辩的时候紧张到声音发抖手打颤,但好歹也算是马马虎虎通过了毕业答辩,能够毕业了。

针对这件事,我本人非常想给大家分享一句话。这句话是我学生时代的导师分享给我的。原话很简单,就六个字:“识不足,则多虑。”什么意思呢,相信语文学得好的小伙伴们一眼就理解了。“识”在这里指的是“学识,知识,学问”,而“虑”字拆开就是“心”“虚”二字,在这里的意思就是“心虚,焦虑”。那么这句话的意思说的就是,学识知识储备不足,或者说是准备不充分,在有一些事情需要你担当或者面对的时候,你就会觉得焦虑、紧张、心虚。我觉得这句话说出了当前大多数年轻人的状态。一碰到考试会紧张,一碰到面试,或者是各种需要面对的场合,会紧张的不得了。多半就是因为我们的准备并不够充分。假设明天考试或面试的场合,只会问你十以内的加减法,那么你一定不会紧张了。为什么,因为你会啊!所以,保证扎实的基本功,厚积薄发,才是我们每个人需要去做的正确的事情。好了,今天前话有点多,下面我们言归正传,进入新的一讲:使用固件库库函数的方式,点亮LED彩灯。

在上一讲的基础上,我们了解了如何新建一个固件库的工程,下面我们直接使用上一讲当中建好的工程进行讲解。

首先我们新建一个文件File,并保存,同时将其命名为main.c,我们的LED点灯的代码就将在这个函数里实现。如下所示

然后将这个main.c添加到我们工程project中的application目录中去

下一步就开始编写C语言代码,点LED灯了。

由原理图可知,LED彩灯中的RGB三种颜色的LED发光二极管分别接在PB5PB0PB1上,并且低电平的时候,能够将其点亮。

因此如果我们要想使这三个灯轮流亮灭,那么只需轮流给PB5PB0PB1三个GPIO口依次输出低电平即可。

那么怎么样才能让PB5PB0PB1三个GPIO口输出低电平呢?带着这个问题,我们继续往下分析。在 大白带你重玩STM32系列(三)------STM32的通用GPIO口(寄存器法操作)》一讲当中,我们已经了解了,如果想让一个GPIO口正常工作,需要以下三个步骤。

1)打开这些GPIO口所对应端口的时钟;

2)配置PB5PB0PB1这三个GPIO口的工作模式;

3)令PB5PB0PB1这三个GPIO口输出高低电平以熄灭或点亮对应的LED发光管。

在第三讲中,我们是使用寄存器的方式来实现的。那么问题来了,在本讲当中,我们要想通过库函数的方式来实现,又该如何操作呢?下面依旧分步进行说明。

1)打开这些GPIO口所对应端口的时钟;

在第三讲当中,我们分析了,要想使用GPIO口,必须激活这个GPIO口所对应的的时钟,而PB端口都挂在APB2总线上,因此,我们需要首先激活APB2总线上的GPIOB端口的时钟。

通过查询STM32f10固件库使用手册(STM32固件库使用手册中文版.pdf摸我下载),可以知道,如果想激活GPIOB端口的时钟,需要使用到函数RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph , FunctionalState NewState)

由上图可以看出,RCC_APB2PeriphClockCmd函数有两个参数:第一个参数是RCC_APB2Periph,这个是APB2外设时钟门控。它的取值范围由下表所示。

第二个参数是一个FunctionalState类型的值,它有两种取值。一是ENABLE,另一个是DISABLE。顾名思义,就是使能和失能两种作用。

由上图中结合官方给出的例子,可以看出,如果我们想使用GPIOB端口,那么我们就应该将GPIOB端口的时钟使能,那么就应该在RCC_APB2PeriphClockCmd这个函数的第一个参数处填入RCC_APB2Periph_GPIOB,在第二个参数处填入ENABLE即可。例如在本节中,我们需要激活GPIOB端口时钟,代码如下:

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);

2)配置PB5PB0PB1这三个GPIO口的工作模式;

第二步,仍然是需要配置PB5PB0PB1三个GPIO口的工作模式,第三讲当中我们分析了,由于我们使用这三个口点亮LED灯(LED灯作为负载),因此需要使用推挽输出的模式,与此同时,我们把GPIO口的输出最大频率设定为50MHz。那么在库函数当中,到底哪个函数才是用来配置GPIO口的工作模式的呢?我们还是打开固件库使用手册。查阅到和GPIO口相关的所有库函数,发现了一个名为 GPIO_Init的函数,在这个里面能够选择使用GPIOxx=ABCDE...)口的端口序号(0~15),同时能够设置这个GPIO口的工作模式以及输出信号的最大频率。如图。

由图可以看出,这个函数的第一个参数是GPIOx,用来选择使用哪个GPIO端口。第二个参数则是指针指向的一个结构体,里面包含了和端口序号,工作模式,最大输出速度相关的参数。首先我们先看一下第一个参数GPIO_Pin。这个参数的取值范围如下图。由图中可知,要想使用PB5只需将GPIO_Pin选择为GPIO_Pin_5即可。程序如下:

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5

接下来是选择GPIO口的工作模式。而工作模式的取值范围如下表。如果想使PB5工作在推挽输出模式下,只需将GPIO_Mode的值选择为GPIO_Mode_Out_PP即可。程序如下:

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

再接着,我们需要配置输出的频率。根据之前的分析,输出频率配置为50MHz即可。由下表可以查到,只需将GPIO_Speed选择为GPIO_Speed_50MHz就行了。

程序如下:

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

分别将以上参数配置好之后,使用GPIO_Init这个函数,把上述配置的参数传递到相应地址中去,完成对此GPIO口的配置。

库函数使用手册中也给我们提供了,使用GPIO_Init这个函数的例程。截图如下:

这是一个将GPIOA端口的所有GPIO口都配置为输入浮空模式且最大频率为10MHz的函数例程。依据这个例程,同时根据以上分析。我们要想把PB5PB0PB1三个GPIO口配置成最大频率为50MH推挽输出模式。可以得到程序如下:

void LED_config(void)

{

GPIO_InitTypeDef GPIO_InitStructure; //定义结构体

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);  //激活GPIOB端口的时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 |GPIO_Pin_0 |GPIO_Pin_1;        //使用PB5PB0PB1三个GPIO

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //PB5PB0PB1三个GPIO口配置成输出频率50MHz

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //PB5PB0PB1三个GPIO口配置成推挽输出模式

GPIO_Init(GPIOB , &GPIO_InitStructure);     //传递配置参数,初始化以上GPIO

}

3)令PB5PB0PB1这三个GPIO口输出高低电平以熄灭或点亮对应的LED发光管。

这一部分中,我们主要解决如何使用库函数点亮或者熄灭LED发光管。我们依旧查看固件库使用手册,发现有这么两个函数GPIO_SetBitsGPIO_ResetBits。他们在固件库中函数的说明如下:

由上图可以看出,GPIO_SetBits函数可以使相应的GPIO口输出高电平信号,而GPIO_ResetBits则可以使相应的GPIO口输出低电平信号。

结合着给出的例程,我们很容易学会使用这两个函数。

例如,在本节中我们分析得出,如果需要点亮红、绿、蓝这三个LED发光二极管,就只需要使PB5PB0PB1三个GPIO口输出低电平即可。因此程序如下:

GPIO_ResetBits(GPIOB , GPIO_Pin_5);  //点亮红色LED

GPIO_ResetBits(GPIOB , GPIO_Pin_0);  //点亮绿色LED

GPIO_ResetBits(GPIOB , GPIO_Pin_1);  //点亮蓝色LED

同理,要想熄灭这三个LED灯,只需使PB5PB0PB1三个GPIO口输出高电平即可。

程序如下:

GPIO_SetBits(GPIOB , GPIO_Pin_5);  //熄灭红色LED

GPIO_SetBits(GPIOB , GPIO_Pin_0);  //熄灭绿色LED

GPIO_SetBits(GPIOB , GPIO_Pin_1);  //熄灭蓝色LED

经过上述1)(2)(3步的分析,我们可以写一个程序实现红绿蓝三个灯轮流闪烁。现将程序贴出如下:

#include "stm32f10x.h"

#define RCC_GPIO_LED        RCC_APB2Periph_GPIOB
#define GPIO_LED_PORT       GPIOB    
#define GPIO_LEDR           GPIO_Pin_5    
#define GPIO_LEDG           GPIO_Pin_0    
#define GPIO_LEDB           GPIO_Pin_1    
#define GPIO_LED_ALL        GPIO_LEDR |GPIO_LEDG |GPIO_LEDB

void LED_config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //定义结构体 

  RCC_APB2PeriphClockCmd(RCC_GPIO_LED | RCC_APB2Periph_AFIO , ENABLE);  //激活GPIOB端口的时钟
  
  GPIO_InitStructure.GPIO_Pin = GPIO_LED_ALL;        //使用PB5、PB0、PB1三个GPIO口
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //将PB5、PB0、PB1三个GPIO口配置成输出频率50MHz
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //将PB5、PB0、PB1三个GPIO口配置成推挽输出模式
  GPIO_Init(GPIO_LED_PORT, &GPIO_InitStructure);     //传递配置参数,初始化以上GPIO口
}

void Led_Turn_on_all(void)
{
	/* Turn On All LEDs */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED_ALL);
}

void Led_Turn_on_R(void)
{
	/* Turn On LED1 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LEDR);
}

void Led_Turn_on_G(void)
{
	/* Turn On LED2 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LEDG );
}

void Led_Turn_on_B(void)
{
	/* Turn On LED3 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LEDB);
}

void Led_Turn_off_all(void)
{
	/* Turn Off All LEDs */
    GPIO_SetBits(GPIO_LED_PORT, GPIO_LED_ALL);
}

void Led_Turn_on(u8 led)
{
    Led_Turn_off_all();

	/* Turn Off Select LED */
    switch(led)
    {
        case 0:
          Led_Turn_on_R();
          break;

        case 1:
          Led_Turn_on_G();
          break;

        case 2:
          Led_Turn_on_B();
          break;
          
        default:
          Led_Turn_on_all();
          break;
    }
}


static void Delay(__IO uint32_t nCount)
{
  for (; nCount != 0; nCount--);
}


int main(void)
{
  u8 KeyNum = 0;

  LED_config();

  while (1)
  {
      Led_Turn_off_all();
      Led_Turn_on(KeyNum%3);
      KeyNum++;
      Delay(5000000);
  }  
}




到此,本讲就算是全部结束啦。GPIO口的操作,还远不止于此。GPIO口的库函数中也还有很多其他的函数可以实现更多的功能。希望读者自行了解一下其他的GPIO口部分其他的一些库函数。为今后的学习做准备。

“路漫漫其修远兮,吾将上下而求索”欢迎继续关注大白带你玩转STM32系列,感谢大家的支持。我会一如既往~

摸我跳转下一节:

大白带你重玩STM32系列(七)------STM32的复位电路与时钟源




关键词: STM32     GPIO    

管理员
2017-05-24 22:12:16    评分
2楼
谢谢楼主分享  涨姿势了

菜鸟
2017-05-24 23:43:41    评分
3楼
厉害了,楼主辛苦了打这么字,讲的很详细,几乎包含gpio操作所有问题。

菜鸟
2017-05-24 23:58:46    评分
4楼
老师码字辛苦了!快更新操作系统的教程吧

专家
2017-05-25 08:36:41    评分
5楼
不错,图文并茂的好贴子。

高工
2017-05-25 11:51:50    评分
6楼
涨知识

菜鸟
2017-05-26 09:36:37    评分
7楼
给祝老师赞一个,我能进入嵌入式行业,祝老师功不可没

专家
2017-05-26 13:43:59    评分
8楼
认真看完,继续跟帖。

高工
2017-05-27 10:46:36    评分
9楼
写的好,学习和参考

工程师
2017-06-15 07:07:01    评分
10楼
祝老师,什么时候更新第七节?

共15条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]