PSoCマイコン

2011年1月22日 (土)

25A流せるモータードライブ回路(パワーMOSFETを用いたHブリッジ回路)

前回の記事にある回路を設計したわけですが、実際にブレッドボード上で組み立てて、モーターの代わりにLEDを光らせようとしてみました。25Aも流せる回路で、LEDを光らすなんて少しもったいない気もしますね。

ただし、あの回路図の2SC1815はなくして、上側のFETは[LOW]もしくは[ハイ・インピーダンス]で制御しました。
PSoCと回路を接続して、PSoCはArduinoから来た指令で動きます。
PSoCとArduinoはI2Cで通信します。
Arduinoの役目は、PSoCに指令することです。PSoCの役目はArduinoの指令通りにFETのゲートの開閉をすることです。
上側のFETに接続したPSoCのピンは、オープンドレインLOWに設定しました。PSoC内のレジスタに、0を書きこむとLOWが出力され、1を書きこむとハイインピーダンスが出力されます。つまり、0を書きこめばFETのゲートが開き、1を書きこめばFETのゲートが閉じます。
下側のFETに接続したPSoCのピンは、普通のHIGHもしくはLOWです。

結果:うまくいきませんでした。ドライブすると、I2C通信ができなくなりました。モータードライブ回路とPSoCの接続を電気的に切断すると、再びI2C通信ができるようになりました。

原因:様々な調査の結果、FETの入力容量が大きいため、FETのゲートを開こうとした時にPSoCのピンからFETのゲートに流れる電流が瞬間的に大きくなり、PSoCが不安定になることが推測されました。
2SJ334のCiss(入力容量)は3300pFです。
前回の記事にある回路を見ていただければ分かるように、PSoCのピンとFETのゲートの間に挟んだ抵抗は47Ωです。電源電圧は5Vですから、最大で約100mA流れる可能性があります(実際はもっと少ないはずです)。
ピン出力は10mAに抑えるべきです。
この原因を見つけるのにとても時間がかかりました。

解決方法:
パワーMOSFETのゲートにはマイコンのピンをつながず、小さいFETを間にかまして、制御しようと思います。
トランジスタを使わず小さいFETを使う理由は、トランジスタの方がFETのほうよりも反応時間が遅いからです。
また、パワーMOSFETのゲートとマイコンの間の抵抗をもっと高い抵抗にしFETを追加せずに、済ましてしまわない理由は、パワーMOSFETのゲートとマイコンの間の抵抗をもっと高い抵抗にすると、パワーMOSFET内のコンデンサ(入力容量)を充電するまでの時間が遅くなるからです。すると、ピン出力からゲートが開くまでの時間が遅くなります。
PWM制御をするにあたって、反応時間を早くすることは大切な事です。
追加するFETは、2N7000にしようと思っています。
”パワーMOSFETのゲートドライブなどのスイッチング用途に最適です”
と書いてありますので、まさに使いたいFETです。

 

回路を検証しながら気づいたことその①
「はじめてのPSoCマイコン」の68ページ上には

⑦オープン・ドレイン・ドライブLow('0' : ハイ・インピーダンス, '1' : High出力)
⑧オープン・ドレイン・ドライブHigh('0' : Low出力, '1' : ハイ・インピーダンス)

と書いてありますが、
70ページの回路図を見ても分かるように、

⑦オープン・ドレイン・ドライブLow('0' : Low出力, '1' : ハイ・インピーダンス)
⑧オープン・ドレイン・ドライブHigh('0' : ハイ・インピーダンス, '1' : High出力)

の間違いではないでしょうか?

 

回路を検証しながら気づいたことその②
オープンドレインで出力するときの注意ですが、
PRT0DR |= 0x02;
のように出力していると、
他のピンを出力するときに、オープンドレインに設定したピンに予期せぬ出力が行われることがあります。それは PRT0DR |= 0x02; は一度読み込み(入力)をしてから、出力しているからです。
これは、内部プルアップ抵抗を設定している時も同様です(問題となるのはオープンドレインよりもプルアップの方が多いでしょう)。
僕はしばらく気づかずにいていました。

 

回路を検証しながら気づいたことその③
I2C仕様書を見ていると、予約されたスレーブアドレスがあるとのことなので、それらのアドレスは使わないようにしなければなりません。

 

Hブリッジ回路部分↓

