Vol.922 11.Jul.2025

中間スイッチ 電動ネッククーラー プチFATでバイナリーデータ

I 中間スイッチ(Intermediate switch)

by fjk

 電子工作時に安定化電源としてAD-9724DS(A&D)を使っているが、出力用のスイッチが無く、その都度につまみを回して電圧を設定しなければならず、不便を感じていた。そこで出力コードの中間にスイッチを取り付けることにした。
 なお、中間スイッチは、43x15mmのミニインラインイッチ(759円/4個、uxcell、オン/オフ)をAmazonで入手した。
 プッシュスイッチで現在出力がONかOFFかよく判らないが、出力スイッチがあるのはやはり便利です。
 <おまけ> 少し大きくなりますが、シーソー式スイッチ(ジャック+プラグ付、637円)でも試してみました。


作成した中間スイッチと使用パーツ
 

試作スイッチの使用状況

★シーソー式SWを使った場合


N 電動ネッククーラー

by fjk

 暑い日が続きますね。でも外仕事をしなければならない時には、冷凍庫で冷凍した「ネックリング」を首に付けているが、1時間程度で冷たくなくなる。
 そこで、ネックリングに変わる冷却グッズがないかケーズデンキの店内を廻っていると、ペルチェ効果を使った「ネッククーラーAir」(TKNC23SWH、5,726円、サンコー)を見つけゲット。同機はUSB充電バッテリーで「プレートで首を冷やす」(2,000mAh)と「プレート+ファンで風を送る」(2,600mAh)の2つのユニットを使い分けることができる。どちらも使ってみたが、結構涼しい(ファン風は汗のベタつき防止用で強くない)。
 内蔵バッテリで「ファン+強」で使用すると、1時間弱で使えなくなるが、付属type-CケーブルとUSBバッテリー(別売り10,000mAh)を使うと、(ファン+弱で)4時間程度に伸ばすことができた。
 なお、USBバッテリー(要出力5V2.0A以上)によっては自動で電源がOFFになる物もあり、使ってみないと判らないので注意。


ファン付状態(手前は別電池とケーブル)

ケース表

ケース裏


P PICでSDカードを使う(9)  〜バイナリーファイル

by fjk

 abc921でSDカードのテキストファイルをプチFATで読み書きすることができたが、BMPやBINファイルなどのバイナリーデータの読み書きを試みた。

【ハード】
abc919の回路をそのまま利用した。
 
【ソフト】
MCCの設定はabc919と同じ。
 
<ソフトの主な修正・追加箇所>
・SDに書込むデータタイプをcharからBYTE(pff.hでtype宣言)に変更。そのため、データ数(bt)の指定が必要。
・文字列置換関数strNRepl()を、バイト列置換関数byteNRepl()に変更。
・my_xtoi()関数は戻り値としてuint32_tを返しているので、my_xtol()に名称変更
・テキスト形式ファイルはTXTのみとしていたが、CSVファイルの読み書きにも対応した。
   (バイナリーデータの読み書きはファイル種類に制限無し)
・U、Bコマンドをabc921に追加した(16進数の接頭辞"0x"は付けないこと)。
・W、B、r、i、sコマンドは、R(またはU、o)コマンドを一度は実行(ファイルオープン)してから使用すること。
<バイナリーデータのダンプ表示> ( [ ]はオプション)
U[Hofs][,byte]
・読出しデータは1行に最大16byte毎に表示
Hofs:最大32ビット16進数、読出開始オフセット、
   (Hofs無し:前回読出しの続きから)
byte:1回の読出しバイト数{10進数}、
   (デフォルトは128、バイト数は以後記憶)
Hofsbyte も無しは、次データから

<バイナリーデータ書込> ( [ ]はオプション)
B[Hofs],Hex[,Hex[,・・]]
Hofs:最大32ビット16進数、書込開始オフセット、
   (Hofs無し:前回書込の次データから)
Hex:データ{1byte16進数}はコンマに続けて連続指定可

