读取单个寄存器

让我们将所有理论付诸实践!

首先,我们需要知道芯片内的加速度计和磁力计的从地址,这些可以在第39页的LSM303AGR数据表中找到,它们是:

  • 0011001 for the accelerometer
  • 0011110 for the magnetometer

注意:请记住,这些只是地址的前7位,第8位将是决定我们是执行读取还是写入的位。

接下来我们需要一个寄存器来读取。许多I2C芯片将提供某种设备标识寄存器,供其主机读取。这样做是因 为考虑到成千上万(甚至数百万)的I2C芯片, 很可能在某一时刻,两个具有相同地址的芯片最终将被构建 (毕竟地址"仅"7位宽)。有了这个设备ID寄存器,驱动程序可以确保它确实在与LSM303AGR通信,而不是 与恰好具有相同地址的其他芯片通信。正如您可以在 LSM303AGR 的数据表(特别是第46页和第61页) 中阅读的那样,它确实提供了两个寄存器, 分别称为WHO_AM_I_A地址0x0fWHO_AM_I_M地址0x4f 其中包含一些设备独有的位模式(A与加速度计相同,M与磁力计相同)。

现在唯一缺少的是软件部分,即microbit我们应该为此使用/the HAL crates的哪个API。但是,如果您仔 细阅读您正在使用的nRF芯片的数据表, 您很快就会发现它们实际上并没有I2C外设。不过对我们来说幸运的是,它们 有与I2C兼容的TWI(双线接口)和TWIM(取决于您使用的芯片,就像UART和UART一样)。

现在,如果我们将microbit crate中twi(m)模块的文档与我们迄今为止收集到的所有其他信息放在一起, 我们将得到这段代码来读取和打印两个设备ID:

#![deny(unsafe_code)]
#![no_main]
#![no_std]

use cortex_m_rt::entry;
use rtt_target::{rtt_init_print, rprintln};
use panic_rtt_target as _;

use microbit::hal::prelude::*;

#[cfg(feature = "v1")]
use microbit::{
    hal::twi,
    pac::twi0::frequency::FREQUENCY_A,
};

#[cfg(feature = "v2")]
use microbit::{
    hal::twim,
    pac::twim0::frequency::FREQUENCY_A,
};

const ACCELEROMETER_ADDR: u8 = 0b0011001;
const MAGNETOMETER_ADDR: u8 = 0b0011110;

const ACCELEROMETER_ID_REG: u8 = 0x0f;
const MAGNETOMETER_ID_REG: u8 = 0x4f;

#[entry]
fn main() -> ! {
    rtt_init_print!();
    let board = microbit::Board::take().unwrap();


    #[cfg(feature = "v1")]
    let mut i2c = { twi::Twi::new(board.TWI0, board.i2c.into(), FREQUENCY_A::K100) };

    #[cfg(feature = "v2")]
    let mut i2c = { twim::Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100) };

    let mut acc = [0];
    let mut mag = [0];

    // First write the address + register onto the bus, then read the chip's responses
    i2c.write_read(ACCELEROMETER_ADDR, &[ACCELEROMETER_ID_REG], &mut acc).unwrap();
    i2c.write_read(MAGNETOMETER_ADDR, &[MAGNETOMETER_ID_REG], &mut mag).unwrap();

    rprintln!("The accelerometer chip's id is: {:#b}", acc[0]);
    rprintln!("The magnetometer chip's id is: {:#b}", mag[0]);

    loop {}
}

除了初始化之外,如果您理解前面描述的I2C协议,那么这段代码应该是直截了当的。这里的初始化与UART章节中的初始化类似。 我们将外围设备以及用于与芯片通信的引脚传递给构造器;然后是我们希望总线工作的频率,在这种情况下为100kHz(K100)。

测试

与往常一样,您必须修改Embed.toml以适合您的MCU,然后可以使用:

# For micro:bit v2
$ cargo embed --features v2 --target thumbv7em-none-eabihf

# For micro:bit v1
$ cargo embed --features v1 --target thumbv6m-none-eabi

为了测试我们的小示例程序。