Img_1655_2

2N7000が手元になかったので、47Ωの抵抗を470Ωの抵抗に入れ替えてみました。
すると、正常に動作しました。
よって上に書いた推測した原因は正しいことが証明されました。
470Ωの抵抗に入れ替えても正常に動作しますが、反応時間を速くするため、2N7000が届けば、2N7000を用いて製作したいと思います。

470Ωの抵抗に入れ替えて動作確認したビデオ↓

2010年11月28日 (日)

超音波センサー…・・・・・・ ・ ・ ・

超音波センサーを
「はじめてのPSoCマイコン」
という本のサンプルプログラムを用いて作ってみたのですが、どう頑張っても50cmくらいまでしか測定できません…
一瞬であれば80cmくらいも測定できますが、それ以上の長さは無反応なのです・・
ただ、50cmくらいまでの測定の精度はそんなに悪くはありません。

本にはきちんと160cmくらい測定できている(と書いてある)のですが・・・

う~ん
どうしてうまくいかないか分かりません・・・

思いついた原因①
送信用超音波センサーにつなげるためのピンと受信用超音波センサーにつなげるためのピンを1回つないでしまったことがあります。
あとで分かったのですが、その時にAGND(受信用超音波センサーにつなげるためのピン)とVDD,VSS(送信用超音波センサーにつなげるためのピン)がショートしたのではないかと・・
その1回のショートでマイコン内の線が切れて受信もしくは送信が鈍っているのではないかと・・
ただ、50cmくらいまではきちんと測定できていることから考えると、これが原因ではない気がします。

思いついた原因②
本の超音波センサーと自分が使っている超音波センサーが違うから。
この原因は考えられそうです。

 

思いついた解決方法①
PSoCマイコンを交換してみる
ただ今はPSoCマイコンを1つしか持っていないので購入しないとできません。

思いついた解決方法②
本で用いられている超音波センサーと同じものを使う。
ただ、僕は32.8kHzの超音波センサーを作るのを目的としているため、この解決方法だと40kHzしか使えなくなってしまいます。

思いついた解決方法③
遠い距離が認識できないようなので
送信してから一定の時間が経ったらPGAの増幅率を引き上げる

そこでPGAの増幅率だけを上げてみると、送信した超音波の反響を受信してしまうみたいで、ずっと14cmになってしまいました。
そこで不感帯(反響による誤動作を防ぐため、送信してから一定時間受信しないようにする期間)を長くして同じくPGAの増幅率を上げた状態でやってみると、120cmくらいまで測定出来るようになりました^^;ただ不感帯を長くしたために、測定可能な最短距離が18cmになってしまいました。
以上の結果から言うと解決方法③は有効な気がします。

うーん・・
一定の時間が経ったらPGAの増幅率を引き上げるのは難しそうです・・・

2010年11月21日 (日)

IRセンサーのデータ解析

IRセンサーで取ったデータのグラフです(クリックすると拡大します)

Ir

センサーの値の取り方はいたってカンタン!
2000回デジタル入力してそのうち何回HIGHであったかというのがここで言うセンサーの値です。
赤外線リモコンモジュールは受信するとLOWになるので、ボールとの距離が近づけば値は小さくなります。

グラフを見てみると10cm違ってもあまりセンサーの値が変わらないことが分かります。

近似曲線を引いてみました。(7区間平均してみました)

Ir

これで、10cm以上誤差が出る確率は20%くらいに抑えることができました。

これらは処理によって誤差を少なくしようというものですが、それだと限界があり、また、ボールへの反応速度がガクンと落ちてしまうので、ハードウェアでも工夫しようと思います(というかハードの工夫の方が大切です)。

ちなみに前回の記事に書いたPSoCのCPU_Clockですが、SysClk/1にすると電源電圧が4.7Vを下回ったときに動作不可能になるようです。
ブレッドボードが錆び始めていて内部抵抗が高い→電圧が一瞬下がることがある→4.7V以下になったときに動作不可能になる
というのが原因で動作不可能になったと考えられます。

SysClk/2にしたら今のところ順調に動いています。

2010年11月20日 (土)

PSoCマイコンのCPU_Clock

IRセンサーの信号をPSoCマイコンで受け取っていたら、ブレッドボードの線を少し揺らすだけでPSoCマイコンが動作しなくなるという状況が起きました。

