Rust嵌入式开发库nrf52840-pac的使用,为Nordic nRF52840芯片提供外设访问控制与硬件抽象功能
Rust嵌入式开发库nrf52840-pac的使用,为Nordic nRF52840芯片提供外设访问控制与硬件抽象功能
nrf52840-pac是一个Rust嵌入式开发库,专门为Nordic nRF52840芯片提供外设访问控制(Peripheral Access Crate)与硬件抽象功能。
安装
在项目目录中运行以下Cargo命令:
cargo add nrf52840-pac
或者在Cargo.toml中添加以下行:
nrf52840-pac = "0.12.2"
示例代码
以下是一个使用nrf52840-pac控制GPIO的完整示例:
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use nrf52840_pac as pac; // 导入nRF52840外设访问库
use panic_halt as _;
#[entry]
fn main() -> ! {
    // 获取外设实例
    let p = pac::Peripherals::take().unwrap();
    
    // 配置P0.13引脚为输出
    p.P0.pin_cnf[13].write(|w| {
        w.dir().output()      // 设置为输出模式
         .input().disconnect() // 断开输入
         .pull().disabled()    // 禁用上拉/下拉
         .drive().s0s1()       // 标准驱动强度
         .sense().disabled()   // 禁用感应
    });
    
    // 无限循环,闪烁LED
    loop {
        // 设置P0.13为高电平
        p.P0.outset.write(|w| w.p極13().set());
        cortex_m::asm::delay(1_000_000); // 简单延时
        
        // 设置P0.13为低电平
        p.P0.outclr.write(|w| w.pin13().clear());
        cortex_m::asm::delay(1_000_000);
    }
}
更完整的UART通信示例
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use nrf52840_pac as pac;
use panic_halt as _;
#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();
    
    // 1. 配置GPIO
    // 设置P0.06为UART TX
    p.P0.pin_cnf[6].write(|w| {
        w.dir().output()
         .input().disconnect()
         .pull().disabled()
         .drive().s0s1()
         .sense().disabled()
    });
    
    // 设置P0.08为UART RX
    p.P0.pin_cnf[8].write(|w| {
        w.dir().input()
         .input().connect()
         .pull().disabled()
         .drive().s0s1()
         .sense().disabled()
    });
    
    // 2. 配置UART
    // 先禁用UART
    p.UART0.enable.write(|w| w.enable().disabled());
    
    // 配置波特率为115200
    p.UART0.baudrate.write(|w| w.baudrate().baud115200());
    
    // 配置引脚选择
    p.UART0.pseltxd.write(|w| unsafe { w.bits(6) });
    p.UART0.pselrxd.write(|w| unsafe { w.bits(8) });
    
    // 禁用CTS/RTS
    p.UART0.pselcts.write(|w| w.bits(0xFFFFFFFF));
    p.UART0.pselrts.write(|w| w.bits(0xFFFFFFFF));
    
    // 启用UART
    p.UART0.enable.write(|w| w.enable().enabled());
    
    // 3. 发送数据
    let message = b"Hello from nRF52840!\n";
    for &byte in message {
        // 等待发送缓冲区准备就绪
        while p.UART0.events_txdrdy.read().bits() == 0 {}
        p.UART0.events_txdrdy.write(|w| unsafe { w.bits(极) });
        
        // 发送字节
        p.UART0.txd.write(|w| unsafe { w.bits(u32::from(byte)) });
    }
    
    loop {}
}
SPI通信完整示例
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use nrf52840_pac as pac;
use panic_halt as _;
#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();
    // 1. 配置SPI引脚
    // MOSI - P0.20
    p.P0.pin_cnf[20].write(|w| {
        w.dir().output()
         .input().disconnect()
         .pull().disabled()
         .drive().s0s1()
         .sense().disabled()
    });
    // MISO - P0.21
    p.P0.pin_cnf[21].write(|w| {
        w.dir().input()
         .input().connect()
         .pull().disabled()
         .drive().s0s1()
         .sense().disabled()
    });
    // SCK - P0.19
    p.P0.pin_cnf[19].write(|w| {
        w.dir().output()
         .input().disconnect()
         .pull().disabled()
         .drive().s0s1()
         .sense().disabled()
    });
    // 2. 配置SPI外设
    p.SPI0.enable.write(|w| w.enable().disabled());
    
    // 配置SPI模式0 (CPOL=0, CPHA=0)
    p.SPI0.config.write(|w| {
        w.order().msb_first()  // 高位在前
         .cpha().leading()     // 模式0
         .cpol().active_high() // 模式0
    });
    // 设置频率为1MHz
    p.SPI0.frequency.write(|w| w.frequency().m1());
    // 配置引脚选择
    p.SPI0.psel.mosi.write(|w| unsafe { w.bits(20) });
    p.SPI0.psel.miso.write(|w| unsafe { w.bits(21) });
    p.SPI0.psel.sck.write(|w| unsafe { w.bits(19) });
    // 启用SPI
    p.SPI0.enable.write(|w| w.enable().enabled());
    // 3. SPI数据传输示例
    let tx_data: [u8; 4] = [0xAA, 0xBB, 0xCC, 0xDD];
    let mut rx_data: [u8; 4] = [0; 4];
    for i in 0..tx_data.len() {
        // 写入要发送的数据
        p.SPI0.txd.write(|w| unsafe { w.bits(u32::from(tx_data[i])) });
        
        // 等待接收完成
        while p.SPI0.events_ready.read().bits() == 0 {}
        p.SPI0.events_ready.write(|w| unsafe { w.bits(0) });
        
        // 读取接收到的数据
        rx_data[i] = p.SPI0.rxd.read().bits() as u8;
    }
    loop {}
}
nrf52840-pac提供了对nRF52840芯片所有外设的低级访问,包括GPIO、UART、SPI、I2C、PWM、ADC等。通过这个库,开发者可以安全高效地开发nRF52840嵌入式应用。
        
          1 回复
        
      
      
        nrf52840-pac - Nordic nRF52840芯片的Rust外设访问控制库
