在Led和Delay抽象 现在,我将介绍两个高级抽象,我们将用它来实现LED轮盘应用程序。

辅助包,aux5公开一个名为的初始化函数init。当调用此函数时,返回在元组中打包的两个值:Delay值和Leds值。

Delay 可用于阻止程序达到指定的毫秒数。

Leds实际上是一个八Led秒的数组。每个Led代表在F3板上的LED中的一个,并公开了两种方法:on和off其可用于以导通LED或关闭,分别。

让我们通过修改起始代码来尝试这两个抽象,如下所示:

![deny(unsafe_code)]

![no_main]

![no_std]

use aux5::{entry, prelude::*, Delay, Leds};

[entry]

fn main() -> ! { let (mut delay, mut leds): (Delay, Leds) = aux5::init();

  1. let half_period = 500_u16;
  2. loop {
  3. leds[0].on();
  4. delay.delay_ms(half_period);
  5. leds[0].off();
  6. delay.delay_ms(half_period);
  7. }

} 现在构建它:

$ cargo build —target thumbv7em-none-eabihf 注意在启动GDB会话之前,可能会忘记重建程序; 这种遗漏会导致调试会话非常混乱。为了避免这个问题,你可以打电话cargo run 而不是cargo build; cargo run将构建并启动调试会话,确保您永远不会忘记重新编译您的程序。

现在,我们将重复我们在上一节中所做的闪烁过程:

$ # this starts a GDB session of the program; no need to specify the path to the binary $ arm-none-eabi-gdb -q target/thumbv7em-none-eabihf/debug/led-roulette Reading symbols from target/thumbv7em-none-eabihf/debug/led-roulette…done. (gdb) target remote :3333 Remote debugging using :3333 (..)

(gdb) load Loading section .vector_table, size 0x188 lma 0x8000000 Loading section .text, size 0x3fc6 lma 0x8000188 Loading section .rodata, size 0xa0c lma 0x8004150 Start address 0x8000188, load size 19290 Transfer rate: 19 KB/sec, 4822 bytes/write.

(gdb) break main Breakpoint 1 at 0x800018c: file src/05-led-roulette/src/main.rs, line 9.

(gdb) continue Continuing. Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at src/05-led-roulette/src/main.rs:9 9 let (mut delay, mut leds): (Delay, Leds) = aux5::init(); 好。让我们逐步完成代码。这一次,我们将使用next命令而不是step。不同之处在于next命令将跳过函数调用而不是进入函数调用。

(gdb) next 11 let half_period = 500_u16;

(gdb) next 13 loop {

(gdb) next 14 leds[0].on();

(gdb) next 15 delay.delay_ms(half_period); 执行该leds[0].on()语句后,您应该看到一个红色LED指示灯,指向北方,指示灯亮起。

让我们继续踩过这个计划:

(gdb) next 17 leds[0].off();

(gdb) next 18 delay.delay_ms(half_period); 该delay_ms调用将阻止该程序半秒,但您可能不会注意到,因为该 next命令也需要一些时间来执行。但是,在单步执行leds[0].off() 语句后,您应该看到红色LED熄灭。

你已经可以猜出这个程序的作用了。让它使用continue命令不间断地运行。

(gdb) continue Continuing. 现在,让我们做一些更有趣的事情。我们将使用GDB修改程序的行为。

首先,让我们通过点击停止无限循环Ctrl+C。你可能会在某个地方结束 Led::on,Led::off或者delay_ms:

Program received signal SIGINT, Interrupt. 0x080033f6 in core::ptr::read_volatile (src=0xe000e010) at /checkout/src/libcore/ptr.rs:472 472 /checkout/src/libcore/ptr.rs: No such file or directory. 在我的例子中,程序在read_volatile函数内停止执行。GDB输出显示了一些有趣的信息:core::ptr::read_volatile (src=0xe000e010)。这意味着该函数来自corecrate并且它是通过参数调用的src = 0xe000e010。

您知道,显示函数参数的更明确的方法是使用info args 命令:

(gdb) info args src = 0xe000e010 无论你的程序停止在哪里,你都可以随时查看backtrace命令的输出 (bt简称)来了解它是如何到达的:

(gdb) backtrace

0 0x080033f6 in core::ptr::read_volatile (src=0xe000e010)

  1. at /checkout/src/libcore/ptr.rs:472

1 0x08003248 in >::get (self=0xe000e010)

  1. at $REGISTRY/vcell-0.1.0/src/lib.rs:43

2 >::read (self=0xe000e010)

  1. at $REGISTRY/volatile-register-0.2.0/src/lib.rs:75

3 cortex_m::peripheral::syst::::has_wrapped (self=0x10001fbc)

  1. at $REGISTRY/cortex-m-0.5.7/src/peripheral/syst.rs:124

4 0x08002d9c in >::delay_us (self=0x10001fbc, us=500000)

  1. at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:58

5 0x08002cce in >::delay_ms (self=0x10001fbc, ms=500)

  1. at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:32

6 0x08002d0e in >::delay_ms (self=0x10001fbc, ms=500)

  1. at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:38

7 0x080001ee in main () at src/05-led-roulette/src/main.rs:18

backtrace 将从当前函数的一系列函数调用打印到main。

回到我们的主题。为了做我们追求的目标,首先,我们必须回到这个main功能。我们可以使用finish命令来做到这一点。该命令恢复程序执行,并在程序从当前函数返回后立即再次停止。我们必须多次打电话。

(gdb) finish cortex_m::peripheral::syst::::has_wrapped (self=0x10001fbc) at $REGISTRY/cortex-m-0.5.7/src/peripheral/syst.rs:124 124 self.csr.read() & SYST_CSR_COUNTFLAG != 0 Value returned is $1 = 5

(gdb) finish Run till exit from #0 cortex_m::peripheral::syst::::has_wrapped ( self=0x10001fbc) at $REGISTRY/cortex-m-0.5.7/src/peripheral/syst.rs:124 0x08002d9c in >::delay_us ( self=0x10001fbc, us=500000) at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:58 58 while !self.syst.has_wrapped() {} Value returned is $2 = false

(..)

(gdb) finish Run till exit from #0 0x08002d0e in >::delay_ms (self=0x10001fbc, ms=500) at $REGISTRY/stm32f30x-hal-0.2.0/src/delay.rs:38 0x080001ee in main () at src/05-led-roulette/src/main.rs:18 18 delay.delay_ms(half_period); 我们回来了main。我们在这里有一个局部变量:half_period

(gdb) info locals half_period = 500 delay = (..) leds = (..) 现在,我们将使用以下set命令修改此变量:

(gdb) set half_period = 100

(gdb) print half_period $1 = 100 如果你让程序再次使用该continue命令运行,你会发现LED现在会以更快的速度闪烁!

题!如果你继续降低价值,会发生什么half_period?什么价值的 half_period你不能再看到LED闪烁?

现在,轮到你编写程序了。