历史上的今天
今天是:2024年12月15日(星期日)
2021年12月15日 | STM32固件库实现点亮LED
2021-12-15
前言
使用固件库点亮LED
提示:以下是本篇文章正文内容
一、原理图

二、软件设计
在工程之上新建“bsp_led.c”及“bsp_led.h”文件,这些文件不属于STM32 标准库的内容,是由我们自己根据应用需要编写的,编程步骤如下:
使能 GPIO 端口时钟;
初始化 GPIO 目标引脚为推挽输出模式;
编写简单测试程序,控制 GPIO 引脚输出高、低电平
三、代码
1.LED 灯引脚宏定义
在编写应用程序的过程中,要考虑更改硬件环境的情况,即提高可移植性。
这个时候一般把硬件相关的部分使用宏来封装,若更改了硬件环境,只修改这些硬件相关的宏即可,这
些定义一般存储在头文件,即本例子中的“bsp_led.h”文件中
代码如下:
// R-红色
#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED1_GPIO_PIN GPIO_Pin_5
// G-绿色
#define LED2_GPIO_PORT GPIOB
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED2_GPIO_PIN GPIO_Pin_0
// B-蓝色
#define LED3_GPIO_PORT GPIOB
#define LED3_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED3_GPIO_PIN GPIO_Pin_1
以上代码分别把控制 LED 灯的 GPIO 端口、GPIO 引脚号以及 GPIO 端口时钟封装起来了。在实际控制的时候我们就直接用这些宏,以达到应用代码硬件无关的效果。
2. 控制 LED 灯亮灭状态的宏定义
为了方便控制 LED 灯,我们把 LED 灯常用的亮、灭及状态反转的控制也直接定义成宏。
/* 直接操作寄存器的方法控制 IO */
#define digitalHi(p,i) {p->BSRR=i;} //输出为高电平
#define digitalLo(p,i) {p->BRR=i;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态
#define LED2_TOGGLE digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_OFF digitalHi(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_ON digitalLo(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED3_TOGGLE digitalToggle(LED2_GPIO_PORT,LED3_GPIO_PIN)7
#define LED3_OFF digitalHi(LED2_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_ON digitalLo(LED2_GPIO_PORT,LED3_GPIO_PIN)
/* 定义控制 IO 的宏 */
#define LED1_TOGGLE digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_OFF digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_ON digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)
//红
#define LED_RED
LED1_ON;
LED2_OFF
LED3_OFF
这部分宏控制 LED 亮灭的操作是直接向 BSRR、BRR 和 ODR 这三个寄存器写入控制指令来实现的,对 BSRR 写 1 输出高电平,对 BRR 写 1 输出低电平,对 ODR 寄存器某位进行异或操作可反转位的状态。
代码中的“”是 C 语言中的续行符语法,表示续行符的下一行与续行符所在的代码是同一行。代码中因为宏定义关键字“#define”只是对当前行有效,所以我们使用续行符来连接起来,应用续行符的时候要注意,在“”后面不能有任何字符(包括注释、空格),只能直接回车。
3. LED GPIO 初始化函数
利用上面的宏,编写 LED 灯的初始化函数
1 void LED_GPIO_Config(void)
2 {
3 /*定义一个 GPIO_InitTypeDef 类型的结构体*/
4 GPIO_InitTypeDef GPIO_InitStructure;
5
6 /*开启 LED 相关的 GPIO 外设时钟*/
7 RCC_APB2PeriphClockCmd( LED1_GPIO_CLK|
8 LED2_GPIO_CLK|
9 LED3_GPIO_CLK, ENABLE);
10 /*选择要控制的 GPIO 引脚*/
11 GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
12
13 /*设置引脚模式为通用推挽输出*/
14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
15
16 /*设置引脚速率为 50MHz */
17 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
18
19 /*调用库函数,初始化 GPIO*/
20 GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);
21
22 /*选择要控制的 GPIO 引脚*/
23 GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;
24
25 /*调用库函数,初始化 GPIO*/
26 GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
27
28 /*选择要控制的 GPIO 引脚*/
29 GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;
30
31 /*调用库函数,初始化 GPIOF*/
32 GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);
33
34 /* 关闭所有 led 灯 */
35 GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
36
37 /* 关闭所有 led 灯 */
38 GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);
39
40 /* 关闭所有 led 灯 */
41 GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
函数执行流程如下:
(1) 使用 GPIO_InitTypeDef 定义 GPIO 初始化结构体变量,以便下面用于存储 GPIO 配置。
(2) 调用库函数 RCC_APB2PeriphClockCmd 来使能 LED 灯的 GPIO 端口时钟。
(3) 向 GPIO 初始化结构体赋值,把引脚初始化成推挽输出模式。
(4) 使用以上初始化结构体的配置,调用 GPIO_Init 函数向寄存器写入参数,完成 GPIO 的初始化。
(5) 使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它 LED 灯使用的GPIO 引脚。
(6) 使用宏控制 RGB 灯默认关闭。
4. 主函数
编写完 LED 灯的控制函数后,就可以在 main 函数中测试了:
1 #include "stm32f10x.h"
2 #include "./led/bsp_led.h"
3
4 #define SOFT_DELAY Delay(0x0FFFFF);
5
6 void Delay(__IO u32 nCount);
7
8 /**
9 * @brief 主函数
10 * @param 无
11 * @retval 无
12 */
13 int main(void)
14 {
15 /* LED 端口初始化 */
16 LED_GPIO_Config();
17
18 while (1)
19 {
20 LED1_ON; // 亮
21 SOFT_DELAY;
22 LED1_OFF; // 灭
23
24 LED2_ON; // 亮
25 SOFT_DELAY;
26 LED2_OFF; // 灭
27
28 LED3_ON; // 亮
29 SOFT_DELAY;
30 LED3_OFF; // 灭
31
32 /*轮流显示 红绿蓝黄紫青白 颜色*/
33 LED_RED;
34 SOFT_DELAY;
35
36 LED_GREEN;
37 SOFT_DELAY;
38
39 LED_BLUE;
40 SOFT_DELAY;
41
42 LED_YELLOW;
43 SOFT_DELAY;
44
45 LED_PURPLE;
46 SOFT_DELAY;
47
48 LED_CYAN;
49 SOFT_DELAY;
50
51 LED_WHITE;
52 SOFT_DELAY;
53
54 LED_RGBOFF;
55 SOFT_DELAY;
56 }
57 }
58
59 void Delay(__IO uint32_t nCount) //简单的延时函数
60 {
61 for (; nCount != 0; nCount--);
62 }
在 main 函数中,调用我们前面定义的 LED_GPIO_Config 初始化好 LED 的控制引脚,然后直接调用各种控制 LED 灯亮灭的宏来实现 LED 灯的控制。
四、下载验证
把编译好的程序下载到开发板并复位,可看到 RGB 彩灯轮流显示不同的颜色。

