[应用相关] 驱动可配置化开发 --- LED驱动

[复制链接]
562|17
 楼主| condition 发表于 2020-5-10 09:26 | 显示全部楼层 |阅读模式
本博客中示例代码下载路径: https://github.com/maziot-stm32/A1/releases/tag/v0.6


作者:mz8023yt
链接:https://www.jianshu.com/p/3b332a82b0f1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 楼主| condition 发表于 2020-5-10 09:26 | 显示全部楼层
驱动可配置化开发
前面已经提到了代码要分层, 便于理解和阅读代码. 这里针对其中的驱动层引入一个新的概念, 驱动可配置化开发.
 楼主| condition 发表于 2020-5-10 09:27 | 显示全部楼层
何为可配置化开发, 举个最简单的例子:
原来我的 STM32F103RC 小板子(简称A1设备)上 PA8 和 PD2 接了一个 LED 灯, 现在我重新画了一个板子(简称C3设备), 用的依然是 F103RC 主控, 但是 LED 灯的接在 PC13 引脚上. 现在我希望 C3 可以直接复用 A1 的驱动, 驱动代码中改动量控制在仅仅只需要修改硬件上外挂的 LED 灯个数, 有效电平, 连接的 GPIO 引脚等与硬件电路强相关的信息, 其余与硬件不相关的代码不需要做任何修改.
 楼主| condition 发表于 2020-5-10 09:28 | 显示全部楼层
简单总结下:

可配置化开发目的是为了提高代码的复用性
可配置化开发将与硬件设计强相关的参数剥离出来, 针对不同的设备做不同的配置
 楼主| condition 发表于 2020-5-10 09:28 | 显示全部楼层
LED 驱动可配置化抽象
基于上面的概念, 想一下, LED 灯与硬件强相关的配置有哪些?
目前我想到的有这些:

硬件连接: 接在STM32的哪个GPIO口上, 包括PORT和PIN.
有效电平: 高电平点亮还是低电平点亮.
默认状态: 上电后默认是点亮还是熄灭.
 楼主| condition 发表于 2020-5-10 09:30 | 显示全部楼层
用结构体描述如下:
  1. typedef struct _MAZDRV_LED_CTRL_
  2. {
  3.     MAZDRV_LED_GPIO_PORT port;              // 连接LED的GPIO PORT
  4.     MAZDRV_LED_GPIO_PIN pin;                // 连接LED的GPIO PIN
  5.     MAZDRV_LED_GPIO_LEVEL light;            // 高电平还是低电平点亮
  6.     MAZDRV_LED_STATUS status;               // 默认状态是点亮还是熄灭
  7. } MAZDRV_LED_CTRL;
 楼主| condition 发表于 2020-5-10 09:31 | 显示全部楼层
每一个成员分别定义对应的枚举类型, 用于规范配置项, 枚举定义如下:

  1. typedef enum _MAZDRV_LED_GPIO_PORT_
  2. {
  3.     MAZDRV_LED_GPIO_PORTA = GPIOA_BASE,
  4.     MAZDRV_LED_GPIO_PORTB = GPIOB_BASE,
  5.     MAZDRV_LED_GPIO_PORTC = GPIOC_BASE,
  6.     MAZDRV_LED_GPIO_PORTD = GPIOD_BASE,
  7.     MAZDRV_LED_GPIO_PORTE = GPIOE_BASE,
  8.     MAZDRV_LED_GPIO_PORTF = GPIOF_BASE,
  9.     MAZDRV_LED_GPIO_PORTG = GPIOG_BASE,
  10. } MAZDRV_LED_GPIO_PORT;

  11. typedef enum _MAZDRV_LED_GPIO_PIN_
  12. {
  13.     MAZDRV_LED_GPIO_PIN0 = GPIO_PIN_0,
  14.     MAZDRV_LED_GPIO_PIN1 = GPIO_PIN_1,
  15.     MAZDRV_LED_GPIO_PIN2 = GPIO_PIN_2,
  16.     MAZDRV_LED_GPIO_PIN3 = GPIO_PIN_3,
  17.     MAZDRV_LED_GPIO_PIN4 = GPIO_PIN_4,
  18.     MAZDRV_LED_GPIO_PIN5 = GPIO_PIN_5,
  19.     MAZDRV_LED_GPIO_PIN6 = GPIO_PIN_6,
  20.     MAZDRV_LED_GPIO_PIN7 = GPIO_PIN_7,
  21.     MAZDRV_LED_GPIO_PIN8 = GPIO_PIN_8,
  22.     MAZDRV_LED_GPIO_PIN9 = GPIO_PIN_9,
  23.     MAZDRV_LED_GPIO_PIN10 = GPIO_PIN_10,
  24.     MAZDRV_LED_GPIO_PIN11 = GPIO_PIN_11,
  25.     MAZDRV_LED_GPIO_PIN12 = GPIO_PIN_12,
  26.     MAZDRV_LED_GPIO_PIN13 = GPIO_PIN_13,
  27.     MAZDRV_LED_GPIO_PIN14 = GPIO_PIN_14,
  28.     MAZDRV_LED_GPIO_PIN15 = GPIO_PIN_15,
  29.     MAZDRV_LED_GPIO_PIN_ALL = GPIO_PIN_All,
  30. } MAZDRV_LED_GPIO_PIN;

  31. typedef enum _MAZDRV_LED_GPIO_LEVEL_
  32. {
  33.     MAZDRV_LED_GPIO_LEVEL_HIGH = GPIO_PIN_SET,
  34.     MAZDRV_LED_GPIO_LEVEL_LOW = GPIO_PIN_RESET,
  35. } MAZDRV_LED_GPIO_LEVEL;

  36. typedef enum _MAZDRV_LED_STATUS_
  37. {
  38.     MAZDRV_LED_STATUS_ON = 0,
  39.     MAZDRV_LED_STATUS_OFF,
  40.     MAZDRV_LED_STATUS_TOGGLE,
  41. } MAZDRV_LED_STATUS;
 楼主| condition 发表于 2020-5-10 09:32 | 显示全部楼层
