Vol.901 23.Aug.2024

コードレス掃除機 GameBar PICミニBB(11)_EEPROMライター

C コードレス掃除機  〜マキタCL181FDW

by fjk

 我が家ではコードレス掃除機としてダイソンなどを使っているが、女房の不満は「稼働時間が短い」(カタログでは40分とあるが、多くのコードレス掃除機を強で使うと10分ももたない)と、結局コード付掃除機を使うことが多い。
 稼働時間がもっと長い機種がないか,ネットで探していると、マキタのCL181FDZW(37/10W)が38%引きの8,145円で売られていた(稼働時間:強で20分/BL1830B使用時)。同機は発売時期が2016年と古いが、安価でパワーがあると人気の機種で、さらにサイクロンアタッチメントを使えば、吸引力が落ちることなく長時間の使用ができそうである。そして、我が家には同機に使えるバッテリー(BL1830B/BL1860B)と充電器が既にある。より強力で稼働時間もほぼ同じCL281FD(60/42/15W)も気になったが、価格(\18,000)が倍以上違うので、CL181FDZWを購入した。

本体の他に、追加したパーツは、(金額は全て税込)
@サイクロンアタッチメント(A-68856、\2,671)・・サイクロンの効率は良いのだが・・
AショートサイクロンSw(A-72475、\2,791)・・・A-68856はチョット大きいので・・
BフロアジュータンノズルS(A-59950、\1,730)・・ジュータン用
C短いストレートパイプ320(459246-9、\351)・・・サイクロン取付時に長さを短くするため
DLANMUフィルターカバー(\849/2個)・・・・サイクロン使用時、ゴミ分離効率向上
E高機能フィルターEX(A-68971、\743)・・・・・フィルター洗濯時などの予備

マキタCL181FDW(+A-72475+A-59950)


G GameBar  〜windows10のキャプチャーツール

by fjk

 GameBarを使っていますか?
 正式にはXbox_Game_Barと呼ばれXboxゲーム用に開発されたものですが、windows10以降に組み込まれ、ゲームやアプリの画面録画やキャプチャーが可能です。
 使い方は、ここ(win11)などが詳しい。
 実際にユーチューブの録画に使ってみると、確かに録画はできるのだが、何故か音声が録音されていない。実はデフォルトのままではゲーム音声のみの録音になっており、以下の設定をすることで、他のアプリの音声も録音できるようなる。

  1. GameBarのメニューバーで、「設定」を選ぶ
  2. 設定画面の左画面メニューで、「ウィジット」を選ぶ
  3. 録音するオーディオで、「全て」のボタンをオン
  4. この状態で、録画ボタンを押すと、音声も記録できる。

※ただし、GameBarではブルーレイ画面はキャプチャーできません。


録音設定


P PICミニBBシリーズ(11)  〜ExcelVBAでPic外付けEEPRomライター

by fjk

 abc889でPICの外付けi2c-EEPROMの読み書き、abc900でExcel-VBAでPICとのシリアル通信、を行ったので、Excel-VBAでPICの外付けi2c-EEPROMの読み書きを行ってみた。
 Excel_VBAはabc900をベースに、複数行データの受信と(各セル)表示ができるように変更した。受信エラーに対応できるようTimeOutも設定した。

  【Excel_VBAプログラム】testEasyComm31.xlsm/bas(zip) (赤字部修正済み、9/26)


VBA開発画面例
(余分なコメントもあるけど・・)
Option Explicit

Sub EasyCommTest()
    Dim cmd As String
    Dim row As Integer
    Dim rcv As String
    Dim S_Time   As Date
'@初期設定
    ec.COMn = Range("B2")
    ec.Setting = "115200,n,8,2"
    ec.AsciiLineTimeOut = 1000
'Aデータの送信
    cmd = Range("B5")
    ec.AsciiLine = cmd
'Bデータの受信
    row = 6
    Range("B6:B18").Value = ""
    S_Time = Now
    Do
        If Now > S_Time + TimeSerial(0, 0, 1) Then Exit Do
        DoEvents
        If ec.InBuffer > 0 Then
            DoEvents
            rcv = ec.AsciiLine
            Cells(row, 2) = rcv
            row = row + 1
        End If
    Loop
    ec.InBufferClear 	'受信バッファをクリア
