だいたい300円ぐらいのものです。MAX7219 というLEDドライバを使っていて、SPI で表示を変えられます。(正確には 7219 は SPI 対応とは書いてないのですが、CS の扱いが違うだけ? なのか、ほぼSPIと同じインターフェイスです。よくわかりません)

SPI を使ったことがなかったので一応自分で書いてみました。BCD のデコーダが入っており、数字ぐらいの表示なら自分でLEDとのマッピングを持つ必要はありません。

モードがいくつかあって

  • 全桁自分で制御 (7セグメント+ドットに対応するビットを自分で入れる)
  • 最下位桁だけBCDで残りは自分で制御
  • 上位4桁は自分で制御して、下位4桁はBCD
  • 全桁BCD

と選べます。7セグでアルファベット表示したい、みたいな場合は全桁自分でやる必要があります (マッピングすなわちフォント情報を持つ)

コード

書いたコードでは、全桁BCDでやるようにしてみました。マッピング持つのが面倒なのと、実質自分が使おうと思う用途だと数字以外表示しなそうだな、という気がしています (7セグでアルファベット表示させるのは視認性が悪いので好きじゃない)

SPI 通信はビット数のキリがいいのでハードウェアを使ってやっています。MAX7219 は 10MHz の SPI らしいのでそのようにしてみました。チップセレクトだけコンストラクタに渡すようにしています。

#include <Arduino.h>
#include <SPI.h>

#include <string.h>
class MAX7219 {
	uint8_t CS;

public:
	enum class ADDRESS : uint8_t {
		NOOP = 0b0000,
		DIGIT0 = 1,
		DIGIT1 = 2,
		DIGIT2 = 3,
		DIGIT3 = 4,
		DIGIT4 = 5,
		DIGIT5 = 6,
		DIGIT6 = 7,
		DIGIT7 = 8,
		DECODE_MODE = 0b1001,
		INTENSITY = 0b1010,
		SCAN_LIMIT = 0b1011,
		SHUTDOWN = 0b1100,
		DISPLAY_TEST = 0b1111,
	};

	enum class SHUTDOWN_MODE : uint8_t {
		SHUTDOWN = 0b0,
		NORMAL = 0b1,
	};

	enum class DECODE_MODE : uint8_t {
		NO_DECODE_FOR_DIGITS_7_0 = 0b00000000,
		CODE_B_DECODE_FOR_DIGIT_0_NO_DECODE_FOR_DIGITS_7_1 = 0b00000001,
		CODE_B_DECODE_FOR_DIGIT_3_0_NO_DECODE_FOR_DIGITS_7_4 = 0b00001111,
		CODE_B_DECODE_FOR_DIGIT_7_0 = 0b11111111,
	};

	MAX7219(uint8_t _cs) :
		CS(_cs)
	{
		pinMode(CS, OUTPUT);
	}

	void write(ADDRESS address, uint8_t data) {
		SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
		digitalWrite(CS, LOW);
		SPI.transfer(static_cast<uint8_t>(address));
		SPI.transfer(data);
		digitalWrite(CS, HIGH);
		SPI.endTransaction();
	}
	void begin() {
		SPI.begin();

		setDecodeMode(DECODE_MODE::CODE_B_DECODE_FOR_DIGIT_7_0);
		setScanLimit(7);
		setShutdown(false);

		setIntensity(8);

		for (int i = 0; i < 8; i++) {
			write(static_cast<ADDRESS>(i + 1), 1);
		}
	}

	void setDecodeMode(DECODE_MODE mode) {
		write(ADDRESS::DECODE_MODE, static_cast<uint8_t>(mode));
	}

	void setScanLimit(uint8_t limit) {
		write(ADDRESS::SCAN_LIMIT, limit);
	}

	void setIntensity(uint8_t intensity) {
		write(ADDRESS::INTENSITY, intensity);
	}