基于上述剥离出来的参数, 硬件上不同的 LED 灯就可以用 MAZDRV_LED_CTRL 对象来描述了. 示例代码如下:
  1. typedef enum _MAZDRV_LED_
  2. {
  3.     MAZDRV_LED0 = 0,
  4.     MAZDRV_LED1,
  5.     MAZDRV_LED_MAX,
  6. } MAZDRV_LED;

  7. static MAZDRV_LED_CTRL g_mazdrv_led_ctrl[MAZDRV_LED_MAX] =
  8. {
  9.     [MAZDRV_LED0] =
  10.     {
  11.         .port   = MAZDRV_LED_GPIO_PORTA,
  12.         .pin    = MAZDRV_LED_GPIO_PIN8,
  13.         .light  = MAZDRV_LED_GPIO_LEVEL_LOW,
  14.         .status = MAZDRV_LED_STATUS_OFF,
  15.     },
  16.     [MAZDRV_LED1] =
  17.     {
  18.         .port   = MAZDRV_LED_GPIO_PORTD,
  19.         .pin    = MAZDRV_LED_GPIO_PIN2,
  20.         .light  = MAZDRV_LED_GPIO_LEVEL_LOW,
  21.         .status = MAZDRV_LED_STATUS_OFF,
  22.     },
  23. };
 楼主| condition 发表于 2020-5-10 09:33 | 显示全部楼层
LED 可配置化驱动程序
上面通过 MAZDRV_LED_CTRL 对象将硬件上 LED 的信息描述出来了. 现在我们的驱动就必须以这些硬件信息为输入, 支持各种各样的配置情况.
 楼主| condition 发表于 2020-5-10 09:33 | 显示全部楼层
