2025/08/22(金)中華USBISP改造版のUSBasp

AVR用のISP書き込み機の話題、UPDI方式が浸透している今では古い話になります。

USBasp_china.jpg


aliexpressや、amazonなのでUSBメモリサイズのコンパクトなAVRライタのUSBISPが売られています。これ、USBaspに似ていますが全くの別物で中華独自のようです。そのままでは使いづらさがあるので、ネット情報にあるUSBasp化改造というものがあります。
参考になるのは、
で、このデバイスに書き込むカスタムUSBaspのリポジトリが
となっています。一応これらを参考に真似すればちゃんとArduino IDEの「USBasp」として「書き込み装置を使って書き込み」で使えるのですがどうも不安定です。素のATMEGA328Pにブートローダを書き込むときにエラーになったり、正式なUSBaspには起こらない、微妙に使えない場面に出くわします。この現象にずっとなんだろな、という曖昧な感覚で納めていたのですが、今回ちゃんと調べたところカスタム版のFWに問題があることがわかりました。

カスタム版のFWは、本家とのピン配置の違いなどを変更して修正したFWになりますがそのほかに一転重要なところを「良い感じに改造したぜ?」(意訳)というコメントともに改造されています。
それは、デフォルト時のSCKクロックスピードで、本家の375kHzから750kHzに変更されていた点です。ArduinoIDEから書き込む場合このSCKクロックを明示的に変更することはできませんので、必然的に750kHzクロックでの書き込みとなります("-B 10" などのオプションを通せない)。新品のATMEGA328Pは内蔵クロック1MHzで動作していますから、間に合わないわけです。
原因を突き止めたので、ソースコード変更してデフォルトクロックを93.75kまでさげてビルドしたものを書き込みました。本家よりも下げた理由は、互換機なんだから低速でもちゃんと書き込める装置としてあるべき、と考えたからです。

長年使ってきたレガシーなAVRの心残りがなくなった気がしました。

続きを読む

2025/04/03(木)Windowsのスクリーンショットファイル名をリネーム

Windowsでスクリーンショットを撮ると"2024-08-26.png"のような日付で保存されますが、同日に複数枚とると
2024-08-26.png
2024-08-26 (1).png
2024-08-26 (2).png
...
という、どうしようもないファイル名になってくれます。いろいろ面倒なのでファイル更新日時をつかってファイル名をリネームするバッチファイルを作成。
完全なリネームは怖いのでファイルコピー生成して問題なさそうであれば元のファイルは手動で削除する方法とした。

続きを読む

2024/07/04(木)GP2Y0A21YKのArduino用軽量ライブラリ

GP2Y0A21YKを簡単な計算式で使う で書いた大げさな計算じゃない軽量なライブラリをArduino IDEのライブラリマネージャーでインストールできるライブラリとして登録申請しました。"GP2Y"で検索すれば出てきます。
GP2Y0A21YK_scr.png

申請に際して
Arduino IDEのライブラリ一覧に自作ライブラリを登録する
を参考にしました。

公開ライブラリのGithubリポジトリは、GP2Y0A21YK_libです。
公式サイトにもGP2Y0A21YK_libから辿れるようになっています。
これが非常に嬉しいですね。

2024/06/23(日)ffmpegでアニメーションgifの容量をできるだけ小さくする

今時は、mp4やmovなどの動画ファイルを気軽にアップロードできますが、プログラムライブラリに動画を同梱する場合は
  • なるべく容量を抑えたい
  • 画質は問わない
  • そのため動作内容がわかればよい
  • 汎用性の高いファイル形式にしておきたい
という要件があると思います。じゃあffmpegで良い感じにできないかといろいろ調べた結果以下のコマンド
./ffmpeg.exe -i "C:\soft\ffmpeg\input.mp4" -vf "fps=1, setpts=PTS/1.5, scale=600:-1, split[a][b]; [a]palettegen=max_colors=8[c]; [b][c]paletteuse;" -ss 3 -loop 0 output.gif
  • 1fps
  • 8色
  • そこそこサイズの幅600
※-ss 3 は元ソース3秒目から変換、パスなどは適宜読み替え。

で600KB程度の数十秒間の動画の作成ができました。

2024/05/16(木)GP2Y0A21YKを簡単な計算式で使う

