嵌入式驱动分层

参考链接:分享一个通用的嵌入式驱动层

以下为我阅读这篇博客的理解,如果错误请帮忙指正。

1.首先创建一个链表控制的文件,此文件将会把每一个硬件的相关信息(cola_device,name用于查找设备,dops对硬件进行操作的相关函数)插入链表。

struct cola_device_ops
{
  int  (*init)   (cola_device_t *dev);
  int  (*open)   (cola_device_t *dev, int oflag);
  int  (*close)  (cola_device_t *dev);
  int  (*read)   (cola_device_t *dev, int pos, void *buffer, int size);
  int  (*write)  (cola_device_t *dev, int pos, const void *buffer, int size);
  int  (*control)(cola_device_t *dev, int cmd, void *args);
};

struct cola_device
{
  const char * name;
  struct cola_device_ops *dops;
  struct cola_device *next;
};

2.在cola_device_ops这个结构体中涉及所有关于硬件的操作(初始化,打开,关闭,读,写,控制),实际上大多数硬件只需要实现部分操作。然后通过在main函数中调用led_register()这个函数就将其注入到链表中了(并且这一步还初始化了硬件)

static cola_device_t led_dev;

static void led_gpio_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;                           
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                    
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                 
  GPIO_Init(PORT_GREEN_LED, &GPIO_InitStructure);
  LED_GREEN_OFF;
}

static int led_ctrl(cola_device_t *dev, int cmd, void *args)
{
  if(LED_TOGGLE == cmd)
  {
    LED_GREEN_TOGGLE;
  }
  else {
  }
  return 1;
}

static struct cola_device_ops ops =
{
  .control = led_ctrl,
};

void led_register(void)
{
  led_gpio_init();
  led_dev.dops = &ops;
  led_dev.name = "led";
  cola_device_register(&led_dev);
}

3.当需要操作硬件的时候,先用名字查找这个硬件设备,然后就可以对其进行控制了

void app_init(void)
{
    app_led_dev = cola_device_find("led");
    app_led_dev.control(app_led_dev, LED_TOGGLE, 0);
}

4.既然这里没有设计到硬件层的删除,那么也就意味着这里没有必要使用链表。我们完全可以使用数组进行操作。不管是上面的链表还是这个用数组,在我看来我都不会去使用它,即使我理解了用法,这个实在是对单片机那小的可怜内存的高看(在实际开发中)。

struct cola_device{  const char * name;  struct cola_device_ops *dops;  struct cola_device *next;};

改为: 

struct cola_device{  const char  dev_num;//用枚举来代替设备,或者你也可以不用  struct cola_device_ops *dops;};

//注册函数

//在这里搞一个用于存储所有设备信息的数组
cola_device_t dev_arr[10] = {0};

void cola_device_register(cola_device_t dev)
{
    dev_arr[dev.dev_num] = dev;
}



//如何调用
//1.直接extern cola_device_t dev_arr[10]
//2.第一中方法也许会让你觉得很low,那我们再写个函数
cola_device_t* find_dev(const char dev_num)
{
    return &dev_arr[dev.dev_num];
}

总结:这些所有的操作其实就是用同一个函数名,来掩盖不同的设备,不同的操作方法。 

以上写于2022年11月, 现在(2024年1月)对以上的说法不合理的地方解答:

1. 抽象是没毛病的, 这种抽象肯定不能用于8位单片机中, 并且要对功能有大概了解, 太复杂, 而老板给的芯片太小, 肯定也不能取用抽象.

2. 可以将struct cola_device_ops用const声明, 这样可以将内存占用降下去.

3. 使用数组太鸡肋, 在模块化中不灵活, 可能我取消某个模块, 还要去修改其他地方的代码, 如果用链表, 那我就不需要去修改代码.链表在模块化, 动态化编程必定是必不可少的.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

入门->放弃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值