'Cポートを閉じる
    ec.COMn = -1 	'終了処理
End Sub

 シリアル通信によるROMアクセスコマンドは、基本的にはabc899と同じだが、少し強化した。


"R0,5"コマンド実行例

"U"コマンド実行例

【PICプログラム】(PICハードはabc899と同じで、LCDをバックライト付に)
 abc899をベースに、I2Cメモリ関係を "i2c_EEPROM.c/h" にまとめ、ライブラリとして使うことにした。
 EUSARTおよびi2cLCD_ST7032iについてはabc900を参照。
 テラタームでは "ECHO = ON" としたが、Excelターミナルでは "ECHO = OFF" とした。それでも、Excelでは余計な改行が発生したので、"#define VBA" を定義し、改行が発生しないようにした(Excelターミナルのデリミタを "CrLf" に設定すればOKと思っていたが、Excelで正しく受信できなかったので)。
 また、コマンドの強化として、「S」コマンドの追加と「P」コマンドを以下のように強化した。

P
64バイトのデータバッファーの表示 (Uコマンドはデータを読み込んで表示)
PW[aaaa]
[aaaa]番地を含む64バイトにバッファーの内容を書き込み
PR[aaaa]
[aaaa]番地を含む64バイトをバッファーに読み込み、表示
 
S[aa][.[d0,・・[,]]]
64バイトのデータバッファーに書き込む以外はWコマンドと同じ
(連続書込モードも有効、aaは下位6ビットのみ有効)

※一応、ExcelターミナルでROMの読み書きができたが、時々Excelが異常終了する(以下の処理により解決済み、9/26)。

<原因>
読込Doループ内で、指定時間が経過したならDoループを脱出する設定としたが、脱出できていなかった。
<対策>
初期設定で"ec.AsciiLineTimeOut=1000"を追加、DOループ内の脱出経過時間を1秒に。
無信号から合計2秒後にDoループ脱出。(TimeOut設定値である程度変更可)
<考察>
ec内でタイムアウト処理が混乱していたためか(ExitDoが実行されない)?

【abc901-18325.cファイル】 abc901-18325.c(zip)

/*****************************(abc901-18325.c)***
 *     I2Cメモリ読み書きライブラリーテスト
 *************************************************/

#include "mcc_generated_files/mcc.h"
#include "myProject.h"
#include "i2cEEPROM.h"

char RBuf[BFSIZE];                	// シリアル受信バッファー
uint8_t SFlg;                     	// シリアル受信フラグ

//---- ターミナルにプロンプト文字表示
void prtPrompt(uint8_t m){
    if(m)  printf("# ");           	// 連続書込モード中
    else   printf("$ ");           	// 通常書込モード
}

/*===========================================
 *      Main application
 *==========================================*/
void main(void){
    char cmd;                     	// コマンド文字

    SYSTEM_Initialize();
    LCD_init();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    puts("ready!\r");
    LCD_str("Ready!");
    #ifndef VBA
        prtPrompt(i2cRom_SqMode());
    #endif
        
    while (1) {
        if(SFlg){
            LCD_clr(); LCD_str(RBuf);   // LCDにコマンド表示
            cmd = RBuf[0];            	// コマンドは第1文字
            #ifndef VBA
                printf("\n\r");
            #endif
            switch(cmd) {             	// 各コマンドの実行
                case 'W': i2cRom_cmd_W(RBuf);  break;
                case 'R': i2cRom_cmd_R(RBuf);  break;
                case 'Q': i2cRom_cmd_Q(RBuf);  break;
                case 'M': i2cRom_cmd_M(RBuf);  break;
                case 'U': i2cRom_cmd_U(RBuf);  break;
                case 'S': i2cRom_cmd_W(RBuf);  break; // バッファーWコマンド
                case 'P': i2cRom_cmd_P(RBuf);  break;
                                                   // 有効なコマンドがなく 
                default:  if(i2cRom_SqMode()){     // 連続書込モード中なら
                            i2cRom_cmd_WSQ(RBuf);  // 書込シーケンスを実行
                          }
                          break; 
            }
            SFlg = 0;
            #ifndef VBA
                prtPrompt(i2cRom_SqMode());
            #endif
        }
        IO_RA4_Toggle();
        __delay_ms(500);
    }
}
/****  End of File  ****/

 
【myProject.hファイル】 myProject.h(zip)