	void setShutdown(bool shutdown) {
		write(ADDRESS::SHUTDOWN, static_cast<uint8_t>(shutdown ? SHUTDOWN_MODE::SHUTDOWN : SHUTDOWN_MODE::NORMAL));
	}

	void print(const char* buf) {
		size_t len = strlen(buf);
		uint8_t digit = 0, dp = 0;
		for (size_t i = 0; i < len && digit < 8; i++) {
			const char c = buf[len - i - 1];
			if (c == '.') {
				dp = 1<<7;
				continue;
			} 

			uint8_t b;
			if (c == '-') {
				b = 0b1010;
			} else
			if (c == ' ') {
				b = 0b1111;
			} else
			if ('0' <= c && c <= '9') {
				b = static_cast<uint8_t>(c - '0');
			} else {
				continue;
			}

			write(static_cast<ADDRESS>(digit + 1), b | dp);
			dp = 0;
			digit++;
		}

		for (; digit < 8; digit++) {
			write(static_cast<ADDRESS>(digit + 1), 0b1111);
		}
	}
};


MAX7219 leds(10);

void setup() {
	leds.begin();
	leds.print("-1234.567");
	delay(3000);
}

void loop() {
	leds.print(String((float)micros() / 1000).c_str());
	delay(29);
}
  1. トップ
  2. tech
  3. MAX7219 8桁 7セグメント LED モジュール / Arduino

切削を2回ぐらい失敗したあと、そこそこ良さそうなのができたので、実装してみました (まだ途中ですが)。右側でブリッジしているような部分がありますがこれは設計上の意図的なもので、右側はほぼ完璧です。

マクロで撮るとスケール感がわかりにくいので右側に SOIC のパッケージのものも入れています。ほぼ同じサイズで約2倍のピンが並びます。

残念ながらプレッシャーフットなどがないのでワークのZ軸に傾きがあり、これがどうしても消せませんでした。左側は低くて、右側は高い (といっても0.1mm〜0.2mm程度の傾き) という状態です。ほとんど基板に触れない状態から切削を開始して、ダメそうなら 0.02mm ずつZを下げていきました。これ以上下げるとTSSOPの部分のパッドが消滅しそうなのでやめました。

左側は手作業でショート部分を削ったのでだいぶ汚ないです。

一応 TSSOP も実装できそうです。しかし、このサイズ (30mmx23mm程度) でも傾きがこれほど問題になるので、もっと大きな基板では現状のセッティングではまず無理そうです。プレッシャーフットを自作するか、あるいは基板を固定しているジュラコンを精密に水平出しをすればいけるのかあるいは設定を詰めればいけるのか、よくわかりません。プレッシャーフットも万能ではないのでなんともいえなそうです。


やはり気楽にやれる範囲は SOIC ぐらいだと思います。実装の点でも SOIC まではルーペなしで実装可能ですが、TSSOP ぐらいからルーペ確認が必須になってきます。

主要ピン幅

  • DIP : 2.54mm
  • SOIC: 1.27mm
  • TSSOP: 0.65mm
  • MSOP: 0.5mm

先端 0.1mm、60度のVカッターだと0.1mm の深さで幅 0.215mm。

ソルダーマスク

このように PCB Milling で普通に作るとソルダーマスクがないので、ハンダブリッジをとても起こしやすい状態になります。

いくつか作って実装してみてわかりましたが、表面実装品ではソルダーマスクがなくても案外ブリッジしません。一方でリード品をハンダづけすると高確率でブリッジします。

これはおそらく使用するハンダの量の違いだと思います。また、リード品だとリードが邪魔で正確にコテ先をあてにくいのも一因としてありそうです。

TSSOPでもパッドがしっかり成形できていれば、ハンダ付け自体にはそれほど困難に感じません。ただしフラックスは必須です。

「リード部品のほうがハンダ付けしやすい」という刷り込みを持っていたので、意外な発見でした。

  1. トップ
  2. tech
  3. PCB Milling で TSSOP

