2015年11月29日日曜日

加工と検証が出来る準備が出来た。

PSoC5LPで機能を造る事は出来ても、
外側やフレーム等の加工や回路のチェックをする機材がありませんでした。
実のところ、電子工作をする上で回路のチェックは
テスター(デジタルマルチメーター)だけでは、無理があります。
例えば、アナログ回路で作成した波形出力機はテスターで見る事が出来ません。
また、混ざった波形にどの周波数が隠れているか
正しい周波数なのかを調べるにはオシロスコープや周波数解析器が必要となります。

電子回路は作れても、外側の箱やメカニカルな機能が残ります。
外形加工は測る道具もそうですが切る道具、削る道具も多くそろえる必要があります。
また穴あけも含め電動の工具は割と大きな音が出るものが多いため
なかなか都心の真ん中では運用に問題があります。

正直なところ、私の家には外形加工と回路検証の手立てがありませんでした。
特に回路の検証は深刻で、手の届きやすい機器が易々と手に入る訳ではありません。
予算もないですしね。
アナログもしっかりやりたい私には少なくとも10Mhz対応のオシロスコープと
周波数解析、デジタルの通信をモニターするロジックアナライザーが欲しいと考えていました。
ただ、これだの機材を揃えようと思うとかなりの高額な金額になります。
外形加工も夕方や夜に出来れば良いのですが
そんな訳にも行かないので低騒音なNC加工の機器が欲しいと考えていました。
多くの時間をかけて考えた結果として、私はこれらを解決するのに2つの機器を買いました。

1つはビットスコープマイクロと言う多機能検査機器
もう1つはda Vinci Jr1.0と言う3Dプリンターです。

ビットスコープマイクロと言うのは、
2Ch20Mhzオシロスコープ、ロジックアナライザー,スペクトラムアナライザー(周波数解析)
8chスペクトラムアナライザーが1つに合わさったUSB検査機器です。
またビットスコープはraspberry Piの様なLinuxボードでも動きます。
Linuxボードを使えば作業用のパソコンとも切り離せますし
OSの割り込みによる測定ミスの可能性を減らせます。

このビットスコープは日本だとどこも取り扱いがないので今回は個人輸入をしました。
梱包ミスがあったりしてオーストラリアのお店とのやり取りが多かったですが
無事に手元に届きました。
pcDuino3nanoで動かすとこんな感じです。


da Vinci Jr 1.0は5万円以内かつスタンドアローンで出力のできる、
今のところ唯一の3Dプリンターでしょう。

 樹脂部分のヒビによって返品交換をしたりしましたが
どうにか運用出来ている感じかと思います。
3Dプリンターは削って作りこんでいく訳ではないので都心でも安心して使えます。


とは言え大きい事もあるので定位置はクローゼットとなりました。
セミクローズド制御でもないので加工精度としてはイマイチですが
時間を気にせずに運用が出来るので良しとしましょう。3mm以下の円形は苦手の様です。
実際に作ったpcDuino3nanoのケース。
売っていないのでda Vinci jr 1.0で作った。



2015年10月17日土曜日

キャラクターLCDの文字コードを使ってみる。

今回はキャラクターLCDの「文字コード」を使って
半角英数だけでは無い表示をさせてみようと思います。

さて、キャラクターLCDの文字コードとはなに?
っと言う話を少ししておこうと思います。

パソコンはもちろんなのですが
コンピューターは人間の文字が分かりません。
なので、数値の組み合わせに人間の文字を対応させる事によって
コンピューターが人間へ文字を見せられる様になります。
数値の組み合わせと文字の対応の事を「文字コード」と言います。
この文字コードで有名なのは恐らくASCIIコードでしょう。

では、なんで文字コードとキャラクターLCDに関係があるかと言うと
キャラクターLCDとPSoCは文字コードを使ってLCDに表示させているのです。
つまりは、キャラクターLCDに文字コードが内蔵されているいてそれを使っているのです。

え、「プログラムで文字コードなんて意識していないって?」

