#![no_main]
#![no_std]
use panic_halt;
use microbit::hal::nrf51::{interrupt, GPIOTE, UART0};
use microbit::hal::prelude::*;
use microbit::hal::serial;
use microbit::hal::serial::BAUD115200;
use cortex_m::interrupt::Mutex;
use cortex_m::peripheral::Peripherals;
use cortex_m_rt::entry;
use core::cell::RefCell;
use core::fmt::Write;
use core::ops::DerefMut;
static GPIO: Mutex<RefCell<Option<GPIOTE>>> = Mutex::new(RefCell::new(None));
static TX: Mutex<RefCell<Option<serial::Tx<UART0>>>> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
if let (Some(p), Some(mut cp)) = (microbit::Peripherals::take(), Peripherals::take()) {
// 引入两个版本的外设
cortex_m::interrupt::free(move |cs| {
/* 开启外部设备的 GPIO 中断 */
cp.NVIC.enable(microbit::Interrupt::GPIOTE);
microbit::NVIC::unpend(microbit::Interrupt::GPIOTE);
/* 切分 GPIO 口,方便使用 */
let gpio = p.GPIO.split();
/* 将 Button 的 IO 口作为输入 IO 口 */
let _ = gpio.pin26.into_floating_input();
let _ = gpio.pin17.into_floating_input();
/* 当 GPIO 17 ( A 键)出现了下降沿的时候,触发中断 */
p.GPIOTE.config[0]
.write(|w| unsafe { w.mode().event().psel().bits(17).polarity().hi_to_lo() });
p.GPIOTE.intenset.write(|w| w.in0().set_bit());
p.GPIOTE.events_in[0].write(|w| unsafe { w.bits(0) });
/* 当 GPIO 26 (B键)出现了下降沿的时候,触发中断 */
p.GPIOTE.config[1]
.write(|w| unsafe { w.mode().event().psel().bits(26).polarity().hi_to_lo() });
p.GPIOTE.intenset.write(|w| w.in1().set_bit());
p.GPIOTE.events_in[1].write(|w| unsafe { w.bits(0) });
*GPIO.borrow(cs).borrow_mut() = Some(p.GPIOTE);
/* 根据需要,设置 GPIO 口作为输入输出口 */
let tx = gpio.pin24.into_push_pull_output().downgrade();
let rx = gpio.pin25.into_floating_input().downgrade();
/* 将准备的 GPIO 口作为串口来使用 */
let (mut tx, _) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split();
let _ = write!(
tx,
"\n\rWelcome to the buttons demo. Press buttons A and/or B for some action.\n\r",
);
*TX.borrow(cs).borrow_mut() = Some(tx);
});
}
loop {
continue;
}
}
// 定义一个中断(如果函数出现了错误,就会触发中断),当我从按钮按下接收到了一个中断,这个函数就会被调用。
#[interrupt]
fn GPIOTE() {
/* 进入中断内部的内容 */
cortex_m::interrupt::free(|cs| {
if let (Some(gpiote), &mut Some(ref mut tx)) = (
GPIO.borrow(cs).borrow().as_ref(),
TX.borrow(cs).borrow_mut().deref_mut(),
) {
let buttonapressed = gpiote.events_in[0].read().bits() != 0; // 识别出 A 键按下
let buttonbpressed = gpiote.events_in[1].read().bits() != 0; // 识别出 B 键按下
/* 将按钮打印到串口中 */
let _ = write!(
tx,
"Button pressed {}\n\r",
match (buttonapressed, buttonbpressed) {
(false, false) => "",
(true, false) => "A",
(false, true) => "B",
(true, true) => "A + B",
}
);
/* 清空事件 */
gpiote.events_in[0].write(|w| unsafe { w.bits(0) });
gpiote.events_in[1].write(|w| unsafe { w.bits(0) });
}
});
}
Code language: PHP (php)
分类目录归档:Micro:Bit
Micro:bit 收信强度测试
本代码用于测试不同信号强度下的发信距离。
radio.onReceivedNumber(function (receivedNumber) {
basic.showNumber(radio.receivedPacket(RadioPacketProperty.SignalStrength))
})
input.onButtonPressed(Button.A, function () {
basic.showString("A")
})
input.onButtonPressed(Button.B, function () {
basic.showString("B")
})
basic.showIcon(IconNames.Yes)
Code language: JavaScript (javascript)
Micro:bit 学习资料
下面是我自己看过的一些 Micro:bit 的学习资料:
书/教程
- Networking with the micro:bit: https://microbit.nominetresearch.uk/networking-book-online/
项目
- AWESOME-micro:bit:https://github.com/carlosperate/awesome-microbit
Micro:bit 显示室内温度
Micro:bit 所使用的核心芯片 nrf51822 自带了温度传感器,因此,我们可以使用micro:bit 来显示室内的温度。
实现
实现方法很简单,只需要在 makecode 上加入这样的代码,就可以实现输出温度了。
如何使用 MakeCode 来进行 micro:bit 的串口调试
micro:bit 支持在串口输出一些信息,并在你的调试工具中展示这些数据。
这个时候,你可以直接使用 MakeCode 自带的 WebUSB 的功能来实行这个操作。
如何使用?
想要使用串口调试非常方便,首先,你需要确保你的 micro:bit 可以使用 WebUSB (固件版本为 249,250及以上),然后,在你的 make:code 中使用设备配对的功能,来进行配对,将你的 micro:bit 与编辑器进行配对。
然后,新增一个串口输出字符串的块
添加完成块以后,将代码烧入到你的 micro:bit 中,然后在左侧会看到提示。
我这里只显示了“模拟器”,你链接了设备以后,这里还会显示设备的提醒,点击进去就可以看到控制台的输出了。
Micro:bit 的 WebUSB 的限制
在使用 micro:bit 的 Web USB的时候需要注意,该功能在 Windows 上仅支持 Windows 8 及以上的版本。
Reference
https://support.microbit.org/support/solutions/articles/19000084059-beta-testing-web-usb
Micro:Bit 是如何将 600K + 的文件烧入 NRF51822 的?
前置信息
Micro:bit 的蓝牙芯片是 NRF51822
根据 Nodric Semiconductor 公司的说明,NRF51822 的 ROM 大小只有 256/128 K,但是当我们从 makecode 编辑器上下载 hex 文件的时候,即使只是输出一个 1 ,你的代码文件也有足足 630K。
在我的 micro:bit 还没有到手的时候,我一直在怀疑,make:code 是使用了什么样的黑科技,才能够实现将 630K 的文件烧录到 256K 的 ROM 里。我甚至怀疑 micro:bit 根本无法烧录这个文件。
micro:bit 到手以后,我试着去烧录,发现虽然文件大,但是的的确确可以烧录进去。
当时我就震惊了!Micro:bit 这是掌握了核心科技啊,能够把 600K + 的文件烧录进 256K 的 ROM 里。
随着研究的深入,以及开始对 hex 文件进行解包以后。我发现,原来 hex 文件中包含了整个项目的所有的文件,我们看到的 ts 文件等都会打包在这个文件中。
这就更加令我震惊了,难道 Micro:bit 已经可以实现在 16K Ram ,256K Rom 的芯片上移植一个 Node.js 的运行环境?那这个公司的黑科技未免也太多了。而且,因为要烧录整个文件进去,600K+的文件再怎么压缩也要占个100~200K,剩下给运行环境的空间并不大。
继续研究,发现我可以在本地重新打包,于是,我尝试重新打包文件
pxt build
打包完成后,生成了 built 文件夹,里面就是我们的 hex 文件。
诶,这里怎么还有一个 asm 文件? asm 不是汇编语言 assembly language 的缩写么?打开一看,的确是汇编语言。
再看一下文件大小,豁然开朗。
原来, Makecode 将整个项目文件都打包进入到 package 中,然后,将代码文件转译为汇编语言文件(实际应该是转成二进制可执行文件,这里的 asm 文件应该是用于调试的),写入到 nrf51822 中。
这样,我们实际写入的代码其实只有 24 K,就能够理解为什么 600 多K 的项目能够写入到 nrf51822 了,因为其实 其中的 600 k 都是源码文件,在烧录的时候会被抛弃掉。
如何在本地运行一个 Micro:bit 编辑器
一般来说,我们会使用 micro:bit 的 makecode 平台进行内容的编辑,不过,有些时候,我们希望在本地进行编辑,因此, 我们需要把 编辑器运行在本地。
在本地运行编辑器的方法非常的简单,首先,确保你已经安装了 Node.js
环境,然后执行如下命令安装 pxt
npm install pxt
安装完成后,执行如下命令来启动编辑器
mkdir microbit # 创建一个新的目录,方便管理文件
pxt target microbit # 创建 micro:bit 目录
pxt serve # 启动编辑器
Code language: PHP (php)
启动后,会自动打开浏览器,访问编辑器。如果没有启动,你可以点击命令行里的连接,自己打开编辑器。
打开以后,就可以看到在本地运行的 makecode 编辑平台了。
如何解包 Micro:bit 可视化编辑器生成的 Hex 文件
在上一篇文章《Micro:Bit 中隐藏的 Typescript 文件》中我提到,micro:bit 的代码中有一些 Typescript 文件,记录了我们的接口。如果我们可以将其下载到本地,完整的解读,那么我们可以得到一个更加完善的接口文档。接下来,我们就对编辑器生成的 Hex 文件进行解包。
Hex 解包过程
生成 Hex 文件
首先,你需要生成一个 用于解包的 Hex 文件,这样可以方便你看自己想看的接口。比如我要看的蓝牙接口默认并不在项目里,需要自己以拓展的形式加入到项目中。
安装 PXT 命令行工具
想要解包,你需要使用 micro:bit 自己的解包工具(集成在其命令行里)
我们需要使用 npm 来安装 pxt 命令行工具,所以,在继续执行下面的命令前,使用 node --version
来确定你已经装了 node.js 环境。
npm install pxt
安装完成后,创建一个新的文件夹,比如叫 extract ,并安装 micro:bit 解包所需的依赖
cd extract
pxt target microbit
解包 Hex 文件
当环境好了以后,我们就可以开始准备解包我们的 Hex 文件了。
pxt extract 文件路径
解压完成后,会在文件路径下生成一个项目文件夹
这样,你就可以看到我们在在线编辑器中所看到的文件了。
Micro:bit 中隐藏的 TypeScript
Micro:Bit 目前提供的可视化编程是基于 JavaScript 实现的,如果你将你的界面从 Block 块编辑器切换为 JavaScript 编辑器,就可以看到对应的代码了。
除了 JavaScript 以外,你还可以在 Micro:Bit 中找到 TypeScript 代码。
点击右上方的小齿轮,选择项目设定
在页面的左侧可以看到一个资源管理器,点击资源管理器,就可以看到你的项目中的所有文件。
在这些 typescript 中,你可以看到一些我们在使用块时的定义
借助这些 Typescript 文件,相信可以帮助你更好的使用 micro:bit 的编辑器。