背景简介

在MCU驱动开发时可能会遇到以下场景:

需要通过降低主频来降低MCU功耗,一旦修改了MCU主频,其它外设的时钟将会受到影响,如串口原本是按照9600波特率在通信,主频修改后其波特率就不再是9600了,这时候就需要根据新的主频重新设置串口波特率;定时器、IIC、SPI等外设也都存在类似的问题。

这种场景总结起来就是:主频修改了,其它相关外设都需要知道并同步重新配置。这很符合观察者模式的应用场景:被观察者发生了某种变化,观察者可以及时被通知并做相应的动作,而不是让观察者定时查询被观察者是否发生了变化。

在驱动开发中,一般都是使用C语言,也可以像C++、Java那样实现一些设计模式,这些设计模式一被提起,就倍感高端,给人一种感觉就是:这个人编程技术很厉害……然而本人并不这么认为,设计模式是前人的经验总结,一方面它有其固定的适用场景,另一方面其宗旨是让代码具有较高的易理解性、可移植性/可修改性。

例如:修改主频这种场景,虽说与观察者模式的应用场景非常吻合,但按照观察者模式的条条框框写完代码后会发现:一个很简单的功能,却用了一大堆代码来实现,耗RAM、耗Flash很多不说,新人接手一下子不一定看得懂。

观察者模式简介

设计模式在网上有很多资料,讲的也比较详细,这里就不详细展开,下面这个资料可以参考:

详细解读设计模式:观察者模式

观察者模式的C语言实现

设计模式的C实现资料网上也很多,这里也不展开描述了,可参考下面的资料:

设计模式之观察者模式(C语言)_Hongggggggg的博客-CSDN博客_c语言观察者设计模式

C语言实现MCU主频修改方案(类观察者模式)

分析:主频修改必然引起相关外设时钟源频率变化,每一个外设都必须订阅该主频的变化,否则该外设将不会按预设的方式工作;而且没有取消订阅的说法。这么来看,观察者模式中的一些机制比较啰嗦,下面一步步解析怎么简化该场景下的观察者模式。

先定义回调函数类型,再定义一个该回调数组,该数组用于注册需要订阅主频变化的各个观察者回调:

typedef void (* CallbackUpdate)(uint32_t freq);static const CallbackUpdate UpdateFreqList[] = {NULL,
};void Notify(uint32_t freq) // 对外接口:在修改主频时候调用即可
{CallbackUpdate *p_update_freq = UpdateFreqList;while(p_update_freq != NULL){(*p_update_freq)(freq);p_update_freq++;}
}

由于是在低功耗管理模块修改主频,那么就在低功耗管理模块中调用Notify接口即可实现的通知/发布功能。

现在就可在每个观察者模块中定义各自的回调接口,例如重新配置串口:

void UpdateUartConfig(uint32_t freq)
{……
}

每增加一个UpdateXXXConfig就在回调数组中增加一个对应成员即可,如

extern void UpdateUartConfig(uint32_t freq);
extern void UpdateIICConfig(uint32_t freq);
extern void UpdateTIMxConfig(uint32_t freq);
extern void UpdateSPIConfig(uint32_t freq);static const CallbackUpdate UpdateFreqList[] = {UpdateUartConfig,UpdateIICConfig,UpdateTIMxConfig,UpdateSPIConfig,NULL,
};

这样每增加一个外设,只用维护UpdateFreqList这张表即可,不会修改低功耗管理模块;这里的attach注册操作在编译前就已经完成,代码简洁、可读性强,可修改性或可移植性高;每个模块内部都以功能实现为目标,其内聚等级为功能内聚;模块之间没有直接交互,耦合等级为非直接耦合。

总结

观察者模式的适用场景有两个要素:

1、被观察者发生了某种变化,观察者可以及时被通知并做相应的动作,而不是让观察者定时查询被观察者是否发生了变化;

2、观察者存在不确定性,即是否订阅该观察者是动态调整的;

如果观察者都是确定的,订阅与否也是不会动态改变的,这时强行使用观察者模式那套代码结构,只会让代码看起来很臃肿,且可维护性差。

我曾经见过有人写驱动,用了一大堆设计模式在里面,甚至把微服务那套机制也搬过来,搞得代码用了一大堆所谓的高级技术,似乎是在炫耀:看,我用了xxx技术……似乎不用点高级货显摆不出自己很厉害,最后的结果是:一个很普通的应用,MCU有1M的Flash、192K的RAM都给撑满了,而别人实现同样功能的产品,MCU的Flash只有512K,RAM只有64K。

