历史上的今天
返回首页

历史上的今天

今天是: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 软件自动根据注释生成帮助文档。

推荐阅读

史海拾趣

Cal Test Electronics公司的发展小趣事

随着客户需求的多样化,Cal Test Electronics开始关注小批量定制型测试电缆组件的市场。公司利用自身的技术优势和生产能力,为客户提供个性化的定制服务。这些定制产品不仅满足了客户的特殊需求,也提高了公司的市场竞争力。通过这一策略,Cal Test Electronics成功打开了一个全新的市场领域,为公司的发展注入了新的动力。

BusBoard Prototype Systems公司的发展小趣事

在发展过程中,BusBoard Prototype Systems深知单打独斗难以取得长远的发展。因此,公司积极寻求与上下游企业的合作,共同推动电子行业的发展。通过与芯片制造商、软件开发商等建立紧密的合作伙伴关系,BusBoard不仅能够获得更优质的资源支持,还能够为客户提供更加全面的解决方案。

倍思特(BEST)公司的发展小趣事

在发展过程中,BusBoard Prototype Systems深知单打独斗难以取得长远的发展。因此,公司积极寻求与上下游企业的合作,共同推动电子行业的发展。通过与芯片制造商、软件开发商等建立紧密的合作伙伴关系,BusBoard不仅能够获得更优质的资源支持,还能够为客户提供更加全面的解决方案。

Daito Communication Apparatus Co Ltd公司的发展小趣事

随着微电子学的快速发展,电子设备对元器件的要求也越来越高。Daito公司敏锐地捕捉到了这一市场趋势,决定对保险丝进行进一步的创新。在1995年,他们成功开发出了适用于电路板安装的高精度小型报警保险丝。这一产品的推出,不仅满足了市场对小型化、高精度保险丝的需求,也进一步巩固了Daito公司在电子行业中的领先地位。

随后,Daito公司又针对微电子学的进一步发展,推出了可以连续自动安装的方形微型保险丝。这一产品的推出,大大提高了生产效率,降低了成本,同时也为客户提供了更加便捷的使用体验。近年来,随着面安装技术的兴起,Daito公司又迅速推出了适用于面安装技术的片状保险丝,再次展示了他们在电子行业中的创新实力。

请注意,由于篇幅限制,以上仅为两个故事示例。如果需要更多故事,可以进一步深入研究和探索Daito公司在电子行业中的发展历程和创新实践。

Epitex Inc公司的发展小趣事

随着技术的不断进步,Epitex不断加大对研发的投入。XXXX年,他们成功研发出了一种具有更高导热性能的电子材料,这种材料在高性能计算机和服务器等高端电子产品中得到了广泛应用。这一技术突破不仅提升了Epitex的市场竞争力,也为其带来了可观的经济效益。

在技术突破的基础上,Epitex开始积极拓展国际市场。他们通过与全球知名的电子制造商建立合作关系,将产品推向了更广阔的舞台。同时,Epitex还积极参与国际技术交流和展览,提升了公司在国际市场的知名度。

Focus公司的发展小趣事

Focus科技股份有限公司(虚构)在深耕外贸电商领域的同时,也敏锐地捕捉到了教育与医疗行业的数字化转型机遇。公司利用自身在互联网技术和大数据分析方面的优势,研发了智慧教育平台和移动医疗应用。智慧教育平台通过提供个性化学习资源和在线互动教学服务,有效提升了教育资源的利用率和学生的学习效果;移动医疗应用则通过远程医疗咨询、健康管理等功能,为用户提供了便捷的医疗服务体验。这些跨界融合的产品不仅丰富了公司的业务线,也进一步提升了公司的品牌影响力和市场竞争力。

问答坊 | AI 解惑

模拟电路设计黄金时代结束了吗?

在ISSCC大会开幕的头一天晚上,按照惯例举办了一场晚间技术研讨会。其中,由模拟技术研究领域的著名研究员们进行研讨的模拟电路技术专题研讨会,是每次都有众多人员参加的重头会议。今年的主题是“模拟电路设计的黄金时代结束了吗?(Is the Golden ...…

查看全部问答>

基于台达PLC 的工厂产量监控查询系统

:局限于技术条件,目前生产中在统计生产产品产量方面不少还是依靠人工进行统计。在实际操作过程中,往往出现产品严重丢失,投入的原料量和产出的成品量严重失衡,因此,有必要采用工厂产量监控查询系统对整个工厂的产品产量进行准确的计量,文章基 ...…

查看全部问答>

节能灯的标准长度

节能灯的标准长度怎么规定?有标准的规定吗?…

查看全部问答>

cpld资源问题讨论

cpld在编码和译码的时候占用的资源很大,不知哪位大虾可有什么妙法来减少资源的使用吗?如何较少宏单元的使用呢?…

查看全部问答>

MSP430F449 接455K晶振问题

不能起振,有解决办法吗? 同样的板,有的可以,有的不行 电容配多少合适?…

查看全部问答>

GPRS模块

M660是一款可支持开放平台的GSM/GPRS工业无线模块,预留了CPU资源以及丰富的硬件接口,可以提供高品质的语音、短信、数据业务等功能,在各种工业和民用领域得到广泛的应用。 产品特性:  双频:900M / 1800M  可靠性高:特殊EMI ...…

查看全部问答>

业余时间想做个遥控小车,问个问题?

我想用wifi控制小车,并在小车上装个摄像头,把视频传到PC端显示,看到网上很多成功的,但不知道具体的实现,有谁做过吗?比如小车上用什么操作系统?实时性怎么样?用arm直接控制马达还是单加一个单片机?越具体越好,谢谢大家了…

查看全部问答>

【C2000 LaunchPad】单相交流电压+电流表__算法篇

目前,电力行业里面计算电量参数使用最多的是傅里叶算法(FFT)。网上有一篇非常经典的关于FFT的介绍文章“FFT结果的物理意义”,作者是网络名人“电脑圈圈”。我就不多说了。直接转载过来,给大家参考。    FFT是离散傅立叶变换的快 ...…

查看全部问答>

TIVA C Launchpad第四周的心得---ADC

程序内容:Launchpad使用ADC1 通道0采集信号源产生的正弦波(1Vp-p,offset 0.5V,5KHz)。 根据以前学习的方法导入存在的工程文件Lab5,根据程序内容修改其中的ADC的设置。 源程序是使用了Workshop中的Lab5修改而来。 调试界面: 采集100 ...…

查看全部问答>