Rust嵌入式开发库rp-pico的使用:专为树莓派Pico微控制器设计的硬件抽象与驱动支持
Rust嵌入式开发库rp-pico的使用:专为树莓派Pico微控制器设计的硬件抽象与驱动支持
rp-pico是一个为Raspberry Pi Pico微控制器板设计的Rust嵌入式开发库,它基于RP2040芯片,提供了硬件抽象层(HAL)和引脚配置支持。
使用方式
在Cargo.toml中添加依赖:
rp-pico = "0.9.0"
在程序中需要调用rp_pico::Pins::new
来创建一个新的Pins
结构,这将设置所有GPIO引脚。
示例项目搭建
创建一个新项目并添加必要的依赖:
cargo new project-name
cd project-name
cargo add rp-pico
cargo add cortex-m-rt
cargo add panic-halt
还需要从rp-hal-boards仓库复制.cargo/config文件和memory.x文件到项目根目录。
完整示例代码
以下是内容中提供的最简单工作示例:
#![no_std]
#![no_main]
use rp_pico::entry;
use panic_halt as _;
#[entry]
fn see_doesnt_have_to_be_called_main() -> ! {
loop {}
}
这是一个最基本的框架程序,它只是无限循环而不做任何操作。
更多功能示例
内容中提到的几个示例功能:
- pico_blinky - 闪烁Pico板载LED
- pico_gpio_in_out - 读取GPIO 15上的按钮状态并控制板载LED
- pico_rtic - 演示在Pico上使用RTIC框架
- pico_countdown_blinky - 使用定时器的倒计时模式控制LED闪烁
- pico_pwm_blink - 在GPIO 25上输出模拟三角波
- pico_pwm_servo - 控制微型伺服电机
- pico_usb_serial - 创建USB串口设备
- pico_usb_serial_interrupt - 带中断处理的USB串口
- pico_usb_twitchy_mouse - 模拟USB鼠标输入设备
- pico_spi_sd_card - 使用SPI接口与SD卡通信
完整示例demo
以下是一个完整的LED闪烁示例(pico_blinky):
#![no_std]
#![no_main]
// 禁用标准库并指定无main函数的入口
use panic_halt as _; // 使用简单的panic处理
use rp_pico::entry;
use rp_pico::hal::gpio::Pin;
use rp_pico::hal::pac;
use rp_pico::hal::prelude::*;
use rp_pico::Pins;
#[entry]
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap(); // 获取RP2040外设
let core = pac::CorePeripherals::take().unwrap(); // 获取ARM Cortex-M0+核心外设
// 初始化时钟系统
let mut watchdog = rp_pico::hal::Watchdog::new(pac.WATCHDOG);
let clocks = rp_pico::hal::clocks::init_clocks_and_plls(
rp_pico::XOSC_CRYSTAL_FREQ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// 初始化延迟
let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
// 初始化GPIO引脚
let pins = Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
pac.SIO.gpio_bank0,
&mut pac.RESETS,
);
// 配置板载LED引脚(GPIO25)为输出
let mut led_pin = pins.led.into_push_pull_output();
// 主循环 - LED闪烁
loop {
led_pin.set_high().unwrap(); // 点亮LED
delay.delay_ms(500); // 延迟500ms
led_pin.set_low().unwrap(); // 熄灭LED
delay.delay_ms(500); // 延迟500ms
}
}
编译和运行示例
要编译示例:
rp-hal-boards/boards/rp-pico $ cargo build --release --example <name>
要转换为UF2格式并自动复制到板子:
rp-hal-boards/boards/rp-pico $ cargo run --release --example <name>
许可证
rp-pico采用双许可证:MIT OR Apache-2.0
贡献
欢迎贡献代码,具体步骤包括:
- Fork项目
- 创建特性分支
- 进行修改
- 提交变更
- 推送分支
- 创建Pull Request
- 等待审核和合并
1 回复
Rust嵌入式开发库rp-pico的使用指南
概述
rp-pico是一个专为树莓派Pico微控制器设计的Rust硬件抽象层(HAL)和驱动支持库。它提供了对RP2040微控制器的全面支持,使开发者能够使用Rust语言进行树莓派Pico的嵌入式开发。
主要特性
- 完整的RP2040微控制器外设支持
- 基于embedded-hal标准的硬件抽象
- 丰富的驱动程序生态系统
- 友好的Rust API设计
- 支持Pico开发板的各种功能
使用方法
1. 添加依赖
在Cargo.toml中添加rp-pico作为依赖:
[dependencies]
rp-pico = "0.9.0"
rp2040-hal = "0.9.0"
2. 基本设置示例
以下是一个简单的LED闪烁示例:
#![no_std]
#![no_main]
use rp_pico::entry;
use rp_pico::hal::{
clocks::{init_clocks_and_plls, Clock},
pac,
sio::Sio,
watchdog::Watchdog,
};
use embedded_hal::digital::v2::OutputPin;
use panic_halt as _;
#[entry]
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);
// 外部时钟为12MHz
let external_xtal_freq_hz = 12_000_000u32;
let clocks = init_clocks_and_plls(
external_xtal_freq_hz,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
let pins = rp_pico::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
let mut led_p极in = pins.led.into_push_pull_output();
loop {
led_pin.set_high().unwrap();
cortex_m::asm::delay(1_000_000);
led_pin.set_low().unwrap();
cortex_m::asm::delay(1_000_000);
}
}
3. 外设使用示例
GPIO输入输出
use rp_pico::hal::gpio::{Pin, PullUpInput, PushPullOutput};
use rp_pico::hal::prelude::*;
// 配置GPIO25为输出
let mut output_pin: Pin<_, PushPullOutput> = pins.gpio25.into_push_pull_output();
// 配置GPIO15为输入(上拉)
let input_pin: Pin<_, PullUpInput> = pins.gpio15.into_pull_up_input();
UART通信
use rp_pico::hal::uart::{UartConfig, DataBits, StopBits, Parity, UartPeripheral};
let uart = UartPeripheral::new(
pac.UART0,
&mut pac.RESETS,
clocks.peripheral_clock.into(),
)
.enable(
UartConfig::new(115200.0, DataBits::Eight, None, StopBits::One),
clocks.peripheral_clock.into(),
)
.unwrap();
uart.write_full_blocking(b"Hello, Pico!\n");
PWM输出
use rp_pico::hal::pwm::{Pwm, FreeRunning, Channel, A, B};
let pwm = Pwm::new(pac.PWM0, &mut pac.RESETS);
let mut channel_a = pwm.channel_a.pin(pins.gpio0.into_mode::<A>());
let mut channel_b = pwm.channel_b.pin(pins.gpio1.into_mode::<B>());
pwm.set_divider(1.0);
channel_a.set_duty(32768); // 50%占空比
channel_b.set_duty(16384); // 25%占空比
4. 中断处理
use rp_pico::hal::pac::interrupt;
use cortex_m::interrupt::free as interrupt_free;
#[interrupt]
fn TIMER_IRQ_0() {
interrupt_free(|cs| {
// 中断处理代码
});
}
构建和部署
- 安装必要的工具链:
rustup target add thumbv6m-none-eabi
cargo install elf2uf2-rs
- 构建项目:
cargo build --release
- 将程序刷写到Pico:
cargo run --release
注意事项
- 确保项目配置为
no_std
- 需要正确设置内存布局(linker script)
- 对于复杂项目,考虑使用
cortex-m-rt
提供的宏和功能 - 调试可以使用probe-rs或其他支持的工具
完整示例代码
以下是一个结合多种功能的完整示例,展示了如何使用rp-pico库实现LED控制、UART通信和PWM输出:
#![no_std]
#![no_main]
use rp_pico::entry;
use rp_pico::hal::{
clocks::{init_clocks_and_plls, Clock},
gpio::{Pin, PushPullOutput},
pac,
pwm::{Pwm, Channel, A, B},
sio::Sio,
uart::{UartConfig, DataBits, StopBits, UartPeripheral},
watchdog::Watchdog,
};
use embedded_hal::digital::v2::OutputPin;
use panic_halt as _;
#[entry]
fn main() -> ! {
// 初始化外设
let mut pac = pac::Peripherals::take().unwrap();
let core = pac::CorePeripherals::take().unwrap();
let mut watchdog = Watchdog::new(pac.WATCHDOG);
let sio = Sio::new(pac.SIO);
// 配置时钟
let external_xtal_freq_hz = 12_000_000u32;
let clocks = init_clocks_and_plls(
external_xtal_freq_hz,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// 初始化GPIO
let pins = rp_pico::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
// LED控制
let mut led_pin = pins.led.into_push_pull_output();
// UART初始化
let uart = UartPeripheral::new(
pac.UART0,
&mut pac.RESETS,
clocks.peripheral_clock.into(),
)
.enable(
UartConfig::new(115200.0, DataBits::Eight, None, StopBits::One),
clocks.peripheral_clock.into(),
)
.unwrap();
// PWM初始化
let pwm = Pwm::new(pac.PWM0, &mut pac.RESETS);
let mut channel_a = pwm.channel_a.pin(pins.gpio0.into_mode::<A>());
let mut channel_b = pwm.channel_b.pin(pins.gpio1.into_mode::<B>());
pwm.set_divider(1.0);
channel_a.set_duty(32768); // 50%占空比
channel_b.set_duty(16384); // 25%占空比
// 主循环
let mut counter = 0;
loop {
// LED闪烁
led_pin.set_high().unwrap();
cortex_m::asm::delay(500_000);
led_pin.set_low().unwrap();
cortex_m::asm::delay(500_000);
// UART发送计数
counter += 1;
uart.write_full_blocking(b"Counter: ");
uart.write_full_blocking(itoa::Buffer::new().format(counter).as_bytes());
uart.write_full_blocking(b"\n");
// 调整PWM占空比
channel_a.set_duty((counter % 65535) as u16);
}
}
这个完整示例展示了:
- 系统初始化和时钟配置
- LED控制实现闪烁效果
- UART通信用于输出调试信息
- PWM输出控制
- 综合应用的主循环逻辑
要运行此示例,需要在Cargo.toml中添加额外的依赖:
[dependencies]
itoa = "1.0"