嵌入式开发中应用层与硬件层的分层管理实现策略

2026-02-08 0 519

STM32开发时,例程中的文件层级设置常常让人感到困扰。有时候,应用层的文件竟然混杂着硬件层的文件,看上去十分杂乱。这就像整理房间,东西摆放不当,整个空间就显得乱糟糟的,影响了整体的美观。这确实让开发者感到挺烦恼的。

STM32例程现状

嵌入式开发中应用层与硬件层的分层管理实现策略

网络下载的资源或开发板自带的程序中,经常遇到应用层混用了本该属于硬件层的.h文件。这种现象很常见。就拿我之前开发的一个STM32小项目来说,看到那些层次混乱的文件,真是让人头疼。这不但让代码的结构显得杂乱无章,还使得后续的维护和扩展变得十分困难。尤其是对于初学者,这种混乱的分层结构会让他们在理解代码逻辑时遇到不小的挑战。

在实际的项目开发过程中,若出现层次混乱,可能会使开发周期变长。比如,对于急需上线的项目,开发者若需花费更多时间去理清代码之间的联系,这无疑是不利的。

Linux系统的启示

熟悉Linux的人都知道,Linux系统无法直接对硬件进行操作。观察其源代码,可以发现其中设有驱动程序这一层。以某个Linux服务器的开发为例,我们注意到其代码明确划分了各个层级。这种层级的划分使得整体结构一目了然。Linux对硬件层的隔离措施有效地保障了系统的稳定性。一旦出现故障,我们能够迅速判断是驱动层还是应用层出了问题。

这种分层设计思路就好比将不同部门各自设立办公区域,各自负责各自的工作。在STM32的开发过程中,我们可以采纳这种设计思路,将软件和硬件部分分开管理,这样做不仅能提高开发速度,而且后续的维护工作也会变得更为便捷。

实现原理剖析

在理论层面,将硬件操作接口置于驱动链表中,比如open、read、write等操作在驱动层完成。以智能家居控制系统为例,其中各类硬件设备的操作接口可以纳入驱动链表。然而,此方法存在不足,查找驱动时需遍历整个链表,导致代码执行时间延长。这就像在一家大型公司中寻找文件,若缺乏有效索引,便需逐个文件夹搜索,耗费大量时间。

此时,开发者需考量利弊得失。若代码对实时性的需求不高,软硬分层可通过此法顺利实现。然而,对于对实时性要求极高的项目,可能需对现有方法进行优化调整。

/*
    驱动注册
*/
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);;

代码实现要点

编写代码时,通常遵循国际规范,首先编写头文件。在此例中,我们使用了单向链表来简化操作,若感兴趣,不妨探究双向链表。确保头文件接口定义准确至关重要。例如,本次仅实现部分接口,其他部分可自行深入研究。以一个简单的传感器数据采集项目为例,在代码编写过程中,采用这种分层结构,应用层仅需调用相应接口即可实现功能。

#ifndef _COLA_DEVICE_H_
#define _COLA_DEVICE_H_
enum LED_state
{
    LED_OFF,
    LED_ON,
    LED_TOGGLE,
};
typedef struct cola_device  cola_device_t;
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;
};
/*
    驱动注册
*/
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 

编写头文件.h和源文件.c时,需依据功能需求做好规划。这好比建造房屋前先确定好结构框架,如此编写出的代码运行更流畅,也便于其他开发者阅读与维护。

硬件注册方式示例

以LED为例,存在一个初始化接口,名为void(void),这是在初始化过程中必须调用的。在处理实际硬件接入的项目中,例如LED显示屏的控制项目,这种硬件注册方法能保证在应用层无需调用led.h头文件,从而实现软件与硬件的分离。这就像在组装一台复杂机器时,每个部件都有其特定的安装步骤,遵循这些步骤可以确保设备能顺畅运作。

#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)
        {
            return true;
        }
        cur = cur->next;
    }
    return false;
}
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;
    }
    return 1;
}
/*
    驱动注册
*/
int cola_device_register(cola_device_t *dev)
{
    if((NULL == dev) || (cola_device_is_exists(dev)))
    {
        return 0;
    }
    if((NULL == dev->name) ||  (NULL == dev->dops))
    {
        return 0;
    }
    return device_list_inster(dev);
}
/*
    驱动查找
*/
cola_device_t *cola_device_find(const char *name)
{
    cola_device_t* cur = device_list;
    while( cur != NULL )
    {
        if( strcmp(cur->name,name)==0)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}
/*
    驱动读
*/
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size)
{
    if(dev)
    {
        if(dev->dops->read)
        {
            return dev->dops->read(dev, pos, buffer, size);
        }
    }
    return 0;
}
/*
    驱动写
*/
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
{
    if(dev)
    {
        if(dev->dops->write)
        {
            return dev->dops->write(dev, pos, buffer, size);
        }
    }
    return 0;
}
/*
    驱动控制
*/
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg)
{
    if(dev)
    {
        if(dev->dops->control)
        {
            return dev->dops->control(dev, cmd, arg);
        }
    }
    return 0;
}

这种硬件注册过程既简便又高效,它有助于使代码结构更加分明,同时降低了不必要的相关性。

代码下载与总结


#include \"stm32f0xx.h\"
#include \"led.h\"
#include \"cola_device.h\"
#define PORT_GREEN_LED                 GPIOC                   
#define PIN_GREENLED                   GPIO_Pin_13              
/* LED亮、灭、变化 */
#define LED_GREEN_OFF                  (PORT_GREEN_LED->BSRR = PIN_GREENLED)
#define LED_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_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);
}

这里并未提供代码下载的具体链接,不过我们必须认识到软硬件分层的至关重要。这种分层能提高开发速度,并使代码更易维护与理解。我想问问大家,在使用STM32进行开发时,是否遇到过因软硬件分层不清而引发的大麻烦?欢迎点赞和转发这篇文章,并在评论区参与讨论。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 嵌入式开发中应用层与硬件层的分层管理实现策略 https://www.zuozi.net/72694.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务