各位盆友们,我们有两周没见了,这两周楼主所在的学校开始进行本科生的毕业答辩了,时间上确实有点忙,导致帖子稍有耽搁,接下来的两周我会加紧赶一赶,大家不要太心急哦。
既然说到了毕业设计,楼主就在这里给大家分享一下毕业设计过程中的一些小插曲。情况是这样的。楼主指导的几位同学的其中一个,在答辩前两天告诉我:“老师,我紧张的不行了,这两天都睡不着觉。总是做梦梦到自己会挂掉,毕不了业。害怕答辩老师会问到我不会回答的问题。”
这位同学是我所带学生里面做毕业设计不怎么用心的一位同学,而作为他的指导老师,在这个节骨眼上,我可是对他好一顿精心的安慰+鼓励,告诉他不用紧张,把论文和毕业设计多看几遍多了解了解,并站在答辩老师的角度给他提出了几个问题,让他下去提前准备。最终这位同学虽然在答辩的时候紧张到声音发抖手打颤,但好歹也算是马马虎虎通过了毕业答辩,能够毕业了。
针对这件事,我本人非常想给大家分享一句话。这句话是我学生时代的导师分享给我的。原话很简单,就六个字:“识不足,则多虑。”什么意思呢,相信语文学得好的小伙伴们一眼就理解了。“识”在这里指的是“学识,知识,学问”,而“虑”字拆开就是“心”“虚”二字,在这里的意思就是“心虚,焦虑”。那么这句话的意思说的就是,学识知识储备不足,或者说是准备不充分,在有一些事情需要你担当或者面对的时候,你就会觉得焦虑、紧张、心虚。我觉得这句话说出了当前大多数年轻人的状态。一碰到考试会紧张,一碰到面试,或者是各种需要面对的场合,会紧张的不得了。多半就是因为我们的准备并不够充分。假设明天考试或面试的场合,只会问你十以内的加减法,那么你一定不会紧张了。为什么,因为你会啊!所以,保证扎实的基本功,厚积薄发,才是我们每个人需要去做的正确的事情。好了,今天前话有点多,下面我们言归正传,进入新的一讲:使用固件库库函数的方式,点亮LED彩灯。
在上一讲的基础上,我们了解了如何新建一个固件库的工程,下面我们直接使用上一讲当中建好的工程进行讲解。
首先我们新建一个文件File,并保存,同时将其命名为main.c,我们的LED点灯的代码就将在这个函数里实现。如下所示
然后将这个main.c添加到我们工程project中的application目录中去
下一步就开始编写C语言代码,点LED灯了。
由原理图可知,LED彩灯中的R、G、B三种颜色的LED发光二极管分别接在PB5、PB0、PB1上,并且低电平的时候,能够将其点亮。
因此如果我们要想使这三个灯轮流亮灭,那么只需轮流给PB5、PB0、PB1三个GPIO口依次输出低电平即可。
那么怎么样才能让PB5、PB0、PB1三个GPIO口输出低电平呢?带着这个问题,我们继续往下分析。在 《大白带你重玩STM32系列(三)------STM32的通用GPIO口(寄存器法操作)》一讲当中,我们已经了解了,如果想让一个GPIO口正常工作,需要以下三个步骤。
(1)打开这些GPIO口所对应端口的时钟;
(2)配置PB5,PB0,PB1这三个GPIO口的工作模式;
(3)令PB5,PB0,PB1这三个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)配置PB5,PB0,PB1这三个GPIO口的工作模式;
第二步,仍然是需要配置PB5、PB0、PB1三个GPIO口的工作模式,第三讲当中我们分析了,由于我们使用这三个口点亮LED灯(LED灯作为负载),因此需要使用推挽输出的模式,与此同时,我们把GPIO口的输出最大频率设定为50MHz。那么在库函数当中,到底哪个函数才是用来配置GPIO口的工作模式的呢?我们还是打开固件库使用手册。查阅到和GPIO口相关的所有库函数,发现了一个名为 GPIO_Init的函数,在这个里面能够选择使用GPIOx(x=A、B、C、D、E...)口的端口序号(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的函数例程。依据这个例程,同时根据以上分析。我们要想把PB5、PB0、PB1三个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; //使用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(GPIOB , &GPIO_InitStructure); //传递配置参数,初始化以上GPIO口
}
(3)令PB5,PB0,PB1这三个GPIO口输出高低电平以熄灭或点亮对应的LED发光管。
这一部分中,我们主要解决如何使用库函数点亮或者熄灭LED发光管。我们依旧查看固件库使用手册,发现有这么两个函数GPIO_SetBits和GPIO_ResetBits。他们在固件库中函数的说明如下:
由上图可以看出,GPIO_SetBits函数可以使相应的GPIO口输出高电平信号,而GPIO_ResetBits则可以使相应的GPIO口输出低电平信号。
结合着给出的例程,我们很容易学会使用这两个函数。
例如,在本节中我们分析得出,如果需要点亮红、绿、蓝这三个LED发光二极管,就只需要使PB5、PB0、PB1三个GPIO口输出低电平即可。因此程序如下:
GPIO_ResetBits(GPIOB , GPIO_Pin_5); //点亮红色LED灯
GPIO_ResetBits(GPIOB , GPIO_Pin_0); //点亮绿色LED灯
GPIO_ResetBits(GPIOB , GPIO_Pin_1); //点亮蓝色LED灯
同理,要想熄灭这三个LED灯,只需使PB5、PB0、PB1三个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口部分其他的一些库函数。为今后的学习做准备。
“路漫漫其修远兮,吾将上下而求索”欢迎继续关注大Z带你玩转STM32系列,感谢大家的支持。我会一如既往~