それはPSoC Creatorのライブラリーが見えない様にしていたからです。
普段は文字コードを意識せずに表示させていました。
ですが今回は文字コードを使って表示させようと思います。

キャラクターLCDモジュールはHD44780(コンパチブル)っと言う
コントロールICを返してLCDに表示させています。
先ずはHD44780が使う文字コードを調べましょう。

これはSparkFanにあったHD44780データシートの抜粋



これが内蔵されている文字コード
アルファベットとカタカナと特殊な文字が使える様になっています。
HD44780互換であればこの文字コードが使えます。
また、任意の文字や絵を8個まで表示させる事が出来ます。

表の上の番号がありますね、それはHD44780が使う文字コードの上位ビットです。
表の左側にも番号がありますね、文字コードの下位ビットを表しています。
この表を使うには8bit分の上位4bitと下位4bit分を合わせないと
使えないと言う訳なのですね。

例えばカタカナの「ア」であれば上位ビットの「1011
下位ビットの「0001を合わせた「10110001」となる訳です。
16進数表記であれば「0xB1と言う事になります。
では実際にやってみましょう。

まずはいつも通りに空のプロジェクトを作って、
キャラクターLCDのコンポーネントを入れます。



しかし今回は任意で作った絵や文字を入れたいので設定を変えちゃいます。


設定画面を開いたら、ラジオボタンのNoneUser Definedに切り替えます
これで任意の表示が出来るようになりました。



今の状態はCustom 0が選択されている状態です。
このマトリックス状に表させているのが1文字分です。
このマトリックスをマウスでクリックして任意の文字を作って行きます。
白をクリックし見ると黒へと逆に黒をクリックすると白へと変わります。



何でも良いのですが、携帯のアンテナみたいなのを作ってみました。
これで文字のデザインはおしまいです。
デザイン増やしたい場合はとなりのYの字ブロックをクリックしてみると
Custom1と変わっています。このようにして変えていきます。


ではOKをクリックして閉じましょう。

配線は以前の書いた記事にあるので省略します。


配線が終わったら、一度コンパイルをしましょう。
コンパイルが終わったら次はプログラミングですね。
今回のプログラムの内容は意外とシンプル
int main()
{
    CyGlobalIntEnable; /* Enable global interrupts. */

    LCD_Char_1_Start();//LCDをスタートさせる
    LCD_Char_1_Position(0,0);//上の段の左端からスタート
    LCD_Char_1_PrintString("Hello PSoC3");///まずは普通のやり方
   
    LCD_Char_1_Position(1,0);//下の段の左端からスタート
    LCD_Char_1_PutChar(0xB1);//文字コードを使うときはPutCharを使う。数字は16進数表記
    LCD_Char_1_PutChar(LCD_Char_1_CUSTOM_0);//作った文字には***_CUSTM_*で使える
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */

    for(;;)
    {
        /* Place your application code here. */
    }
}
打てたら、再度コンパイルをしましょう。
コンパイル出来たら、実際にPSoC5LPへと書き込みましょう。
(今回はPSoC3を使いましたがPSoC5LPでも全く同じです)



こういう風に表記されれば完成(/・ω・)/
どうでしょうか出来ましたか??

MedAruinoで同じことが出来るかは知りませんが、
文字コードを使えば簡単にカタカナが出力出来ましたね。
またコンポーネントのエディターで絵文字も作れました。

いや~PSoC5LPは便利ですね。

PS:
スイッチサイエンスの
16×2 日本語フォント付きLCDモジュール(青地・白文字)
https://www.switch-science.com/catalog/2448/
でも使えるはずだぞ~。

2015年8月15日土曜日

PSoC3の変数で迷う

PSoC5LPを開発するの様に
PSoC3でもPSoC5LPと同じように開発が出来る訳ですが
やっぱり、微妙に差があるのですね。



さて、変数と言うと
intやcharの様に文字や数値を入れておく道具ですね。
通常は、main()関数の中でも外でもどっちでも
平気なのですが、PSoC3ではどっちでも良いと言うわけでは無いようです。