<その他のコマンド> ( [ ]はオプション)
F[filname]
ファイル名の指定(FilName無し:現在ファイル)
R[filname]
(先頭から)テキストデータを読み出す
W[ofs,]str
文字列strを書込、ofs:書込開始位置{10進数}
D[path]
ファイルリスト表示、path:ディレクトリ名
  −(テスト用 & 補助コマンド)−
m
SDをマウント(テスト用)
o
(Fコマンドで指定した)ファイルをオープン
r
(オフセットから)文字列を読み出す(最大512字)
i
オープン中のファイル情報表示
s ofs
SDシーク、ofs:オフセット{10進数}

      U、Bコマンド実行例
 (テキストファイルをバイナリーモードで編集)

【abc922-18326.c】 abc922-18326.c + myFunction.c+myProject.h(zip)


/*****************************(abc922-18326.c)*******
 *   Test Petit FatFS
 ****************************************************/
#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "pff.h"
#include "myProject.h"

#define   SEC_SZ     512                      // セクターサイス(FAT32)
#define   PATH_SIZE   32                      // パス+ファイル名サイズ
#define   WR_BFSIZE   32                      // データ書込時ワークサイズ

enum { NON = 0, TXT, CSV, BIN = 8, BMP };

static char Dlm[] = ",";                      // 文字列区切りデリミタ

//--- タイマー・汎用変数
char     Msg[40];                             // コメント等送信用文字列
uint8_t  	TFlg;                               // タイマーフラグ

//--- SDカード用変数
FATFS   Fs;                                   // ファイルシステム変数
FILINFO Fno;                                  // ファイルシステム情報
DIR     Dir;                                  // ディレクトリー情報
BYTE    Buf[SEC_SZ + 1];                      // ファイルデータ用バッファー
UINT    Br;                                   // 送受信完了データ数
char    FilNam[PATH_SIZE] = "TEST00.TXT";     // ファイル名(8.3))
uint8_t F_ext = TXT;                          // 1:TXT, 2:CSV, 8:BIN, 9:BMP
DWORD   Wofs;                                 // 書込オフセット
DWORD   Rofs;                                 // 読込オフセット
DWORD   Dsz = 128;                            // ダンプバイトサイス
BYTE    Wbf[WR_BFSIZE];                       // 書込用データバイト配列

//--- EUSART用変数
char    RBuf[EU_BFSIZE];                      // シリアル受信バッファー
uint8_t SFlg;                                 // シリアル受信フラグ

/*******************************************
 *  タイマ0 Callback関数 (1秒周期割り込み)
 *******************************************/
void TMR0_Process(void){
    TFlg = 1;                                 // タイマーフラグセット
}

/*******************************************
 *  SDカード用汎用関数
 *******************************************/
//--- SDカードのマウント
FRESULT SD_Mount(void) {
    uint8_t i = 0;
    FRESULT res;
    
    do{
        res = pf_mount(&Fs);
        i++;
        EUSART_Write('.');
    }while((res != FR_OK) && (i < 10));	      // 10回まで試みる

    if(res != FR_OK){                         // マウント失敗なら
        EU_Puts("** SD Not Mounted !!");
    }else{
        EU_Puts("-- SD Mount OK!");
    }
    return res;	
}

//--- ファイルのオープン(SDアクセステスト用)
FRESULT SD_Open(void){
    FRESULT res;
    
    res = SD_Mount();
    if(res != FR_OK) return res;
    res = pf_open(FilNam);
    if(res != FR_OK){                         // オープン失敗なら
        EU_Puts("** SD Not Open !!");
    }else{
        EU_Puts("File Open OK!");
    }
    return res;
}

//---  データの読み出し(SDアクセステスト用)
FRESULT SD_Read(void){
    FRESULT res;
    
    res = pf_read(Buf,SEC_SZ,&Br);
    if(res != FR_OK){                         // 読出し失敗なら
        EU_Puts("** File Not Read !!");
    }else{
        Buf[Br] = 0;                          // 文字列デリミタセット
        EU_Puts((char *)Buf);
        my_itoa(Msg,Br);                      // 読み出し文字数表示
        EU_Puts(Msg);
    }
    return res;
}