結局の原因を率直に言うと、CPU_ClockをSysClk/1にしていたからでした。
デフォルト設定はSysClk/8です。

CPU_ClockをSysClk/1にすると動作が不安定になることを確かめるため、次のような実験を行いました。
PSoCに電源が入ったらLEDを点灯させるだけのプログラムを入れました。デフォルト設定からCPU_ClockだけをSysClk/1に変更しました。電源を入れて、LEDが点灯します。そこで、ブレッドボードの線を少し揺らすといきなりLEDが暗くなりはじめて点灯したり消えたりするのです(大量にリセットがかかっていると考えられます)。
次に他は全く同じプログラムでCPU_Clockだけをデフォルト(SysClk/8)に戻します。電源を入れて、LEDが点灯します。それから、ブレッドボードの線を揺らしてもずっと点灯したままになるのです(正常な証拠)。

これらのことから、CPU_ClockをSysClk/1にするとかなり動作が不安定になる(というか動作不可能になる)ことが分かりました。ただ、なぜCPU_ClockをSysClk/1にすると動作不可能になるかは分かりません。なので、とりあえず、CPU_Clockはデフォルト設定のままにしておこうと思います。

 

今日、LPFやADCなしでIRセンサーの情報を読み取ることができました(今までのアナログブロックでの苦労はなんだったんでしょう・・?)。
IRM-3638を使い、PSoCマイコンでデジタル入力して演算しました。
ボールまで距離の誤差は+/-10cm以内くらいに収められました。(だいたいです)
このくらい正確に距離が分かれば制御もできそうです。
ボールがどこかに存在すればたとえボールがIRセンサー受光部の反対側にあってもIRセンサーは反応してしまいました。
でも、IRセンサー受光部の反対側にボールがあった場合、ボールまでの距離はかなり低く示される(光が弱いということ)ので大丈夫そうです(ちなみにIRセンサーは真正面の光によく反応し横からの光にはあまり反応しません。この性質はけっこう使えます)
まだ1つしかIRM-3638を買っていないので、これからやっていきたいと思います。

2010年11月18日 (木)

LPFを通したあとの波形

パルスボールの赤外線を赤外線リモコン受信モジュールで受けて、その信号をLPFに通してみました。LPFはPSoCマイコンの内部に作ることができるので外付け部品は要りません。

オシロスコープで波形を見てみました。
波形はそこそこキレイです。
2次フィルタは少しガタガタしていて4次フィルタはよりキレイな波形になりました。
4次フィルタでは50Hzで0dBで1000Hzで-100dBになるようにしました。
と・・いうことは50分の1秒くらいは遅れているということかも知れません(それ以上かも)。

IRセンサーのボールまでの距離の情報は、LPFを通しAD変換してから(これらの処理はPSoCマイコンで行って)メインコンピューターに送ろうと思っていたのですが、LPFやADCを使わなくても、たくさんデジタル入力を行って平均値を求めればデューディー比が分かる気がします(これだとPSoCじゃなくてもいけるではないか!)。
でも、LPFの出力をADCで読み取っても大丈夫そうなのでこのまま行こうかな・・と考えたりしています。

不安なことは、モーターを動かした時に放射ノイズによってデジタル通信(PSoCマイコンとメインコンピューターとのI2C通信のこと)に転送エラーがたくさん出てしまうかもしれないということですが、被害が出てから考えようと思います。(アナログで情報を送っても情報が曲げられるだけですが、デジタル通信は情報が途切れるのが欠点かなとは感じています。)

2010年11月17日 (水)

LPFやってみたが・・

PSoCマイコンのLPFブロックを使ってみたのですが全くうまくいかず・・
LPFブロックに与えるクロックを全く何も考えずにやったからだと思います。
うまくいかないのも当然です・・・
クロック周波数をきちんと考えて設定しようと思います。

2010年11月16日 (火)

簡単なミスほど見つかりにくく時間がかかる!?

