文章目录
- 一、LED
- 本文导读
- 二、常用函数
- 1. 初始化
- 2. 电平控制
- 三、驱动源码分析
- `bsp_led.h`:类型定义与函数声明
- `bsp_led.c`:初始化与电平控制实现
- 四、使用示例
- 1. LED 不亮
- 2. 亮度异常
- 3. 引脚冲突
- 小结
一、LED
本文将介绍 NRF51 如何点亮 LED 灯,涵盖驱动源码分析、使用示例与常见问题排查。
本文导读
本文围绕 NRF51 的点灯流程展开,涵盖以下内容:
- LED 驱动源码分析:通过
bsp_led.h与bsp_led.c了解 LED 的类型定义、初始化及电平控制/翻转函数,可跳转至常用函数。 - 使用示例:演示在
main函数中调用bsp_led_init()、bsp_led_on()、bsp_led_off()、bsp_led_toggle()的完整流程,可跳转至使用示例。 - 常见问题排查:梳理 LED 不亮、亮度异常、引脚冲突等典型问题的排查与解决方法,可跳转至常见问题与排查。
二、常用函数
1. 初始化
voidbsp_led_init(void);voidbsp_led_deinit(void);bsp_led_init()用于初始化 LED 引脚,将其配置为推挽输出并默认关闭所有 LED;bsp_led_deinit()用于反初始化,将引脚恢复为浮空输入并关闭 LED。两个函数均无参数、无返回值。
2. 电平控制
voidbsp_led_on(bsp_led_tch);voidbsp_led_off(bsp_led_tch);voidbsp_led_toggle(bsp_led_tch);bsp_led_on(ch):点亮指定 LED。bsp_led_off(ch):关闭指定 LED。bsp_led_toggle(ch):翻转指定 LED 的电平状态。
下表对三个电平控制函数进行对比,便于快速选择:
| 函数 | 输入参数 | 返回值 | 功能描述 | 典型使用场景 |
|---|---|---|---|---|
bsp_led_on(ch) | ch:LED 组号(bsp_led_t枚举) | void | 点亮指定 LED,根据BS_LEDx_LIGHT_LEVEL输出对应电平 | 状态指示、告警提示、按键反馈等需要点亮 LED 的场景 |
bsp_led_off(ch) | ch:LED 组号(bsp_led_t枚举) | void | 关闭指定 LED,输出与点亮相反的电平 | 熄灭指示灯、复位状态、低功耗待机前关闭 LED 等场景 |
bsp_led_toggle(ch) | ch:LED 组号(bsp_led_t枚举) | void | 翻转指定 LED 的电平状态,亮则灭、灭则亮 | 心跳指示、运行状态闪烁、调试信号输出等场景 |
说明:三个函数的
ch参数均需小于BS_LEDN,否则函数内部会直接返回,不会产生任何操作。
三、驱动源码分析
下面分别从bsp_led.h与bsp_led.c两个文件分析 LED 驱动的类型定义、初始化及电平控制实现。
bsp_led.h:类型定义与函数声明
bsp_led.h定义了 LED 组号枚举bsp_led_t,并声明了初始化、反初始化及电平控制等接口函数:
/******************************************************************************** * @file bsp_led.h * @author jianqiang.xue * @version V1.0.0 * @date 2021-04-03 * @brief LED驱动头文件 ********************************************************************************/#ifndef__BSP_LED_H#define__BSP_LED_H/* Includes ------------------------------------------------------------------*/#include<stdint.h>/* Public enum ---------------------------------------------------------------*/typedefenum{BSP_LED_0=0,BSP_LED_1,BSP_LED_2,BSP_LED_3,BSP_LED_4,BSP_LED_5,BSP_LED_6,BSP_LED_7}bsp_led_t;/* Public Function Prototypes ------------------------------------------------*/voidbsp_led_init(void);voidbsp_led_deinit(void);voidbsp_led_on(bsp_led_tch);voidbsp_led_off(bsp_led_tch);voidbsp_led_toggle(bsp_led_tch);#endif/******************************************************************************** * @file bsp_led.c * @author jianqiang.xue * @version V1.0.0 * @date 2021-07-01 * @brief LED控制 ********************************************************************************//* Includes ------------------------------------------------------------------*/#include"RTE_Components.h"#includeCMSIS_device_header#include"nrf_gpio.h"#include"bsp_gpio.h"#include"bsp_led.h"/* Private Includes ----------------------------------------------------------*/#include"business_gpio.h"#include"business_function.h"/* Private Define ------------------------------------------------------------*//* Private Variables ---------------------------------------------------------*/#ifBS_LEDN!=0staticconstuint16_tg_led_pin[BS_LEDN]={#if(BS_LEDN>0)BS_LED0_PIN#endif#if(BS_LEDN>1),BS_LED1_PIN#endif#if(BS_LEDN>2),BS_LED2_PIN#endif#if(BS_LEDN>3),BS_LED3_PIN#endif#if(BS_LEDN>4),BS_LED4_PIN#endif#if(BS_LEDN>5),BS_LED5_PIN#endif#if(BS_LEDN>6),BS_LED6_PIN#endif#if(BS_LEDN>7),BS_LED7_PIN#endif};staticconstbool g_led_light_state[BS_LEDN]={#if(BS_LEDN>0)BS_LED0_LIGHT_LEVEL#endif#if(BS_LEDN>1),BS_LED1_LIGHT_LEVEL#endif#if(BS_LEDN>2),BS_LED2_LIGHT_LEVEL#endif#if(BS_LEDN>3),BS_LED3_LIGHT_LEVEL#endif#if(BS_LEDN>4),BS_LED4_LIGHT_LEVEL#endif#if(BS_LEDN>5),BS_LED5_LIGHT_LEVEL#endif#if(BS_LEDN>6),BS_LED6_LIGHT_LEVEL#endif#if(BS_LEDN>7),BS_LED7_LIGHT_LEVEL#endif};/* Public Function Prototypes -----------------------------------------------*//** * @brief led初始化 使能引脚时钟 配置为推免输出 * @note NULL * @retval None */voidbsp_led_init(void){uint8_ti;for(i=0;i<BS_LEDN;i++){/* Configure the GPIO_LED pin */bsp_gpio_init_output(NULL,g_led_pin[i],BSP_GPIO_PIN_OUT_PP);/* Reset PIN to switch off the LED */bsp_gpio_set_pin(NULL,g_led_pin[i],(bsp_gpio_pin_state_t)!g_led_light_state[i]);}}/** * @brief led反初始化 将引脚配置为浮空输入 * @note NULL * @retval None */voidbsp_led_deinit(void){uint8_ti;if(BS_LEDN==0){return;}for(i=0;i<BS_LEDN;i++){/* Turn off LED */bsp_gpio_set_pin(NULL,g_led_pin[i],(bsp_gpio_pin_state_t)!g_led_light_state[i]);/* DeInit the GPIO_LED pin */bsp_gpio_deinit(NULL,g_led_pin[i]);}}/** * @brief 点亮LED * @note NULL * @param ch: LED组号 * @retval None */voidbsp_led_on(bsp_led_tch){if(ch>=BS_LEDN){return;}bsp_gpio_set_pin(NULL,g_led_pin[ch],(bsp_gpio_pin_state_t)g_led_light_state[ch]);}/** * @brief 关闭LED * @note NULL * @param ch: LED组号 * @retval None */voidbsp_led_off(bsp_led_tch){if(ch>=BS_LEDN){return;}bsp_gpio_set_pin(NULL,g_led_pin[ch],(bsp_gpio_pin_state_t)!g_led_light_state[ch]);}/** * @brief 翻转LED * @note NULL * @param ch: LED组号 * @retval None */voidbsp_led_toggle(bsp_led_tch){if(ch>=BS_LEDN){return;}bsp_gpio_set_toggle(NULL,g_led_pin[ch]);}#elsevoidbsp_led_init(void){}voidbsp_led_deinit(void){}voidbsp_led_on(bsp_led_tch){}voidbsp_led_off(bsp_led_tch){}voidbsp_led_toggle(bsp_led_tch){}#endifbsp_led.c:初始化与电平控制实现
bsp_led.c实现了上述接口。核心逻辑包括:
- 引脚映射表
g_led_pin[]:通过BS_LEDN与BS_LEDx_PIN宏配置 LED 对应的 GPIO 引脚。 - 电平映射表
g_led_light_state[]:通过BS_LEDx_LIGHT_LEVEL配置每个 LED 的点亮电平(高电平点亮为true,低电平点亮为false)。 - 初始化
bsp_led_init():将引脚配置为推挽输出,并默认输出熄灭电平。 - 反初始化
bsp_led_deinit():关闭 LED 并将引脚恢复为浮空输入。 - 电平控制
bsp_led_on()/bsp_led_off()/bsp_led_toggle():根据ch参数操作对应引脚,ch越界时直接返回。
四、使用示例
下面通过一个完整的main函数示例,演示如何调用bsp_led_init()、bsp_led_on()、bsp_led_off()和bsp_led_toggle()。
需要注意的是,示例中的nrf_delay_ms()仅用于示意,实际开发时可根据 SDK 版本替换为其它延时函数。
#include<stdbool.h>#include"nrf_delay.h"/* 根据需要引入对应延时函数 */#include"bsp_led.h"/* 引入 LED 驱动接口 */intmain(void){/* 1. 初始化 LED 引脚为推挽输出,并默认关闭 LED */bsp_led_init();while(true){/* 2. 点亮 LED0 */bsp_led_on(BSP_LED_0);nrf_delay_ms(500);/* 3. 关闭 LED0 */bsp_led_off(BSP_LED_0);nrf_delay_ms(500);/* 4. 翻转 LED0 电平:若当前为亮则熄灭,若为灭则点亮 */bsp_led_toggle(BSP_LED_0);nrf_delay_ms(500);/* 5. 再次翻转,恢复到本轮回退前的状态 */bsp_led_toggle(BSP_LED_0);nrf_delay_ms(500);}}以上流程会形成 LED0 “亮 → 灭 → 亮 → 灭”的循环效果。实际使用时请根据硬件连接确认BSP_LED_0对应的 GPIO 引脚,并确保BS_LEDN大于 0。
下面再演示同时控制多个 LED 的场景:让BSP_LED_0与BSP_LED_1交替闪烁。实际使用时,请根据硬件原理图确认BS_LED0_PIN与BS_LED1_PIN对应的 GPIO 引脚号。
#include<stdbool.h>#include"nrf_delay.h"/* 根据需要引入对应延时函数 */#include"bsp_led.h"/* 引入 LED 驱动接口 */intmain(void){/* 1. 初始化所有 LED 引脚为推挽输出,并默认关闭 LED */bsp_led_init();while(true){/* 2. 点亮 LED0(对应引脚 BS_LED0_PIN,高电平点亮时输出高电平) */bsp_led_on(BSP_LED_0);/* 3. 关闭 LED1(对应引脚 BS_LED1_PIN,输出与点亮相反的电平) */bsp_led_off(BSP_LED_1);nrf_delay_ms(500);/* 4. 关闭 LED0 */bsp_led_off(BSP_LED_0);/* 5. 点亮 LED1 */bsp_led_on(BSP_LED_1);nrf_delay_ms(500);}}以上流程会形成 LED0 与 LED1 交替闪烁的效果:LED0 亮时 LED1 灭,LED0 灭时 LED1 亮。请确保BS_LEDN大于等于 2,且BS_LED0_PIN、BS_LED1_PIN与硬件连接一致。
若需要同时控制多个 LED,可分别调用bsp_led_on()/bsp_led_off()操作不同的bsp_led_t枚举值。## 常见问题与排查
1. LED 不亮
现象:调用bsp_led_on()后 LED 没有任何反应。
排查步骤:
- 确认
bsp_led_init()是否已被调用。 - 检查
g_led_pin[]中的引脚号是否与硬件原理图一致。 - 检查
BS_LEDN是否大于 0;若为 0,所有 LED 函数都是空实现。 - 用万用表测量 GPIO 引脚电平,观察调用
bsp_led_on()前后电平是否变化。 - 确认该引脚没有被其它外设抢占,也没有被
bsp_led_deinit()反初始化。
解决方法:
- 修正引脚配置,并在使用前调用
bsp_led_init()。 - 核对
BS_LEDx_LIGHT_LEVEL的电平逻辑:高电平点亮的 LED 配置为true,低电平点亮的 LED 配置为false。
2. 亮度异常
现象:LED 能点亮,但亮度偏暗、偏亮或闪烁。
排查步骤:
- 检查 GPIO 是否配置为推挽输出,避免误配为开漏或输入模式。
- 检查硬件限流电阻与供电电压是否合理。
- 确认该引脚没有被其它外设复用,导致电平被拉低或拉高。
- 检查快速翻转时 GPIO 是否发生误操作。
解决方法:
- 将 GPIO 配置为
BSP_GPIO_PIN_OUT_PP推挽输出。 - 根据 LED 参数调整限流电阻。
- 给 LED 分配独立、空闲的 GPIO 引脚。
3. 引脚冲突
现象:LED 点亮后影响串口、SPI、I2C 等功能,或外设初始化后 LED 失控。
排查步骤:
- 核对
g_led_pin[]使用的引脚是否与外设复用。 - 查看芯片默认引脚功能和复用配置,确认初始化顺序是否会互相覆盖。
- 检查 LED 使用完成后是否正确调用
bsp_led_deinit()释放引脚。
解决方法:
- 更换空闲 GPIO 驱动 LED。
- 如需复用引脚,明确引脚占用与释放时机,避免同时初始化。
下表汇总了三类常见问题的现象、可能原因与解决方法,便于快速查阅:
| 问题 | 现象 | 可能原因 | 解决方法 |
|---|---|---|---|
| LED 不亮 | 调用bsp_led_on()后 LED 没有任何反应 | 未调用bsp_led_init();引脚号与原理图不一致;BS_LEDN为 0;电平逻辑配置错误;引脚被其它外设抢占 | 使用前调用bsp_led_init();核对g_led_pin[]引脚号;确保BS_LEDN大于 0;核对BS_LEDx_LIGHT_LEVEL电平逻辑;释放被占用的引脚 |
| 亮度异常 | LED 能点亮,但亮度偏暗、偏亮或闪烁 | GPIO 未配置为推挽输出;限流电阻或供电电压不合理;引脚被外设复用拉低/拉高电平;快速翻转导致误操作 | 将 GPIO 配置为BSP_GPIO_PIN_OUT_PP推挽输出;根据 LED 参数调整限流电阻;给 LED 分配独立、空闲的 GPIO 引脚 |
| 引脚冲突 | LED 点亮后影响串口、SPI、I2C 等功能,或外设初始化后 LED 失控 | g_led_pin[]与外设复用;初始化顺序互相覆盖;使用完成后未释放引脚 | 更换空闲 GPIO 驱动 LED;明确引脚占用与释放时机,避免同时初始化;使用完成后调用bsp_led_deinit()释放引脚 |
提示:排查问题时建议先确认 GPIO 引脚配置、电平逻辑与初始化调用,再结合硬件连接逐项核对,可快速定位大多数故障。
小结
本节介绍了 NRF51 点亮 LED 的常用函数与排查方法。
核心要点:先通过bsp_led_init()完成引脚初始化,再使用bsp_led_on()/bsp_led_off()/bsp_led_toggle()控制电平;
实际开发时应先确认 GPIO 引脚配置、电平逻辑和初始化调用,遇到问题优先排查硬件连接与引脚复用情况。