/**************************(myProject.h)***
 *   プロジェクト個別条件指定ファイル     *
 *   (main.cと同じフォルダーに作成)     *
 ******************************************/
#include "mcc_generated_files/mcc.h"
#include "i2cLCDST7032i.h"

#define  ON    1
#define  OFF   0

/***** 使用電源電圧 ***********************/
//--- VCC宣言無しは5V(VCC=50と同じ)
#define VCC   50		// 電源電圧は5V
//#define VCC   33		// 電源電圧は3.3V

/***** EUSARTモジュール *******************/
#define BFSIZE  80
//--- ECHO宣言はどちらかを必ず行うこと
//#define ECHO  ON		// エコー有り
#define ECHO  OFF		// エコー無し

define VBA     			// Excel_VBAを使用

/***** MSSPモジュール *********************/
#define MASTER 1
#define SRAVE  2
#define I2CMODE MASTER    	// マスターとして使用
//#define I2CMODE SRAVE    	// スレーブとして使用
//--- MSSPが一つしか無い場合は I2C宣言無し
#define I2C  1            	// I2C1を使用
//#define I2C  2            	// I2C2を使用

#if I2CMODE == MASTER
    #if I2C == 1
        #include "mcc_generated_files/examples/i2c1_master_example.h"
    #elif I2C == 2
        #include "mcc_generated_files/examples/i2c2_master_example.h"
    #else
        #include "mcc_generated_files/examples/i2c_master_example.h"
    #endif
  //  #define I2CLCD_Adr 0x3c // LCDのI2Cアドレス(i2cLCD_ST7032i.hで設定)
#endif

 
【i2c_EEPROM.hファイル】 i2c_EEPROM.c/h(zip)

/******************************(i2c_EEPROM.h)***************
 *	I2C接続EEPROM(24FC1025)読み書きヘッダーファイル
 ***********************************************************/

#include "i2cLCD_ST7032i.h"
#include "ctype.h"                      // isxdigit()
#include "stdio.h"                      // puts(),..
#include "stdlib.h"                     // atoi()...
#include "string.h"                     // strtok()...
#include "myProject.h"


//----- Wコマンド   W[aaaa][,[d0,・・[,]]]
uint16_t i2cRom_cmd_W(char *str);

//---- Rコマンド  R[aaaa][,n]
uint16_t i2cRom_cmd_R(char *str);

//---- WSQ (連続書込モード)
uint16_t i2cRom_cmd_WSQ(char *str);

//---- MBコマンド  MBn
int i2cRom_cmd_M(char *str);

//---- Qコマンド(連続書込モードの解除)   Q
void i2cRom_cmd_Q(char *str);

//---- U(dump)コマンド    U[aaaa]
//         (64バイトのデータをDBuf[]に読み出す)
int i2cRom_cmd_U(char *str);

//---- P(Page)コマンド    PW[aaaa]
//          (DBuf[]の64バイトをメモリに書き込む)
int i2cRom_cmd_P(char *str);

//----  シーケンスモードの確認
uint8_t i2cRom_SqMode();

 
【i2c_EEPROM.cファイル】

/******************************(i2c_EEPROM.c)************
 *	I2C接続EEPROM(24FC1025)読み書きライブラリ
 **********************************************************/
#define DEVICE	0x50      		// Blk0=0x50,Blk1=0x54
#define MBFSIZE 78  			// メモリ操作用バッファーサイズ

#include "i2cEEPROM.h"


//=== グローバル変数 ============
char     Dlm[] = ",";    		// 文字列区切りデリミタ
char     SBuf[20];     			// 文字列処理用バッファー

//--- I2Cメモリー用
static uint8_t  BlkNum = 0; 		// メモリブロック番号
static uint16_t CrtAdr = 0;  		// カレントアドレス
static uint8_t  DBuf[MBFSIZE];  	// ページメモリ用バッファー
static uint8_t  SqMode = 0;   		// シーケンスモードフラグ
static char     lstCmd;          	// 最終コマンド

/*************************************
 *  I2C EEPROM function
 **************************************/
