LEDフラッシャーIC「M34-1L,2L,8L」の点滅をPICで再現する

LEDを点滅させるためのICとして、M34シリーズの三端子LEDフラッシャ-ICというものが有ります。
これは、トランジスタのように3本の端子が出ているパーツで、接続するだけで指定された周期でLEDを点滅させる事が出来ます。

点滅の周期は型番によって異なり、以下の通りとなっています。

M34-1L  1.0  秒周期 ON-OFF比率 = 1:8
M34-2L  0.5  秒周期 ON-OFF比率 = 1:8
M34-4L  0.25 秒周期 ON-OFF比率 = 1:8
M34-8L  0.125秒周期 ON-OFF比率 = 1:2



実際にどんな感じで点滅するか、YouTubeに動画があがってました。


M34シリーズの主な用途は、製造元のデータシートによると以下のものが想定されているようです。

点滅するバッチ
イヤリング
グリーティングカード
ディスコライト
自転車のライト
車のアラーム
警告ライト
クリスマス用のデコレーション
おもちゃ等...



このICは、1個50円くらいの安価なICですが仕様上1つで最大2~3つのLEDまでしかコントロールする事が出来ません。


そこで今回は、このフラッシャ-IC相当の機能をPIC(16F88)で再現してみます。

PICの16F88は、I/Oに最大16ピン割り当てることが出来るため、5倍以上のLEDをコントロールできます。
また、マイコンを使用するとLED毎に異なる点滅パターンを割り当てたり、すべてのLEDを正確に同じタイミングで点滅させる事も簡単です。


で、実際に作ってみた結果が以下の通りです。
4秒周期で、M34-1L, M34-2L, M34-8Lの機能を順に再現しています。


3つ目の0.125秒周期のパターンは動画だと綺麗に点滅できていなさそうですが、これは動画がフレームレートが15fpsしかないからで、実物を見るとちゃんと毎秒8回点滅しています。
また回路は、前回作ったPICライタの動作確認回路を流用しました。


プログラムは以下の通りです。
タイマ割込みを使用して点滅パターンを制御しています。

#include <stdio.h>
#include <htc.h>
 
#define TIMER_INTERVAL (0xffff - 20000) // TMRモジュールのカウント初期値
                                       // 2000を指定すると 8MHz, 1/1プリスケーラで1msecになる
 
__CONFIG (  FOSC_INTOSCIO & // 内部クロック
            WDTE_OFF &      // watchdogオフ
            PWRTE_OFF &     // Power-up Timer
            MCLRE_OFF &     // MCLRピンを汎用I/Oとして使用
            BOREN_OFF &     // 電圧降下によるリセットオフ
            LVP_OFF &       // Low-Voltage Programmingオフ
            CPD_OFF &       // EEPROM  プロテクトオフ
            WRT_OFF &       // FrashROMプロテクトオフ
            DEBUG_ON &      // ICDデバッグを有効にする
            CCPMX_RB0 &     // RB0をCCPとして使用
            CP_OFF );       // コードプロテクトオフ
 
 
// プロトタイプ宣言
void SetLED( unsigned char data );
void HardwareSetup( void );
 
// グローバル変数
unsigned char       GL_LedData;         // LED表示パターン
unsigned long int   GL_SystemTimeSec = 0;   // CPU起動からの経過時間
 
 
//****************************************************************************************
// Function     : main
// Description  : メイン処理
//****************************************************************************************
void main( void )
{
    unsigned long int loop = 0;
 
    // ハードウェアの初期化
    HardwareSetup()
 
    // 割り込みベースで動作するので、メイン処理は無し
    while( 1 ) {
        ; // nop
    }           
}
 
//****************************************************************************************
// Function     : intr
// Description  : 割り込み処理(10msec周期)
//****************************************************************************************
static void interrupt intr( void )
{
    static int intr_counter;
    //------------------------------------
    // Timer1割り込みが発生したときの処理
    //------------------------------------
    if ( PIR1bits.TMR1IF == 1 ) {
        TMR1 = TIMER_INTERVAL;  // タイマーをリセット
 
        //----------------------------
        // カウンタを加算(100で1秒)
        //----------------------------
        intr_counter++;
        if ( intr_counter >= 100 ) {
            intr_counter = 0;
            GL_SystemTimeSec++;
        }
 
        //----------------------------------------------
        // 点滅させるべきLEDを、1秒周期で切り替える
        //----------------------------------------------
        if ( GL_SystemTimeSec % 2 == 0 ) {
            GL_LedData = 0b00111100;
        } else {
            GL_LedData = 0b11000011;
        }
 
        //----------------------------------------------
        // 4秒周期で点滅パターンを切り替える
        //----------------------------------------------
        switch ( ( GL_SystemTimeSec / 4 ) % 3 ) {
            case 0:
                // M34-1L相当点滅パターン : 1秒(ON-OFF比1:8)
                if ( intr_counter <= 12 ) {
                    SetLED( GL_LedData ); 
                } else {
                    SetLED( 0x00 );
                }
                break;
            case 1:
                // M34-2L   相当点滅パターン : 0.5秒(ON-OFF比1:8)   
                if (    (intr_counter >=  0 && intr_counter <=  6) ||
                    (intr_counter >= 50 && intr_counter <= 56) ) {
                    SetLED( GL_LedData );
                } else {
                    SetLED( 0x00 );
                }
                break;
            case 2:
                // M34-8L   相当点滅パターン : 0.125秒(ON-OFF比1:2) 
                if (    (intr_counter%12) <= 5 ) {
                    SetLED( GL_LedData );
                } else {
                    SetLED( 0x00 );
                }
                break;
        }
 
        PIR1bits.TMR1IF = 0;    // 割り込みフラグを落とす
    }   
}
 
 
//****************************************************************************************
// Function     : HardwareSetup
// Description  : ハードウェア初期化処理
//****************************************************************************************
void HardwareSetup( void )
{
    //----------------------------------
    // 内部クロックを8MHz駆動にする
    //----------------------------------
    OSCCONbits.IRCF = 7;        
 
    //----------------------------------
    // ポートのモードを初期化する
    //----------------------------------
    ANSEL = 0;
    T1CONbits.T1OSCEN = 0;  
    TRISB = 0x00;
    TRISAbits.TRISA0 = 0;   // RA0を出力にする
    TRISAbits.TRISA1 = 0;   // RA1を出力にする  
 
 
    //----------------------------------
    // Timer1の初期化
    //----------------------------------
    PIR1bits.TMR1IF = 0;    // Timer1割り込みフラグを落としておく
    PIE1bits.TMR1IE = 1;    // Timer1割り込みを有効
 
    T1CONbits.T1CKPS = 0;   // プリスケーラを1/1にする
    TMR1 = TIMER_INTERVAL;  // タイマー値をセットします
 
    T1CONbits.TMR1ON = 1;   // Timer1を有効にする
 
    //----------------------------------
    // 割り込みを有効にする
    //----------------------------------
    INTCONbits.PEIE = 1;    // 外部割込みを有効にする
    INTCONbits.GIE  = 1;    // Grobal interruptを有効にする
}
 
 
//****************************************************************************************
// Function     : SetLED
// Description  : 指定されたビットに対応するLEDを点灯する
//****************************************************************************************
void SetLED( unsigned char data )
{
    PORTBbits.RB0 = (data & 0x01) ? 1 : 0;
    PORTBbits.RB1 = (data & 0x02) ? 1 : 0;
    PORTBbits.RB2 = (data & 0x04) ? 1 : 0;
    PORTBbits.RB3 = (data & 0x08) ? 1 : 0;
    PORTBbits.RB4 = (data & 0x10) ? 1 : 0;
    PORTBbits.RB5 = (data & 0x20) ? 1 : 0;
    PORTAbits.RA0 = (data & 0x40) ? 1 : 0;
    PORTAbits.RA1 = (data & 0x80) ? 1 : 0;
}

[PIC]全ピン数対応のライタ基板を製作(PICkit3使用)



半年ほど前、PICのライタとしてPICkit3を購入しました。
これまで書き込み側の回路はブレッドボードで組んでいたのですが、ブレッドボードだと書き込み/デバッグ中にライタが外れてしまう事もあり不便でした。

ライタは頻繁に使いますしPICの開発も慣れてきたので、今回、書き込み用の回路をユニバーサル基板で作成する事にしました。
PICはブレッドボードにさせるタイプのPDIP形式のものだけでも、ピン数が8, 14, 18, 20, 28, 40ピンと6種類も有り、それぞれ書き込みピンの位置が異なるので、これら全種類に対応できるようにします。

また、ライタにPICを刺したまま状態で、簡単な回路なら確認できるようにもしておきます。


PIC Writerのピンアサインを確認

今回はPICのライタとPICkit3で書き込めるような基板を考えます。
ですので、まずはPICkit3のピン配置を確認します。

