[开发工具] 嵌入式软件分层模块封装例子

[复制链接]
1727|1
 楼主| LOVEEVER 发表于 2024-9-12 14:32 | 显示全部楼层 |阅读模式
一、前言

以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。

使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。

1.png

二、实现原理

原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。

三、代码实现

国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread

头文件接口:

本次只实现如下接口,device_open  和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:

  1. /*
  2.     驱动注册
  3. */
  4. int cola_device_register(cola_device_t *dev);
  5. /*
  6.     驱动查找
  7. */
  8. cola_device_t *cola_device_find(const char *name);
  9. /*
  10.     驱动读
  11. */
  12. int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);
  13. /*
  14.     驱动写
  15. */
  16. int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
  17. /*
  18.     驱动控制
  19. */
  20. int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);;
  21. 头文件cola_device.h:

  22. #ifndef _COLA_DEVICE_H_
  23. #define _COLA_DEVICE_H_


  24. enum LED_state
  25. {
  26.     LED_OFF,
  27.     LED_ON,
  28.     LED_TOGGLE,

  29. };

  30. typedef struct cola_device  cola_device_t;

  31. struct cola_device_ops
  32. {
  33.     int  (*init)   (cola_device_t *dev);
  34.     int  (*open)   (cola_device_t *dev, int oflag);
  35.     int  (*close)  (cola_device_t *dev);
  36.     int  (*read)   (cola_device_t *dev, int pos, void *buffer, int size);
  37.     int  (*write)  (cola_device_t *dev, int pos, const void *buffer, int size);
  38.     int  (*control)(cola_device_t *dev, int cmd, void *args);

  39. };

  40. struct cola_device
  41. {
  42.     const char * name;
  43.     struct cola_device_ops *dops;
  44.     struct cola_device *next;
  45. };

  46. /*
  47.     驱动注册
  48. */
  49. int cola_device_register(cola_device_t *dev);
  50. /*
  51.     驱动查找
  52. */
  53. cola_device_t *cola_device_find(const char *name);
  54. /*
  55.     驱动读
  56. */
  57. int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);
  58. /*
  59.     驱动写
  60. */
  61. int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
  62. /*
  63.     驱动控制
  64. */
  65. int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);

  66. #endif


源文件cola_device.c:

  1. #include "cola_device.h"
  2. #include <string.h>
  3. #include <stdbool.h>


  4. struct cola_device *device_list = NULL;

  5. /*
  6.     查找任务是否存在
  7. */
  8. static bool cola_device_is_exists( cola_device_t *dev )
  9. {
  10.     cola_device_t* cur = device_list;
  11.     while( cur != NULL )
  12.     {
  13.         if( strcmp(cur->name,dev->name)==0)
  14.         {
  15.             return true;
  16.         }
  17.         cur = cur->next;
  18.     }
  19.     return false;
  20. }


  21. static int device_list_inster(cola_device_t *dev)
  22. {
  23.     cola_device_t *cur = device_list;
  24.     if(NULL == device_list)
  25.     {
  26.         device_list = dev;
  27.         dev->next   = NULL;
  28.     }
  29.     else
  30.     {
  31.         while(NULL != cur->next)
  32.         {
  33.             cur = cur->next;
  34.         }
  35.         cur->next = dev;
  36.         dev->next = NULL;
  37.     }
  38.     return 1;
  39. }

  40. /*
  41.     驱动注册
  42. */
  43. int cola_device_register(cola_device_t *dev)
  44. {
  45.     if((NULL == dev) || (cola_device_is_exists(dev)))
  46.     {
  47.         return 0;
  48.     }

  49.     if((NULL == dev->name) ||  (NULL == dev->dops))
  50.     {
  51.         return 0;
  52.     }
  53.     return device_list_inster(dev);

  54. }
  55. /*
  56.     驱动查找
  57. */
  58. cola_device_t *cola_device_find(const char *name)
  59. {
  60.     cola_device_t* cur = device_list;
  61.     while( cur != NULL )
  62.     {
  63.         if( strcmp(cur->name,name)==0)
  64.         {
  65.             return cur;
  66.         }
  67.         cur = cur->next;
  68.     }
  69.     return NULL;
  70. }
  71. /*
  72.     驱动读
  73. */
  74. int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size)
  75. {
  76.     if(dev)
  77.     {
  78.         if(dev->dops->read)
  79.         {
  80.             return dev->dops->read(dev, pos, buffer, size);
  81.         }
  82.     }
  83.     return 0;
  84. }
  85. /*
  86.     驱动写
  87. */
  88. int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
  89. {
  90.     if(dev)
  91.     {
  92.         if(dev->dops->write)
  93.         {
  94.             return dev->dops->write(dev, pos, buffer, size);
  95.         }
  96.     }
  97.     return 0;
  98. }
  99. /*
  100.     驱动控制
  101. */
  102. int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg)
  103. {
  104.     if(dev)
  105.     {
  106.         if(dev->dops->control)
  107.         {
  108.             return dev->dops->control(dev, cmd, arg);
  109.         }
  110.     }
  111.     return 0;
  112. }


 楼主| LOVEEVER 发表于 2024-9-12 14:33 | 显示全部楼层
硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。


  1. #include "stm32f0xx.h"
  2. #include "led.h"
  3. #include "cola_device.h"


  4. #define PORT_GREEN_LED                 GPIOC                  
  5. #define PIN_GREENLED                   GPIO_Pin_13              

  6. /* LED亮、灭、变化 */
  7. #define LED_GREEN_OFF                  (PORT_GREEN_LED->BSRR = PIN_GREENLED)
  8. #define LED_GREEN_ON                   (PORT_GREEN_LED->BRR  = PIN_GREENLED)
  9. #define LED_GREEN_TOGGLE               (PORT_GREEN_LED->ODR ^= PIN_GREENLED)


  10. static cola_device_t led_dev;

  11. static void led_gpio_init(void)
  12. {
  13.     GPIO_InitTypeDef GPIO_InitStructure;
  14.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
  15.     GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;                           
  16.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                     
  17.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  
  18.     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     
  19.     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                  
  20.     GPIO_Init(PORT_GREEN_LED, &GPIO_InitStructure);
  21.     LED_GREEN_OFF;
  22. }

  23. static int led_ctrl(cola_device_t *dev, int cmd, void *args)
  24. {
  25.     if(LED_TOGGLE == cmd)
  26.     {
  27.         LED_GREEN_TOGGLE;
  28.     }
  29.     else
  30.     {

  31.     }
  32.     return 1;
  33. }


  34. static struct cola_device_ops ops =
  35. {
  36.     .control = led_ctrl,
  37. };

  38. void led_register(void)
  39. {
  40.     led_gpio_init();
  41.     led_dev.dops = &ops;
  42.     led_dev.name = "led";
  43.     cola_device_register(&led_dev);
  44. }

应用层app代码:

  1. #include <string.h>
  2. #include "app.h"
  3. #include "config.h"
  4. #include "cola_device.h"
  5. #include "cola_os.h"

  6. static task_t timer_500ms;
  7. static cola_device_t *app_led_dev;

  8. //led每500ms状态改变一次
  9. static void timer_500ms_cb(uint32_t event)
  10. {
  11.     cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
  12. }

  13. void app_init(void)
  14. {
  15.     app_led_dev = cola_device_find("led");
  16.     assert(app_led_dev);
  17.     cola_timer_create(&timer_500ms,timer_500ms_cb);
  18.     cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
  19. }

这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

350

主题

2689

帖子

6

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