//-----  アドレスadrから、1バイトを読み出す
uint8_t I2C_Mem_Read(uint16_t adr){
    uint8_t bf[2];

    bf[0] = adr >> 8;
    bf[1] = (uint8_t)adr;
    #if I2C == 1
        I2C1_WriteNBytes(DEVICE + BlkNum,bf,2);
        I2C1_ReadNBytes(DEVICE + BlkNum,bf,1);
    #elif I2C == 2
        I2C2_WriteNBytes(DEVICE + BlkNum,bf,2);
        I2C2_ReadNBytes(DEVICE + BlkNum,bf,1);
    #else
        I2C_WriteNBytes(DEVICE + BlkNum,bf,2);
        I2C_ReadNBytes(DEVICE + BlkNum,bf,1);
    #endif
    return bf[0];
}

//-----  アドレスadrに、1バイトdtを書き込む
void I2C_Mem_Write(uint16_t adr, uint8_t dt){
    uint8_t bf[3];

    bf[0] = adr >> 8;
    bf[1] = (uint8_t)adr;              		// アドレスセット
    bf[2] = dt;                         	// データセット
    #if I2C == 1
        I2C1_WriteNBytes(DEVICE + BlkNum,bf,3);  //書き込む
    #elif I2C == 2
        I2C2_WriteNBytes(DEVICE + BlkNum,bf,3);  //書き込む
    #else
        I2C_WriteNBytes(DEVICE + BlkNum,bf,3);   //書き込む
    #endif    __delay_ms(5);
}

//-----  アドレスadrからnバイトをary[]に読み出す
void I2C_Mem_NRead(uint16_t adr, uint8_t *ary, uint8_t n){
    uint8_t bf[2];

    bf[0] = adr >> 8;
    bf[1] = (uint8_t) adr;
    if(n > MBFSIZE) n = MBFSIZE;           	// 配列要素数以内
    #if I2C == 1
        I2C1_WriteNBytes(DEVICE+BlkNum,bf,2);  // アドレス送信
        I2C1_ReadNBytes(DEVICE+BlkNum,ary,n);  // データ読込
    #elif I2C == 2
        I2C2_WriteNBytes(DEVICE+BlkNum,bf,2);  // アドレス送信
        I2C2_ReadNBytes(DEVICE+BlkNum,ary,n);  // データ読込
    #else
        I2C_WriteNBytes(DEVICE+BlkNum,bf,2);  // アドレス送信
        I2C_ReadNBytes(DEVICE+BlkNum,ary,n);  // データ読込
    #endif
}

//-----  アドレスadrからary[]のnバイトを書き込む
void I2C_Mem_NWrite(uint16_t adr, uint8_t  *ary, uint8_t n){
    uint8_t bf[MBFSIZE + 2];

    bf[0] = adr >> 8;                   	// アドレスセット
    bf[1] = (uint8_t) adr;              	// ページ境界に注意!
    if(n > MBFSIZE) n = MBFSIZE;
    memcpy(bf+2,ary,n);                 	// ary[]をbf[]にコピー
    #if I2C == 1
        I2C1_WriteNBytes(DEVICE+BlkNum,bf,n+2);
    #elif I2C == 2
        I2C2_WriteNBytes(DEVICE+BlkNum,bf,n+2);
    #else
        I2C_WriteNBytes(DEVICE+BlkNum,bf,n+2);
    #endif    __delay_ms(5);
}

//---- ページバッファープリント
void prt_PBf(){
    uint8_t i;

    for(i = 0; i < 64; i++){            	// 16x4文字表示
    #ifdef VBA
        if(i % 16 == 0) printf("\r");
    #else
        if(i % 16 == 0) printf("\n\r");
    #endif
        printf(" %02X",DBuf[i]);
    }
    puts("\r");
}

//---- 16進文字列を10進数に変換
int32_t my_xtoi(char *str){
    uint32_t dec;

    dec = strtoul(str,NULL,16);
    return (int32_t)dec;
}

/************************************
 * 	コマンドアクション
 ************************************/