//--- ファイル名セットするコマンド  F[filename]
/*    filname:指定するファイル名
 *    (filnameが無い場合、現在ファイル名を表示)   */
void SD_cmd_F(char *str) {
    size_t i,n;
    char   *p;
    
    n = strlen(str);
    if(n > 1){
        if(n > PATH_SIZE) n = PATH_SIZE - 1;
        for(i = 0; i < n; i++)
            FilNam[i] = (char)toupper(str[i+1]);
        FilNam[n]=0;
    } 
    p = strchr(FilNam,'.');
    if     (strncmp(p+1,"TXT",3)==0) 	F_ext = TXT;
    else if(strncmp(p+1,"CSV",3)==0) 	F_ext = CSV;
    else if(strncmp(p+1,"BIN",3)==0) 	F_ext = BIN;
    else if(strncmp(p+1,"BMP",3)==0) 	F_ext = BMP;
    else                             	F_ext = NON;
    sprintf(Msg,"NewFileName = %s: %d\n",FilNam,F_ext);
    EU_Puts(Msg);
}

//--- ファイルシステム(FATFS)データの表示(FAT32ならCLUST=DWORD)
void SD_Info(void){
    printf("FAT_Type = %d\n", Fs.fs_type);    // FAT sub type
    printf("FS_Flag  = %d\n", Fs.flag);       // File status flags
    printf("Cls_Size = %d\n", Fs.csize);      // sectors per cluster
    printf("Pad1     = %d\n", Fs.pad1);       // (BYTE)
    printf("Root_Dir = %d\n", Fs.n_rootdir);  // root_dir entries
    printf("Cls_Num  = %ld\n",Fs.n_fatent);   // FAT entries
    printf("FAT_Sec  = %ld\n",Fs.fatbase);    // FAT start sector
    printf("Root_Sec = %ld\n",Fs.dirbase);    // Root_dir start sect
    printf("Data_Sec = %ld\n",Fs.database);   // Data start sector
    printf("F_Point  = %ld\n",Fs.fptr);       // File R/W pointer
    printf("F_Size   = %ld\n",Fs.fsize);      // File size
    printf("F_Clst   = %ld\n",Fs.org_clust);  // File start cluster
    printf("F_Cr_Cls = %ld\n",Fs.curr_clust); // File current clust
    printf("F_Cr_Sec = %ld\n",Fs.dsect);      // current data sect
}

//--- SDカードから読込コマンド    R[filename]
/*    filnameファイルから読み出す(TXTファイルのみ)
 *    (filnameが無い場合は現在ファイルから読み出す)   */
void SD_cmd_R(char *str){
    FRESULT res;
    UINT    sz = 0;
    
    if(strlen(str)>1)   SD_cmd_F(str);
    if((F_ext < 1)|(F_ext > 2)){              // *.TXTまたは*.CSV
        EU_Puts("Not Text File!");
        return;
    }
    EU_Puts("Start Command R");
    if(SD_Mount() != FR_OK) return;
    res = pf_open(FilNam);                    // ファイルオープン
    if(res == FR_OK){
        sprintf(Msg,"Open %s",FilNam);
        EU_Puts(Msg);
        do{
            pf_read(Buf, SEC_SZ, &Br);        // SDから読込む
            Buf[Br] = 0;
            EU_Puts((char *)Buf);
            sz += Br;
        }while(Br!=0);
    }else{
        sprintf(Msg,"** Can't open %s !!",FilNam);
        EU_Puts(Msg);
    }
    sprintf(Msg,"Size = %d",sz);
    EU_Puts(Msg);
}

//---- 16進数リストプリント
/*      BYTE *bf:	表示データバイト配列
 *      UINT  n:  	表示バイト数		***/
void prt_HxLst(BYTE *bf, UINT n){
    UINT i;
    char hx[3];
    for(i = 0; i < n; i++){
        if(i % 16 == 0) putch('\r');
        my_utoa(hx,bf[i],2);
        putch(hx[0]); putch(hx[1]); putch(' ');
    }
    puts("\r");
}