五、收获
1.如何防止头文件重复包含
1 #ifndef __LED_H
2 #define __LED_H
在头文件的开头,使用“#ifndef”关键字,判断标号“__LED_H”是否被定义,若没有被定义,则从“#ifndef”至“#endif”关键字之间的内容都有效,也就是说,这个头文件若被其它文件“#include”,它就会被包含到其该文件中了,且头文件中紧接着使用“#define”关键字定义上面判断的标号“__LED_H”。当这个头文件被同一个文件第二次“#include”包含的时候,由于有了第一次包含中的“#define __LED_H”定义,这时再判断“#ifndef __LED_H”,判断的结果就是假了,从“#ifndef”至“#endif”之间的内容都无效,从而防止了同一个头文件被包含多次,编译时就不会出现“redefine(重复定义)”的错误了。
2.注释规范
/**
2 * @brief 初始化控制 LED 的 IO
3 * @param 无
4 * @retval 无
5 */
这是一种名为“Doxygen”的注释规范,如果在工程文件中按照这种规范去注释,可以使用 Doxygen 软件自动根据注释生成帮助文档。
上一篇:STM32固件库实现按键控制
史海拾趣
|
在ISSCC大会开幕的头一天晚上,按照惯例举办了一场晚间技术研讨会。其中,由模拟技术研究领域的著名研究员们进行研讨的模拟电路技术专题研讨会,是每次都有众多人员参加的重头会议。今年的主题是“模拟电路设计的黄金时代结束了吗?(Is the Golden ...… 查看全部问答> |
|
:局限于技术条件,目前生产中在统计生产产品产量方面不少还是依靠人工进行统计。在实际操作过程中,往往出现产品严重丢失,投入的原料量和产出的成品量严重失衡,因此,有必要采用工厂产量监控查询系统对整个工厂的产品产量进行准确的计量,文章基 ...… 查看全部问答> |
|
我想用wifi控制小车,并在小车上装个摄像头,把视频传到PC端显示,看到网上很多成功的,但不知道具体的实现,有谁做过吗?比如小车上用什么操作系统?实时性怎么样?用arm直接控制马达还是单加一个单片机?越具体越好,谢谢大家了… 查看全部问答> |
|
【C2000 LaunchPad】单相交流电压+电流表__算法篇 目前,电力行业里面计算电量参数使用最多的是傅里叶算法(FFT)。网上有一篇非常经典的关于FFT的介绍文章“FFT结果的物理意义”,作者是网络名人“电脑圈圈”。我就不多说了。直接转载过来,给大家参考。 FFT是离散傅立叶变换的快 ...… 查看全部问答> |
|
程序内容:Launchpad使用ADC1 通道0采集信号源产生的正弦波(1Vp-p,offset 0.5V,5KHz)。 根据以前学习的方法导入存在的工程文件Lab5,根据程序内容修改其中的ADC的设置。 源程序是使用了Workshop中的Lab5修改而来。 调试界面: 采集100 ...… 查看全部问答> |




