裸机 Rust 上午练习

罗盘

(返回练习)

  1. #![no_main]
  2. #![no_std]
  3. extern crate panic_halt as _;
  4. use core::fmt::Write;
  5. use cortex_m_rt::entry;
  6. use core::cmp::{max, min};
  7. use lsm303agr::{
  8. AccelMode, AccelOutputDataRate, Lsm303agr, MagMode, MagOutputDataRate,
  9. };
  10. use microbit::display::blocking::Display;
  11. use microbit::hal::prelude::*;
  12. use microbit::hal::twim::Twim;
  13. use microbit::hal::uarte::{Baudrate, Parity, Uarte};
  14. use microbit::hal::{Delay, Timer};
  15. use microbit::pac::twim0::frequency::FREQUENCY_A;
  16. use microbit::Board;
  17. const COMPASS_SCALE: i32 = 30000;
  18. const ACCELEROMETER_SCALE: i32 = 700;
  19. #[entry]
  20. fn main() -> ! {
  21. let board = Board::take().unwrap();
  22. // Configure serial port.
  23. let mut serial = Uarte::new(
  24. board.UARTE0,
  25. board.uart.into(),
  26. Parity::EXCLUDED,
  27. Baudrate::BAUD115200,
  28. );
  29. // Use the system timer as a delay provider.
  30. let mut delay = Delay::new(board.SYST);
  31. // Set up the I2C controller and Inertial Measurement Unit.
  32. writeln!(serial, "Setting up IMU...").unwrap();
  33. let i2c = Twim::new(board.TWIM0, board.i2c_internal.into(), FREQUENCY_A::K100);
  34. let mut imu = Lsm303agr::new_with_i2c(i2c);
  35. imu.init().unwrap();
  36. imu.set_mag_mode_and_odr(
  37. &mut delay,
  38. MagMode::HighResolution,
  39. MagOutputDataRate::Hz50,
  40. )
  41. .unwrap();
  42. imu.set_accel_mode_and_odr(
  43. &mut delay,
  44. AccelMode::Normal,
  45. AccelOutputDataRate::Hz50,
  46. )
  47. .unwrap();
  48. let mut imu = imu.into_mag_continuous().ok().unwrap();
  49. // Set up display and timer.
  50. let mut timer = Timer::new(board.TIMER0);
  51. let mut display = Display::new(board.display_pins);
  52. let mut mode = Mode::Compass;
  53. let mut button_pressed = false;
  54. writeln!(serial, "Ready.").unwrap();
  55. loop {
  56. // Read compass data and log it to the serial port.
  57. while !(imu.mag_status().unwrap().xyz_new_data()
  58. && imu.accel_status().unwrap().xyz_new_data())
  59. {}
  60. let compass_reading = imu.magnetic_field().unwrap();
  61. let accelerometer_reading = imu.acceleration().unwrap();
  62. writeln!(
  63. serial,
  64. "{},{},{}\t{},{},{}",
  65. compass_reading.x_nt(),
  66. compass_reading.y_nt(),
  67. compass_reading.z_nt(),
  68. accelerometer_reading.x_mg(),
  69. accelerometer_reading.y_mg(),
  70. accelerometer_reading.z_mg(),
  71. )
  72. .unwrap();
  73. let mut image = [[0; 5]; 5];
  74. let (x, y) = match mode {
  75. Mode::Compass => (
  76. scale(-compass_reading.x_nt(), -COMPASS_SCALE, COMPASS_SCALE, 0, 4)
  77. as usize,
  78. scale(compass_reading.y_nt(), -COMPASS_SCALE, COMPASS_SCALE, 0, 4)
  79. as usize,
  80. ),
  81. Mode::Accelerometer => (
  82. scale(
  83. accelerometer_reading.x_mg(),
  84. -ACCELEROMETER_SCALE,
  85. ACCELEROMETER_SCALE,
  86. 0,
  87. 4,
  88. ) as usize,
  89. scale(
  90. -accelerometer_reading.y_mg(),
  91. -ACCELEROMETER_SCALE,
  92. ACCELEROMETER_SCALE,
  93. 0,
  94. 4,
  95. ) as usize,
  96. ),
  97. };
  98. image[y][x] = 255;
  99. display.show(&mut timer, image, 100);
  100. // If button A is pressed, switch to the next mode and briefly blink all LEDs
  101. // on.
  102. if board.buttons.button_a.is_low().unwrap() {
  103. if !button_pressed {
  104. mode = mode.next();
  105. display.show(&mut timer, [[255; 5]; 5], 200);
  106. }
  107. button_pressed = true;
  108. } else {
  109. button_pressed = false;
  110. }
  111. }
  112. }
  113. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  114. enum Mode {
  115. Compass,
  116. Accelerometer,
  117. }
  118. impl Mode {
  119. fn next(self) -> Self {
  120. match self {
  121. Self::Compass => Self::Accelerometer,
  122. Self::Accelerometer => Self::Compass,
  123. }
  124. }
  125. }
  126. fn scale(value: i32, min_in: i32, max_in: i32, min_out: i32, max_out: i32) -> i32 {
  127. let range_in = max_in - min_in;
  128. let range_out = max_out - min_out;
  129. cap(min_out + range_out * (value - min_in) / range_in, min_out, max_out)
  130. }
  131. fn cap(value: i32, min_value: i32, max_value: i32) -> i32 {
  132. max(min_value, min(value, max_value))
  133. }