Vol.856 11.Nov.2022

小型充電電池と充電器 IRリモコン(3)〜リモコン解読器

C 小型充電電池と充電器

by fjk

 いざ使おうとすると買い置きの乾電池が無く困ることがある。そんな時便利なのが充電電池(二次電池)で、充電すれば何度でも使える。そして、主な小型充電電池には以下の種類がある。

1.ニッケル・カドミウム電池(水酸化Ni / 水酸化Cd、1.2V)
大電流の充放電が可能だが消費電力は小さい。電動工具、非常用電源などに使用。
2.ニッケル水素電池(水酸化Ni / 水素吸蔵合金、1.2V)
ニッケル・カドミウム電池と同じ電圧で電気容量が約2。ポータブル電子機器、ハイブリッドカー用途などに使用。
3.リチウムイオン電池(リチウム遷移金属酸化物 / 黒鉛、3.7V)
リチウム遷移金属酸化物 / 黒鉛をつかった電池で。電圧が高く、軽量コンパクト。電解液に可燃性液体の液漏れを防止したポリマーが使われる物もある。ポータブル電子機器、ハイブリッドカー用途などに使用。
4.鉛蓄電池(二酸化鉛 / 鉛、2V)
単セルあたりの電圧が高めで材料も安価。短時間×大電流放電または長時間×少量放電のいずれでも安定に使用可能。自動車用バッテリー、バックアップ電源用電池などに使用。。
 

電池のリサイクルマーク

エボルタ(上)とエネループ(下)

 なお、小型二次電池は「資源有効利用促進法」により、リサイクルすることが義務付けられ、回収対象の電池は上のようなマークが付けられている。必ず住んでいる自治体のゴミマニュアルに従うこと。
 充電電池と充電器との関係は、使用が保証されている組み合わせ以外を使うと、電池の寿命が悪くなるだけでなく、発火などの事故に繋がる場合もあるので、必ず決められた組み合わせを使うこと。
 たとえば、パナソニックのエボルタ・エネループ電池と充電器の関係は、以下を参照。
   充電池   充電器1   充電器2
 パナソニックのニッケル水素電池には、「エネループ」と「エボルタ」の2種類があるが、エネループは元々サンヨーの製品で、以下のような違いがある。
(括弧内はエネループproとエボルタエコノミー。電池容量の単位はmAh)。

 ===== 単3 ===== ===== 単4 =====
 電池容量 充電回数 電池容量 充電回数
エネループ1,900 (2,500)2,100 (500) 750 (930) 600 (150)
エボルタ 1,950 (1,000)1,800 (1,200) 780 (650) 500 (1,000)

繰り返し回数に拘るなら「エネループ」、長持ちを重視するなら「エボルタ」。
また、エネループにはproもあり、カメラ(フラッシュ)などパワーが必要な機器に向いている。


R 赤外線リモコン(3) 〜リモコン解読器(2)

by fjk

 前報(abc855)でIOデータのリモコンコードを解読することが出来るようになったが、PIC16F18424(ROM=4k、RAM=512)ではやはりメモリ容量が少なく、リピートがあるデータではメモリオーバーになることもある。そこで、マルツオンラインでPIC16F18426(ROM=16k、RAM=2k)を入手した。
 USB接続は115200bpsに高速化し(パソコン端末も合わせること)、メモリが増えたので、多くのフォーマットの確認・解読ができるようになった。さらに、パソコンがなくても16文字×2行のLCD(AQM1602Y、秋月電子)にも解読データを表示するようにした。バックライト付きLCDはピンヘッダーでかさ上げし、ライト端子も配線(LCDのバックライトは30mA程度が推奨)。なお、mark部の長さが変わるSonyフォーマット等の解読には未対応だが、生データはパソコンで確認可能。
 リモコンデータの取得プログラムはabc855をベースにLCD表示部を追加した。LCDのコントローラはST7032iで、AQM0802Aも同じなので、共通のライブラリ(LCD_ST7032i.c)として作り直した。そのついでに、1行の表示文字数が16文字だが、LCDの内部データは40文字まで使えるので、新たに「画面表示位置のシフト」と「ユーザ用CGパターンの登録」もライブラリに追加した。なお、Redirect STDIO を有効にすると、printf文などの出力がLCDに表示されるようになる(今回はEUSARTでprintf文を使うのでコメントにしてある)。
 MPLAB_Xでライブラリを追加・使用するにはabc840を参考に。
 赤外線リモコン受信モジュールは、シールド付きのPL-IRM0101(秋月電子、I-00622、@110)を用いたところ、ノイズに少し強くなったようだ。。