/**
zun-doko-kiyoshi in ARM Linux EABI
 */

.section .text
.global _start

.macro sys_write
        mov r7, $0x04
        svc $0x00
.endm

.macro rand_init
        /* using all high resiters for rand: r8-r12 */
        /* set seed from time */
        ldr r0, =time
        /* sys_time */
        mov r7, $0x0d
        svc $0x00
        ldr r0, =time
        ldr r8, [r0]
        /* load constant for rand */
        ldr r9, =1103515245
        ldr r10, =12345
        ldr r11, =2147483647
.endm

.macro rand
        /* random update r8 */
        mov r12, r8
        mla r8, r12, r9, r10
        and r8, r8, r11
.endm


_start:
        rand_init
        /* r6 is current zun count */
        mov r6, $0

loop:
        rand
        /* check bit / eq = zun, ne = doko */
        tst r8, $0x80
        adreq r1, zun
        moveq r2, #zun_len
        addeq r6, $1
        adrne r1, doko
        movne r2, #doko_len
        mov r0, $0x01
        sys_write
        bne check_kiyoshi
        b loop

check_kiyoshi:
        /* now this is doko state and check zun count */
        cmp r6, $5
        /* zun count is greater than 5 */
        bge call_kiyoshi
        /* failed to call kiyoshi and reset state */
        mov r6, $0
        b loop

call_kiyoshi:
        /* now this is kiyoshi state */
        adr r1, kiyoshi
        mov r2, #kiyoshi_len
        mov r0, $0x01
        sys_write
        mov r0, $0x00
        /* sys_exit */
        mov r7, $0x01
        svc $0x00

zun:
        .string "ズン\n"
zun_len = . - zun
        .align 2

doko:
        .string "ドコ\n"
doko_len = . - doko
        .align 2

kiyoshi:
        .string "キヨシ\n"
kiyoshi_len = . - kiyoshi
        .align 2


.section .data
time: .word 0

cross compile

 arm-linux-gnueabi-as ./sketch.s -o sketch.o && arm-linux-gnueabi-ld -o sketch -e _start sketch.o && qemu-arm-static ./sketch
  1. トップ
  2. tech
  3. arm-linux-eabi でのアセンブリ ズンドコ

ほんとにイライラすることばかりが起きる。なんでこんなめにあうのか。本当の意味がわからない。

いくら自分から面白いことを探そうとしても、ひたすらに不幸が追いかけてくる。嫌なことは自動的に毎日起き続けるのに、面白いことは追いかけても逃げていく。


とにかくこの毎日嫌なことばかりが起きるのをなんとかしたい。

自分の中からはただただやりたいことが沸いてくる。大半の嫌なことは他人に起因していて、

  • 嫌なことを言われる
  • 嫌なことを言われると予期される
  • 嫌なことをやらされる

となる。しかし他人に起因することは自分にどうすることもできない。無力。原因が解決しないので、運用でカバーとするしかないが、運用力がない。

もっと果てしないスルー力があれば解決するかもしれない。どのようにしてそれを手に入れればいいかはわからない。他人の重要性をもっともっと下げていきたい。お前らとかどうでもいいと思えるようになりたい。他人の評価を全て無視したい。

とにかくなんとかしてストレス解消したい。最近とことん些細なことでイライラする。

精神的余裕がないのに、追い討ちをかけるような事態しか起きない。ひどいめにあうということしかない。インターネットのほうがまだ安全ではないか。

自分は自分のルールで生きており、つまりこのルールは道徳ないし宗教なので、他人にどうこう言われるようなものではない。ただ生きてるわけでもなく、自分のルールに従って生きている限り、それをどうこう言われる筋合いは全くない。

事情を知らない人間はクソなことを言ってくる。お前の事情なんてこちらとしても存じあげない。コミュニケーションをしないやつに、コミュニケーション能力が低いと罵られる意味はなんだ。