0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一个通用嵌入式驱动层的代码实现

工程师进阶笔记 来源:工程师进阶笔记 作者:工程师进阶笔记 2022-11-16 11:31 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、前言

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

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

二、实现原理

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

三、代码实现

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

头文件接口:

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

/*
驱动注册
*/
int cola_device_register(cola_device_t *dev);


/*
驱动查找
*/
cola_device_t*cola_device_find(constchar*name);


/*
驱动读
*/
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);


/*
驱动写
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);


/*
驱动控制
*/
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;

头文件cola_device.h:

#ifndef_COLA_DEVICE_H_
#define _COLA_DEVICE_H_


enumLED_state
{
  LED_OFF,
  LED_ON,
  LED_TOGGLE,
};


typedefstructcola_devicecola_device_t;
structcola_device_ops
{
  int(*init)(cola_device_t*dev);
  int(*open)(cola_device_t*dev,intoflag);
  int(*close)(cola_device_t*dev);
  int(*read)(cola_device_t*dev,intpos,void*buffer,intsize);
  int(*write)(cola_device_t*dev,intpos,constvoid*buffer,intsize);
  int(*control)(cola_device_t*dev,intcmd,void*args);
};


structcola_device
{
  constchar*name;
  structcola_device_ops*dops;
  structcola_device*next;
};


/*
驱动注册
*/
int cola_device_register(cola_device_t *dev);


/*
驱动查找
*/
cola_device_t *cola_device_find(const char *name);


/*
驱动读
*/
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);


/*
驱动写
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);


/*
驱动控制
*/
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);


#endif

源文件cola_device.c:

#include"cola_device.h"
#include
#include 


struct cola_device *device_list = NULL;


/*
查找任务是否存在
*/
static bool cola_device_is_exists( cola_device_t *dev )
{
  cola_device_t*cur=device_list;
  while(cur!=NULL)
  {
    if(strcmp(cur->name,dev->name)==0)
{
returntrue;
}
cur=cur->next;
}
returnfalse;
}


static int device_list_inster(cola_device_t *dev)
{
  cola_device_t *cur = device_list;
  
  if(NULL==device_list)
  {
    device_list=dev;
    dev->next=NULL;
  }
  else
  {
    while(NULL!=cur->next)
    {
        cur=cur->next;
    }
    
    cur->next=dev;
    dev->next=NULL;
  }
  return1;
}


/*
驱动注册
*/
int cola_device_register(cola_device_t *dev)
{
  if((NULL==dev)||(cola_device_is_exists(dev)))
  {
    return0;
  }
  if((NULL==dev->name)||(NULL==dev->dops))
  {
    return0;
  }
  returndevice_list_inster(dev);
}


/*
驱动查找
*/
cola_device_t*cola_device_find(constchar*name)
{
  cola_device_t*cur=device_list;
  while(cur!=NULL)
  {
    if(strcmp(cur->name,name)==0)
    {
      returncur;
    }
    cur=cur->next;
  }
  returnNULL;
}


/*
驱动读
*/
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)
{
  if(dev)
  {
    if(dev->dops->read)
    {
      returndev->dops->read(dev,pos,buffer,size);
    }
  }
  return0;
}


/*
驱动写
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
{
  if(dev)
  {
    if(dev->dops->write)
    {
      returndev->dops->write(dev,pos,buffer,size);
    }
  }
  return0;
}


/*
驱动控制
*/
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
{
  if(dev)
  {
    if(dev->dops->control)
    {
      returndev->dops->control(dev,cmd,arg);
    }
  }
  return0;
}

硬件注册方式:以LED为例,初始化接口voidled_register(void),需要在初始化中调用。

#include"stm32f0xx.h"
#include"led.h"
#include"cola_device.h"
#definePORT_GREEN_LEDGPIOC
#define PIN_GREENLED GPIO_Pin_13             


/*LED亮、灭、变化*/
#defineLED_GREEN_OFF(PORT_GREEN_LED->BSRR=PIN_GREENLED)
#defineLED_GREEN_ON(PORT_GREEN_LED->BRR=PIN_GREENLED)
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)


static cola_device_t led_dev;


static void led_gpio_init(void)
{
  GPIO_InitTypeDefGPIO_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{
  }
  return1;
}


staticstructcola_device_opsops=
{
  .control=led_ctrl,
};


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

应用层app代码:

#include
#include"app.h"
#include"config.h"
#include"cola_device.h"
#include "cola_os.h"


statictask_ttimer_500ms;
static cola_device_t *app_led_dev;


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


void app_init(void)
{
  app_led_dev=cola_device_find("led");
  assert(app_led_dev);
  cola_timer_create(&timer_500ms,timer_500ms_cb);
  cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
}

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

四、总结

这样就可以实现软硬件分层了,是不是非常好用!

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5186

    文章

    20151

    浏览量

    328875
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73151

原文标题:一个通用的嵌入式驱动层,基本都是这么玩的

