ras pico Wと7セグで時計作ってみた
tl;dr
ras pico wでダイナミック点灯の4桁7セグを使って時刻表示させてみた。
時刻はapiをpicoから叩いて取得。
最終的な産物は↓
全てはここに書いてあります。
きっかけ
秋月の2階で見つけた50円の7セグを買ってしまったので動かしてみる。それだけ
7セグ
とりま型番ググってデータシートを見る。
あれ、予期していたものと違う、
もっとなんか二進数突っ込めるのかと思っていた。
ちゃんと見てみると、
ダイナミック点灯用の4桁7セグメントLED表示器です。
と書いてあったので、ダイナミック点灯でググってみる。
どうやら、桁ごとに位相をずらして任意の数字を入れ替えていくとpwmの要領で4つ全部違う数字を表示できるらしい、
つまりこういうことだな(2N7000)↓

コードもこんな感じにして、
loop {
{
seg_4.set_low().unwrap();
d.set_low().unwrap();
seg_1.set_high().unwrap();
a.set_high().unwrap();
}
delay.delay_ms(5);
{
seg_1.set_low().unwrap();
a.set_low().unwrap();
seg_2.set_high().unwrap();
b.set_high().unwrap();
}
delay.delay_ms(5);
{
seg_2.set_low().unwrap();
b.set_low().unwrap();
seg_3.set_high().unwrap();
c.set_high().unwrap();
}
delay.delay_ms(5);
{
seg_3.set_low().unwrap();
c.set_low().unwrap();
seg_4.set_high().unwrap();
d.set_high().unwrap();
}
delay.delay_ms(5);
}
まだピンの番号ちゃんと振ってないのでaとかbとかズレてます
途中で使うcrateを変えたので↑のコードは少し後述のと違う
動かしてみると...

おー!うまい具合に期待通りの動きをした!
ras pico wはgpioの流せる電流が小さいらしくて適当に100Ω置いたけど、思ったより光ったね。
api叩く
さて、7セグがいい感じに動いたので時刻の取得をやりたいですね。
まあ、適当なapi探すのが一番手っ取り早いはずなのでとりあえず、examples/でも覗きましょう。
いい感じのがありましたね。
apiはこれ↓を使います。
なんか先例がページソースのhtmlから見て取ってたんで面白いしそれに倣う。

