性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

嵌入式大雜燴
認(rèn)證:普通會員
作者動態(tài)
嵌入式必備工具 CMake 的使用套路!
1天前
嵌入式設(shè)備配網(wǎng):從基礎(chǔ)到實(shí)戰(zhàn)!
4天前
嵌入式設(shè)備聯(lián)網(wǎng)的 “捷徑” ——DHCP 詳解
04-22 17:08
嵌入式軟件:函數(shù)式 VS 非函數(shù)式編程
04-22 09:05
嵌入式領(lǐng)域:Linux 與 RTOS 的巔峰對決!
04-21 09:40

嵌入式編程模型 | 觀察者模式

大家好,我是雜燴君。

本次我們分享的是嵌入式中常用的一種思想 / 編程模型——觀察者模式。

觀察者模式概述

觀察者模式(Observer Pattern)是一種行為設(shè)計(jì)模式,其核心在于建立對象間的動態(tài)訂閱-通知機(jī)制。

它定義了對象之間的一對多依賴關(guān)系,當(dāng)一個對象(被觀察對象,也稱為主題)的狀態(tài)發(fā)生變化時,所有依賴它的對象(觀察者)都會收到通知并自動更新。

在嵌入式系統(tǒng)中,觀察者模式廣泛應(yīng)用于解耦事件發(fā)布者與訂閱者,特別適合的應(yīng)用場景:

  • 處理傳感器數(shù)據(jù)更新
  • 硬件狀態(tài)變化
  • 多模塊協(xié)作

嵌入式應(yīng)用場景

1、傳感器數(shù)據(jù)分發(fā)

多個模塊(如顯示、存儲、報(bào)警)需要實(shí)時獲取傳感器數(shù)據(jù)變化,觀察者模式可將傳感器作為主題(Subject),各模塊作為觀察者(Observer),實(shí)現(xiàn)數(shù)據(jù)更新時的自動通知。

類圖:

主題類(SensorSubject)

  • 包含觀察者列表(observers數(shù)組)
  • 維護(hù)當(dāng)前傳感器值(sensor_value)
  • 提供attach和set_value兩個關(guān)鍵方法

觀察者接口(ObserverCallback)

  • 定義統(tǒng)一的update接口
  • 對應(yīng)代碼中的函數(shù)指針類型

具體觀察者類

  • DisplayObserver:處理顯示更新
  • LoggerObserver:處理日志記錄
  • AlarmObserver:處理閾值報(bào)警

代碼:

#include

#define OBSERVER_MAX_NUM  5

// 觀察者回調(diào)函數(shù)類型
typedefvoid(*ObserverCallback)(int value);

// 主題(被觀察者)
typedefstruct
{
    ObserverCallback observers[OBSERVER_MAX_NUM];
    int count;
    int sensor_value;
} SensorSubject;

// 附加觀察者到主題
voidsensor_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;
}

// 更新傳感器值并通知觀察者
voidsensor_set_value(SensorSubject* subject, int value)
{
    if (!subject) 
    {
        printf("Invalid parameters!\n");
        return;
    }

    subject->sensor_value = value;
    
    // 遍歷所有觀察者進(jìn)行通知
    for (int i = 0; i < subject->count; ++i) 
    {
        if (subject->observers[i]) 
        {
            subject->observers[i](subject->sensor_value);
        }
    }
}

// 觀察者1:顯示模塊
voiddisplay_update(int value)
{
    printf("[Display] Value: %d\n", value);
}

// 觀察者2:日志模塊回
voidlogger_update(int value)
{
    printf("[Logger] Value: %d\n", value);
}

// 觀察者3:報(bào)警模塊
voidalarm_update(int value)
{
    if (value > 100) 
    {
        printf("[Alarm] Value %d exceeds limit!\n", value);
    }
}

intmain(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);

    // 模擬傳感器數(shù)據(jù)更新
    sensor_set_value(&sensor, 25);
    sensor_set_value(&sensor, 120);

    return0;
}

這個例子允許對象(顯示、日志、報(bào)警模塊)訂閱另一個對象(傳感器),當(dāng)主題狀態(tài)變化時自動通知所有觀察者。

注意:這個例子只是為了解釋觀察者模式的基本思想,在單線程環(huán)境下基本實(shí)現(xiàn)了觀察者模式的核心功能。若需要模仿應(yīng)用于實(shí)際應(yīng)用,需要增加線程安全機(jī)制、動態(tài)內(nèi)存管理、更完善的錯誤處理等。

