91视频免费?看_蜜芽MY188精品TV在线观看_国产免费无遮挡在线观看视频_深夜国产_亚洲精品欧洲精品_欧美黑人粗暴多交

在單片機中使用Rust閉包優雅應對中斷

什么是閉包

閉包這個詞語由來已久,自上世紀 60 年代就由 Scheme 語言引進之后,被廣泛用于函數式編程語言中,進入 21 世紀后,各種現代化的編程語言也都不約而同地把閉包作為核心特性納入到語言設計中來。那么到底何為閉包?

閉包是一種匿名函數,它可以賦值給變量也可以作為參數傳遞給其它函數,不同于函數的是,它允許捕獲調用者作用域中的值,例如:

fn main() {
   let x = 1;
   let sum = |y| x + y;

    assert_eq!(3, sum(2));
}

上面的代碼展示了非常簡單的閉包 sum,它擁有一個入參 y,同時捕獲了作用域中的 x 的值,因此調用 sum(2) 意味著將 2(參數 y)跟 1(x)進行相加,最終返回它們的和:3。

可以看到 sum 非常符合閉包的定義:可以賦值給變量,允許捕獲調用者作用域中的值。

使用閉包優雅處理中斷

本篇文章將介紹如何使用閉包優雅處理中斷。Rust 使用閉包處理中斷的設計模式,目的是讓中斷處理更加及時、同時讓 Rust 中的所有權檢查能夠順利通過,也讓API的使用更加簡潔,符合人體工學設計,同時保證上層應用與底層邏輯的分離。

crate倉庫:https://crates.io/crates/py32f030_hal  

代碼示例:examples/adc_block_interrupt_closure.rs

#![no_std]
#![no_main]

externcrate alloc;

use defmt::Debug2Format;
use hal::adc::{AdcChannel, AnyAdc, ChannelConfig, Config, Event, SampleCycles, TrigleSignal};

use py32f030_hal::adc::ConversionMode;
use py32f030_hal::clock::peripheral::PeripheralInterrupt;
use py32f030_hal::clock::sys_core_clock;
use py32f030_hal::{selfas hal, mode::Blocking};

use {defmt_rtt as _, panic_probe as _};

#[cortex_m_rt::entry]
fn main() -> ! {
    // -------- Setup Allocator --------
    const HEAP_SIZE: usize = 128;
    staticmut HEAP: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
    #[global_allocator]
    static ALLOCATOR: alloc_cortex_m::CortexMHeap = alloc_cortex_m::CortexMHeap::empty();
    unsafe {
        ALLOCATOR.init(
            &mut HEAP as *constu8asusize,
            core::mem::size_of_val(&HEAP),
        )
    }
    let p = hal::init(Default::default());

    defmt::info!("{}", sys_core_clock());

    letmut adc: AnyAdc<_, Blocking> = AnyAdc::new(
        p.ADC,
        Config::default().sample(SampleCycles::Cycle_239_5),
        ChannelConfig::default()
            .over_write(false)
            .wait(true) // 轉換完成后等待讀取完畢再開始轉換
            .singal(TrigleSignal::Soft)
            .mode(ConversionMode::Continuous),
        &[AdcChannel::Channel11, AdcChannel::Channel12],
        // &[AdcChannel::Channel11],
    )
    .unwrap();

    // 使用閉包的方式在中斷中調用閉包處理函數
    // 兼顧友好型 api
    staticmut QUEUE: [u16; 16] = [0; 16];
    adc.on_interrupt(
        Event::EOC.into(), /* EOC 中斷 */
        alloc::boxed::Box::new(move |adc| {
            /* 中斷自動調用的閉包 */
            staticmut CNT: usize = 0;
            unsafe {
                QUEUE[CNT] = adc;
                CNT += 1;
                if QUEUE.len() == CNT {
                    CNT = 0;
                }
            }

            // 打印轉換成功的adc, 打印耗時會導致打印完畢后直接再次進入中斷哦,
            // 導致很難看到loop里面的打印
            // defmt::info!("adc: {}", adc);
        }),
    );

    // 開啟 EOC 中斷
    adc.event_config(Event::EOC, true);
    adc.id().enable_interrupt();
    adc.start();
    loop {
        cortex_m::asm::wfi();

        defmt::info!(
            "adc {:?} sum: {} avrage: {}",
            Debug2Format(unsafe { &QUEUE }),
            unsafe { QUEUE.iter().sum::() },
            unsafe { QUEUE.iter().sum::() / QUEUE.len() asu16 }
        );
    }
}

測試代碼中使用接口來注入閉包函數,讓上下文能夠輕松地進入中斷處理函數中,中斷發生時能被調用。

pub fn on_interrupt(
        &mut self,
        events: EnumSet,
        callback: alloc::boxed::Box,
) 

那么如何實現這種設計模式呢? 在ADC 模塊的驅動中可以閱讀 src/adc/interrupt.rs 以及 src/adc/mod.rs