ピン配置は、PICkit3ユーザガイドを確認すると、以下の通りである事が分かります。


Pin番号 接続先
------- --------------
1       MCLR/VPP
2       VDD
3       Ground
4       PDG (ICSPDAT)
5       PGC (ICSPCLK)


PICkit3からは6本のピンが出ていますが、6番ピンのLVPは使用しないので無視します。
LVPは、Low Voltage Programmingの略で低電圧プログラミングを行う事に使います。


PICのピン配置確認

次に書くピン数毎に、ピン配置を確認します。
PICはピン数が同じなら、基本的に書き込みに関するピンのアサインは同じです。

ですので、ピン数だけ気にすればどの製品でチェックしても良いのですが、今回はPIC16,12シリーズでピン数別お勧めPICとして選ばれていた以下の商品で確認します。

 8pin : 12F683
14pin : 16F688
18pin : 16F88 
20pin : 16F690
28pin : 16F886
40pin : 16F887




というわけでデータシートより確認した結果です。書き込みに関係するピンの背景色を変えて有ります。

色とピン番号の対応は抵抗のカラーコードと同じで、以下の通りです。

Pin番号 色
------- ----
1       茶
2       赤
3       橙
4       黄
5       緑




8ピン: 12F683


14ピン: 16F688


18ピン: 16F88


20ピン: 16F690


28ピン: 16F886


40ピン: 16F887


おまけ:この画像を作るのにPaint.NETを使用したのですが、その時使用した*.pdnファイルです-> ダウンロード:PicPinAssign_pdn.zip



色の付いたピンの位置をよく見比べてみると、以下のことが分かります。

40,28ピンのPICは上端を合わせれば位置が同じになる。
20,14,8ピンも同じです
18ピンは他と異なるので別途対応が必要です。



という訳で、書き込みピンだけ見ると大きく3種類になります。但し28/40ピンはVcc/GNDピンが複数有り、場所が異なるのですが、片側だけ繋いでおけば書き込みには影響しないようです。
(もし影響が出る場合は、後述のピンソケットで配線して対応する事にします)

また、ピン幅は300milのものと、600milのものが有ります。
milというのは1/1000インチの事で、要はブレッドボードの幅3マスと6マスという意味です。

この辺はゼロプレッシャーのソケットで幅にゆとりがあるものを使用します。

回路図

PICkit3の場合、1ピンと2ピンを10kの抵抗でつなぐ必要があります。
これと、上記のピン配置を考慮すると以下の様な配線となります。



部品を購入する

回路図を書いたら、次に必要な部品を購入します。

回路図の上では、ゼロプレッシャーのコネクタが3つとなっているのですが18ピンのゼロプレッシャーは無いので、普通のICソケットで代用します。
20ピンのほうは売っているのですが、たまたま買出しに行ったときに売り切れにだったので28ピンのソケットで代用する事にしました。


ユニバーサル基板は、後で回路を追加できるようにちょっと余裕を見て、大きめのサンハヤトのICB-96を使用します。ICB-96は0.1inchピッチで、55×45の穴が空いてます。


簡単な実験だったらライタ上でジャンパを飛ばすだけでブレッドボードと配線できるようにしておきたいので、ソケットの横にピンソケットをつける事にします。
ピンソケットは14×2のものが2個と10×2のものが2個です。
(あと、18ピンPIC用にシングルのピンソケットが18ピン分必要ですが、写真を取り忘れました…)


あと必要なものは、ピンヘッダ、抵抗やLED等ぐらいです。


ユニバーサル基板で組み上げる

購入したパーツを実際にユニバーサル基板においてみます。

今回は、以下の様な感じに配置する事にしました。


PICライタのPICkit3とは18ピンソケットの上にあるピンヘッダで接続します。
どっちが1ピンが分かりやすいように、修正液でマーキングしておきます。



裏面は、こんな感じです。
回路は単純ですが、ICソケットの横にピンソケットを追加したので、作業量がちょっと多くなります。



この手の同じパターンが連続する配線作業は1本づつ仕上げていくと面倒なので、全てのピンを1作業づつ一気に進めたほうがはかどります。

どういう事かというと、例えば下の画像は40ピンソケットの配線ですが、左側を見るとまず、左端のソケットに、スズめっき線をつけてしまいます。


次に、全て右側をハンダします。


そして、最後に真ん中をつける。というようにすると、同じ作業が続き道具の持ち替えも少なくなるので作業が速いです。



基板にスペースが余っているので、動作確認用のLEDを8個右上に追加しました。


こちらの裏側はこんな感じです。
左上につながっている白いジャンパ線は、PICライタ側のGNDとつながっています。
スズめっき線でつないでしまってもよかったのですが、負論理にしたいことがあるかもしれないので、つなぎかえが楽なようにジャンパ線での仮接続に留めてます。


配線が完了したら誤配線が無いか、テスタで通電チェックします。


動作確認

問題が無さそうならPICkit3を接続して、動作確認用のプログラムを動かしてみます。
今回は18ピンの16F88を使用して、LEDの点灯プログラムを作ってみました。

LEDは8個用意したので、RB0-5とRA0,RA1を使用します。
本当はRB0-7の8ピンで分かりやすく繋ぎたかったのですが、16F88はRB6,7がライタの書き込み用で使用するため、本基板では使えません(デバッグ実行が出来なくなります)。

配線用のソケットを作っておいたおかげで、さくっと配線出来て便利です。



コードは以下の様な感じです。
HI-TECH C用ですが、特に難しいところは無いので説明は省略します。

#include <stdio.h>
#include <htc.h>
 
__CONFIG (  FOSC_INTOSCIO & // 内部クロック
            WDTE_OFF &      // watchdogオフ
            PWRTE_OFF &     // Power-up Timer
            MCLRE_OFF &     // MCLRピンを汎用I/Oとして使用
            BOREN_OFF &     // 電圧降下によるリセットオフ
            LVP_OFF &       // Low-Voltage Programmingオフ
            CPD_OFF &       // EEPROM  プロテクトオフ
            WRT_OFF &       // FrashROMプロテクトオフ
            DEBUG_ON &      // ICDデバッグを有効にする
            CCPMX_RB0 &     // RB0をCCPとして使用
            CP_OFF );       // コードプロテクトオフ
 
 
void SetLED( unsigned char data );
 
void main( void )
{
    unsigned long int loop = 0;
    unsigned char data = 0x01;
    ANSEL = 0;
    T1CONbits.T1OSCEN = 0;  
    TRISB = 0x00;
    TRISAbits.TRISA0 = 0;   // RA0を出力にする
    TRISAbits.TRISA1 = 0;   // RA1を出力にする
 
 
    while( 1 ) {
        // LEDを点灯
        SetLED( data );
 
        // ちょっと待つ
        for ( loop = 0; loop < 20; loop++ ) {
            ; // nop
        }   
 
        // 表示するLEDをずらす
        if ( data == 0x80 ) {
            data = 0x01;
        } else {
            data <<= 1;
        }
    }       
 
}
 
// 指定されたビットに対応するLEDを点灯する
void SetLED( unsigned char data )
{
    PORTBbits.RB0 = (data & 0x01) ? 1 : 0;
    PORTBbits.RB1 = (data & 0x02) ? 1 : 0;
    PORTBbits.RB2 = (data & 0x04) ? 1 : 0;
    PORTBbits.RB3 = (data & 0x08) ? 1 : 0;
    PORTBbits.RB4 = (data & 0x10) ? 1 : 0;
    PORTBbits.RB5 = (data & 0x20) ? 1 : 0;
    PORTAbits.RA0 = (data & 0x40) ? 1 : 0;
    PORTAbits.RA1 = (data & 0x80) ? 1 : 0;
}




上記プログラムを実際に動作させた結果です。
いい感じに動作してくれました。




TODO

今回の製作でとりあえず満足するものが作れましたが、まだスペースが有るので、そのうち以下の辺りぐらいはチェック用回路を増設しておきたいところです。

スイッチ(タクトスイッチx4個ぐらい?)
可変抵抗によるアナログ入力
シリアルポート
USBポート
ブザー
キャラクタLCD


[PIC18シリーズ]ピン数別の機能・評価一覧

PIC18シリーズの価格と特徴を分かりやすく整理してくれている一覧です。
この一覧にある製品は、秋月で販売されているという事で入手性も良いです。

PIC16シリーズについて知りたい場合はこちらの記事を参考にして下さい。
 [PIC16シリーズ]ピン数別の機能・評価一覧


PIC専用のスレ Part40
http://uni.2ch.net/test/read.cgi/denki/1345537082/ より編集


秋月のPIC18シリーズDIP品限定ピン数別評価


特徴

