码迷,mamicode.com
首页 > 其他好文 > 详细

Rust嵌入式初探(三):外部中断

时间:2021-03-09 13:35:03      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:文章   deb   ext   源码   you   sage   try   cat   wrap   

实验器材及参考资料

同本系列的第一篇文章

实验内容

在stm32上用rust编写简单的中断程序,实验电路如下:
技术图片
技术图片
本实验实现在按下按键KEY0时,灯LED0就会改变状态,比如LED0是亮着的,一旦按键按下就会立马灭掉.

源码分析

我直接在下面列出源代码,源代码有些长,大部分是花在全局变量的处理上了,有时间再详细解释一下:

#![no_std]
#![no_main]

use cortex_m::interrupt::{free, Mutex};
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
                     // use panic_abort as _; // requires nightly
                     // use panic_itm as _; // logs messages over ITM; requires ITM support
                     // use panic_semihosting as _; // logs messages to the host stderr; requires a debugger

use cortex_m_rt::entry;
//use cortex_m_semihosting::{hprint, hprintln};
use core::{cell::RefCell, ops::DerefMut};
use stm32f1::stm32f103;
use stm32f103::{interrupt, Interrupt};
//use stm32f103::{GPIOB, RCC};

static PERIPH: Mutex<RefCell<Option<stm32f103::Peripherals>>> = Mutex::new(RefCell::new(None)); //静态全局变量,方便获取总线
fn periph_init(in_data: stm32f103::Peripherals) {
    free(|cs| {
        let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
        let opthion_ref = tmp_ref.deref_mut();
        *opthion_ref = Some(in_data);
    });
}
struct Led {
    inited: bool,
    status: bool, //true为开启状态
}
impl Led {
    fn init(&mut self) {
        //初始化led灯的总线状态
        if !self.inited {
            free(|cs| {
                let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
                match tmp_ref.deref_mut().as_mut() {
                    Some(periph) => {
                        periph.RCC.apb2enr.modify(|_, w| w.iopben().bit(true)); //使能portB时钟
                        periph.GPIOB.crl.modify(|_, w| w.mode5().bits(0b11)); //将gpioB 第五口设为推挽输出
                        periph.GPIOB.odr.modify(|_, w| w.odr5().bit(true)); //灯灭
                    }
                    _ => {}
                }
            });
            self.inited = true;
            self.status = false;
        }
    }
    fn led_on(&mut self) {
        //让灯亮
        if self.inited {
            free(|cs| {
                let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
                match tmp_ref.deref_mut().as_mut() {
                    Some(periph) => {
                        periph.GPIOB.odr.modify(|_, w| w.odr5().bit(false)); //灯亮
                    }
                    _ => {}
                }
            });
            self.status = true;
        }
    }
    fn led_off(&mut self) {
        //灯灭
        if self.inited {
            free(|cs| {
                let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
                match tmp_ref.deref_mut().as_mut() {
                    Some(periph) => {
                        periph.GPIOB.odr.modify(|_, w| w.odr5().bit(false)); //灯亮
                    }
                    _ => {}
                }
            });
            self.status = true;
        }
    }
    fn status(&self) -> bool {
        return self.status;
    }
}
static mut LED1: Led = Led {
    inited: false,
    status: false,
};
#[entry]
fn main() -> ! {
    // your code goes here
    let peripherals = stm32f103::Peripherals::take().unwrap(); //stm32的总线
    periph_init(peripherals);
    unsafe {
        LED1.init();
    }

    /*判断中断分组的初始值,我尝试的结果是000,即中断分组未初始化.
    let core_peripherals = cortex_m::Peripherals::take().unwrap();
    let aircr_data = core_peripherals.SCB.aircr.read();
    match (aircr_data>>4) &0x0000000F {
        0x00000000 =>hprintln!("000!").unwrap(),
        0x00000007 =>hprintln!("111!").unwrap(),
        0x00000006 =>hprintln!("110!").unwrap(),
        0x00000005 =>hprintln!("101!").unwrap(),
        0x00000004 =>hprintln!("100!").unwrap(),
        0x00000003 =>hprintln!("011!").unwrap(),
        _=>hprintln!("unexpect error!").unwrap(),
    };
     */
    /*因此下面需要设置中断分组*/
    let core_peripherals = cortex_m::Peripherals::take().unwrap();
    unsafe {
        core_peripherals.SCB.aircr.write(0x05FA0700); //设置中断分组为0
        cortex_m::peripheral::NVIC::unmask(Interrupt::EXTI4); //开PE4的中断
    }

    /*下面是关于io口的设置*/
    free(|cs| {
        let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
        match tmp_ref.deref_mut().as_mut() {
            Some(periph) => {
                periph.RCC.apb2enr.modify(|_, w| w.afioen().enabled()); //使能io复用时钟
                periph
                    .AFIO
                    .exticr2
                    .write(|w| unsafe { w.exti4().bits(0b0100) }); //映射PE4口到中断线4
                periph.GPIOE.crl.modify(|_,w| w.mode4().bits(0b00).cnf4().bits(0b10));//这里设置PE4口为上/下拉输入
                periph.GPIOE.odr.modify(|_,w| w.odr4().bit(true));//设置为上拉
            }
            _ => {}
        }
    });

    /*从这里配置EXTI控制器的相关属性 */
    free(|cs| {
        let mut tmp_ref = PERIPH.borrow(cs).borrow_mut();
        match tmp_ref.deref_mut().as_mut() {
            Some(periph) => {
                periph.EXTI.imr.modify(|_,w| w.mr4().bit(true));//允许中断线发送中断
                periph.EXTI.ftsr.modify(|_,w| w.tr4().bit(true));//允许4中断线在下降沿发送中断
            }
            _ => {}
        }
    });

    loop {}
}
#[interrupt]
fn EXTI4() {
    //一旦触发中断反转灯的亮暗
    unsafe {
        if LED1.status() {
            LED1.led_off();
        } else {
            LED1.led_on();
        }
    }
}