PSoCでのADCのデーターをI2C通信でArduinoに送って液晶に表示させようとしたら、80035とか   -2405とか出たのであります(アラビックリ!!)。
なぜかを簡潔にいうと
バグその①PSoCのADCのデーターは12ビットの場合「-2048 ~ +2047」で表される。だからそのまま使うとマイナスが出るのは当たり前。
このバグはまだ納得できるのですが・・・
バグその②液晶でいちいちクリアしなきゃならなかった。いちいちクリアしないと、例えば"12345"と表示した後"800"と表示しようとすると、重なって"80045"と表示される。
そりゃ~変な値がでるはずです!
これを見つけるのに4時間くらいかかりました。ADCからは正しいデータが出ているかとか1つずつ原因をつぶしていっても奇妙なことが起こるので、う~~んとうなり、PSoCとArduinoにそれぞれ液晶につなげてどういう風にデーターが曲げられているかを眺めたら、あぁぁ~~なるほど!!となりました。
もう爆笑しました!何時間もバグを探し続けてこれですから!
同時に後悔と自分を責めるという気持ちとでもいいますか・・とにかくひどい!

でも、今日中に見つかってよかったかな?とポジティブになりつつ(?)、これを書いている次第でございます。
I2Cのエラーは今のところ出ていないです・・(たぶん)

明日もボチボチ頑張ります!

(あとちなみに、前の記事のI2C日本語仕様書はやはり誤植で原文が正しいようです)

2010年11月15日 (月)

ArduinoとPSoCのI2C通信(複数バイト)

2バイトでのArduinoとPSoCのI2C通信をしてみました。

PSoCではI2CHWブロックを使い、Arduinoがマスタ、PSoCがスレーブというように設定しました。

ここで注意すべきことがありまして、

たとえばPSoC側を
  dat = 1234;             //16進数で4D2になります
  buf_tx[0] = dat >> 8; //この場合0x04になります
  buf_tx[1] = dat;        //この場合0xD2になります
(buf_tx[n]とは送信するためのバッファ変数です。またdatはintでbuf_txはBYTEです。)
(PSoCマイコンではバッファ変数に送りたいものをあらかじめ入れておいて、マスタから送信しなさいと言われたら何も考えずにバッファ変数の内容を答えます。だから、マスタからいつ「送信しなさい!」といわれても良いようにあらかじめ言うことを準備しておきます。これらは、その準備のコードです。)

というコードにして、Arduino側で
  Wire.requestFrom(18,2);//1バイト要求することを宣言
  rd_data[1] = Wire.receive();//受信してrd_data[1]に代入
  rd_data[0] = Wire.receive();//受信してrd_data[0]に代入
という風に受信すると、
rd_data[1]には0x04が入り、rd_data[0]には0xD2が入ります。

つまり、PSoCでは「変数名[0]」にMSBを入れて、「変数名[n]」にLSBを入れなければいけないと考えられます。

普通上位バイトから受信して、後で下位バイトを受信すると思い込んでいるのですが、ArduinoのWire関数は少々ブラックボックス化されているので、確実ではありません。
ただ、PSoCのバッファ変数の[0]は、Arduinoでは最初に受信されるのは確かです。

配列の[n]のnが少ないほうが下位バイトで後から送信するのだと思っていた僕は混乱しました。

ともかく、Wire.receive();で最初に返されたデーター(つまり最初に何らかの変数に代入したデーター)は、I2Cで実際に最初に受信したデーターであるということがはっきりすればこれらが確実になるということでございます。

分かりにくい文章ですみませんが、Wire.receive();で最初に返されたデーターが、I2Cで実際に最初に受信したデーターであるかどうか分かる方は御教授ください。お願いします。

  

 

さて、ちなみに僕がなぜこんなにPSoCマイコンとArduinoとのI2C通信をやっているかというと、
IRセンサー ― PSoC ========== Arduino (===はI2Cでつなぐと思ってください)
という感じでつないで、
利点①Arduinoの少ないアナログ入力を節約でき、1つのArduinoでたくさんのIRセンサーと2本の線だけでつなぐことができる
利点②アナログでないので、(PSoCとArduinoの間の線が長くても)モーターからの外部ノイズの影響を受けにくい(たぶん・・)
利点③外付け部品がほとんどいらない
と考えているからです。
といいながら想像だけでIRセンサー部分がまったくできていないのですが・・・
早くI2C通信を終えてLPF(ローパスフィルタ)に移りたいと思います。

2010年11月11日 (木)

I2C通信によるArduinoと外部EEPROMの接続成功&PSoCの超音波センサの想像

I2C通信によるArduinoと外部EEPROMの接続に成功しました。使用したEEPROMはマイクロチップ社の24LC64です。