2、Zephyr傳感器子系統(tǒng)

在 Zephyr 中,傳感器子系統(tǒng)使用了類似觀察者模式的機(jī)制。傳感器驅(qū)動作為主題,當(dāng)傳感器數(shù)據(jù)更新時,會觸發(fā)相應(yīng)的事件。

而應(yīng)用程序可以注冊為觀察者,監(jiān)聽這些事件并在數(shù)據(jù)更新時進(jìn)行處理。

#include
#include
#include
#include

// 傳感器事件處理函數(shù),作為觀察者的更新方法
staticvoidsensor_callback(const struct device *dev, struct sensor_trigger *trig)
{
    structsensor_valuetemp;

    if (sensor_sample_fetch(dev) < 0) {
        return;
    }
    if (sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp) < 0) {
        return;
    }
    // 處理傳感器數(shù)據(jù)
    printk("Temperature: %d.%06d\n", temp.val1, temp.val2);
}

voidmain(void)
{
    conststructdevice *dev = device_get_binding(DT_LABEL(DT_INST(0, st_stts751)));
    if (dev == NULL) {
        return;
    }

    structsensor_triggertrig = {
       .type = SENSOR_TRIG_DATA_READY,
       .chan = SENSOR_CHAN_AMBIENT_TEMP
    };

    // 注冊傳感器事件回調(diào),相當(dāng)于注冊觀察者
    if (sensor_trigger_set(dev, &trig, sensor_callback) < 0) {
        return;
    }

    while (1) {
        k_sleep(K_MSEC(100));
    }
}

3、任務(wù)間通信和同步機(jī)制

在 RTOS 中,任務(wù)之間的通信和同步機(jī)制可以類比為觀察者模式。

EventGroupHandle_t xEventGroup;

// 創(chuàng)建事件組
xEventGroup = xEventGroupCreate();

// 任務(wù) 1 作為主題設(shè)置事件
voidvTask1( void *pvParameters )
{
    while(1)
    {
        // 設(shè)置事件位
        xEventGroupSetBits( xEventGroup, 0x01 );
        vTaskDelay( pdMS_TO_TICKS( 1000 ) );
    }
}

// 任務(wù) 2 作為觀察者等待事件
voidvTask2( void *pvParameters )
{
    EventBits_t uxBits;
    while(1)
    {
        // 等待事件位
        uxBits = xEventGroupWaitBits(
            xEventGroup,   // 事件組句柄
            0x01,          // 等待的事件位
            pdTRUE,        // 退出時清除事件位
            pdFALSE,       // 不需要所有位都設(shè)置
            portMAX_DELAY  // 無限期等待
        );
        // 處理事件
        if( ( uxBits & 0x01 ) != 0 )
        {
            // 執(zhí)行相應(yīng)操作
        }
    }
}

事件組(Event Group)就可以看作是一個主題,而等待這些事件的任務(wù)則可以看作是觀察者。

當(dāng)事件組中的某個事件被設(shè)置(狀態(tài)改變)時,等待該事件的任務(wù)會被喚醒并執(zhí)行相應(yīng)的操作,就如同觀察者接收到主題的通知后進(jìn)行更新一樣。

4、MQTT

MQTT 是一種輕量級的消息傳輸協(xié)議,主要用于物聯(lián)網(wǎng)設(shè)備之間的通信,其在設(shè)計(jì)和使用上應(yīng)用了觀察者模式的思想。

其核心概念包括:

  • 發(fā)布者(Publisher):產(chǎn)生消息并將其發(fā)布到特定的主題(Topic)。
  • 主題(Topic):消息的分類標(biāo)簽,用于區(qū)分不同類型的消息。
  • 代理(Broker):負(fù)責(zé)接收發(fā)布者的消息,并將消息轉(zhuǎn)發(fā)給訂閱了相應(yīng)主題的訂閱者。
  • 訂閱者(Subscriber):訂閱一個或多個主題,當(dāng)這些主題有新消息發(fā)布時,會收到代理轉(zhuǎn)發(fā)的消息。

以上就是本次的分享,如果覺得文章有幫助,麻煩幫忙轉(zhuǎn)發(fā),謝謝!

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 3
收藏 5
關(guān)注 28
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