下の写真はmain()関数の内側で変数の宣言(変数を使いますよ)をしています。
通常は、この方法で問題は無いのですがビルドをかけると



この通り、エラーが出てしまいます。
しかもエラーの説明も「近くに原因がありますよ」位なので
何が原因だったのかが良く分かりません。

ちょっと古い書き方でmain()関数の外側で変数の宣言をして
ビルドをかけると



ビルドが通りました。
使うコンパイラーがPSoC3では異なるので
ちょっとした違いはあるのかなと思います。

*すこし追加

手ほどきをしていただいて、分かったのですが
「 CyGlobalIntEnable」の前に変数の宣言をしてあげる必要があるようです。

つまり
int main(){

   uint32 cou;

 CyGlobalIntEnable;




としてあげれば良い様です。

2015年7月18日土曜日

PSoC5LPでI2Cを使おう(マスター編)

前回、I2Cってどんなものなのかって言うお話をしました。
今回は実践的な話で、「I2Cを使ってみましょう」と言う話です。


先ずはいつもの様に、空のPSoC5LPプロジェクトを作ります。
I2Cを通じてセンサーの結果をキャラクターLCDに出力したいので
キャラクターLCDコンポーネントを入れます。
つぎにI2Cのコンポーネントを入れるわけですが、
I2Cのコンポーネントにはいくつか種類があります。
まずはCommunicationsのツリーを開いてI2Cのツリーを開きます。
I2Cに関するコンポーネントが表示されました。



前回話した通り、I2Cにはマスターとスレーブの関係性があります。
PSoCはマスターにもスレーブにもなることが出来ます。
また、PSoC5LP,PSoC3,PSoC4にはI2C専用の通信ペリフェラル
UDBを消費してI2Cペリフェラルを生成する2通りがあります。
(PSoC4では通信ペリフェラルが複合型)
今回はI2C専用の通信ペリフェラルを使ってPSoC5LP側がマスター側で通信します。




なのでI2C Master (Fixed Function)を選んで入れます。
ピンも付いた状態で画面に入るので今回はpinを入れる必要は無いです。
必要なコンポーネントは今回、これだけです。



さて、I2Cのコンポーネントがこれで入りましたのでI2Cの設定をしたいと思います。
I2Cのコンポーネントをダブルクリックで設定を出しましょう。
そうすると通信方式と通信スピードについての設定が出てきます。



通信方式は複数選ぶことが出来ますが、単一マスターなので
ModeのプルダウンメニューからMaster選びます。




 PSoCの場合通信スピードは1Mbit/sまでの通信に対応しています。
今回、通信スピードは400kbit/sにしたいので
Date rateのプルダウンメニューから400を選びます。


ここまで出来るとこんな感じになるので「OK」をクリックして閉じましょう。



ピンアサインは今まで通り、任意のピンを設定です。



今回は、数値文字変換のsprintf()を使うので、ヒープサイズも再設定しておきましょう。
リンカーの設定もして置きましょう。*トラブルシューティングを参照



ここまで出来たら、1回目のビルドをしましょう。

ビルドが終わったので今度はPSoC5LPとセンサーモジュールとの接続をしましょう。
I2Cのピン同士はオープンドレインと呼ばれる状態にあります。
7セグLEDの時にPSoC5LPのソース電流とシンク電流の話をしました。
オープンドレインはプルアップ抵抗を使うシンク電流の接続方法と似た状態です
しかしシンク電流時とは違い、電源電圧を超えてON,OFFする場合
I2Cの様な通信の用途で使われています。

I2Cで使われるプルアップ抵抗には適当な抵抗を用いる事が出来ません。
何故かと言うと配線に使われる銅線は小さいながらも
コンデンサーの様な働きもあります
なので、適当な抵抗をつないでしまうとパッシブフィルターの様な状態となり
正しいON,OFFの信号がデバイス間に伝わりません。
本来ならば、オシロスコープを使いながら選定するのが良いのですが
今回はモジュールの基板に実装されているプルアップ抵抗を用いりたいと思います。




配線が終わったら、プログラミングをしましょう。
今回は長いです…。


#include <project.h>
#include <stdio.h>
#define HTDU21D_ADDRESS 0x40

#define TRIGGER_TEMP_MEASURE_HOLD  0xE3
#define TRIGGER_HUMD_MEASURE_HOLD  0xE5
#define TRIGGER_TEMP_MEASURE_NOHOLD  0xF3
#define TRIGGER_HUMD_MEASURE_NOHOLD  0xF5
#define WRITE_USER_REG  0xE6
#define READ_USER_REG  0xE7
#define SOFT_RESET  0xFE


//
//I2Cの通信で使う高度API
//タイムアウト処理が無いので注意。
//

uint8 I2C_Write(uint8 SlaveAddress, uint8 *DataAddress, uint8 Byte_Count, uint8 I2C_Mode){
    uint8 temp;
    temp = I2C_1_MasterWriteBuf(SlaveAddress,DataAddress,Byte_Count,I2C_Mode);
    while (temp != I2C_1_MSTR_NO_ERROR);
    while(I2C_1_MasterStatus() & I2C_1_MSTAT_XFER_INP);
    temp = I2C_1_MasterClearStatus();
    return (temp);
}

uint8 I2C_Read(uint8 SlaveAddress, uint8 *DataAddress, uint8 Byte_Count, uint8 I2C_Mode){
    uint8 temp;
    temp = I2C_1_MasterWriteBuf(SlaveAddress,DataAddress,1,I2C_Mode);
    while (temp != I2C_1_MSTR_NO_ERROR);
    while(I2C_1_MasterStatus() & I2C_1_MSTAT_XFER_INP);
    temp = I2C_1_MasterClearStatus();
   
    CyDelay(60);//このデバイスではいるが、通常は要らない。
   
    temp = I2C_1_MasterReadBuf(SlaveAddress,DataAddress,Byte_Count, I2C_Mode);
    while (temp != I2C_1_MSTR_NO_ERROR);
    while(I2C_1_MasterStatus() & I2C_1_MSTAT_XFER_INP);
    temp = I2C_1_MasterClearStatus();
    return (temp);
}
//
//高度APIはここまで
//


//
//gitにあるArduinoのデザインリファレンスから取ってきた
//デバイスからのデータ演算用
//

//Given the raw temperature data, calculate the actual temperature
float calc_temp(int SigTemp)
{
  float tempSigTemp = SigTemp / (float)65536; //2^16 = 65536
  float realTemperature = -46.85 + (175.72 * tempSigTemp); //From page 14

  return(realTemperature); 
}

//Given the raw humidity data, calculate the actual relative humidity
double calc_humidity(int SigRH)
{
  float tempSigRH = SigRH / (float)65536; //2^16 = 65536
  float rh = -6 + (125 * tempSigRH); //From page 14

  return(rh); 
}



//
//main
//
int main()
{
    CyGlobalIntEnable; /* Enable global interrupts.(割り込みを使う事を許可する) */

    LCD_Char_1_Start();
    LCD_Char_1_Position(0,0);
    LCD_Char_1_PrintString("HTU21D");
    /* Place your initialization/startup code here (e.g. MyInst_Start()) */
    I2C_1_Start();
    uint8 wr_buff[2]={TRIGGER_HUMD_MEASURE_NOHOLD,0x00};//取り出すレジスターと空の配列
    int R=0;
    uint16_t HBIT,LBIT,RESULT;//配列受け渡し用の変数
    char out[10];//文字変換後の配列
    R=I2C_Read(HTDU21D_ADDRESS,wr_buff,2,I2C_1_MODE_COMPLETE_XFER);//アドレス、レジスターが入った配列、配列の個数、I2Cのモード
    LCD_Char_1_PrintInt8(R);//エラーの出力(01ならok)
    LCD_Char_1_PrintString("/");
    //LCD_Char_1_Position(1,0);
    LCD_Char_1_PrintInt8(wr_buff[0]);//配列の0番目を出力
    LCD_Char_1_PrintInt8(wr_buff[1]);//1番目を出力
    //LCD_Char_1_PrintString("/");
    HBIT = wr_buff[0];
    LBIT = wr_buff[1];
    RESULT = HBIT<<8|LBIT;//上位ビットを左に8個分シフト(ずらす)して下位ビットとORを行う。
    RESULT &= 0xFFFC;//ステータスビットを0にして計算出来るようにする。
    LCD_Char_1_Position(1,0);
    //LCD_Char_1_PrintInt16(RESULT);
    double FRESULT;//小数点が出るのでダブル型の変数
    FRESULT = calc_humidity(RESULT);//湿度の計算をしてダブル型の変数に渡す
    sprintf(out,"%.2f",FRESULT);//数値文字変換をする。
    LCD_Char_1_PrintString(out);
    LCD_Char_1_PrintString("% ");
    wr_buff[0] = TRIGGER_TEMP_MEASURE_NOHOLD;
    wr_buff[1] = 0x00;
    I2C_Read(HTDU21D_ADDRESS,wr_buff,2,I2C_1_MODE_COMPLETE_XFER);
    HBIT = wr_buff[0];
    LBIT = wr_buff[1];
    RESULT = HBIT<<8|LBIT;
    RESULT &= 0xFFFC;
    FRESULT = calc_temp(RESULT);
    sprintf(out,"%.2f",FRESULT);
    LCD_Char_1_PrintString(out);
    //LCD_Char_1_PutChar(LCD_Char_1_CUSTOM_0);//LCDのカスタムモードで出す場合
    LCD_Char_1_PrintString("C");
    for(;;)
    {
        /* Place your application code here. */
    }
}


I2C_Write();I2C_Read();の関数は私が作成したAPIです。
戻り値(R=I2C_Reas();とした場合のRの値)には
エラーコード等が入るようになっています。
I2C_Write()を使う場合は*DataAddressには配列を使うと良いと思います。
I2Cデバイスの多くがスレーブ側のアドレスを
インクリメントしてくれる機能がある様です。
配列の先頭(***[0])レジスターの番号を使い、次の配列(***[1]には
先頭のレジスターに入れたい、数値設定を入れます。
数値設定は8bit分を16進数表記にしてあげる必要があるので注意してください。
また、その次の配列(***[2]には先頭のレジスター番号に
インクリメント(レジスター番号+1のレジスター番号)された
レジスター番号に入れたい設定数値が入ります。
I2C_Read();を使う場合には*DataAddressにつかった配列と
同じ様な使い方をすると良いと思います。
I2C_Readで使う場合の配列では、先頭の配列に読み出したいレジスター番号入れてあげます。実行すると、先頭の配列には読み出したいレジスターに入っている数値が入っています。
先頭の配列の2番目には読み出したいレジスター番号に
インクリメントした番号のレジスターに入っている数値が入っています。
もちろん配列が多ければ、読み出したいレジスターをインクリメントし続けて読み出します。

まだ接続をしていない場合にタイムアウトする機能や、
今回の様に読み出しの際に時間差をつける機能無いのですが
今後追加して行こうと思います。

プログラムを入れ終わったら、もう一度コンパイルしましょう。
これで完成(/・ω・)/
実際に書きこんで見ましょう。



どうでしょうか?
LCDに湿度や温度が表記されたでしょうか?
For();の中で使う場合には湿度や温度には
移動平均フィルターをかけた方が良いと思います。
湿度や温度は常に変化し続けるので、安定しません。

また、main()の前に沢山関数を書きました。
これはC言語ではよくあるルールでもありますが
PSoC Creatorではmainの前に関数を書いてあげると
コード補完によって「これ使うの?」と聞いてきます。
これを使うとコードを書く苦労が少し減るかな?


いずれスレーブ編も書こうかなと思います。

**今回の高度APIはITショップ「えとせとら」さんのブログを参考に作成しました。ありがとうございます。