//----- Wコマンド   W[aaaa][,[d0,・・[,]]]
uint16_t i2cRom_cmd_W(char *str){
    char     *pt;               		// 文字列操作用ポインタ
    uint8_t  last;               		// 文字列の最後の位置
    int32_t  res = 0;           		// Hex文字数値変換結果
    uint8_t  dt = 0;            		// 書き込むバイトデータ
    uint16_t cnt = 0;           		// 実際に書き込んだバイト数

    lstCmd = str[0];
    if(strlen(str)==1){          		// 'W'のみなら
        SqMode = 1;             		// 連続書込モードにセット
        #ifndef VBA
             puts("SqMode ON\n\r");
        #endif
        return 0;               		// データは書き込まない
    }
    last = (uint8_t)strlen(str)-1;		// 文字列の行末位置を取得
    if(str[last] == ','){         		// 行末がコンマなら
        SqMode = 1;             		// 連続書込モードにセット
        #ifndef VBA
            puts("SqMode ON\n\r");
        #endif
        str[last]='\0';          		// 行末のコンマを消す
    }
    if(str[1]!=','){             		// 第2文字がコンマか?
        pt = strtok(str+1,Dlm);    		// コマンドの次文字から
        if(pt != NULL){         		// アドレスデータがある
            res = my_xtoi(pt);
            CrtAdr = (uint16_t)res;
        }
        pt = strtok(NULL,Dlm);     		// 次文字列取込
    }else{
        pt = strtok(str+1,Dlm);   		// 文字列取込
    } 
    do{
        if(pt != NULL){          		// データがあるか?
            res = my_xtoi(pt);
            if(res < 0) return cnt;
            dt = (uint8_t)res;
            if(lstCmd=='W'){
                I2C_Mem_Write(CrtAdr,dt); 	// データを書込む
            }else if(lstCmd == 'S'){
                DBuf[CrtAdr & 0x3F]= dt;  
            }
            sprintf(SBuf,"%d:%04X < %02X",BlkNum,CrtAdr,dt);
            #ifdef VBA
                printf("%s\r",SBuf);
            #else
                printf("%s\n\r",SBuf);
            #endif            
            LCD_cursor(1,1); LCD_str(SBuf);
            CrtAdr++; cnt++;          
            pt = strtok(NULL,Dlm);   		// 次文字へ
        }
    }while(pt != NULL);         		// データがあるだけ繰り返す
    return cnt;                 		// 書き込んだ文字数を返す
}

//---- Rコマンド  R[aaaa][,n]
uint16_t i2cRom_cmd_R(char *str){
    char *pt;                   		// 文字列操作用ポインタ
    uint16_t n = 1;             		// 指定された読込バイト数
    int32_t  res = 0;           		// Hex文字数値変換結果
    uint8_t  dt;                		// 読み込んだバイトデータ
    uint16_t cnt = 0;            		// 実際に読み出されたバイト数
    uint8_t  i;                 		// ループ変数

    lstCmd = str[0];
    if(strlen(str) > 1){
        if(str[1]==','){
            pt = strtok(str+2,Dlm);
            if(pt != NULL){        		// データ無し?
                res = my_xtoi(pt);
                n = (uint16_t)res;
            }
        }else{
            pt = strtok(str+1,Dlm);
            if(pt != NULL){          		// addressがある?
                res = my_xtoi(pt);
                CrtAdr = (uint16_t)res;
            }
            pt = strtok(NULL,Dlm);   		// 次文字へ
            if(pt != NULL){          		// データ無し?
                res = my_xtoi(pt);
                n = (uint16_t)res;
            }
        }
    }
    for(i = 0; i < n;i++ ){
        dt = I2C_Mem_Read(CrtAdr);  		// データを読み出す
        sprintf(SBuf,"%d:%04X > %02X",BlkNum,CrtAdr,dt);
        #ifdef VBA
            printf("%s\r",SBuf);
        #else
            printf("%s\n\r",SBuf);
        #endif
        LCD_cursor(1,1); LCD_str(SBuf);
        CrtAdr++; cnt++;
    }
    SqMode = 0;
    return cnt;                   		// 読み込んだデータ数を返す
}