nrf52840-pac是一个Rust嵌入式开发库,专门为Nordic nRF52840系列芯片提供外设访问控制(Peripheral Access Crate)和硬件抽象功能。
功能概述
- 提供对nRF52840所有外设寄存器的安全访问
 - 自动生成的寄存器定义,与芯片手册完全对应
 - 类型安全的寄存器操作接口
 - 支持中断处理
 - 与RTIC框架兼容
 
使用方法
添加依赖
在Cargo.toml中添加:
[dependencies]
nrf52840-pac = "0.10.0"
cortex-m = "0.7.6"
cortex-m-rt = "0.7.1"
基本外设访问示例
use nrf52840_pac as pac;
use cortex_m::peripheral::syst;
fn main() -> ! {
    // 获取外设访问权
    let p = pac::Peripherals::take().unwrap();
    let cp = cortex_m::Peripherals::take().unwrap();
    
    // 配置GPIO
    let gpio = p.P0;
    gpio.pin_cnf[13].write(|w| w.dir().output());
    
    // 配置系统定时器
    let mut syst = cp.SYST;
    syst.set_clock_source(syst::SystClkSource::Core);
    syst.set_reload(16_000_000); // 1秒间隔
    syst.enable_counter();
    syst.enable_interrupt();
    
    loop {
        // 翻转LED引脚
        gpio.out.write(|w| unsafe { w.bits(1 << 13) });
        cortex_m::asm::delay(16_000_000);
        gpio.out.write(|w| unsafe { w.bits(0) });
        cortex_m::asm::delay(16_000_000);
    }
}
中断处理示例
use cortex_m_rt::entry;
use nrf52840_pac::{interrupt, Interrupt};
#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();
    
    // 配置TIMER0
    p.TIMER0.start.write(|w| unsafe { w.bits(1_000_000) });
    p.TIMER0.intenset.write(|w| w.compare0().set());
    
    // 启用中断
    unsafe {
        cortex_m::peripheral::NVIC::unmask(Interrupt::TIMER0);
    }
    
    loop {}
}
#[interrupt]
fn TIMER0() {
    let p = unsafe { pac::Peripherals::steal() };
    
    // 清除中断标志
    p.TIMER0.events_compare[0].write(|w| w.bits(0));
    
    // 处理定时器中断
}
高级功能 - 使用RTIC框架
#![no_main]
#![no_std]
use rtic::app;
use nrf52840_pac as pac;
#[app(device = pac)]
const APP: () = {
    #[init]
    fn init(cx: init::Context) {
        // 初始化外设
        let timer0 = cx.device.TIMER0;
        timer0.prescaler.write(|w| unsafe { w.bits(4) });
    }
    
    #[task(binds = TIMER0, priority = 1)]
    fn timer_handler(cx: timer_handler::Context) {
        // 定时器中断处理
    }
};
完整示例代码
以下是一个完整的LED闪烁示例,结合GPIO控制和定时器中断:
#![no_main]
#![no_std]
use cortex_m_rt::entry;
use nrf52840_pac::{interrupt, Peripherals};
use panic_halt as _;
// LED连接的引脚号
const LED_PIN: usize = 13;
#[entry]
fn main() -> ! {
    let p = Peripherals::take().unwrap();
    
    // 1. 配置GPIO
    // 设置LED引脚为输出
    p.P0.pin_cnf[LED_PIN].write(|w| {
        w.dir().output()  // 设置为输出模式
         .drive().s0s1()  // 标准驱动强度
         .input().disconnect() // 禁止输入
         .pull().disabled() // 禁止上下拉
         .sense().disabled() // 禁止感应
    });
    
    // 2. 配置TIMER0
    // 设置预分频器 (16MHz/16 = 1MHz)
    p.TIMER0.prescaler.write(|w| unsafe { w.bits(4) });
    // 设置比较值0 (500ms)
    p.TIMER0.cc[0].write(|w| unsafe { w.bits(500_000) });
    // 启用比较0事件
    p.TIMER0.intenset.write(|w| w.compare0().set());
    // 启动定时器
    p.TIMER0.tasks_start.write(|w| unsafe { w.bits(1) });
    
    // 3. 启用中断
    unsafe {
        cortex_m::peripheral::NVIC::unmask(interrupt::TIMER0);
    }
    
    loop {
        cortex_m::asm::wfi(); // 进入低功耗模式,等待中断
    }
}
#[interrupt]
fn TIMER0() {
    let p = unsafe { Peripherals::steal() };
    
    // 清除中断标志
    p.TIMER0.events_compare[0].write(|w| w.bits(0));
    
    // 切换LED状态
    let current_state = p.P0.out.read().bits();
    p.P0.out.write(|w| unsafe { w.bits(current_state ^ (1 << LED_PIN)) });
}
注意事项
- 寄存器访问默认是安全的,但使用
unsafe可以绕过编译器检查 - 大多数外设需要先启用时钟才能正常工作
 - 中断处理函数需要正确清除中断标志
 - 在多任务环境中使用时需要适当的同步机制
 
        
      
                    
                  
                    