//--- SDカードから読込コマンド    U[ofs][,n]
/*    現在ファイルからバイナリーデータを読み出す
 *    ofs: 読出し開始オフセット
 *    n:   読み出すバイト数   */
void SD_cmd_U(char *str){
    FRESULT res;
    char    *pts;
    UINT    sz = 0;

    if(strlen(str) >1){                       // パラメータ有り? 
        if(str[1]!=','){                      // オフセット指定あり?
            pts = strtok(str+1,Dlm);          // コマンドの次文字から
            if(pts != NULL){                  // オフセットデータあり
                Rofs = (DWORD)atol(pts);      // オフセット値取得
            }
            pts = strtok(NULL,Dlm);           // コンマの次の文字列へ
        }else{
            pts = strtok(str+2,Dlm);          // コンマの次の文字列へ
        }
        if(pts != NULL){                      // バイト数指定があれば
            Dsz = (DWORD)atol(pts);
        }
    }
    printf("U: Rof = %ld, Dsz = %d\n",Rofs,Dsz);
    
    if(SD_Mount() != FR_OK) return;
    res = pf_open(FilNam);                    // ファイルオープン
    if(res == FR_OK){
        sprintf(Msg,"Open %s",FilNam);
        EU_Puts(Msg);
        pf_lseek(Rofs);
        do{
            pf_read(Buf, SEC_SZ, &Br);        // SDから読込む
            Buf[Br] = 0;
            if(Dsz < Br) Br = (UINT)Dsz;
            prt_HxLst((uint8_t *)Buf,Br);
            sz += Br;
        }while((Br!=0)&(sz < Dsz));
    }else{
        sprintf(Msg,"** Can't open %s !!",FilNam);
        EU_Puts(Msg);
    }
    Rofs += sz;
    sprintf(Msg,"Size = %d",sz);
    EU_Puts(Msg);
}

//---  バイト列s1のn1番目からバイト列s2のn2バイト分を置き換える
void bytNRepl(BYTE *s1, UINT n1, UINT p1, BYTE *s2, UINT n2){
    UINT  i;                                  // ワーク用変数
    BYTE *p;                                  // ワーク用ポインタ

    if(p1 + n2 > n1) n2 = n1 - p1;            // 挿入サイスが超えるか?
    p = s1 + p1;
    for(i = 0; i < n2; i++){
        *p++ = *s2++;
    }
}

//--- セクター単位でSDカードから読込・変更・カードに書込
/*      ofs:   書込オフセット位置
 *      sof:   セクター内オフセット
 *      *str:  書き込むデータ配列
 *      bt:    書き込むバイト数    */
UINT Sec_Write(DWORD ofs, UINT sof, BYTE *str, UINT bt){
    FRESULT res;
    UINT    rw;                               // 読込バイト数
    UINT    bw;                               // 書込バイト数
    DWORD   cr_of;                            // クラスタオフセット

    cr_of = ofs & 0xFFFFFE00;                 // オフセットはセクタ境界
    res = pf_lseek(cr_of);                    // セクター境界にシーク
    res = pf_read(Buf, 512, &rw);             // セクター単位で読出す
    if(sof + bt > 512) bt = 512 - sof;        // 置換はセクター境界まで
    if(sof + bt > rw)  bt = rw - sof;         // 置換は読込データ数まで
    bytNRepl(Buf,SEC_SZ,sof,str,bt);          // 文字列の置換
    res = pf_lseek(cr_of);                    // セクター境界に再シーク
    res = pf_write(Buf,rw,&bw);               // セクターデータを書込
    res = pf_write(0,0,&bw);                  // ファイナライズ
    return bt;
}

//--- SDカードにデータを書き込む(書込バイト数指定付)
/*      ofs:   書込オフセット位置
 *      *str:  書き込むデータ配列
 *      bt:    書込バイト数    */