【PIC18】8bitマイコン。
5V動作可(J除)で比較的高速(10~MIPS) 
新型のKシリーズは多機能で高速(16MIPS)
USB機能付きもラインナップ
命令系は16F(Mid-Range)から+αレベル
MIPS値はクロックの1/4('12/08版)
 
PIC18F共通機能
    VDD ~5.5V
    10bitADC
    eUSART
    TMR8bitx1/16bitx3
    MSSP
追加表記 
    CCPx/y x=CCP数/y=eCCP
    TMRx/y x=8bit/y=16bit



マークの意味

◎ お勧め、用途決まっていないならこれ買っとけ
○ 内蔵モジュール減ってるけど、その分値段も安くなってるから、まあまあ
△ 内蔵モジュール大幅に減ってる、\10でも安くしたいなら、どうぞ
× ソースを変更できない等の理由がないなら、選択する必要なし
 
自分で、プラグラムもハードも作れる人のためのリスト。
そもそも、教科書に載ってるのとか他の方の作品とかを作るだけなら
指名買いするしかないのだから お勧め度は意味がない





40pin PIC


新ラインナップ45K20(注3.6V)か旧だけどUSB&12bitADの4553。不要なら4525もありかな
 
                Prog/ RAM/EEPROM
◎18F45K20 \180 16Kw/1536/ 256    Max64MHz(31k-64MHz),4xPLL,CCP1/1,▲3.6V
◎18F4553  \430 16Kw/2048/ 256    ●USB,Max48MHz(31k-8MHz),PLL,12bitADC,CCP1/1
○18F4550  \370 16Kw/2048/ 256    ●USB,Max48MHz(31k-8MHz),PLL,CCP1/1,SPP
△18F4520  \340 16Kw/1536/ 256    Max40MHz(31k-32MHz),4xPLL,CCP1/1
○18F4525  \380 24Kw/3968/1024    Max40MHz(31k-32MHz),4xPLL,CCP1/1
△18F4585  \500 24Kw/3328/1024    Max40MHz(31k-32MHz),4xPLL,CCP1/1,CAN
×18F452   \500 16Kw/1536/ 256    Max40MHz(内蔵CLK無し),4xPLL,CCP1/1



28pin PIC


新ラインナップが強力。3.6V可ナラ大容量・多機能27J53,高速ナラ多機能の26K22か12bitADCの25K80
 
×18F258   \530 16Kw/1536/ 256    Max40MHz(内蔵CLK無し),4xPLL,CCP1/0,CAN
×18F248   \500  8Kw/ 768/ 256    ↑258のメモリ縮小版
×18F252   \450 16Kw/1536/ 256    Max40MHz(内蔵CLK無し),4xPLL,CCP2/0
×18F242   \420  8Kw/ 768/ 256    ↑252のメモリ縮小版
×18F2580  \430 16Kw/1536/ 256    Max40MHz(31k-32MHz),4xPLL.CCP1/0,CAN
×18F2480  \390  8Kw/ 768/ 256    ↑2580のメモリ縮小版
×18F2620  \420 32Kw/3968/1024    Max40MHz(31k-32MHz),4xPLL,CCP2/0
×18F2420  \280  8Kw/ 768/ 256    Max40MHz(31k-32MHz),4xPLL,CCP2/0
×18F2320  \420  4Kw/ 512/ 256    Max40MHz(31k-8MHz),4xPLL,CCP2/0
△18F2553  \420 16Kw/2048/ 256    ●USB,Max48MHz(31k-8MHz),PLL,12bitADC,CCP2/0
×18F2550  \350 16Kw/2048/ 256    ●USB,Max48MHz(31k-8MHz),PLL,CCP2/0
×18F2455  \340 12Kw/2048/ 256    ●USB,↑2550のメモリ縮小版
×18F2450  \260  8Kw/ 768/   0    ●USB,Max48MHz(31kHz),PLL,CCP1/0,MSSP無,TMR0/2
×18F2523  \390 16Kw/1536/ 256    Max40MHz(31k-32MHz),4xPLL,CCP2/0,12bitADC
○18F2431  \340  8Kw/ 768/ 256    Max40MHz(31k-8MHz),4xPLL,CCP2/0.14bitPWMx6
×18F2321  \240  4Kw/ 512/ 256    Max40MHz(31k-32MHz),4xPLL,CCP2/0
×18F2221  \220  2Kw/ 512/ 256    ↑2321のメモリ縮小版
◎18F26K22 \220 32Kw/3896/1024    Max64MHz(31k-64MHz),4xPLL,eUSART2.TMR3/4,MSSP2,CCP2/3,SRLatch
○18F25K22 \170 16Kw/1536/ 256    ↑26K22のメモリ縮小版
△18F23K22 \160  4Kw/ 512/ 256    ↑25K22のさらにメモリ縮小版
◎18F25K80 \220 16Kw/3648/1024    Max64MHz(31k-64MHz),4xPLL,eUSART2,TMR2/3,CCP4/1,12bitADC.ECAN
○18F26K20 \190 32Kw/3936/1024    Max64MHz(31k-64MHz),4xPLL,CCP1/1
○18F23K20 \150  4Kw/ 512/ 256    ↑26K20のメモリ縮小版
◎18F27J53 \300 64Kw/3776/   0    ●USB,Max48MHz(31k-48MHz),PLL,eUSART2,TMR4/4,MSSP2,CCP7/3,12bitADC,リマップ,▲3.6V
○18F26J50 \260 32Kw/3776/   0    ●USB,Max48MHz(31k-48MHz),PLL,eUSART2,TMR2/3,MSSP2,CCP0/2,リマップ,▲3.6V
○18F25J50 \230 16Kw/3776/   0    ●USB.↑25J50のメモリ縮小版,▲3.6V
△18F26J11 \240 32Kw/3776/   0    Max48MHz(31k-32MHz),4xPLL,eUSART2,TMR2/3,MSSP2,CCP0/2,リマップ,▲3.6V
△18F25J11 \210 16Kw/3776/   0    ↑26J11のメモリ縮小版,▲3.6V



20pin PIC


USBの有無でK50かK22を
 
◎18F14K50 \170  8Kw/ 768/ 256    ●USB,Max48MHz(31k~32MHz),4xPLL,CCP0/1
×18F13K50 \170  4Kw/ 512/ 256    ●USB,↑14K50のメモリ縮小版
◎18F14K22 \160  8Kw/ 512/ 256    Max64MHz(31k-64MHz),4xPLL,CCP0/1,SRLatch
△18F13K22 \150  4Kw/ 256/ 256    ↑14K22のメモリ縮小版



18pin PIC


20ピンから選択すべき、14bitPWMx6に魅力あれば1230を
 
×18F1320 \220  4Kw/ 256/ 256 Max40MHz(31k~8MHz),4xPLL,CCP0/1,MSSP無
×18F1220 \210  2Kw/ 256/ 256 ↑1320のメモリ縮小版
△18F1230 \220  2Kw/ 256/ 128 Max40MHz(31k-32MHz),4xPLL,TMR0/2,MSSP無,CCP無,14bitPWMx6

“Order Fulfillment Report レポート”の自動作成を停止する方法

Amazonのマーケットプレースで、Order Fulfillment Report レポートの自動生成を行っていると、以下の文面のメールが定期的に送信されてきます。



Order Fulfillment Report レポート作成完了のお知らせ 
 
Amazon.co.jpよりお知らせいたします。
 
出品者様がリクエストされたレポートの作成が完了しました。
 
レポートの概要は以下のとおりです。
 
レポートの種類:  Order Fulfillment Report 
レポート リクエスト日時: 2001-01-01T00:00:00
レポート 作成完了日時: 2001-01-01T00:00:00
 
レポートは、以下のリンクからアクセスしてダウンロードいただけます。
 
https://sellercentral-japan.amazon.com/gp/transactions/orderPickup.html
 
今後ともAmazon.co.jpをよろしくお願いいたします。
 
Amazon.co.jp
 
==================================================
注: このEメールアドレスは配信専用です。このメッセージに返信しないようお願いいたします



このメールがわずらわしい場合は、以下の手順でメール送信を抑制する事が出来ます。

通知メールの配信を停止させる

出品者用アカウントページより、設定メニューにある通知設定をクリックします。


レポート通知の編集をクリックします。


出品中の商品レポートからチェックを「外し」て、更新ボタンをクリックします。


これでメール配信が停止されます。


2012/11/19:訂正
“出品中の商品レポート”の項目では、メール配信は停止できないようです…
Amazonテクニカルサポートに改めて問い合わせてみたのですが、メーラーでの受信設定などで回避するしかないとの回答でした。


レポートが自動生成を停止させる

レポートが自動生成されること自体を止めたい場合は、以下の手順で停止できます。

出品者用アカウントページより、注文メニューにある注文レポートをクリックします。


定期的な注文レポートの設定の右にある、編集ボタンをクリックします


新しいスケジュールで”なし”にチェックを入れて、送信をクリックします。


“正常に処理されました”と表示されれば、自動生成が停止されます。

[C#]ManicTime風な,使用アプリ記録ソフトを自作する



WindowsでManicTimeというソフトを使用すると、PCで使用していたアプリケーションのログを採取することが出来ます。PCでどんなアプリを何分使っていたかの作業ログを取る事で、無駄な時間をだらだら過ごしていないか自分の作業内容への振り返りをするきっかけになりまし、ライフログ的な使い方も出来ます。
ライフログの技術

ManicTimeはシンプルかつ分かりやすいUIで、気軽に使うには便利なのですが、採取したログを自分でExcelなどを使用して分析したかったので、同様の機能を持つ記録アプリを作成してみました。


今回作成するのは見た目の部分ではなく、裏方部分のデータ収集処理なので、GUIは最低限のものとなっています。見た目もこだわりたいのならChartコントロールを使用すれば派手なモノも作成できます。

なお、今回の開発環境にはVisualStudio 2010 + C#を使用しています。


C#による起動中プログラムのロギング方法

ManicTimeの仕組みは、1秒周期で最前面に出ているウィンドウのプログラム名&ウィンドウタイトルをロギングしています。

ですが、.Net FrameworkのAPIではアクティブなウィンドウを取る事が出来ないので、Win32APIのGetForegroundWindow()をコールしてProcess情報を取得します。
また、ウィンドウのタイトルも同様にWin32APIのGetWindowText()を使用します。


これらのAPIの使い方ですが、下記のサイトが詳しいので参考にしてみてください。
C#でアクティブウィンドウの取得
C#からWin32 APIをコールする方法


という訳で、ほとんど丸々コピーですが、下記のメソッドで使用しているプロセスの情報が採取します。

using System.Runtime.InteropServices;
...
 
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
 
[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
 
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int length);
 
//*********************************************************************
/// <summary> 現在最前面に表示されているウィンドウのProcessオブジェクトを取得
///             see also: http://mzs184.blogspot.jp/2009/03/c.html
/// </summary>
/// <returns></returns>
//*********************************************************************
public static Process GetActiveProcess()
{
    int id;
    // アクティブなウィンドウハンドルの取得
    IntPtr hWnd = GetForegroundWindow();
 
    // ウィンドウハンドルからプロセスIDを取得
    GetWindowThreadProcessId( hWnd, out id );
 
    Process process = Process.GetProcessById(id);
    return process;
}
 
//*********************************************************************
/// <summary> アクティブなウィンドウのタイトルを取得
///         see also: http://d.hatena.ne.jp/int128/20080110/1199975050
/// </summary>
/// <returns></returns>
//*********************************************************************
public static string GetActiveWindowTitle()
{
    IntPtr hWnd = GetForegroundWindow();
    StringBuilder title = new StringBuilder(1048);
 
    // ウィンドウタイトルを取得
    GetWindowText(hWnd, title, 1024);
    return title.ToString();
}




情報取得のメソッドを作成したら次はアクティブウィンドウ切り替わりタイミングを取ります。
アクティブなウィンドウが変わったことのイベントハンドラは無いので、Timerコントロールを使用して一定周期でポーリングします。

static private string prevProcName    = "";
static private string prevFilePath    = "";
static private string prevProductName = "";
 
//*********************************************************************
// 一定周期でログを取る
//*********************************************************************
private void timer1_Tick( object sender, EventArgs e ) {
    // 現在、最前面ウィンドウのプロセスオブジェクトを取得する
    Process proc = Process.GetCurrentProcess();
 
    string procName;
    string productName;
    string filePath;
 
    try { 
        procName =  GetActiveWindowTitle();
    } catch {
        procName = "unknown";
    }
 
    try { 
        filePath = proc.MainModule.FileName + Environment.NewLine;
    } catch {
        filePath = "unknown" + Environment.NewLine;
    }
 
    // ファイルのプロダクト情報(アプリによって登録状況が異なるので使用しない)
    try { 
        productName = proc.MainModule.FileVersionInfo.ProductName + Environment.NewLine;;
    } catch {
        productName = "unknown" + Environment.NewLine;
    }
 
    // アクティブなプロセスが変わってなければ何もしない
    if ( procName.Equals( prevProcName ) && 
         filePath.Equals( prevFilePath ) && 
         productName.Equals( prevProductName ) ) {
        return;
    }
 
    // 一件前の情報を覚える
    prevProcName = procName;
    prevFilePath = filePath;
    prevProductName = productName;
 
    // ログメッセージを組み立てる
    string logMessage = DateTime.Now.ToString() + "\t" + 
                        productName.Replace( "\t", " "  ).Replace( Environment.NewLine, "" ) + "\t" + 
                        procName.Replace( "\t", " " ).Replace( Environment.NewLine, "" ) + "\t" + 
                        filePath;
 
    WriteLog( logMessage );
    textLog.Text += logMessage;
}



このチェックは1秒程度の短い周期でチェックする事になるのですが、そんなに頻繁に使用プログラムの切り替えは行われないので、大抵の場合は同じプログラムです。ですので、ログを書いたときに記録したアプリケーションの情報を覚えておき、その情報が変わった時のみログファイルに落としておく事にします。



最後は、ログファイルの出力です。

//*********************************************************************
/// <summary> ログをファイルに出力する
/// </summary>
/// <param name="logMessage">出力するメッセージ</param>
//*********************************************************************
public static void WriteLog( string logMessage ) {
    try {
        string fileName = "log.txt";
 
 
        // ファイルにログを出力
        using ( FileStream   stream = new FileStream( fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite ) )
        using ( StreamWriter writer = new StreamWriter( stream, Encoding.GetEncoding(932) ) ) { 
            writer.WriteLine( logMessage );
        }
    } catch {
        // 所詮ログファイルなので、書き込みに失敗しても無視する
    }
}


日付単位でログをローテーションさせる。といった高度な処理は無く、ひたすら追記していきます。
これだと、ディスクを圧迫し続けるのでどこかでログのローテーションが必要なのですが、この辺は運用依存なので利用者に委ねる事にします。
おそらくlogrotateコマンド的なものでローテーションさせるのが良いかと思います。

有り触れたファイル出力処理ですが、ファイル書き込み中にログのローテーションが行われることを想定し、ファイルの共有モードをFileShare.ReadWriteにしています。
ファイルを排他使用しないことで、他プロセスからのアクセスを許容させます。


ファイル出力が目的なので、GUIは凝ったモノにはしません。
動作確認用のテキストボックスと、周期実行用のタイマーが貼り付けてあるだけです。



ダウンロード

今回作成したプログラムの実行ファイルと、ソースコードです。
ソース(VS2010プロジェクト):NanoTaskLogger.zip
プログラム(exe):NanoTaskLogger


ライフログビジネス

[MPLAB]ブレークポイントで表示される黄色い”B”マークの意味

PICの開発環境であるMPLABで、ブレークポイントをセットすると、赤色の”B”マークが表示されます。


ですが、開発を行っていると時々、以下の様に黄色い”B”マークが表示される事があります。


この黄色のBの意味は、アセンブリコードに対するブレークポイントです。
厳密に言うと、C言語1行に対して複数行のアセンブリが生成されたとき、生成後アセンブリの1ステップ目以降のコードにブレークポイントが張られたとき、黄色のマークになります。


C言語レベルでのデバッグを行っている場合、黄色のブレークポイントだと、該当行に矢印がある時点でアセンブリの一部分だけが実行されている事になります。
この為、黄色のBが出た時は通常、一旦ブレークポイントを削除した上で再設定したほうが良いです。
(勿論アセンブラレベルでのデバッグを行っていて、振る舞いを理解した上で使用している場合はこのままでもかまいません)


ブレークポイントの解除の仕方は、アイコンをダブルクリックしても良いですし、F2キーを押してブレークポイント一覧からDeleteを選択するという方法もあります。







ちなみに、ブレークポイントに関しては、これ以外に赤い外枠だけ表示されるパターンもあります。


これはPICkit3などのライタをデバッガとして使用している(ICD)時によく発生します。
マイコンでのデバッグは、VisualStudioによるPC向けアプリのデバッグとは異なり、マイコンの制限によってブレークポイントを設定できる上限数がある事が多いです。


PICの場合この上限は1~4個程度の事が多いのですが、この上限を超えてブレークポイントを設定しようとした場合、前述のような赤い外枠だけが表示されます。


上限値がいくつなのかは、ツールバーのDebug表示で分かります。
HW BPは設定できるハードウェアブレークポイントの上限数で、Usedがその内何個が設定済みかです。


Debug表示が出ない場合は、ツールバーを右クリックしてDebugを選択してください。



ちなみにこの上限が有るのは実物のPICを使用してデバッグしている時だけです。
MPLAB SIMなどのシミュレータで実行する場合は、上限が無いのでこのような制約は有りません。

[PHP]ハッシュの入った配列を,ハッシュ値をキーにソートする

PHPで、例えば以下の様に沢山のハッシュテーブルが配列に格納されていたとします。
DBのテーブルとかをイメージすると分かりやすいかもしれません。

$dataList = array();
$dataList[] = array( "itemcode" => "10001", "itemname" => "みかん" );
$dataList[] = array( "itemcode" => "10010", "itemname" => "たまご" );
$dataList[] = array( "itemcode" => "10005", "itemname" => "りんご" );
$dataList[] = array( "itemcode" => "10002", "itemname" => "ぶどう" );
$dataList[] = array( "itemcode" => "10004", "itemname" => "とうふ" );



上記のデータをitemcode順に並び替えたい時、どの様にすれば良いでしょうか?
このような時、array_multisort()という関数を利用すると便利です。



まずは、array_multisort関数自体の使い方


という訳で、まずはarray_multisort関数の説明をマニュアルで確認してみます。

bool array_multisort( array &$arr [, mixed $arg = SORT_ASC 
                      [, mixed $arg = SORT_REGULAR [, mixed $... ]]] )
 
array_multisort() は、複数の配列を一度に、 
または、多次元の配列をその次元の一つでソートする際に使用可能です。 
この関数は、ソートの際にキーの相関を維持します。
 
連想配列のキー (string) は不変ですが、 数値添字は再度振り直されます。



…ドキュメントの文言だけでは意味が分からないので、例題を出して使い方のイメージを掴んでみます。



まずは、シンプルなサンプルです。

コード

$dataList = array( "e", "o", "h", "l", "l" );
$priority = array( 2, 5, 1, 3, 4 );
 
array_multisort( $priority, SORT_NUMERIC, $dataList );
var_dump( $dataList );
var_dump( $priority );



実行結果:

array
  0 => string 'h' (length=1)
  1 => string 'e' (length=1)
  2 => string 'l' (length=1)
  3 => string 'l' (length=1)
  4 => string 'o' (length=1)
 
array
  0 => int 1
  1 => int 2
  2 => int 3
  3 => int 4
  4 => int 5


第1引数で指定された配列の順(数値順/辞書順)に従って、第3引数の配列も並び替えてくれます。

第2引数はオプション指定で、第一引数のデータ型を指定します。
数値順にソートしたい場合はSORT_NUMERIC、文字コード順の場合はSORT_STRINGです。

一応、「array_multisort( $priority, $dataList );」といった感じで、データ型指定は省略可能なのですが、暗黙の型変換による、予期せぬ振る舞いを避けるために明示しておいたほうが無難です。



逆順にしたい場合は、SORT_DESCオプションを差し込みます。

$dataList = array( "e", "o", "h", "l", "l" );
$priority = array( 2, 5, 1, 3, 4 );
 
array_multisort( $priority, SORT_DESC, SORT_NUMERIC, $dataList );
var_dump( $dataList );
var_dump( $priority );



実行結果:

array
  0 => string 'o' (length=1)
  1 => string 'l' (length=1)
  2 => string 'l' (length=1)
  3 => string 'e' (length=1)
  4 => string 'h' (length=1)
 
array
  0 => int 5
  1 => int 4
  2 => int 3
  3 => int 2
  4 => int 1


SORT_DESC(降順) を省略した時は、SORT_ASC(昇順)がデフォルト値として指定されたと見なされます(明示することも可能です)。

array_multisort関数には他にも色々な使い方が有るのですが、”ハッシュの入った配列をソート”が目的ならここまで分かれば十分です。



“ハッシュの入った配列をソート”する


という訳で、本題に入ります。
ソートキーだけが入った配列があればよいので、以下の様なプログラムで並び替えが可能です。

コード

$dataList = array();
$dataList[] = array( "itemcode" => "10001", "itemname" => "みかん" );
$dataList[] = array( "itemcode" => "10010", "itemname" => "たまご" );
$dataList[] = array( "itemcode" => "10005", "itemname" => "りんご" );
$dataList[] = array( "itemcode" => "10002", "itemname" => "ぶどう" );
$dataList[] = array( "itemcode" => "10004", "itemname" => "とうふ" );
$priority = array();
foreach( $dataList as $data ) {
	$priority[] = $data[ "itemcode" ];
}
 
array_multisort( $priority, SORT_STRING, $dataList );
var_dump( $dataList );



実行結果

array
  0 => 
    array
      'itemcode' => string '10001' (length=5)
      'itemname' => string 'みかん' (length=9)
  1 => 
    array
      'itemcode' => string '10002' (length=5)
      'itemname' => string 'ぶどう' (length=9)
  2 => 
    array
      'itemcode' => string '10004' (length=5)
      'itemname' => string 'とうふ' (length=9)
  3 => 
    array
      'itemcode' => string '10005' (length=5)
      'itemname' => string 'りんご' (length=9)
  4 => 
    array
      'itemcode' => string '10010' (length=5)
      'itemname' => string 'たまご' (length=9)




複数のキーを元にソートする


ソートキーが2つある場合は、以下のようになります。

$dataList = array();
$dataList[] = array( "category" => "1", "itemcode" => "10001", "itemname" => "みかん" );
$dataList[] = array( "category" => "2", "itemcode" => "10010", "itemname" => "たまご" );
$dataList[] = array( "category" => "1", "itemcode" => "10005", "itemname" => "りんご" );
$dataList[] = array( "category" => "1", "itemcode" => "10002", "itemname" => "ぶどう" );
$dataList[] = array( "category" => "2", "itemcode" => "10004", "itemname" => "とうふ" );
 
$pri1 = array();
$pri2 = array();
foreach( $dataList as $data ) {
	$pri1[] = $data[ "category" ];
	$pri2[] = $data[ "itemcode" ];
}
 
array_multisort( $pri1, SORT_ASC,  SORT_STRING, 
                 $pri2, SORT_DESC, SORT_STRING, 
                 $dataList );
 
var_dump( $dataList );




実行結果

array
  0 => 
    array
      'category' => string '1' (length=1)
      'itemcode' => string '10005' (length=5)
      'itemname' => string 'りんご' (length=9)
  1 => 
    array
      'category' => string '1' (length=1)
      'itemcode' => string '10002' (length=5)
      'itemname' => string 'ぶどう' (length=9)
  2 => 
    array
      'category' => string '1' (length=1)
      'itemcode' => string '10001' (length=5)
      'itemname' => string 'みかん' (length=9)
  3 => 
    array
      'category' => string '2' (length=1)
      'itemcode' => string '10010' (length=5)
      'itemname' => string 'たまご' (length=9)
  4 => 
    array
      'category' => string '2' (length=1)
      'itemcode' => string '10004' (length=5)
      'itemname' => string 'とうふ' (length=9)



第1キーがカテゴリの昇順、第2キーが商品コードの降順にソートしています。
この例のように、各ソートキー毎に改行を入れてあげると可読性が高まります。


ソートキーが固定長である事が分かっており、ASC/DESCが混在しない場合は、以下のようにキー文字列を連結するのもありです。

foreach( $dataList as $data ) {
	$priority[] = $data[ "category" ] . "_" . $data[ "itemcode" ];
}
array_multisort( $priority, SORT_STRING, $dataList );




ハッシュポテト【McDonald’s FOOD STRAP 2】

[PHP]file_get_contenst()で複数サイトのhtmlを非同期・高速に取得する

PHPでは、file_get_contenst()関数にURLを指定する事で、他のサイトのhtmlテキストを取得できます。
1つのサイトだけを取得する場合はこれでよいのですが、大量のサイトからデータを取得する場合、
1サイトつづ順番に関数を呼んでいたら非常に時間が掛かります。


このような場合はcURLモジュールに有るcurl_multi_getcontent()関数を使用すると、複数サイトの情報を非同期で同時に取得出来ます。


ですが、curl_multi_getcontent()は、リソースの確保・開放処理が必要で、扱いがちょっと煩雑です。
この為、今回はfile_get_contenst()と同じくらい簡単に使用できるラッパ関数を作成しました。



名前は分かりやすくmulti_file_get_contenst()としました。

呼び側のコードはこんな感じになります。

<?php
$urlList = array();
$urlList[] = "http://www.yahoo.co.jp/";
$urlList[] = "http://www.google.com/";
$urlList[] = "http://www.infoseek.co.jp/";
$urlList[] = "http://www.goo.ne.jp/";
 
//-----------------------------------------
// 複数URLのデータを非同期で同時に取得する
//-----------------------------------------
$htmlTextList = multi_file_get_contents( $urlList );
 
//-----------------------------------------
// 取得結果の使用(データ長をデバッグ出力)
//-----------------------------------------
foreach( $htmlTextList as $htmlText ) {
    echo "text length: " . strlen( $htmlText ) . "<br />";
}



実行結果




で、実際の関数は以下の通りです。

<?php
function multi_file_get_contents( $urlList ) {
    $resList = array(); // 接続情報の一覧
 
    //------------------------------------
    // cUrlのハンドルを取得
    //------------------------------------
    $handle = curl_multi_init();
 
    //------------------------------------
    // 接続毎のリソース情報を一覧に追加
    //------------------------------------
    foreach ( $urlList as $url ) {
        $res= curl_init( $url );
 
        // CURLOPT_RETURNTRANSFER=true
        //   ->  curl_multi_getcontent()の返り値で結果を受け取る
        curl_setopt( $res, CURLOPT_RETURNTRANSFER, TRUE );
 
        curl_multi_add_handle($handle, $res );
 
        $resList[] = $res;
    }
 
    //----------------------------------
    // 非同期でデータを取得する
    //  (全データを取り終わるまで待つ)
    //----------------------------------
    do {
        curl_multi_exec( $handle, $isRunning );
    } while ( $isRunning );
 
    //----------------------------
    // 取得した結果を配列に格納
    //----------------------------
    $htmlTextList = array();
    foreach ( $resList as $res ) {
        $htmlTextList[] = curl_multi_getcontent( $res );
    }
 
 
    // リソースの破棄
    foreach ( $resList as $res ) {
        curl_multi_remove_handle($handle, $res );
        curl_close( $res );
    }
 
    curl_multi_close( $handle );
 
    // 取得結果を返す
    return $htmlTextList;
}






PHPの実行環境によっては、関数内にあるcurl_multi_init()でエラーが出る場合が有ります。


Fatal error: Call to undefined function curl_multi_init()




このような場合はphp.iniを編集し、php_curl.dllのextensionを有効にして下さい

編集前

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;
 
;extension=php_curl.dll




;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;
 
extension=php_curl.dll




[PHP]配列内から、index指定で要素を削除する方法

PHPで配列から要素を削除するには、array_shift(),array_pop(),unset()関数を使用します。
それぞれ配列の「先頭、末尾、index指定」で要素を削除することが出来ます。
index指定というのは、配列の要素番号を指定するという意味です。

それぞれの関数は、以下のサンプルコードで振る舞いを確認できます。

// 先頭を削除
echo "case1----\n";
$dataList = array( "d1", "d2", "d3", "d4", "d5" );
array_shift( $dataList );
var_dump( $dataList );
 
// 末尾を削除
echo "case2----\n";
$dataList = array( "d1", "d2", "d3", "d4", "d5" );
array_pop( $dataList );
var_dump( $dataList );
 
// 2個目の要素を削除
echo "case3----\n";
$dataList = array( "d1", "d2", "d3", "d4", "d5" );
unset( $dataList[1] );
var_dump( $dataList );



実行結果:

case1----
array(4) {
  [0]=>
  string(2) "d2"
  [1]=>
  string(2) "d3"
  [2]=>
  string(2) "d4"
  [3]=>
  string(2) "d5"
}
 
case2----
array(4) {
  [0]=>
  string(2) "d1"
  [1]=>
  string(2) "d2"
  [2]=>
  string(2) "d3"
  [3]=>
  string(2) "d4"
}
 
case3----
array(4) {
  [0]=>
  string(2) "d1"
  [2]=>
  string(2) "d3"
  [3]=>
  string(2) "d4"
  [4]=>
  string(2) "d5"
}



それぞれ意図する場所のデータが削除できました。


先頭、末尾の削除は特に問題ないのですが、case3は、indexの振られ方に注意が必要です。
データの2番目を削除してもd3が$dataList[1]に入らず,$dataList[1]は欠番になります。
これはPHPの配列が内部的に連想配列(ハッシュ)として実装されているからです。

配列のindexもずらしたい場合は、以下のコードで(一応)代替することは可能です。

// $dataList[2]を削除して、配列indexをスライドさせる
echo "case4----\n";
$dataList = array( "d1", "d2", "d3", "d4", "d5" );
$delIndex = 2;
$dataList = array_merge( array_slice( $dataList, 0,           $delIndex                    ),
                         array_slice( $dataList, $delIndex+1, count($dataList) - $delIndex ) );
var_dump( $dataList );



実行結果

case4----
array(4) {
  [0]=>
  string(2) "d1"
  [1]=>
  string(2) "d2"
  [2]=>
  string(2) "d4"
  [3]=>
  string(2) "d5"
}



このコードでは、array_slice()で部分配列を求めた後、array_merge()で再度結合を行っています。


…ですが、処理内容から容易に推測かと思いますが、このコードは実行コストが高い(非常に時間が掛かる)のでお勧めしません。

そもそも順序付けられたデータの集まりから、任意の要素を指定してデータを頻繁に削除する場合、配列にデータを格納するのは、データ操作に時間が掛かる為お徳では有りません。

一般的に、このような場合はリンクリストの利用を検討します。
PHP5.3以降では、データ構造として双方向リンクリストである、SplDoublyLinkedListクラスが用意されているので、このクラスを使用したほうが良いかもしれません。





ちなみに、連想配列の場合,key指定で削除する場合は、以下の様な感じでOKです。
キーが文字列なハッシュの場合は、”ずらす”という概念がそもそも無いので簡単ですね。

unset( $dataList[ 'keyValue1' );




プロになるための PHPプログラミング入門

Androide向けWebサイトで、横スクロールさせないようにする

html>headの中に、以下のタグを入れると、横スクロールが出ないようになります。

<meta name="viewport"
	  content="width=320,
	           height=480,
	           initial-scale=1.0,
	           minimum-scale=1.0,
	           maximum-scale=1.0,
	           user-scalable=yes" />



また、maximum-scaleを2.0とかにすると、ユーザ側で2倍まで拡大させる事が可能になります。



contentのwitdh,heightでは画面の仮想的な幅、高さの指定を行います。
width=320という表記を見ると、表示が320pxの低解像度になるのでは? と思われるかもしれませんが、これは実解像度では有りません。

仮想的に320ピクセル幅と見なすというだけで、サイト内にこれより高解像度の画像がある場合はちゃんと綺麗に表示されます。640などの大きな値にすることも可能ですが、そうすると文字が小さくなりすぎて見づらいので、スマートフォン向けサイトでは320pxを指定する事が多いです。

[PIC]MPLABでICD0191エラーが出た時の対処法

表示されるエラーメッセージ

ICD0191: Unable to perform operation as hardware memories are locked. Try later.



ICD0191エラーが発生するのは、MPLAB ICD2が他の機能で使用されている為、操作したかった作業が出来ない時に発生します。

対処法としては、通常はそのまま待って、しばらくしてからもう一度同じ作業をすると正常に動作します。
それでもダメな場合は、一度MPLABを再起動&ICDのケーブルを刺しなおして下さい。

VMware Playerユーザが仮想ハードウェアをアップグレードさせる方法

本記事は、前回の記事の続きです: Windows7にVMware Converterをインストールする

VMware Playerの機能制限

VMwareから提供されているVMware Playerを使用すると、無償で仮想マシン環境を構築できます。

このVMware Playerですが、有償版のソフト(VMware Workstation等)と比べると、作成したVMのベースとなる仮想ハードウェアのアップグレード/ダウングレードが出来ないという制限があります。


ですので、古いバージョンのVMware製品で作った仮想マシンを使い続けている場合、VMware Playerユーザは最新機能を使う事が出来ないのですが、この制限を回避するワザが有ります。


VMware Playerで仮想ハードウェアをアップグレードさせる方法

それは、VMwareから提供されている無償製品、VMware Converterを使用する方法です。


この製品は、元々物理マシンをVMの仮想マシン環境に変換するのが主目的なのですが、このほかに既存のVMwareマシンイメージを読み込んで、別のバージョンのイメージに変換する事も可能です。

今回はVMware Converterを使用して、仮想ハードウェアを最新版にアップグレードしてみます。


VMware Converterを使用して、実際に仮想ハードウェア変換させる

前回でVMware Converterのインストールは完了しているので、今回は実際に変換を行います。

プログラムを起動し、画面左上に有る”マシンの変換”をクリックします。


変換作業のウィザードが始まります。
まずは、変換元であるソースシステムの指定です。


“ソースのタイプを選択”プルダウンから、”VMware Workstationまたはその他のVMware仮想マシン”を選択し、VMのイメージファイル(*.vmx)を指定します。
次へを押すと、ソースマシンのハード構成の解析が始まるのでしばらく待たされます。



次に変換先のイメージである、ターゲットシステムを指定します。
変換は、既存のイメージを置き換えるのではなく、既存のイメージを元にして、新たに変換後イメージファイルが作成されます。ですので、もう1つ同容量のVMが作れる分の空きディスク容量が必要となります。

まずは、”VMware 製品の選択”で変換後のバージョンを指定します。
最新のVMware Workstation8.0から、古くはVMware Server1.0までのバージョンが指定可能です。


ターゲットタイプは、こちらも”VMware Workstationまたはその他のVMware仮想マシン”を選択します。



次にオプションの指定です。今回はデフォルトのままにしました。



最終確認のサマリ画面です。


変換を開始すると、一覧に変換タスクが登録されます。ステータスの欄に作業の進捗が表示されます。
また、画面下のタスクの進捗状況では、作業工程が表示されています。


サマリのタブでは、ウィザードで指定した内容が表示されています。


終了時刻は、初めは1時間以上という適当な表記がされますが、暫く待つと精度が上がってきます。
下記の表示では16%完了で残り26分となっています。


最終的な完了時点の表示です。
仮想マシンのディスクは17GBのサイズだったのですが、結果的に15分ほどで完了しました。



変換後のフォルダを見ると、vmxとvmdkの2ファイルが作成されていました。



変換後のVMを起動させる

変換後のVMware Playerで開くと、確かに8.0の仮想マシンになっています。


変換後のVMを起動させると、ハード構成が変わっているので、新しいデバイスが次々に認識されていきます。放置しておけばドライバがインストールされていきます。








しばらく待って、”使用準備が出来ました”となればOKです。
この時点でデバイスマネージャを確認し、未認識のデバイスがないことを確認します。



VMの設定画面を見ると、USBデバイスの互換性に2.0や3.0が指定出来る様になっていました。




VMware Converter変換に伴う問題

このように、VMware Converterを使用すると、簡単な作業でVMの仮想マシンをアップルグレードさせることが出来ました。
ですが、自動変換が上手くいかず、人手での作業が必要な点が幾つかあります。
以下に、発生した問題点とその対処法を列挙しておきます。

FDが有効になってしまう

変換前のVMでフロッピーディスクを無効にしていた場合でも、仮想FDが有効になってしまいます。


対処法は、仮想マシン設定のFD設定で”起動時に接続”のチェックを外せばOKです。


キーボードがASCII配列に変わってしまう

JISキーボードを使用していた場合でも、キーボードがASCII配列(101キーボード)になってしまいます。


本問題の対処法は、別記事に書いたので、そちらを参考にして下さい。
JISキーボードがASCII配列に誤認識されるのを修正する


VMの名前が変わってしまう

変換時にVMの名前が既存と異なるものに変更されてしまいます。
(実は、これはVMのコンバート時に指定可能なのですが設定し忘れがちです…)


こちらも仮想マシン設定で変更すればOKです。

PICのスペックを指定して型番を検索できるサイト


個人でもお手軽に利用できるPICマイコンですが、現在では700種類以上あり、欲しい機能を持った製品を探すのが大変です。この問題を解消するために製造元のMicrochipでは、スペックを指定して型番を検索できるサイトを幾つか用意してくれています。

今回は、PICのスペック検索サイトを紹介します。

Microcontroller Product Selector (MPS)

サイト:http://www.microchip.com/productselector/MCUProductSelector.html

以前より存在していた検索ページでAdobeのFlashで作られています。
ページ上部で検索条件を入れると結果が一覧で表示されます。
(画像クリックで拡大表示されます)


結果の一覧は、こんな感じです。


絞り込んだ結果は、PDF出力も可能です。
デフォルトの検索条件でで737製品マッチしたのですが、PDFで60ページになりました。





Microchip Advanced Parts Selector (MAPS)


サイト:Microcontroller
Advancedと付いている事からも分かるように、こちらのほうが新しい検索サイトのようです。


より詳細な条件で検索を行えるのですが、結果の一覧が見づらく、ちょっと不便です。



Product Tables


サイト:FLASH Products – Microchip Technology Inc

こちらはシンプルなページですが、全製品をExcelで出力する事が可能です。


Excel(というかcsvファイル)はこんな感じです。


Excelファイルには以下のスペック情報が載っています。
これだけでも、大まかに絞込みには便利です。

Product
Status
Volume Pricing
Architecture
Memory Type
Program Memory KBytes
Program Memory KWords
Self-write
EEPROM Data Memory
RAM
I/O Pins
Pin count
Max. CPU Speed MHz
CPU Speed MIPS
Internal Oscillator
# of A/D Ch.
Cap Touch Channels
Digital Communication
Timers
Temperature Range
Operation Voltage Range
Packages



この一覧に、UART,CCM,USBなどといった機能もあれば完璧なのですが…
ちょっと残念です。



VMware Toolのアップデートエラー時、vmxの編集時の注意点(KB article 1714)

VMware Player/Workstationを使用時にVMware Toolのアップデートを試みると、以下のエラーが出る事があります。


Tools のアップデート エラー
---------------------------
Tools の更新に失敗しました。 
仮想マシンの vmx ファイルを編集し、次のラインを追加してから再試行してください。
vmx ファイルを編集するヒントで KB article 1714 をよくお読みください。
 
isolation.tools.guestInitiatedUpgrade.disable = "FALSE"



このエラーの対処法は、メッセージの文字通りvmxファイルを編集すればよいです。

作業自体は簡単ですが、vmxファイルを編集する時にはいくつか注意点があり、その詳細がKB article 1714に記載されています。VMwareのKB articleを調べてみたのですが、英語のドキュメントしかなさそうなので、適当に日本語訳しておきました。


*.vmxファイル編集時の注意点

http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1714 が元ネタです

KB article 1714では、*.vmxファイルを編集する上での注意点を説明します。


*.vmxファイルは,通常だとVMがあるフォルダに存在します。

Windows XP, /2003だと、デフォルトでは以下の場所にあります。
    C:\Documents and Settings\ユーザ名\My Documents\Virtual Machines\VMの名前.vmx
 
Windows Vista, 7, 2008は以下の場所です
	C:\Users\ユーザ名\My Documents\Virtual Machines\VMの名前.vmx
 
Linuxの場合は、"vmware-cmd -l" コマンドで登録されているVMのパスが分かります。




VMの起動時は、VMwareが.vmxファイルを上書きする可能性があるので、起動中に編集しないで下さい。

設定内容はバージョンに依存します。
ですのでVMのアップグレードを行った場合、設定の内容が有効でなくなる場合があります。

.vmxファイルを編集する時、事前にすべき事は以下の通りです。

1. まずVMをパワーオフの状態にしてください。
2. ファイルを編集できる権限がある事を確認します。
3. *.vmxファイルをバックアップしておきます。これによって、ファイルの編集に失敗した場合VM自体が起動しなくなってしまうリスクを回避します。






ESX/ESXi, vCenter Serverを使用している場合の注意点

ESX/ESXi環境の場合、手動でvmxファイルを編集しても、vCenter Serverデータベースに格納されているエントリで内容が上書きされてしまいます。
ですので、もし.vmxファイルを編集したい時は、最初にvCenter Serverのインベントリから削除を行います。(右クリックしてRemove from Inventoryを選択してください)その後編集を行い、再度コマンドラインからインベントリへの登録を行います。

ESX 3.xの場合、以下のコマンドで登録が行えます。

vmware-cmd -s register /vmfs/volumes/データストア名/VMフォルダ名/VMの名前.vmx



実行後、”return code =1″が出ればOKです。

ESXi 3.5, ESX/ESXi 4.x, and ESXi 5.0の場合のコマンドは、以下の通りです。

#vim-cmd solo/registervm /vmfs/vol/データストア名/VMフォルダ名/VMの名前.vmx

[PIC]ICD0019エラーが出た時の対処法

MPLABで、ICD 2ライタ/デバッガを使用しているとき、ICD0019エラーが出た場合の対処法です。

エラーメッセージ

Connecting to MPLAB ICD 2
ICD0019: Communications:  Failed to open port (USB): (Windows::GetLastError() = 0x2, 
         '指定されたファイルが見つかりません。')
ICD0021: Unable to connect with MPLAB ICD 2 (USB)




ICD0019エラーは、MPLABがPICのライタを認識できていない事を意味するエラーです。

このエラーが出る時は以下の点を確認してください。

MPLAB ICD2デバッガがPCに正しく接続されているか。
MPLAB ICD2デバッガに電源の供給がされているか。
デバイスマネージャ上で、MPLAB ICD 2 Firmware Clientが表示されているか

Windows7にVMware Converterをインストールする


VMwareから提供されているソフトであるVMware Convereterを使用すると、物理マシン上で動作しているPC環境をVMwareのイメージファイルに変換する事ができます。物理マシンの事は英語でPhysical Machine、仮想マシンはVirtual Machineなので、この変換の事をP2V(Physical to Virtual)と呼びます。


VMware Convereterでは、P2V以外にも以下の製品で作成されたHDDイメージファイルをVMwareのディスクイメージに変換できます。
こちらはV2V(Virtual to Virtual)と呼ばれています。

Microsoft Virtual PC
Symantec Backup Exec System Recovery 
Symantec Backup Exec
Norton Ghost
Acronis True Image
StorageCraft
Parallels Desktop



また、古いバージョンのVMwareで作成された仮想マシンを、新しいものにアップグレードすることも可能です。


このようにVMware Convereterでは、様々な環境をVMwareの仮想マシンイメージファイルに変換する事ができる便利ソフトなのですが、なんと無償で利用する事が出来ます。


今回はVMware Convereterをインストールし、VMwareの仮想マシンをアップグレードさせてみます。

まずは、以下のページにアクセスし、製品のダウンロードを行います。ダウンロードを行うにはユーザ登録(無料)が必要です。
Download VMware vCenter Converter Standalone for P2V Conversion




本エントリのを書いた時点では、Ver5.0.1が最新でした。
ダウンロードしたexeをダブルクリックして起動します。


まずは言語の設定です。今回は日本語を選択します。



ウィザードの開始画面です。



特許&ライセンスの確認です。どちらも次へで進めていきます。




インストール先を指定します。



セットアップタイプですが、ローカルインストールとクライアントサーバインストールの2つが有ります。
後者は、P2V変換を行う際、変換を行なうサーバPCと、変換対象のPCが別のマシンになる場合に選択します。今回は、V2Vの変換で使用するため、ローカルインストールを選択します。




インストールの最終確認です。インストール作業自体は短時間で完了します。




完了の確認画面です。



終了ボタンを押すと、VMware Converterのメイン画面が表示されます。



インストールはこれで完了です。
次回は、VMware Converterを使用して実際に古いバージョンのVMイメージをアップグレードさせてみます。

[PIC18]PWM機能を使用してLEDをふんわり点滅させる

PIC18シリーズのマイコンで、PWM出力を利用してLEDをふんわり点滅させてみます。


今回はCCP機能に含まれるPWM出力を使用して明るさの制御を行います。
この為、LEDはPWM出力ピンであるCPP1のピンに接続します。

#include "p18f4620.h"
#include "timers.h"
#include "delays.h"
#include "pwm.h"
 
// Configuration bitの指定
#pragma config OSC    = HS      // HS oscillator
#pragma config FCMEN  = OFF     // Fail-Safe Clock Monitor disabled  
#pragma config IESO   = OFF     // Oscillator Switchover mode disabled 
#pragma config PWRT   = ON      // PWRT enabled  
#pragma config BOREN  = OFF     // Brown-out Reset disabled in hardware and software  
#pragma config WDT    = OFF     // WDT disabled (control is placed on the SWDTEN bit) 
#pragma config PBADEN = OFF     // PORTB<4:0> pins are configured as digital I/O on Reset  
#pragma config MCLRE  = ON      // MCLR pin enabled; RE3 input pin disabled  
#pragma config STVREN = ON      // Stack full/underflow will cause Reset  
#pragma config LVP    = OFF     // Single-Supply ICSP disabled 
#pragma config XINST  = OFF     // Instruction set extension and Indexed Addressing mode disabled
#pragma config CP0  = OFF, CP1  = OFF, CP2  = OFF, CP3  = OFF, CPB = OFF, CPD = OFF  
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF 
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF, EBTRB = OFF
 
 
void main( void )
{
    int offset = -1;
    int duty = 255;
    int loop = 0;
 
    //--------------------------------------------------
    // PWM出力を開始する
    // プリスケーラ 1:1, 255までカウント
    //      -> CPUが40MHz駆動で、PWMサイクルが39kHz
    //         40M / ( 4 * (255+1) ) = 39.0625kより
    //--------------------------------------------------
    OpenTimer2( TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_1 );
    OpenPWM1( 0xff );
 
    while( 1 ) {
        //-------------------
        // duty比をセット
        //-------------------
        SetDCPWM1( duty );
 
        //------------------------------------
        // duty比を変化させる(5%~100%を往復)
        //------------------------------------
        duty += offset;
        if ( duty <= 64 ) {
            offset = 1; 
        }
        if ( duty >= 1023 ) {
            offset = -1;
        }
 
        //------------------------------------------
        // ゆっくり点滅させる為に,ディレイを入れる
        //------------------------------------------
        for ( loop = 0; loop < 100; loop++ ) {
            ;   // nop
        }
    }
}




periferal libararyを使用せずにPWM機能を使う

上記のコードではMicrochipが用意しているperiferal libararyの関数を使用しています。
具体的には、OpenTimer2() OpenPWM1(), SetDCPWM1()がライブラリの関数です。

これらの関数を使用せずにレジスタへ直接値をセットしたい場合は,以下のコードとなります。
(例ではduty比50%で,CPUが10MHz動作時にPWM周波数を20kHzとして出力しています)

//------------------------
// PWMモード初期設定
//------------------------
CCP1CONbits.CCP1M = 0b1100; //11xx:PWMモード
TRISCbits.TRISC2  = 0;
T2CONbits.TMR2ON  = 0;
PR2               = 124;    // 124までいったらTMR2をリセット(CPU=10MHz時に20kHz出力)
 
//------------------------
// Timer2初期設定   
//------------------------
T2CONbits.T2CKPS1 = 0b00;   // 0b00:プリスケーラ1/1, 0b01:1/4, 0b1x:1/16
TMR2              = 0;      // タイマ値をクリア
PIE1bits.TMR2IE   = 0;      // 割り込み未使用
//PIR1bits.TMR2IF = 0;      // 割り込みフラグを落としておく
T2CONbits.TMR2ON  = 1;      // Timer2スタート
 
// Duty比50%でセット
CCPR1L = PR2 / 2;




PWM出力周波数の計算

PWMで出力する矩形波の周波数は、CPUクロック、TMR2プリスケーラ(T2CONレジスタのT2CKPS)、PR2レジスタの値で決まります。
これは、計算するのが結構面倒なので、Excelで一覧表を作成しました。


以下のファイルをダウンロード後、クロック周波数の値(シートのB3セル)を変更すると、TMR2プリスケーラ、PR2の値毎の周波数一覧が表示されます。

ダウンロード:PIC_PWM周波数計算.zip

PIC向けCコンパイラ(HI-TECH C,C18,C30,C32)のinline関数サポート状況まとめ

PICで使用できるMicrochip社提供のコンパイラには、HI-TECH C,C18,C30,C32等が有ります。
これらのコンパイラで、インライン関数が使用できるかを調べたのでまとめてみました。

HI-TECH C,C18コンパイラ

HI-TECH Cと、C18コンパイラでは、インライン関数はサポートされていません。
使用したい場合は、関数マクロで代替する必要があります。

参考:
HI-TECH Software Frequently Asked Questions

C30,C32コンパイラ

C30とC32のコンパイラではインライン関数はサポートされており、使い方は同じです。
但し、使用するには、コンパイルオプションで以下の2つを指定する必要があります。

オプティマイザで -O2 か -O3を指定する
-finline-functionsオプションを使用する



実際の関数は以下のように定義します。

 static inline int funcname() {
	 ...
}



以下はコンパイラのユーザガイドより、inline functionに関する説明文の引用です。

-O2オプション

-O2 turns on all optional optimizations except for loop unrolling (-funroll-loops), function inlining (-finline-functions), and strict aliasing optimizations (-fstrict-aliasing).
It also turns on force copy of memory operands (-fforce-mem) and Frame Pointer elimination (-fomit-frame-pointer). As compared to -O, this option increases both compilation time and the performance of the generated code


-finline-functions オプション

Integrate all simple functions into their callers. The compiler heuristically decides which functions are simple enough to be worth integrating in this way.
If all calls to a given function are integrated, and the function is declared static, then the function is normally not output as assembler code in its own right

MPLAB_C32_User_Guide_51686a.pdfのLanguage Specificsより

MPLABのエディタを、タブエディタに変更する



PICの統合開発環境であるMPLABですが、通常はMDI構成で複数のエディタウィンドウが表示さます。
ですがこの形式は、設定でVisualStudioやEclipseのようにタブエディタに変更することが出来ます。


その方法は…
エディタの適当なところで右クリックして、Propertiesを選択します。



Generalタブの”Use Tabbed Window”にチェックを入れ、OKをクリックします。



これで、タブエディタに切り替わります。
バグなのか、タブのタイトル文字が大きくなってしまいますがこれでも十分使いやすいです。


[VMware]Windows8をゲストOSで使用時、放っておくと自動サスペンドするのを止める

VMware Player5.0でゲストOSにWindows8をインストールしてみました。
快調に動作しているのですが、しばらく使わずに放置しておくと自動でサスペンドしてしまいます。

通常だったら省エネ機能で便利なのですが、現在の実行環境はホストOSが24時間稼動しているので、サスペンドしてもらっても不便なだけです。


という訳で、自動サスペンド機能をOFFにしてみました。

カーソルをウィンドウ右端にあて、一番下のギアのアイコンをクリックします。


コントロールパネルを選択します。


電源オプションをクリックし、コンピュータをスリープ状態にするの時間を、”適用しない”を選択します。




これで自動サスペンドしなくなりました。
どうでも良い事ですが、VMwareのウィンドウ内でWin8を実行させていると、”画面の右端にカーソルを合わせ…”というUIは実に不便です。

VMwareによる仮想マシンの構築・活用