//---- WSQ (連続書込モード)
uint16_t i2cRom_cmd_WSQ(char *str){
    char     *pt;               		// 文字列操作用ポインタ
    uint8_t  dt;               			// 書き込むバイトデータ
    int32_t  res;                 		// Hex文字数値変換結果
    uint16_t cnt = 0;          			// 実際に読み出されたバイト数

    pt = strtok(str,Dlm);
    while(pt != NULL){       	 		// データがあるだけ繰り返す
        res = my_xtoi(pt);
        dt = (uint8_t)res;
        if(lstCmd == 'W'){
            I2C_Mem_Write(CrtAdr,dt);		// データを書き込む
        }else if(lstCmd=='S'){
            DBuf[CrtAdr & 0x3F]= dt;  
        }    
        #ifdef VBA
            printf("%d:%04X < %02X\r",BlkNum,CrtAdr,dt);
        #else
            printf("%d:%04X < %02X\n\r",BlkNum,CrtAdr,dt);
        #endif
        CrtAdr++; cnt++;
        pt = strtok(NULL,Dlm);     		// 次文字列へ
    }
    return cnt;                   		// 書き込んだデータ数を返す
}

//---- MBコマンド  MBn      (メモリバンクの指定)
int i2cRom_cmd_M(char *str){
    char     *pt;               		// 文字列操作用ポインタ
    uint8_t  b;                   		// メモリバンク番号

    lstCmd = str[0];
    if(str[1] != 'B') return -1;  		// 第2文字がBか?
    pt = strtok(str+2,Dlm);
    if(pt==NULL) return -1;       		// 文字列変換エラー
    b = atoi(pt) & 0x01;
    #ifdef VBA
    	printf("Bank %d selected\r",b);
    #else
    	printf("Bank %d selected\n\r",b);
    #endif
    BlkNum = b * 4;               		// Blk = bit2
    CrtAdr = 0;                  		// 現在アドレスは0に
    SqMode = 0;
//    puts("SqMode OFF\r");
    return b;
}

//---- Qコマンド(連続書込モードの解除)   Q
void i2cRom_cmd_Q(char *str){
    lstCmd = str[0];
    SqMode = 0;
    #ifndef VBA
        puts("SqMode OFF\r");
    #endif
}

//---- U(dump)コマンド    U[aaaa]
//         (64バイトのデータをDBuf[]に読み出す)
int i2cRom_cmd_U(char *str){
    char    *pt;                  		// 文字列操作用ポインタ
    int32_t  res;                  		// Hex文字数値変換結果
    uint16_t ad;                  		// 指定アドレス

    lstCmd = str[0];
    pt = strtok(str+1,Dlm);
    if(pt != NULL){              		// アドレス有り?
        res = my_xtoi(pt);
        CrtAdr = (uint16_t)res;
    }
    ad = CrtAdr & 0xFFC0;        		// 64バイト単位に 
    I2C_Mem_NRead(ad,DBuf,64); 			// 64バイトをDBuf[]に読出
    printf("%d:%04X - %04X",BlkNum,ad,ad+63);
    prt_PBf();
    SqMode = 0;
    return 0;
}

//---- P(Page)コマンド    PW[aaaa]
//          (DBuf[]の64バイトの読み書き)
int i2cRom_cmd_P(char *str){
    char     *pt;                  		// 文字列操作用ポインタ
    int32_t  res;                		// Hex文字数値変換結果
    uint16_t ad;                   		// 指定アドレス

    lstCmd = str[0];
    if(strlen(str)==1){
        printf("PageBuffer");
        prt_PBf();
        return 0;
    }
    if(str[1]=='R'){         			// 第2文字がR?
        i2cRom_cmd_U(str+1);
        return 0;
    }
    if(str[1] != 'W') return -1;    		// 第2文字がW?
    pt = strtok(str+2,Dlm);
    if(pt != NULL){               		// アドレス有り?
        res = my_xtoi(pt);
        CrtAdr = (uint16_t)res;
    }
    ad = CrtAdr & 0xFFC0;         		// 64バイト単位に
    I2C_Mem_NWrite(ad,DBuf,64);   		// DBuf[]の64バイト書込
    #ifdef VBA
    	printf("Page Write %d:%04X - %04X\r",BlkNum,ad,ad+63);
    #else
    	printf("Page Write %d:%04X - %04X\n\r",BlkNum,ad,ad+63);
    #endif
    SqMode = 0;    
    return 0;
}

//----  シーケンスモードの確認
uint8_t i2cRom_SqMode(){
    return SqMode;
}
/******* End of File ********/


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


コードレス掃除機 GameBar PICミニBB(11)_EEPROMライター