getすると、こんな感じですね。
~$ curl http://3fe5a5f690efc790d4764f1c528a4ebb89fa4168.nict.go.jp/cgi-bin/json
{
"id": "ntp-a1.nict.go.jp",
"it": 0.000,
"st": 1771410820.312,
"leap": 36,
"next": 1483228800,
"step": 1
}
このstがUNIX時間というものらしくて決まった時刻からの経過秒数らしいです。
↓のcrateを使って、dateに変換してます。(後述)
rtcを実装する
さてrtcも実装しましょう。
大体の実装はexamplesから持ってきてます。
先ほどの実装と合わせると、
#[allow(unused)]
#[derive(Deserialize)]
struct UnixTime<'a> {
id: &'a str,
it: f64,
st: f64,
leap: u8,
next: u64,
step: u8,
}
let bytes = body.as_bytes();
match from_slice::<UnixTime>(bytes) {
Ok((unix, _used)) => {
let mut st = unix.st;
st += 9. * 3600.; //JST
let (year, month, day, hour, minute, second) = { secs_to_datetime(st as i64) };
let date = DateTime {
year: year as u16,
month: month,
day: day,
day_of_week: DayOfWeek::Monday, //I dont need it so no matter what its ok
hour: hour,
minute: minute,
second: second,
};
rtc.set_datetime(date).unwrap();
}
Err(e) => {
let mut buf: String<64> = String::new();
write!(&mut buf, "Error buf: {:?}\r\n", e).ok();
let _ = class.write_packet(buf.as_bytes()).await;
}
}
曜日の実装は面倒そうだったので無視、
stの小数点を切り捨てているので少しラグができるかも...?(後付けの予言)
動いたもの
無限にエラーと格闘してやっと動いたはいいものの、どんなことしてたか忘れて何解説すればいいか分からないのであとは動画とリポジトリ見てください。
電源を入れるとwifiに接続→rtc動かす→rtcを7セグに表示→ボタンを押したらwebrequest→rtcに反映→表示にも反映→rtcで動き続ける
って感じの所まで動いた!!xD
何か間違い等あればよしなに。
やっぱなんか解説したい1
7セグうまく扱うためにこんなstruct書きました。
static CONVERTED_TIME: AtomicU16 = AtomicU16::new(0);
//
//
pub struct SevenSegment<'a> {
seg_1_gnd: Output<'a>, //assuming pins connecting mosfet's gate
seg_2_gnd: Output<'a>, //so that cathode is connected to gnd through drain and source
seg_3_gnd: Output<'a>,
seg_4_gnd: Output<'a>,
a: Output<'a>,
b: Output<'a>,
c: Output<'a>,
d: Output<'a>,
e: Output<'a>,
f: Output<'a>,
g: Output<'a>,
dp: Output<'a>,
}
impl<'a> SevenSegment<'a> {
pub fn display_digit_number(
&mut self,
digit: u8,
number: u8,
) {
self.turn_off_all();
match digit {
4 => self.seg_4_gnd.set_high(),
3 => self.seg_3_gnd.set_high(),
2 => self.seg_2_gnd.set_high(),
1 => self.seg_1_gnd.set_high(),
_ => self.seg_1_gnd.set_high(),
}
match number {
1 => {
self.b.set_high();
self.c.set_high();
},
2 => {
self.a.set_high();
self.b.set_high();
self.g.set_high();
self.e.set_high();
self.d.set_high();
},
3 => {
self.a.set_high();
self.b.set_high();
self.g.set_high();
self.c.set_high();
self.d.set_high();
},
4 => {
self.f.set_high();
self.g.set_high();
self.b.set_high();
self.c.set_high();
},
5 => {
self.a.set_high();
self.f.set_high();
self.g.set_high();
self.c.set_high();
self.d.set_high();
},
6 => {
self.a.set_high();
self.f.set_high();
self.g.set_high();
self.c.set_high();
self.d.set_high();
self.e.set_high();
},
7 => {
self.f.set_high(); //there stil remains a strong debate about wheather f is needed, at least on me
self.a.set_high();
self.b.set_high();
self.c.set_high();
},
8 => {
self.a.set_high();
self.b.set_high();
self.c.set_high();
self.d.set_high();
self.e.set_high();
self.f.set_high();
self.g.set_high();
},
9 => {
self.a.set_high();
self.f.set_high();
self.b.set_high();
self.g.set_high();
self.c.set_high();
self.d.set_high();
},
10 => {
self.dp.set_high();
},
_ => {
self.a.set_high(); //0 and sth other than 0~9
self.b.set_high();
self.c.set_high();
self.d.set_high();
self.e.set_high();
self.f.set_high();
}
}
}
fn turn_off_all(&mut self) {
self.seg_1_gnd.set_low();
self.seg_2_gnd.set_low();
self.seg_3_gnd.set_low();
self.seg_4_gnd.set_low();
self.a.set_low();
self.b.set_low();
self.c.set_low();
self.d.set_low();
self.e.set_low();
self.f.set_low();
self.g.set_low();
self.dp.set_low();
}
}
//continue to light 7 segment behind main
#[embassy_executor::task]
async fn seven_segment_task(
mut seven_segment: SevenSegment<'static>,
) {
loop {
let converted_time = CONVERTED_TIME.load(Ordering::Relaxed);
seven_segment.display_digit_number(4, (converted_time / 1000) as u8);
Timer::after_micros(700).await;
seven_segment.display_digit_number(3, ((converted_time % 1000) / 100) as u8);
Timer::after_micros(700).await;
seven_segment.display_digit_number(2, (((converted_time % 1000) % 100) / 10) as u8);
Timer::after_micros(700).await;
seven_segment.display_digit_number(1, (((converted_time % 1000) % 100) % 10) as u8);
Timer::after_micros(700).await;
}
}
//
//
if let Ok(dt) = rtc.now() {
CONVERTED_TIME.store((dt.hour as u16 * 100 as u16 + dt.minute as u16) as u16, Ordering::Relaxed);
}
を参考にして、mainと別で7セグ光らせてます。
2
なんかデバッグ用のinfo!とか見るために、新しく本体より高いプローブを買わないといけない?っぽくて(チャッピー情報)
仕方がないのでシリアルも実装しました。examplesコピペしてlet's tera term!
Err(e) => {
let mut buf: String<64> = String::new();
write!(&mut buf, "Error buf: {:?}\r\n", e).ok();
let _ = class.write_packet(buf.as_bytes()).await;
}
3
embassy_rpのリポジトリにあるファイル一式、
をそのまま持ってきてビルドしようとすると変なエラーが出てきます。
これはmemory.xの定義が足りていないっぽくて、rp235xの方から少しコピペしたらなぜか動きました、
error: linking with `rust-lld` failed: exit code: 1
|
= note: "rust-lld" "-flavor" "gnu" "C:\\Users\\apten\\AppData\\Local\\Temp\\rustcByD48l\\symbols.o" "<120 object files omitted>" "--as-needed" "-Bstatic" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\deps/{libpanic_probe-824e78c81b8b8145,libdefmt_rtt-eca06006586ac888,libstatic_cell-cc8ea1773b3517dc,libportable_atomic-47a24cc9ae84e575,libembassy_executor-38137dd6d0ed97b5,libcordyceps-3be73f4e3856beb0,libcyw43_pio-1a528dbbbcbd48ab,libembassy_rp-c6b629c66bedd672,librp2040_boot2-2a00839c473c1092,libembedded_hal_nb-59137653f7978abb,librand_core-411c9c5518bb2fa9,librand_core-7389a1a0829778a9,libembassy_usb_driver-5cbebf512611303d,libembassy_time_queue_utils-0d554f775b4a566a,libembassy_executor_timer_queue-8d096e56a3986bf6,libembassy_embedded_hal-b1656dceff7279e5,libembedded_storage_async-d4aed1aa753921ff,libsmart_leds-774fb1332b49f776,libsmart_leds_trait-ab45a6bb36cbe8cf,librgb-6c8637597fc9152e,libpio-cb7e42f83145c8b4,libpio_core-3868aee09eae8c89,libnum_enum-77800f757095a480,libarrayvec-630eb01a1dcdb8ac,libfixed-d9f2f2d180b7c682,libtypenum-959058eff57ca5e6,libbytemuck-957d958065068eda,libhalf-c3fd13823bd49759,libcfg_if-4991334e5068247d,libzerocopy-509e48c981ca3e27,libaz-ee7ebe980b81e7be,libembedded_storage-28f0466b651a0539,libembassy_hal_internal-1fe73e7df27736e8,libnum_traits-b26fe3fbec700894,librp_pac-a7e6ba5a134266cb,libcortex_m-be4d84a2e81e84b9,libvolatile_register-19c3e13e515e0d79,libvcell-e94f2925f3f3d4ce,libbare_metal-84bf6df7326800be,libcortex_m_rt-4083c8d63da42ec5,librp_binary_info-206c6bfd4feda82e,libcyw43-61c8e870ba41350f,libfutures-7bce6c35429713f1,libfutures_util-19feb166361ecc0b,libpin_project_lite-c9b9be6908f4d484,libfutures_task-e9bff477a4ecfaf8,libembassy_futures-68055b86d7962a14,libaligned-5ddcc4e8881f7716,libas_slice-403cdf192641b7c7,libstable_deref_trait-027230e88763d35f,libembassy_time-1a6d0a47c68e4d2a,libembedded_hal-6f88a01fd3da7fdc,libvoid-284b593cb404183f,libnb-dd8cdd8a17337947,libnb-8adacb666a7bcae8,libembedded_hal_async-b01b721ad30a1753,libembedded_hal-998cd20d744aa3be,libembassy_time_driver-229afb24b22e9c19,libembassy_net_driver_channel-bd522e9667b0a252,libembassy_sync-6067644278b4a708,libembedded_io_async-589354ff5c237f46,libembedded_io-2b9a7e9987765ef7,libfutures_core-67868a53cc3e8e18,libfutures_sink-b27ea3a4bad0d242,libcritical_section-0691b3273a361911,libheapless-683bf9e4af79aaea,libhash32-b187723ee8b4127c,libbyteorder-b14ff681908e4fb3,libembassy_net_driver-07f3df04f7d8b19c,libdefmt-0e87687cee5e37c0,libbitflags-154d96929d54c92c}.rlib" "<sysroot>\\lib\\rustlib\\thumbv6m-none-eabi\\lib/{libcore-*,libcompiler_builtins-*}.rlib" "-L" "C:\\Users\\apten\\AppData\\Local\\Temp\\rustcByD48l\\raw-dylibs" "-Bdynamic" "--eh-frame-hdr" "-z" "noexecstack" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\ras_4dig_7seg-21592ee684802f1d\\out" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\cortex-m-adfde400b17c0df2\\out" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\cortex-m-rt-2181d87f43e48262\\out" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\defmt-592c31180701ba14\\out" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\embassy-rp-4fe88fcb73a5cd5c\\out" "-L" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\build\\rp-pac-4084183bdeadad6e\\out" "-o" "C:\\Users\\apten\\Documents\\ras_4dig_7seg\\target\\thumbv6m-none-eabi\\debug\\deps\\ras_4dig_7seg-28cc861bb617c6d4" "--gc-sections" "--nmagic" "-Tlink.x" "-Tlink-rp.x" "-Tdefmt.x"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: rust-lld: error: undefined symbol: __bi_entries_start␍
>>> referenced by lib.rs:122 (src\lib.rs:122)␍
>>> rp_binary_info-206c6bfd4feda82e.rp_binary_info.cb793aa65dfab2d1-cgu.0.rcgu.o:(rp_binary_info::PICOTOOL_HEADER::hebb3f9eb0fe70f85) in archive C:\Users\apten\Documents\ras_4dig_7seg\target\thumbv6m-none-eabi\debug\deps\librp_binary_info-206c6bfd4feda82e.rlib␍
␍
rust-lld: error: undefined symbol: __bi_entries_end␍
>>> referenced by lib.rs:122 (src\lib.rs:122)␍
>>> rp_binary_info-206c6bfd4feda82e.rp_binary_info.cb793aa65dfab2d1-cgu.0.rcgu.o:(rp_binary_info::PICOTOOL_HEADER::hebb3f9eb0fe70f85) in archive C:\Users\apten\Documents\ras_4dig_7seg\target\thumbv6m-none-eabi\debug\deps\librp_binary_info-206c6bfd4feda82e.rlib␍
␍
rust-lld: error: section .vector_table virtual address range overlaps with .boot_info␍
>>> .vector_table range is [0x10000100, 0x100001BF]␍
>>> .boot_info range is [0x10000100, 0x10000113]␍
␍
rust-lld: error: section .vector_table load address range overlaps with .boot_info␍
>>> .vector_table range is [0x10000100, 0x100001BF]␍
>>> .boot_info range is [0x10000100, 0x10000113]␍
error: could not compile `ras_4dig_7seg` (bin "ras_4dig_7seg") due to 1 previous error
Discussion