【MCC】 オリジナル(初めてのPIC)の設定に以下を追加・変更
@ MSSP1を追加し、I2C、Master、Clock=100000に設定
A ピン設定で、i2Cの SCK を RC4 に、SDA を RC3 に設定し、2つのWPUもON
B RC0(SwC0)、RC1(SwC1)、RC2(SwC3)をデジタル入力とし、3つのWPUもON
C ESUARTの端子はabc855と変わらないが、ボーレートを115200(bps)に変更
* SMT1の設定・ピンの変更は無く、abc855と同じ

赤外線リモコン解析器回路図(5V電源はUSBから)

赤外線受信モジュール
(PL-IRM0101)

かさ上げしたLCD表示器
 

信号解析後のLCD表示例

表示を左に少しシフト
(ボタンは、左から「左シフトボタン」「右シフトボタン」「ホームボタン」)

【プログラム】 青字は前回、赤字は今回、オリジナルに追加・変更したところ。

/****************************
 *    abc865_main.c         *
 ****************************/

#include "mcc_generated_files/mcc.h"
#include "i2cLCD_ST7032i.h"

#define maxdata 200                              	// 赤外線データー配列数
#define RIGHT   0
#define LEFT    1

uint16_t PW[maxdata];                            	// Mark配列
int16_t  PR[maxdata];                            	// Space配列
uint8_t  p_PW;                                   	// Mark配列ポインタ
uint8_t  p_PR;                                    	// Space配列ポインタ
char     sBf[20];                                  	// 文字列作業エリア

char heart[7] = {                                 	// テスト用 user CG-data
		 0b01010,
		 0b11011,
		 0b11111,
		 0b11111,
		 0b01110,
		 0b00100,
		 0b00000,
		} ; 

/********    Main application **********/

void main(void)
{
    uint8_t ird;                                   	// 赤外線データ
    uint8_t sbt;                                   	// ビットセット用シフトバイト
    uint8_t bct;                                   	// 有効ビットデータカウンタ

    SYSTEM_Initialize();
    LCD_init();

    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();

    LCD_CGchar(0,heart);
    LCD_cursor(0,0);
    LCD_dat(0);
    LCD_str("ready");    

    while (1)                                     	// 赤外線信号受信 繰り返し
    {

            ・・・

        // ---------- 赤外線信号を受信する --------
        while((p_PR < maxdata)){                  	// バッファ満杯まで繰返

            ・・・
 
            if(SwC2_GetValue() == 0){
                LCD_sift(RIGHT);
                __delay_ms(100);
            }
            if(SwC1_GetValue() == 0){
                LCD_sift(LEFT);
                __delay_ms(100);
            }
            if(SwC0_GetValue() == 0){
                LCD_home();
            }
        }
        //------------ 受信結果を送信する -------
        SMT1CON1bits.SMT1GO = 0;                   	// 測定終了
        printf(" -  mark  space (us)\r\n");        	// タイトル送信
        LCD_clr();
        LCD_cursor(0,1);
        ird = 0;
        sbt = 1;
        bct = 0;
        for(char i=0;i < p_PW;i++){                	// 保存した時間を送信
            printf("%2d,%5d,",i,(uint16_t)PW[i]);  	// mark時間
            if(PR[i]==0) {                         	// 無信号なら
                printf("   ---\r\n");              	//  「---」を送信
                LCD_str("--");
            }else if(PR[i] > 0){                   	// 10ms未満なら
                printf(" %5d",PR[i]);             	//   us単位で送信(改行を外す)
                if(PW[i] < 900){                 	// markが900未満なら
                    if(PR[i] < 2000){             	// spaceが2000未満なら
                        if(PR[i] > 900){          	// さらにspaceが900以上なら
                            ird |= sbt;            	// シフトバイトを加える
                            printf(",  1");
                        }else{
                            printf(",  0");
                        }
                        sbt <<= 1;                 	// シフトバイトを左へシフト
                        bct++;                     	// 有効データ数を1増やす
                        if((bct % 8) == 0){        	// データ数が8の倍数なら
                            printf(",  %02XH",ird);	// 16進数で送信(表示)
                            sprintf(sBf,"%02X",ird);
                            LCD_str(sBf);
                            ird = 0;              	// 赤外データをクリア
                            sbt = 1;              	// シフトバイトも初期化
                        }
                    }
                }
                printf("\r\n");
            }else{                                 	// 10ms未満なら
                printf("%7d,(ms)\r\n",-PR[i]);     	//   ms単位で送信
                LCD_dat('+');
            }
        }
        if(p_PW >= maxdata){                       	// バッファ満杯なら
            printf("-- Buffer Full --\r\n");       	//  Buffer Full 送信
            LCD_str("***");
        }
        LCD_home();
        sprintf(sBf,"%3d",bct);
        LCD_str(sBf);
        sprintf(sBf,"%6d %5d",PW[0],PR[0]);
        LCD_str(sBf);
        LCD_home();
    }
}
/**==== End of File ====*/
/******************************************
 *      LCD library  (i2cLCD_ST7032i.h)   *
 *      use for AQM0802A,AQM1602Y,....    *
 ******************************************/