//  src/adc/interrupt.rs
use crate::pac::interrupt;

pub(super) staticmut CLOSURE: Option<*constdynFn()> = None;

pubfn dispatch() {
    unsafe {
        ifletSome(func) = CLOSURE {
            (*func)()
        }
    }
}

// ADC 中斷服務函數
#[interrupt]
fn ADC_COMP() {
    // ADC1 的中斷 eoc
    critical_section::with(|_cs| {
        dispatch();
    })
}

// src/adc/mod.rs

impl<'d, T: Instance, M: Mode> AnyAdc<'d, T, M> {
    pubfn on_interrupt(
        &mutself,
        events: EnumSet,
        callback: alloc::boxed::Box,
    ) {
        crate::interrupt::register(
            #[allow(static_mut_refs)]
            unsafe {
                &mut CLOSURE
            },
            alloc::boxed::Box::new(move || {
                callback(T::data_read());
                for e in events {
                    T::event_flag(e);
                }
            }),
        );
        for e in events {
            self.event_config(e, true);
        }
    }
}

ADC 的中斷服務函數為:fn ADC_COMP(), 中斷發生時,進入 fn dispatch() 函數,fn dispatch() 內部檢查存儲ADC中斷專用的閉包全局變量,當設置了 Option 的值后,即注冊了閉包,則執行閉包的邏輯。

on_interrupt 函數為 ADC 內部成員函數,負責提供給上層應用接口注入閉包邏輯。 crate::interrupt::register(...) 函數實現如下:

// src/interrupt.rs
use alloc::boxed::Box;

pubfn register(closure: &'staticmutOption<*constdynFn()>, f: Box) {
   unsafe {
       ifletSome(old) = *closure {
           *closure = None;
           let _ = alloc::boxed::Box::from_raw(old as *mutdynFn());
       }
       let raw = alloc::boxed::Box::into_raw(f);
       *closure = Some(raw)
   }
}

注冊函數將會使用 Box 申請堆空間用于存儲閉包邏輯,因此可在測試的 main 函數中看到設置堆區的初始化邏輯。要求堆的大小必須保證大于上層接口中的閉包所占用的空間大小。在注冊新的閉包時,register 內部會管理舊的閉包,即釋放舊的堆空間,讀者可以嘗試注釋let _ = alloc::boxed::Box::from_raw(old as *mut dyn Fn()); 后,多次調用 on_interrupt 即可。

測試結果

運行:cargo r --example adc_block_interrupt_closure --no-default-features -F "example"

注意需要關閉默認的宏embassy, 在 cargo r 命令后添加 --no-default-features 即可

 Erasing ? [00:00:00] [#######################################################################] 16.00 KiB/16.00 KiB @ 193.12 KiB/s (eta 0s )
 Programming ? [00:00:01] [#######################################################################] 13.75 KiB/13.75 KiB @ 8.18 KiB/s (eta 0s )    Finished in 1.784s
INFO  8000000
└─ adc_block_interrupt_closure::__cortex_m_rt_main::{closure#0} @ examples/adc_block_interrupt_closure.rs:35
INFO  adc "[0, 1441, 2170, 1394, 2243, 1446, 2172, 1399, 2251, 1442, 2182, 1412, 2261, 0, 0, 0]" sum: 1441 avrage: 1133
└─ adc_block_interrupt_closure::__cortex_m_rt_main::{closure#0} @ examples/adc_block_interrupt_closure.rs:78
INFO  adc "[2210, 1426, 2278, 1370, 2220, 1429, 2258, 1380, 2228, 1435, 2182, 1412, 2261, 1428, 2278, 1362]" sum: 26881 avrage: 1820
└─ adc_block_interrupt_closure::__cortex_m_rt_main::{closure#0} @ examples/adc_block_interrupt_closure.rs:78
INFO  adc "[2268, 1456, 2180, 1402, 2256, 1408, 2202, 1418, 2274, 1367, 2203, 1419, 2278, 1363, 2212, 1430]" sum: 29056 avrage: 1819
└─ adc_block_interrupt_closure::__cortex_m_rt_main::{closure#0} @ examples/adc_block_interrupt_closure.rs:78

引用

Rust語言圣經(Rust Course):https://course.rs/advance/functional-programing/closure.html 

py32f030-hal:https://github.com/hysonglet/py32f030-hal

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 1
收藏 2
關注 14
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: 奉节县| 原平市| 镶黄旗| 蕲春县| 共和县| 宁化县| 新和县| 棋牌| 东乡族自治县| 本溪| 东阿县| 合水县| 大埔区| 彭阳县| 岫岩| 宁波市| 陆河县| 东安县| 五大连池市| 罗定市| 广昌县| 疏勒县| 阳原县| 衡山县| 湟源县| 崇礼县| 宁津县| 咸宁市| 上杭县| 常德市| 万山特区| 固阳县| 九龙县| 小金县| 前郭尔| 临安市| 亳州市| 青神县| 鄂托克旗| 临海市| 越西县|