UINT SD_WritePB(DWORD ofs, BYTE *str,UINT bt){
    UINT    sof;                              // セクター内オフセット
    UINT    rmb;                              // 文字列の残りバイト数
    UINT    btw;                              // 書込済み総バイト数
    UINT    bw;                               // 書込済みバイト数
    UINT    sln;                              // 書込文字列のサイズ
    BYTE   *pts;                              // 書込文字列ポインタ

    sof = ofs % 512;                          // 最初セクタ内の書込位置
    sln = bt;
    //--- 書き出し開始
    btw = Sec_Write(ofs,sof,str,sln);         // 最初のセクターに書込
    if(sof + sln > 512){                      // セクター境界を超える?
        pts +=  btw;                          // 文字列ポインタを進める
        rmb = sln - btw;                      // 文字列の残りバイト
        ofs = (ofs + 512) & 0xFFFFFE00;       // 次セクターの先頭に
        while((sln > btw)&(ofs < Fs.fsize)){  // データ残あり?
            bw = Sec_Write(ofs,0,pts,rmb);    // 次セクターに書込
            btw += bw;                        // 書込済み文字数を加える
            ofs += 512;                       // 次セクターの先頭に
            pts += bw;                        // 文字列ポインタを進める
            rmb -= bw;                        // 文字列の残りバイトを減
        };
    }
    return btw;                               // 書込済み文字数を返す
}

//--- SDカードへの書込コマンド     W[ofs,]str
UINT SD_cmd_W(char *str){
    char    *pts;                             // 文字列ポインタ
    UINT    btw ;
    
    if(strlen(str)==1) return 0;              // 'W'のみなら
    if(strchr(str,',')){                      // コンマがあれば?ofs有り
        pts = strtok(str+1,Dlm);              // コマンドの次文字から
        if(pts != NULL){                      // オフセットデータがある
            Wofs = (DWORD)atol(pts);          // オフセット値取得
        }
        pts = strtok(NULL,Dlm);               // 書込文字列指定
    }else{
        pts = str + 1;                        // 書込文字列指定
    }
    btw = 0;
    if(pts != NULL){                          // 文字列データ有り
        btw = SD_WritePB(Wofs,(BYTE*)pts,strlen(pts));
        Wofs += btw;
    }
    return btw;
}

//--- SDカードへ16進数データを書き込むコマンド B[ofs][,Hex[,・・]]
UINT SD_cmd_B(char *str){
    char     *pt;                             // 文字列操作用ポインタ
    uint8_t  last;                            // 文字列の最後の位置
    uint32_t res;                             // Hex文字数値変換結果
    uint8_t  dtn;                             // 書き込むバイトデータ数
    UINT     btw;                             // 書き込んだ実バイト数

    if(strlen(str)==1){                       // 'B'のみなら
        return 0;                             // データは書き込まない
    }
    if(str[1]!=','){                          // 第2文字がコンマか?
        pt = strtok(str+1,Dlm);               // コマンドの次文字から
        if(pt != NULL){                       // アドレスデータがある
            res = my_xtol(pt);
            Wofs = (DWORD)res;                // オフセット値有り
        }
        pt = strtok(NULL,Dlm);                // 次文字列取込
    }else{
        pt = strtok(str+1,Dlm);               // 文字列取込
    }
    dtn = 0; btw = 0;
    do{
        if(pt != NULL){                       // データがあるか?
            Wbf[dtn] = (BYTE)my_xtol(pt);
            dtn++;
            pt = strtok(NULL,Dlm);            // 次文字へ
        }
    }while(pt != NULL);                       // データがあるだけ繰返す
    if(dtn){                                  // 書き込むデータがあれば
        btw = SD_WritePB(Wofs,Wbf,dtn);       // データをSDに書込む
        Wofs += btw;
    }
    return btw;                               // 書込んだ文字数を返す
}

/*--- SDカードにデータを書き込む
void Tst_Write(char *str){
    FRESULT res;
    size_t btw;
    UINT   bw;
    
    btw = strlen(str+1);
    if(btw){
        res = pf_write(str+1,btw,&bw);
        res = pf_write(0,0,&bw);
        printf("Write_SD: %s\n",str+1);
    }else{
        res = pf_write("++XXXX++",8,&bw);
        res = pf_write(0,0,&bw);
        puts("Write_SD: ++XXXX++");
    }
}
*/
//--- 読み書きポインター移動
void Tst_Seek(char *str){
    FRESULT res;
    DWORD   ofs;
    
    if(strlen(str)==1){
        puts("Seek Error!");
        return;
    }
    ofs = (DWORD)atol(str+1);
    res = pf_lseek(ofs);
    if(res) puts("Seek Error!");
    else{
        Rofs = ofs; Wofs = ofs;
        printf("Seek at %ld\n",ofs);
    }
}