#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"

#define I2CLCD_Adr 0x3e

//-------- send command -------------------
void LCD_cmd(char cmd);

//-------- send data ----------------------
void LCD_dat(char chr);

//-------- clear LCD-----------------------
void LCD_clr(void);

//--------- Home --------------------------
void LCD_home(void);

//--------- Cursor X,Y --------------------
void LCD_cursor(int x, int y);

//-------- display strings ----------------
void LCD_str(char *str);

//------- Create CG Char ------------------
uint8_t LCD_CGchar(uint8_t c, char* dt);

void LCD_xsft(uint8_t);

//-------- LCD sift position --------------
void LCD_sift(uint8_t x);

//-------- LCD initialize ------------------
void LCD_init();

/********  End of Header File ******/
/******************************************
 *      LCD library  (i2cLCD_ST7032i.c)   *
 *      use for AQM0802A,AQM1602Y,....    *
 ******************************************/

#include "i2cLCD_ST7032i.h"

#define CONTRAST      0x18       // for 5.0V
//#define  CONTRAST     0x30       // for 3.3V
#define BOOST         0x00       // for 5.0V Bon=off
//#define  BOOST        0x04       // for 3.3V Bon=on

//-------- send command -------------------------
void LCD_cmd(char cmd){
    I2C1_Write1ByteRegister(I2CLCD_Adr, 0x00, cmd);
    if(cmd & 0xFC)      		// bit7-2 = 1 ?
        __delay_us(30); 		// 30us
    else
        __delay_ms(2);			// 2ms Clear or Home
}

//-------- send data ----------------------
void LCD_dat(char chr){
    I2C1_Write1ByteRegister(I2CLCD_Adr, 0x40, chr);
    __delay_us(30); 			// 30us
}

//-------- clear LCD--------------------------
void LCD_clr(void){
    LCD_cmd(0x01);
}

//--------- Home -----------------------------
void LCD_home(void){
    LCD_cmd(0x02);
}

//--------- Cursor X,Y -----------------------
void LCD_cursor(int x, int y){
    if (y == 0)
        LCD_cmd((char)(0x80 + x));
    else if (y == 1)
        LCD_cmd((char)(0xc0 + x));
}

//-------- display strings -------------------------
void LCD_str(char *str){
    while(*str)
 	LCD_dat(*str++); //pointer increment
}

//------- Create CG Char ---------
uint8_t LCD_CGchar(uint8_t c, char* dt){
    uint8_t i;
	if(c > 7) return 1;
	LCD_cmd(0x40 | (char)(c << 3));
	__delay_us(30);
	for(i=0;i<7;i++){
		LCD_dat(*dt++);
	    __delay_us(30);
	}
	return 0;
}

//-------- LCD sift position -----------------

void LCD_sift(uint8_t d){
	if(d) LCD_cmd(0x18);
	else  LCD_cmd(0x1C);    
}

//-------- LCD initialize ---------------------------
void LCD_init(){
    __delay_ms(40);         // 40ms wait
    LCD_cmd(0x38);          // 8bit,2line
    LCD_cmd(0x39);          // IS=1 : extention mode set
    LCD_cmd(0x14);          // Internal OSC Frequency
    LCD_cmd(0x70 + (CONTRAST & 0x0F)); 	//Contrast set
    LCD_cmd(0x58 + BOOST + (CONTRAST >> 4));
                            //Power/ICON/Contrast Control
    LCD_cmd(0x6C);          // Follower control
    __delay_ms(200);        // 200ms wait
    LCD_cmd(0x38);          // IS=0 : extention mode cancel
    LCD_cmd(0x0C);          // Display ON
    LCD_cmd(0x01);          // Clear Display
    __delay_ms(2);          // wait more than 1.08ms
}

//-------- Redirect STDIO to LCD ----------------
/*
void putch(char ch){
    LCD_dat(ch);
}
*/

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


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


小型充電電池と充電器 IRリモコン(3)〜リモコン解読器