我在写的过程中卡住的一个重要问题就是如何在中断中使用相应的寄存器,而我们又显然要在主程序中利用stm32的一些寄存器来配置中断、以及实现相应端口的初始化.而PAC库的peripheral只能被获取一次,这就意味着如果在主程序中获取peripheral结构体的话就无法在中断程序中单独地利用函数来获取了.于是利用我们在C语言的经验,我们就果断地使用公共变量来实现.我们显然可以这么写:

static PERIPH: Option<stm32f103::Peripherals> = None; //静态全局变量,方便获取总线
#[entry]
fn main {
}

然后就可以得到一个报错结果,结果会显示Peripheral没有实现sync Trait,然后就无法继续进行了.经过查阅资料,我渐渐了解,cortex-m库提供了在中断环境中进行同步的机制,于是我们可以利用这个机制这样写:

use cortex_m::interrupt::{free, Mutex};
static PERIPH: Mutex<Option<stm32f103::Peripherals>>  =Mutex::new(None); //静态全局变量,方便获取总线
#[entry]
fn main {
}

然后我们会发现,如果我们想对Peripheral进行操作,那就必须用unsafe 块,这是由Rust的安全机制决定的,于是我们使用Rust提供的内部可变性来解决这一问题:

use cortex_m::interrupt::{free, Mutex};
use core::cell::RefCell;
static PERIPH: Mutex<RefCell<Option<stm32f103::Peripherals>>> = Mutex::new(RefCell::new(None)); //静态全局变量,方便获取总线
#[entry]
fn main {
}

Rust嵌入式初探(三):外部中断

标签:文章   deb   ext   源码   you   sage   try   cat   wrap   

原文地址:https://www.cnblogs.com/flyer20006/p/14502314.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!