(back to exercise)
#![no_main]
#![no_std]
extern crate panic_halt as _;
use core::fmt::Write;
use cortex_m_rt::entry;
use core::cmp::{max, min};
use lsm303agr::{AccelOutputDataRate, Lsm303agr, MagOutputDataRate};
use microbit::display::blocking::Display;
use microbit::hal::prelude::*;
use microbit::hal::twim::Twim;
use microbit::hal::uarte::{Baudrate, Parity, Uarte};
use microbit::hal::Timer;
use microbit::pac::twim0::frequency::FREQUENCY_A;
use microbit::Board;
const COMPASS_SCALE: i32 = 30000;
const ACCELEROMETER_SCALE: i32 = 700;
#[entry]
fn main() -> ! {
let board = Board::take().unwrap();
// Configure serial port.
let mut serial = Uarte::new(
board.UARTE0,
board.uart.into(),
Parity::EXCLUDED,
Baudrate::BAUD115200,
);
// Set up the I2C controller and Inertial Measurement Unit.
writeln!(serial, "Setting up IMU...").unwrap();
let i2c = Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100);
let mut imu = Lsm303agr::new_with_i2c(i2c);
imu.init().unwrap();
imu.set_mag_odr(MagOutputDataRate::Hz50).unwrap();
imu.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();
let mut imu = imu.into_mag_continuous().ok().unwrap();
// Set up display and timer.
let mut timer = Timer::new(board.TIMER0);
let mut display = Display::new(board.display_pins);
let mut mode = Mode::Compass;
let mut button_pressed = false;
writeln!(serial, "Ready.").unwrap();
loop {
// Read compass data and log it to the serial port.
while !(imu.mag_status().unwrap().xyz_new_data
&& imu.accel_status().unwrap().xyz_new_data)
{}
let compass_reading = imu.mag_data().unwrap();
let accelerometer_reading = imu.accel_data().unwrap();
writeln!(
serial,
"{},{},{}\t{},{},{}",
compass_reading.x,
compass_reading.y,
compass_reading.z,
accelerometer_reading.x,
accelerometer_reading.y,
accelerometer_reading.z,
)
.unwrap();
let mut image = [[0; 5]; 5];
let (x, y) = match mode {
Mode::Compass => (
scale(-compass_reading.x, -COMPASS_SCALE, COMPASS_SCALE, 0, 4) as usize,
scale(compass_reading.y, -COMPASS_SCALE, COMPASS_SCALE, 0, 4) as usize,
),
Mode::Accelerometer => (
scale(
accelerometer_reading.x,
-ACCELEROMETER_SCALE,
ACCELEROMETER_SCALE,
0,
4,
) as usize,
scale(
-accelerometer_reading.y,
-ACCELEROMETER_SCALE,
ACCELEROMETER_SCALE,
0,
4,
) as usize,
),
};
image[y][x] = 255;
display.show(&mut timer, image, 100);
// If button A is pressed, switch to the next mode and briefly blink all LEDs on.
if board.buttons.button_a.is_low().unwrap() {
if !button_pressed {
mode = mode.next();
display.show(&mut timer, [[255; 5]; 5], 200);
}
button_pressed = true;
} else {
button_pressed = false;
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Mode {
Compass,
Accelerometer,
}
impl Mode {
fn next(self) -> Self {
match self {
Self::Compass => Self::Accelerometer,
Self::Accelerometer => Self::Compass,
}
}
}
fn scale(value: i32, min_in: i32, max_in: i32, min_out: i32, max_out: i32) -> i32 {
let range_in = max_in - min_in;
let range_out = max_out - min_out;
cap(
min_out + range_out * (value - min_in) / range_in,
min_out,
max_out,
)
}
fn cap(value: i32, min_value: i32, max_value: i32) -> i32 {
max(min_value, min(value, max_value))
}