EEPROMのデーターシートを読んでがんばってプログラムを作ったのですが最初全く動きませんでした。
ひとつづつうまく動かない原因となるものを探していったのですが、まずは、EEPROMのアドレスはきちんと合っているということは確認できたのですが、うまく動かない原因はなかなか見つかりませんでした。
いろいろ検索していると、あるyou tubeの動画を見つけました。
自分のプログラムと照らし合わせてみると、delay(5);を送信と受信とかの間に挟んでいないことに気づき、半信半疑でやってみたら成功しました!!
たったそれだけなのに原因を見つけるのは大変です。
ただ、なぜdelayを入れなければいけないのかはまだ分かりません。

ロボットのデータロガーが取れたらまあ便利かなと思ってやったんですが、モーターもIRセンサーも方位センサーもまったくできていないのに僕はいったい何を目指しているのでしょうか・・・? 早くIRセンサーとかやらないと間に合わない・・・

ちなみにArduinoのWireライブラリは再度開始条件は使用できないみたいなのですが、停止条件を出したあと、何ミリ秒か空けて、開始条件を出せばEEPROMのデーターは読み込めるようです。

超音波センサの話ですが、PSoCマイコンで距離を計算してArduinoに送るのはやめようと思います。PSoCは難しいです!というわけでArduinoからPSoCに送信のタイミングを送信してPSoCは超音波が返ってきたと感知したらArduinoに送る、つまり、Arduinoで時間を計測して距離をだそうと思います。
メインArduinoとPSoCの超音波センサとの間にはスレーブArduinoを別に用意してそれに計算させようと思います。

Arduinoはスタートできるタイマーは僕が探した限り見つからなかったのですが、プログラムを開始(つまり電源を入れたとき)からの時間をμ秒で返してくれる関数があるので(micros)それを使おうと思います。最小分解能が4μ秒なので、音速340m/sのとき1.36mmの分解能で距離が測れるはずです。

まあ要するに難しいPSoCを頑張るよりもできるところはArduinoに任せてしまおうということであります。

2010年11月 4日 (木)

ArduinoとPSoCとのI2C通信成功!!

ArduinoとPSoCとのI2C通信が成功しました!
3時間弱、格闘して、やっと成功したのです!うれしい!3時間弱なのにとーっても長い道のりだった気がします。

今回実験したものは
①ArduinoがマスタでPSoCがスレーブ
②ArduinoとPSoCにそれぞれLEDとスイッチを1つずつつなぐ
③ArduinoとPSoCとの間はGND、VDD、SCL、SDAの4本だけでつなぐ
④Arduinoのスイッチを押したらPSoCのLEDが点灯し、PSoCのスイッチを押したらArduinoのLEDが点灯する
こういう単純なものです。

今回、成功するまでのバグを書きます。
①PSoCのLEDにつなぐピンを間違えていた→直した
②PSoCで内部プルアップがうまくいかなかった→内部プルアップは外して外部プルアップにした
③PSoCでのスイッチ割り込みがうまくいかなかった→割り込みはせず普通の入力にした
④PSoCで②の割り込みの設定を消すときにM8C_EnableGInt;というコマンドも消してしまってI2Cができなくなった→消してしまったM8C_EnableGInt;を初期化の位置に追加した

いまだに②と③は謎のままです・・・(とりあえずI2Cができたので今回はこれでよし!)

これらの目的は
①超音波センサーからArduinoに信号を送る際に、アナログ電圧でするとノイズによって距離の誤差が増えてしまうのではないかと考え、デジタルだとノイズの影響が少ないので、I2C通信で送れるようにするため。
②Arduinoはアナログ入力が少ないのでIRセンサーもI2Cにできれば、4本だけをArduinoにつなぐだけでよくなるから。
なお、目的①のノイズの影響についてですがアナログが劣化するというのはあくまで想像です。ただ、ノイズに強くなると強いモーターが使えて、ノイズによる誤動作の心配がいらなくなるかなと。

マスターは1個の予定なのでたぶん競合の心配はいりません。(というかArduinoって競合調停の機能ってあるんでしょうか?どっちでもいいですが・・・)

あとArduinoのI2Cってたぶん再度開始条件って使えないんですかね?(こっちは外部EEPROM用)
停止条件のあと開始条件を出すしかない気がするのですが・・