Dead manʼs handle
This article goes through some kind of dead manʼs handle imitation realized with micro:bit and LAMP:bit.
![lamp bit mount](./figure/eyelet-art/dead-mans-handle/mount.jpg)
Idea is quite simple. Phototransistor is blocked from incoming light rays. When rays hit it, SOS signal in Morse code is produced via lamp LED.
Morse code 🌐
SOS is global-wide universal signal to communicate distress with no acronym meaning. In fact, there is little more on this. You can try search internet for more information.
SOS in Morse code equals to 3 dots, 3 dashes and again 3 dots, ···---···, and there are rules to proportions to lenght of code units. On details on this check with Morse Code Timing.
const DIT: u16 = 195;
const DAH: u16 = 3 * DIT;
const INT_SP: u16 = DIT;
const WRD_SP: u16 = 7 * DIT;
DIT
stands for “dot” and it is expressed in milliseconds. DAH
is “dash”. INT_SP
is internal spacing used
to divide units in order to have noticable break between them. WRD_SP
is spacing between words. This is used to delay sending each SOS in cycle.
Code here, please! 🌐
There are 2 concepts regard I/O employed: Pull-up vs Pull-down for input and Open Drain vs Push-pull for output. For both of them latter option is chosen. Why it so, one can check with relevant sources.
fn prp(
brd: Board,
) -> (
Timer<TIMER2>,
P0_02<Output<PushPull>>,
P0_03<Input<PullDown>>,
) {
let tmr = Timer::new(brd.TIMER2);
let pins = brd.pins;
let p002 = pins.p0_02;
let drv_pp = p002.into_push_pull_output(Level::Low);
let p003 = pins.p0_03;
let photo_pd = p003.into_pulldown_input();
(tmr, drv_pp, photo_pd)
}
Preparations are straighforward. Output for switching lamp on/off is set up. Input for value coming from phototransistor is established as well. Timer usage is implicated by need of Morse code signaling.
LAMP:bit “driving” pins are connected to P0 and P1 on micro:bit. Real mapping to Nordic nRF52833 MCU can be read out at https://tech.microbit.org/hardware/edgeconnector/.
#![no_std]
#![no_main]
use panic_halt as _;
use microbit::hal::gpio::p0::{P0_02, P0_03};
use microbit::hal::gpio::Level;
use microbit::hal::gpio::{Input, PullDown};
use microbit::hal::gpio::{Output, PushPull};
use microbit::hal::prelude::{InputPin, OutputPin};
use microbit::board::Board;
use microbit::{hal::Timer, pac::TIMER2};
use cortex_m::prelude::_embedded_hal_blocking_delay_DelayMs;
use cortex_m_rt::entry;
#[entry]
fn entry() -> ! {
let brd = Board::take().unwrap();
let (mut tmr, mut drv_pp, photo_pd) = prp(brd);
let hand_ok = move || {
let low = photo_pd.is_low();
if let Ok(low) = low {
low
} else {
false
}
};
const DIT: u16 = 195;
const DAH: u16 = 3 * DIT;
const INT_SP: u16 = DIT;
const WRD_SP: u16 = 7 * DIT;
loop {
if hand_ok() {
continue;
}
// SOS in Morse code: ··· ––– ···
for unit in [DIT, DAH, DIT] {
for _ in 0..3 {
if let Ok(_) = drv_pp.set_high() {
if hand_ok() {
let _ = drv_pp.set_low();
break;
}
tmr.delay_ms(unit);
}
if let Ok(_) = drv_pp.set_low() {
if hand_ok() {
break;
}
tmr.delay_ms(INT_SP);
}
}
}
if hand_ok() {
continue;
}
tmr.delay_ms(WRD_SP);
}
}
// cargo flash --target thumbv7em-none-eabihf --chip nRF52833_xxAA --release
[package]
name = "dead_mans_handle"
authors = [ "software9119.technology" ]
version = "0.0.1-alpha"
edition = "2021"
license = "MIT"
[dependencies]
microbit-v2 = "0.12.0"
cortex-m = "0.7.3"
cortex-m-rt = "0.7.0"
panic-halt = "0.2.0"
No big surprises here. Hand is okay as long as phototransistor is low and for that time no SOS is being send.
Before each delay expressing actual intent, hand is checked again. Thus signaling is shut down fastly. Most notably before sending whole SOS.
Outcome 🌐
This code can also be seen at dead_mans_handle.