一种修改MCU主频的方法:类观察者模式相关推荐

  1. pythontk界面显示函数中的变量值_简单易学,西门子触摸屏3种修改变量值的方法!博图Wincc V14组态...

    应条友要求,今天分享3种修改触摸屏变量值的最常用方法! 全文约700字,通读4分钟! 看完本章,你将收获以下内容: 一:必会知识点:3种修改变量的方法及适用点 二:实例:3种方法修改触摸屏变量值 三: ...

  2. 手机怎么把照片调成一寸?分享两种修改照片尺寸的方法

    怎么使用手机把照片尺寸调成一寸呢?证件照是我们在日常中比较常见的一种证件,在很多地方都会使用得到,通常情况下,在需要使用证件照的时候时间都是比较紧张的,如果这时候我们的证件照尺寸不对,身边又没有电脑, ...

  3. 怎么给视频修改封面?推荐几种修改视频封面的方法

    现在随着短视频的爆发式增长,如果大家想要让自己的短视频在众多的视频当中脱颖而出,就需要给视频设置一个有趣.吸引人的封面.好看的封面可以更好的吸引网页的驻足以及观赏,那你们知道视频修改封面怎么改吗?有需 ...

  4. Mac OS 下三种修改Hosts文件的方法

    一.系统偏好设置修改 1.打开系统偏好设置,底部有一个Hosts的快捷入口 2.输入ip和hostname后,回车确定,勾选改host即可 二.终端命令行修改 sudo vi /etc/hosts 1 ...

  5. 如何修改ftp服务器密码,ftp密码,3种修改ftp密码的方法

    其实FTP服务就相当于共享文件,你要进入FTP服务器首先要知道提供FTP这台电脑的IP或者域名.FTP服务器是可以随意设置访问的用户名和密码的,当然也可以设置匿名访问(设置了匿名访问,用户就不需要输用 ...

  6. 图片尺寸修改工具有哪些?这几种修改图片尺寸的方法分享给你

    平时在使用图片的时候,不知道大家是否注意过图片尺寸,对于做电商的小伙伴来说肯定是注意过的,因为在使用图片做店铺宣传的时候,图片尺寸超过一定数值以后会有图片放大镜效果. 那么图片尺寸是越大越好吗?其实并 ...

  7. 修改使用计算机的名称,Windows 10中修改计算机名称的方法,你知道几种?

    当用户新入手一台电脑时,通常做的第一件事就是做一些个性化设置.一般来说个性化的第一步就是给计算机起一个自己满意的名字,下面介绍几种修改计算机名字的方法. 通过设置更改计算机名字 按Win+I键进入设置 ...

  8. python添加、修改、删除、访问类对象属性的2种方法

    1.直接添加.修改.删除.访问类对象属性 class Employee (object):empCount = 0 def __init__(self, name, salary) :self.nam ...

  9. 极坐标梯度公式_一种基于极坐标系梯度变化的类圆环边缘检测方法与流程

    本发明涉及图形处理技术领域,具体地说是一种基于极坐标系梯度变化的类圆环边缘检测方法. 背景技术: 边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点.图像属性中 ...

最新文章

  1. Centos下卸载openjdk并安装自定义jdk
  2. 在 IDEA 中使用 Debug,真是太厉害了!
  3. .Net/C# 实现: FlashFXP 地址簿中站点密码的加解密算法
  4. 主窗体界面设计及功能实现
  5. C#中的信号量---Semaphore
  6. maven web项目保存log4j日志到WEB-INF
  7. shell中正则表达式详解_Linux中的正则表达式
  8. Redis基于客户端分片的集群案例(待实践)
  9. mysql设置查询结果最大值_查找MySQL查询结果字段的最大值
  10. 【百度地图API】如何给自定义覆盖物添加事件
  11. 统一沟通_边缘安装及配置之十七_(Windows Server 2008 R2 SP1英文版)
  12. 使用CodeIgniter输入类
  13. 常用的排序算法总结(一)
  14. java怎样获取变量的类型
  15. 4.10 风格代价函数
  16. php能从事什么岗位,ps能从事什么工作岗位
  17. Attachments in Oracle Form
  18. Sap Hana触发器
  19. 【机器学习】SVM核方法
  20. 【Electron+Vue】【一】开发跨平台桌面应用了解+构建

热门文章

  1. 给聪明妈妈支一招:如何让宝宝吃到营养更丰富的“后乳”?
  2. 深度学习框架TensorFlow系列之(五)优化器1
  3. 深圳楼市2007vs2016
  4. PackageManagerService启动及初始化流程
  5. 用IDEA打包springboot项目报错:--- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot_homewor
  6. 删除多余迅雷7插件,加快启动速度
  7. 合肥工业大学密码学课设-RSA
  8. post office 问题
  9. 哈佛梅森学者:数字加密货币的泡沫与机遇|万字长文干货
  10. 学习Python必刷的100道经典实战练习真题(第010集 怎样对简单列表元素排序-第011集 怎样实现学生成绩排序)