观察者模式在嵌入式中的妙用:传感器、RTOS、MQTT实例解析

嵌入式的大杂烩 2025-03-16 09:52:58

大家好,我是杂烩君。

本次我们分享的是嵌入式中常用的一种思想 / 编程模型——观察者模式。

观察者模式概述

观察者模式(Observer Pattern)是一种行为设计模式,其核心在于建立对象间的动态订阅-通知机制。

它定义了对象之间的一对多依赖关系,当一个对象(被观察对象,也称为主题)的状态发生变化时,所有依赖它的对象(观察者)都会收到通知并自动更新。

在嵌入式系统中,观察者模式广泛应用于解耦事件发布者与订阅者,特别适合的应用场景:

处理传感器数据更新硬件状态变化多模块协作嵌入式应用场景1、传感器数据分发

多个模块(如显示、存储、报警)需要实时获取传感器数据变化,观察者模式可将传感器作为主题(Subject),各模块作为观察者(Observer),实现数据更新时的自动通知。

类图:

主题类(SensorSubject):

包含观察者列表(observers数组)维护当前传感器值(sensor_value)提供attach和set_value两个关键方法

观察者接口(ObserverCallback):

定义统一的update接口对应代码中的函数指针类型

具体观察者类:

DisplayObserver:处理显示更新LoggerObserver:处理日志记录AlarmObserver:处理阈值报警代码:#include <stdio.h>#define OBSERVER_MAX_NUM 5// 观察者回调函数类型typedef void (*ObserverCallback)(int value);// 主题(被观察者)typedef struct { ObserverCallback observers[OBSERVER_MAX_NUM]; int count; int sensor_value;} SensorSubject;// 附加观察者到主题void sensor_attach(SensorSubject* subject, ObserverCallback callback) { if (!subject || !callback) { printf("Invalid parameters!\n"); return; } if (subject->count >= OBSERVER_MAX_NUM) { printf("Observers full!\n"); return; } subject->observers[subject->count++] = callback;}// 更新传感器值并通知观察者void sensor_set_value(SensorSubject* subject, int value) { if (!subject) { printf("Invalid parameters!\n"); return; } subject->sensor_value = value; // 遍历所有观察者进行通知 for (int i = 0; i < subject->count; ++i) { if (subject->observers[i]) { subject->observers[i](subject->sensor_value); } }}// 观察者1:显示模块void display_update(int value) { printf("[Display] Value: %d\n", value);}// 观察者2:日志模块回void logger_update(int value) { printf("[Logger] Value: %d\n", value);}// 观察者3:报警模块void alarm_update(int value) { if (value > 100) { printf("[Alarm] Value %d exceeds limit!\n", value); }}int main(void) { // 初始化传感器主题 SensorSubject sensor = { .observers = {0}, .count = 0, .sensor_value = 0 }; // 注册观察者 sensor_attach(&sensor, display_update); sensor_attach(&sensor, logger_update); sensor_attach(&sensor, alarm_update); // 模拟传感器数据更新 sensor_set_value(&sensor, 25); sensor_set_value(&sensor, 120); return 0;}

这个例子允许对象(显示、日志、报警模块)订阅另一个对象(传感器),当主题状态变化时自动通知所有观察者。

注意:这个例子只是为了解释观察者模式的基本思想,在单线程环境下基本实现了观察者模式的核心功能。若需要模仿应用于实际应用,需要增加线程安全机制、动态内存管理、更完善的错误处理等。

2、Zephyr传感器子系统

在 Zephyr 中,传感器子系统使用了类似观察者模式的机制。传感器驱动作为主题,当传感器数据更新时,会触发相应的事件。

而应用程序可以注册为观察者,监听这些事件并在数据更新时进行处理。

#include <zephyr.h>#include <device.h>#include <devicetree.h>#include <drivers/sensor.h>// 传感器事件处理函数,作为观察者的更新方法static void sensor_callback(const struct device *dev, struct sensor_trigger *trig){ struct sensor_value temp; if (sensor_sample_fetch(dev) < 0) { return; } if (sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp) < 0) { return; } // 处理传感器数据 printk("Temperature: %d.%06d\n", temp.val1, temp.val2);}void main(void){ const struct device *dev = device_get_binding(DT_LABEL(DT_INST(0, st_stts751))); if (dev == NULL) { return; } struct sensor_trigger trig = { .type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_AMBIENT_TEMP }; // 注册传感器事件回调,相当于注册观察者 if (sensor_trigger_set(dev, &trig, sensor_callback) < 0) { return; } while (1) { k_sleep(K_MSEC(100)); }}

往期相关文章:Zephyr 会成为物联网时代RTOS的佼佼者?

3、任务间通信和同步机制

在 RTOS 中,任务之间的通信和同步机制可以类比为观察者模式。

EventGroupHandle_t xEventGroup;// 创建事件组xEventGroup = xEventGroupCreate();// 任务 1 作为主题设置事件void vTask1( void *pvParameters ){ while(1) { // 设置事件位 xEventGroupSetBits( xEventGroup, 0x01 ); vTaskDelay( pdMS_TO_TICKS( 1000 ) ); }}// 任务 2 作为观察者等待事件void vTask2( void *pvParameters ){ EventBits_t uxBits; while(1) { // 等待事件位 uxBits = xEventGroupWaitBits( xEventGroup, // 事件组句柄 0x01, // 等待的事件位 pdTRUE, // 退出时清除事件位 pdFALSE, // 不需要所有位都设置 portMAX_DELAY // 无限期等待 ); // 处理事件 if( ( uxBits & 0x01 ) != 0 ) { // 执行相应操作 } }}

事件组(Event Group)就可以看作是一个主题,而等待这些事件的任务则可以看作是观察者。

当事件组中的某个事件被设置(状态改变)时,等待该事件的任务会被唤醒并执行相应的操作,就如同观察者接收到主题的通知后进行更新一样。

往期相关文章:嵌入式事件标志组

4、MQTT

MQTT 是一种轻量级的消息传输协议,主要用于物联网设备之间的通信,其在设计和使用上应用了观察者模式的思想。

其核心概念包括:

发布者(Publisher):产生消息并将其发布到特定的主题(Topic)。主题(Topic):消息的分类标签,用于区分不同类型的消息。代理(Broker):负责接收发布者的消息,并将消息转发给订阅了相应主题的订阅者。订阅者(Subscriber):订阅一个或多个主题,当这些主题有新消息发布时,会收到代理转发的消息。

往期相关文章:MQTT应用于进程间通信

以上就是本次的分享,如果觉得文章有帮助,麻烦帮忙转发,谢谢!

0 阅读:10

嵌入式的大杂烩

简介:感谢大家的关注