LED 初始化:

  1. int MAZ_Drv_led_init(void)
  2. {
  3.     MAZDRV_LED led;
  4.     MAZDRV_LED_CTRL *ctrl = NULL;
  5.     GPIO_InitTypeDef GPIO_InitStruct = { 0 };

  6.     ctrl = g_mazdrv_led_ctrl;

  7.     for (led = MAZDRV_LED0; led < MAZDRV_LED_MAX; led++)
  8.     {
  9.         /* GPIO Ports Clock Enable */
  10.         MAZ_Drv_led_gpio_prot_clk_enable(led);

  11.         /* Configure GPIO pin */
  12.         GPIO_InitStruct.Pin = ctrl[led].pin;
  13.         GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  14.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  15.         GPIO_InitStruct.Pull = (ctrl[led].light == MAZDRV_LED_GPIO_LEVEL_HIGH) ? GPIO_PULLDOWN : GPIO_PULLUP;
  16.         HAL_GPIO_Init((GPIO_TypeDef*) ctrl[led].port, &GPIO_InitStruct);

  17.         /* Set default status */
  18.         MAZ_Drv_led_set_status(led, ctrl[led].status);
  19.     }

  20.     return MAZRET_NOERR;
  21. }

  22. int MAZ_Drv_led_gpio_prot_clk_enable(MAZDRV_LED led)
  23. {
  24.     MAZDRV_LED_GPIO_PORT port;
  25.     MAZDRV_LED_CTRL *ctrl = NULL;

  26.     if (led < MAZDRV_LED0 || led >= MAZDRV_LED_MAX)
  27.     {
  28.         return MAZRET_EINVAL;
  29.     }

  30.     ctrl = g_mazdrv_led_ctrl;
  31.     port = ctrl[led].port;

  32.     /* GPIO Ports Clock Enable */
  33.     switch (port)
  34.     {
  35.         case MAZDRV_LED_GPIO_PORTA:
  36.             __HAL_RCC_GPIOA_CLK_ENABLE();
  37.             break;
  38.         case MAZDRV_LED_GPIO_PORTB:
  39.             __HAL_RCC_GPIOB_CLK_ENABLE();
  40.             break;
  41.         case MAZDRV_LED_GPIO_PORTC:
  42.             __HAL_RCC_GPIOC_CLK_ENABLE();
  43.             break;
  44.         case MAZDRV_LED_GPIO_PORTD:
  45.             __HAL_RCC_GPIOD_CLK_ENABLE();
  46.             break;
  47.         case MAZDRV_LED_GPIO_PORTE:
  48.             __HAL_RCC_GPIOE_CLK_ENABLE();
  49.             break;
  50.         case MAZDRV_LED_GPIO_PORTF:
  51.             __HAL_RCC_GPIOF_CLK_ENABLE();
  52.             break;
  53.         case MAZDRV_LED_GPIO_PORTG:
  54.             __HAL_RCC_GPIOG_CLK_ENABLE();
  55.             break;
  56.     }

  57.     return MAZRET_NOERR;
  58. }
 楼主| condition 发表于 2020-5-10 09:34 | 显示全部楼层
LED 设置状态:

  1. int MAZ_Drv_led_set_status(MAZDRV_LED led, MAZDRV_LED_STATUS status)
  2. {
  3.     MAZDRV_LED_GPIO_LEVEL level;
  4.     MAZDRV_LED_CTRL *ctrl = NULL;

  5.     if (led < MAZDRV_LED0 || led >= MAZDRV_LED_MAX)
  6.     {
  7.         return MAZRET_EINVAL;
  8.     }

  9.     if (status < MAZDRV_LED_STATUS_ON || status > MAZDRV_LED_STATUS_TOGGLE)
  10.     {
  11.         return MAZRET_EINVAL;
  12.     }

  13.     ctrl = g_mazdrv_led_ctrl;

  14.     switch (status)
  15.     {
  16.         case MAZDRV_LED_STATUS_ON:
  17.             level = ctrl[led].light;
  18.             HAL_GPIO_WritePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin, level);
  19.             break;
  20.         case MAZDRV_LED_STATUS_OFF:
  21.             if (MAZDRV_LED_GPIO_LEVEL_HIGH == ctrl[led].light)
  22.                 level = MAZDRV_LED_GPIO_LEVEL_LOW;
  23.             else if (MAZDRV_LED_GPIO_LEVEL_LOW == ctrl[led].light)
  24.                 level = MAZDRV_LED_GPIO_LEVEL_HIGH;
  25.             HAL_GPIO_WritePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin, level);
  26.             break;
  27.         case MAZDRV_LED_STATUS_TOGGLE:
  28.             HAL_GPIO_TogglePin((GPIO_TypeDef*) ctrl[led].port, ctrl[led].pin);
  29.             break;
  30.     }

  31.     return MAZRET_NOERR;
  32. }
 楼主| condition 发表于 2020-5-10 09:34 | 显示全部楼层
不难发现, 驱动函数中所有与硬件相关的部分, 全部由 g_mazdrv_led_ctrl 变量提供. 因此移植代码时, 仅需要修改 g_mazdrv_led_ctrl 变量即可实现快速移植.
 楼主| condition 发表于 2020-5-10 09:35 | 显示全部楼层
代码仓库
仓库路径: https://github.com/maziot-stm32/A1
驱动文件: https://github.com/maziot-stm32/A1/tree/master/MAZ_Drivers/MAZ_Drv_led

作者:mz8023yt
链接:https://www.jianshu.com/p/3b332a82b0f1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
heimaojingzhang 发表于 2020-6-2 16:49 | 显示全部楼层
非常感谢楼主分享
keaibukelian 发表于 2020-6-2 16:49 | 显示全部楼层
不用介绍的这么详细吧
labasi 发表于 2020-6-2 16:50 | 显示全部楼层
有些代码不需要咱们操心吧
paotangsan 发表于 2020-6-2 16:50 | 显示全部楼层
楼主辛苦了
renzheshengui 发表于 2020-6-2 16:50 | 显示全部楼层
介绍的太详细了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

14

主题

256

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部