//----  ディレクトリーデータ表示
void Prt_Dir(void){
    if(AM_SYS & Fno.fattrib)
      printf("%-13s  -<sys>-  %2X\n", Fno.fname, Fno.fattrib);
    else if(AM_DIR & Fno.fattrib)
      printf("%-13s  -<dir>-  %2X\n", Fno.fname, Fno.fattrib);
    else
      printf("%-13s  %7ld  %2X\n", Fno.fname, Fno.fsize, Fno.fattrib);
}

//----  ディレクトリーのオープン・取得・表示
FRESULT List_Dir(char *str){
    FRESULT res;
    char    path[PATH_SIZE];
    size_t  n;
    uint8_t i;

    if(SD_Mount() != FR_OK) return FR_NOT_READY;
    n = strlen(str+1);
    if(n > 0){
        if(n >= PATH_SIZE) n = PATH_SIZE - 1;
        for(i = 0; i < n; i++)
            path[i] = (char)toupper(str[i+1]);
    }
    path[n] = 0;      
    res = pf_opendir(&Dir,path);
    if(n == 0)  printf("OpenDir = root  %d\n", res);
    else        printf("OpenDir = %s  %d\n",path, res);
    if(res != FR_OK) return res;
    while(pf_readdir(&Dir,&Fno) == FR_OK){
        Prt_Dir();
    }
    puts("--- dir end ---");
    return res;
}

/***************************************
 *    Main application
 ****************************************/
void main(void) {
    FRESULT res;
    char    cmd;                            // 受信コマンド文字
    
    SYSTEM_Initialize();

  // タイマ0 Callback関数定義
    TMR0_SetInterruptHandler(TMR0_Process);
    
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    SSP1CON1bits.SSPEN = 1;
    
    EU_Puts("--- test ---");
    LED_SetHigh();
    
    while (1) {
        // 1秒周期の処理
        if(TFlg == 1){                      // フラグオンの場合
            LED_Toggle();
            TFlg = 0;                       // フラグリセット
        }
      // コマンド処理
        if(SFlg){                           // 受信ありの場合
          cmd = RBuf[0];  
          sprintf(Msg,"Input = %s\n",RBuf);
          EU_Puts(Msg);

          switch(cmd){
            case 'R': SD_cmd_R(RBuf);   break;  // TXTデータ読出
            case 'F': SD_cmd_F(RBuf);   break;  // ファイル名セット
            case 'W': SD_cmd_W(RBuf);   break;  // TXTデータ書込 
            case 'U': SD_cmd_U(RBuf);   break;  // 16進データ表示
            case 'B': SD_cmd_B(RBuf);   break;  // 16進データ書込
            case 'D': List_Dir(RBuf);   break;  // ディレクトリ表示
            //----  Test Putit_FatFS  ----
            case 'm': SD_Mount();       break;  // SDマウント
            case 'o': SD_Open();        break;  // FileOpen 
            case 'r': SD_Read();        break;  // データ読出し
            case 'i': SD_Info();        break;  // SD情報表示
            case 's': Tst_Seek(RBuf);   break;  // SDシーク
//           case 'w': Tst_Write(RBuf); break;  // データ書込

            default:  EU_Puts("???");   break;  // 無効なコマンド
          }
          SFlg = 0;
        }
    }
}

******   End of File   *****/

【その他のライブラリー】

・プチFAT:
pff.c/h+pffconf.h(zip)
・diskio:
diskio.c/h(zip)


※プログラムのリストをハイライト無しのスタイルで見る場合はここをクリック


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


中間スイッチ 電動ネッククーラー プチFATでバイナリーデータ