Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Зажигаем светодиод

Закончим главу тем, что зажжём один из многочисленных светодиодов MB2. Для этого воспользуемся одним из трейтов, которые предоставляет embedded-hal, а именно трейтом OutputPin, который позволяет включать и выключать вывод.

Светодиоды micro:bit

На обратной стороне micro:bit видно квадрат 5×5 из светодиодов, который обычно называют матрицей светодиодов (LED matrix). Такое расположение позволяет обойтись не 25 отдельными выводами для управления каждым светодиодом, а всего 10 (5+5): ими задаётся, какой столбец и какая строка матрицы будут гореть.

Пока для управления светодиодами мы будем использовать крейт microbit-v2. В следующей главе подробно разберём все доступные варианты.

Зажигаем светодиод!

Код, который зажигает светодиод в матрице, на самом деле довольно прост, но требует небольшой подготовки. Сначала посмотрите на src/main.rs, а затем пройдёмся по нему шаг за шагом.

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

use cortex_m_rt::entry;
use embedded_hal::digital::OutputPin;
use microbit::board::Board;
use panic_halt as _;

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

    board.display_pins.col1.set_low().unwrap();
    board.display_pins.row1.set_high().unwrap();

    loop {
        core::hint::spin_loop();
    }
}

Первые строки до функции main — это базовые импорты и настройка, с которыми мы в основном уже встречались. А вот функция main выглядит совсем иначе, чем всё, что мы видели до сих пор.

Первая строка связана с внутренним устройством большинства HAL, написанных на Rust. Как мы обсуждали ранее, они строятся поверх крейтов PAC, которые владеют (в смысле Rust) всей периферией чипа. Когда мы пишем

let mut board = Board::take().unwrap();

мы забираем всю эту периферию у PAC и связываем её с переменной. В этом случае мы работаем не просто с HAL, а со всем BSP, поэтому вызов также забирает во владение Rust-представление других чипов на плате.

ПРИМЕЧАНИЕ: Если вам интересно, зачем здесь unwrap(): в теории take() может быть вызван более одного раза. Тогда периферия будет представлена двумя разными переменными, и две переменные будут менять один и тот же ресурс, что приведёт к путанице в поведении. Чтобы этого избежать, PAC реализованы так, что при повторном взятии периферии программа запаникует.

(Если всё это вас запутало, в следующей главе всё объясняется ещё раз, подробнее.)

Теперь мы можем зажечь светодиод, подключённый к row1, col1, установив вывод row1 в высокий уровень (то есть включив его). Вывод col1 можно оставить в низком уровне, потому что так устроена схема матрицы светодиодов. Кроме того, embedded-hal спроектирован так, что любая операция с аппаратурой может вернуть ошибку, даже простое включение или выключение вывода. Поскольку в нашем случае это крайне маловероятно, можно просто вызвать unwrap() для результата.

Проверка

Проверить нашу маленькую программу несложно. Запускаем cargo embed и даём ему прошить программу, как и раньше. Затем открываем GDB и подключаемся к GDB-стабу.

$ gdb ../../../target/thumbv7em-none-eabihf/debug/meet-your-software
(gdb) target remote :1337
Remote debugging using :1337
cortex_m_rt::Reset () at /home/nix/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-rt-0.6.12/src/lib.rs:489
489     pub unsafe extern "C" fn Reset() -> ! {
(gdb)

Теперь запускаем программу командой GDB continue: один из светодиодов на передней стороне micro:bit должен загореться.