文章出处:【微信号:工程师进阶笔记,微信公众号:工程师进阶笔记】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    面向单片机、事件驱动嵌入式开发平台介绍

    EventOS,是面向单片机、事件驱动嵌入式开发平台。它主要有两大技术特色:是事件驱动
    发表于 12-05 06:26

    分享嵌入式开发学习路线

    如果你想要学习嵌入式开发,我建议按照这个学习路线准备: 1. 基础铺垫期(1-2月) 理解嵌入式系统的“硬件基础”和“编程入门”,能看懂简单电路,写出基础C语言代码。这
    发表于 12-04 11:01

    嵌入式软件分层架构设计原则

    嵌入式软件分层架构的设计原则如下: 模块化和可扩展性:每一层应当保持松耦合,这样当硬件变化或某些功能扩展时,只需要修改对应的层次,而不影响整体架构。 硬件无关性:上层代码应当尽量避免直接依赖硬件
    发表于 11-28 07:05

    40嵌入式常见名词次讲清!

    一个人的困惑。嵌入式开发涉及的术语确实又杂又多,而且很多词不仅缩写相似,使用语境也相互交叉。为了帮你打通这些基础概念,我们整理了嵌入式常见名词速查表,从最基础的G
    的头像 发表于 11-14 10:28 600次阅读
    40<b class='flag-5'>个</b><b class='flag-5'>嵌入式</b>常见名词<b class='flag-5'>一</b>次讲清!

    嵌入式达到什么水平才能就业?

    :包括GPIO、定时器、中断、ADC 等外设的配置与调试,能实现如温湿度采集、电机控制等功能掌握嵌入式 Linux 驱动开发基础:能编写简单字符设备驱动
    发表于 09-15 10:20

    油介质损耗及电阻率测试仪的嵌入式系统架构与抗干扰设计

    构成测试仪稳定运行的技术基石。 嵌入式系统架构:分层设计实现功能协同 测试仪嵌入式系统采用分层架构,通过“硬件
    的头像 发表于 09-02 13:57 354次阅读
    油介质损耗及电阻率测试仪的<b class='flag-5'>嵌入式</b>系统架构与抗干扰设计

    嵌入式从入门到进阶,怎么学?

    ); 驱动开发字符设备驱动(LED 驱动)、设备树(描述硬件)、GPIO 控制(按键中断驱动); 实践写
    发表于 09-02 09:44

    入行嵌入式应该怎么准备?

    知识: 、C/C++编程C/C++是嵌入式系统开发中最常用的编程语言。熟练掌握C/C++语言将使你能够理解和编写底层驱动程序、操作系统以及与硬件交互的代码。对于
    发表于 08-06 10:34

    嵌入式和单片机,是同一个东西吗?

    各种环境中运行,包括工业控制、汽车电子、医疗设备、家用电器、消费电子产品等。 嵌入式系统设计与通用计算机系统有几个关键区别。首先,嵌入式系统通常有
    发表于 07-09 10:20

    怎么结合嵌入式,Linux,和FPGA三方向达到均衡发展?

    嵌入式领域,不少人都怀揣着让嵌入式、Linux 和 FPGA 三方向实现均衡发展的梦想,然而实践中却面临诸多挑战。就像备受瞩目的全栈工程师稚晖君,他从大学玩单片机起步,凭借将智能算
    的头像 发表于 06-25 10:08 653次阅读
    怎么结合<b class='flag-5'>嵌入式</b>,Linux,和FPGA三<b class='flag-5'>个</b>方向达到<b class='flag-5'>一</b><b class='flag-5'>个</b>均衡发展?

    Linux嵌入式和单片机嵌入式的区别?

    :使用Linux操作系统,可以运行各种复杂的应用程序和驱动程序。 4. 资源需求 : 单片机嵌入式 :对硬件资源的需求较低,通常只需要单片机芯片,内存和存储空间较小。 Lin
    发表于 06-20 09:46

    BlackBerry QNX推出通用嵌入式开发平台

    BlackBerry有限公司(纽交所代码:BB;多伦多证券交易所代码:BB)旗下部门QNX今日宣布推出QNX 通用嵌入式开发平台(General Embedded Developmen
    的头像 发表于 03-11 16:04 943次阅读

    嵌入式系统中的代码优化与压缩技术

    以及资源利用效率。 代码优化的重要性 嵌入式设备往往资源有限,如内存空间小、处理器性能相对较弱。高效的代码能够在有限资源下实现更强
    发表于 02-26 15:00

    如何提高嵌入式代码质量?

    并提升代码质量。 遵循良好的软件工程实践 良好的软件工程实践是提高代码质量的基础,特别是在嵌入式系统中更为重要。以下是几个关键点: 1. 模块化设计:将系统分解为独立的模块,每个模块负责
    发表于 01-15 10:48

    新手怎么学嵌入式?

    实现些简单的功能,如点亮 LED 灯、读取传感器数据等,来加深对嵌入式技术的理解。你还可以参加
    发表于 12-12 10:51