你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

适用于单片机的接口适配器模式的实现

[复制链接]
gaosmile 发布时间:2020-6-1 17:54
前言

    通俗的讲,适配器模式是将一个类的接口转换成客户希望的另外一个接口,在我们编写程序的时候,尤其是在我们使用到单片机做项目的时候,经常会用到。

微信图片_20200601175338.png

    但是往往我们做项目写程序的时候,并没有想到那么多,如果在不带操作系统的情况下,想要整个框架易于移植,易于理解,那么我们真的需要好好想想这个设计模式怎么写了。

    下面我根据自己的项目经验,来说说适用于单片机的接口适配器模式的实现。大佬勿扰,多多指教。

一般实现

    在我们做项目的时候,一般的实现,可能我们会这样写代码

  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. // FileName: test.c
  3. // 来源:公众号【技术让梦想更伟大】
  4. #include <stdio.h>
  5. #include “ExternModule.h”

  6. int main(void)
  7. {

  8.   /*初始化*/
  9.   vAllInit();
  10.   
  11.   while(1)
  12.   {
  13.   
  14.     /*项目逻辑*/
  15.     vLogicModule1();
  16.    
  17.     vLogicModule2();
  18.    
  19.   }
  20. }</font></font></font>
复制代码


    在其外部文件中,调用相对应的初始化函数以及逻辑函数,但是当我们项目很复杂的时候,逻辑关系也层层覆盖、交替的时候,这样的写法就有些不是很好看了。

接口适配器

    首先我们还是要来定义数据结构,一般这样的项目分为这样几个步骤:

  • 初始化
  • 输入
  • 处理
  • 输出


    我们把这四个步骤封装起来,再定义数据结构如下:

  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. // FileName: test1.c
  3. // 来源:公众号【技术让梦想更伟大】
  4. /* 适配器类型定义 */
  5. struct _ADAPTER
  6. {
  7.     void (*Init    )( void );  //初始化函数
  8.     void (*Input   )( void );  //输入转换函数
  9.     void (*Process )( void );  //处理函数
  10.     void (*Output  )( void );  //输出转换函数
  11. };
  12. typedef struct _ADAPTER ADAPTER ;</font></font></font>
复制代码


    那么初始化函数,我们先来这样定义


  1. // FileName: test1.c
  2. // 来源:公众号【技术让梦想更伟大】
  3. /* 模块初始化 */
  4. void moduleInit( ADAPTER *module )
  5. {
  6.     if( module->Init != NULL )
  7.     {
  8.         module->Init();
  9.     }
  10. }
复制代码


    模块的逻辑运行,我们可以这样使用

  1. <font color="#001000"><font style="background-color:rgb(255, 255, 255)"><font face="Tahoma">
  2. // FileName: test1.c
  3. // 来源:公众号【技术让梦想更伟大】
  4. /* 模块逻辑运行 */
  5. void moduleRun( ADAPTER *module )
  6. {
  7.     // 模块输入适配接口不为空,则执行输入适配操作
  8.     if( module->Input != NULL )
  9.     {
  10.         module->Input();
  11.     }

  12.     // 模块处理接口不为空,则执行处理操作   
  13.    
  14.     // 模块输出适配接口不为空,则执行输出适配操作
  15. }</font></font></font>
复制代码


    在定好了这些数据结构以及封装之后,我们在每个子模块中都只需要调用这个模式即可。例如有一个需求,需要点一个灯,我们建立独立文件,在文件中申明


  1. // FileName: led.c
  2. // 来源:公众号【技术让梦想更伟大】
  3. /*led灯运行 */
  4. ADAPTER LedModule = { vLedInit, NULL, vLedRunModule, NULL };
复制代码


    那么接下来只需要对初始化函数,逻辑运行函数进行描述就可以了。同理,我们需要一个按键的功能,在另一个独立文件申请


  1. // FileName: key.c
  2. // 来源:公众号【技术让梦想更伟大】
  3. /*按键运行 */
  4. ADAPTER KeyModule = { vKeyInit, NULL, vKeyRunModule, NULL };
复制代码


    这样的话就便于我们拆分需求,便于移植,同时程序也就模块化了,最后我们在main文件中做的就是调用这些函数就行。我们需要这样做。


  1. // FileName: main.c
  2. // 来源:公众号【技术让梦想更伟大】
  3. /*主函数 */
  4. void main( void )
  5. {

  6.     moduleInit( &LedModule         );
  7.     moduleInit( &keyModule         );
  8.    
  9.     while( 1 )
  10.     {
  11.         moduleRun( &LedModule        );
  12.         moduleRun( &keyModule        );
  13.     }
  14.    
  15. }
复制代码

最后
    main函数就是这么简单了,整个架构也是很清晰,体现出编程之美。
收藏 评论2 发布时间:2020-6-1 17:54

举报

2个回答
likang1202 回答时间:2020-6-2 09:05:13
谢谢分享
乐天乐 回答时间:2020-6-2 11:05:04
好厉害哦

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版