久久久国产精品视频袁燕,99re久久精品国产,亚洲欧美日韩国产综合v,天天躁夜夜躁狠狠久久,激情五月婷婷激情五月婷婷

在單片機中使用Rust閉包優(yōu)雅應對中斷

什么是閉包

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

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

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

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

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

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

使用閉包優(yōu)雅處理中斷

本篇文章將介紹如何使用閉包優(yōu)雅處理中斷。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) // 轉(zhuǎn)換完成后等待讀取完畢再開始轉(zhuǎn)換
            .singal(TrigleSignal::Soft)
            .mode(ConversionMode::Continuous),
        &[AdcChannel::Channel11, AdcChannel::Channel12],
        // &[AdcChannel::Channel11],
    )
    .unwrap();

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

            // 打印轉(zhuǎn)換成功的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 }
        );
    }
}

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

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

那么如何實現(xiàn)這種設計模式呢? 在ADC 模塊的驅(qū)動中可以閱讀 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 中斷服務函數(shù)
#[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 的中斷服務函數(shù)為:fn ADC_COMP(), 中斷發(fā)生時,進入 fn dispatch() 函數(shù),fn dispatch() 內(nèi)部檢查存儲ADC中斷專用的閉包全局變量,當設置了 Option 的值后,即注冊了閉包,則執(zhí)行閉包的邏輯。

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

// 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)
   }
}

注冊函數(shù)將會使用 Box 申請堆空間用于存儲閉包邏輯,因此可在測試的 main 函數(shù)中看到設置堆區(qū)的初始化邏輯。要求堆的大小必須保證大于上層接口中的閉包所占用的空間大小。在注冊新的閉包時,register 內(nèi)部會管理舊的閉包,即釋放舊的堆空間,讀者可以嘗試注釋let _ = alloc::boxed::Box::from_raw(old as *mut dyn Fn()); 后,多次調(diào)用 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語言圣經(jīng)(Rust Course):https://course.rs/advance/functional-programing/closure.html 

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

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