定番の測距モジュール シャープのGP2Y0A21YKがある。

秋月電子 - シャープ測距モジュール GP2Y0A21YK
スイッチサイエンス - 赤外線近接センサGP2Y0A21YKと接続ケーブル
共立電子産業 - PSD測距センサ[鉛F] GP2Y0A21YK

マイコン側ではADCでアナログ電圧を取得、それを計算して検出した障害物までの距離を測ることができる。この距離算出の計算が少々面倒かつ、ネット上ですぐに見つかるライブラリはpow()関数を使っていたり少々大げさなコードが目立つ。そこで、データシートのグラフから逆数回帰で解析して近似曲線を求め、それを測距の関数化をすることにした。このセンサーは最近のレーザー式とは違って精度がでないので10mm程度の誤差は許容するような使い方をする前提と思われる。(男性用小便器の人体検知センサーなどに使われてそう)

目標となる関数は、y = A + (B/x)とし、係数A, Bを求めればよい。

まずは、グラフから手作業で読み取った値を書き出し。
x=0.4のとき Y=80
x=0.5のとき Y=70
x=0.6のとき Y=54
x=0.7のとき Y=44
x=0.8のとき Y=37
x=0.9のとき Y=33
x=1.0のとき Y=29
x=1.1のとき Y=26
x=1.2のとき Y=24
x=1.3のとき Y=21
x=1.4のとき Y=20
x=1.5のとき Y=18
x=1.6のとき Y=17
x=1.7のとき Y=15.5
x=1.8のとき Y=14.5
x=1.9のとき Y=14
x=2.0のとき Y=13
x=2.1のとき Y=12
x=2.2のとき Y=11.5
x=2.3のとき Y=11
x=2.4のとき Y=10.5
x=2.5のとき Y=9.5
計算サイトで理論計算すると、 A = -4.82049, B = 34.83012845 となったのでこれを基に、Google関数グラフで係数を微調整していく。
2024-05-16.png


現物合せで、 A = -4.10000, B = 34.4000 となった。
よって算出する関数は、
const double A = -4.1000;
const double B = 34.4000;
dist = A + B / vol;
となる。コード全体は以下の通り、ヘッダーファイルだけで納めてしまっているので.cppはなし。
#ifndef __GP2Y0A_H__
#define __GP2Y0A_H__

//-----------------------------------------
#define DEF_PIN (A3)
#define OPERATING_VOLTAGE (5.0)
#define RESOLUTION (1024.0)
#define BIT_VOLTAGE (OPERATING_VOLTAGE / RESOLUTION)

#define LOW_LIMIT  (0.0)
#define HIGH_LIMIT (2.6)

//-----------------------------------------
class GP2Y0A
{
public:
    GP2Y0A(uint8_t analog_pin = DEF_PIN)
    {
        pin = analog_pin;
        pinMode(pin, INPUT);
    };
    ~GP2Y0A()
    {
        
    };
    double distance()
    {
        int ad = analogRead(pin);
        double vol = ad * BIT_VOLTAGE;
        double dist = 0.0;
        if(LOW_LIMIT < vol && vol < HIGH_LIMIT)
        {
            // 逆数回帰で解析して近似曲線を求める y = A + (B/x)
            // 理論計算で、 A = -4.82049, B = 34.83012845 
            // 現物合せで、 A = -4.10000, B = 34.4000
            const double A = -4.1000;
            const double B = 34.4000;
            dist = A + B / vol;
        }

        return dist;
    };

private:
    uint8_t pin;

};
#endif
また、距離が近すぎると値が化けるので取得したADC値をLOW_LIMITとHIGH_LIMITで範囲を制限している。使うときはグローバル変数で、
GP2Y0A *psd;
しておいて、Arduinoの場合、setup()関数内で
//PSD init.
psd = new GP2Y0A(A3);// example A3 pin
あとは、loop()関数は、
void loop()
{
    static double kyori;
    char buf[16];
    
    //sample of psd sensor
    kyori = psd->distance();
    dtostrf(kyori, 6, 2, buf);
    Serial->println(buf);

    delay(100);
}
とでもすれば、そこそこ良い感じの値が読み取れているのがわかる。

*1

*1 : 追記:PSD方式とTOF方式は違うとご指摘を受けました。伴ってコードにあるTOF表記をPSDへ変更。