2016-11-08 20:24 | カテゴリ:PIC応用回路


以前にマイコン内蔵のフルカラーLEDをPICで制御して、宇宙家族ロビンソンのロボット「フライデー」の口に仕込んで光らせていました。
あの時は、WEBでいろいろ探して、LEDをドライブする部分だけアセンブラで記述して、高速性を確保しつつ、他の部分はXC8で製作していました。

今回、新しいPIC(16F1716)で複数のPWMやタイマー、あるいはある程度自由の利くロジック回路までが内蔵され、これをうまく使えばシフトレジスタ(MSSPのSPI通信)でアセンブラ部分を置き換えることができるのではないかと考えて、挑戦してみました。

先に結果を言いますと、「残念でした」

マイコンLEDの制御は、短いパルスとちょっと長いパルスを、0と1に見立ててシリアル通信で行うのですが、このパルスの波形の仕様が結構厳しく、結果的に思うようにいきませんでした。
「反面教師」ということで、失敗したところまでちょっと説明させていただきますと、、、

LEDのデータシートでは、

「0」= Hが0.35マイクロ秒  Lが2マイクロ秒のパルス
「1」= Hが1.36マイクロ秒  Lが1.3マイクロ秒のパルス

となっています。
これをRGB各色8ビットで、合計24ビットのデータを送れば、LEDが発色します。

新しいこのPICには、PWMが2系統あり、TMR2をクロックとしてPWMを制御しています。
一方、シフトレジスタとして使用したいSPI通信は、TMR2をクロックに選択できますが、この周波数の1/2でしか駆動できません。
つまり、PWMパルス2個でシフトレジスタの送信が1ビット分となるわけです。
これが第一の問題です。


次に、PWMとSPI通信のクロックを先日導入したロジアナで調べてみたら、なんとPWMの位相とSPIのクロックの位相がズレていることがわかりました。

Phase001.jpg


これでは、PWMの立ち上がり(あるいは立下りのタイミング)とSPI通信クロックのタイミングがずれて、通信データが同期されません。
これが第二の問題。

ただでさえ、0.3マイクロ秒のパルスを送り出すようなシビアな時間計算で動作させるように考えているのに、0.2マイクロ秒も位相がズレていました。

そこでこれらを考慮して、なんとか仕様に合うようなパルスを作ろうと、工夫したのですが、どうも条件に合わせることがむつかしく、近い波形は得られましたが、LEDが動作するには至りませんでした。

Phase002.jpg


この一番下の波形です。

「0」= 0.3マイクロ秒くらい(幅の狭いほう)
「1」= 1.0マイクロ秒くらい(幅の広いほう)

特に、「1」のパルス幅がかなり不足しているようです。
これではちょっと動かないなぁ(笑)

というわけで、新しいロジアナの操作にはちょっと慣れてきました。(任意のピンで計測開始トリガーもかけられます)

追伸:下記のBLOGでも同様にPICでSPIを使用してトライしている人がありましたが、いまだに成功できていないようです。

https://sanje2v.wordpress.com/2013/07/10/controlling-rgb-led-strips-ws2811-chip-with-pic16f877a/#comment-253


で、ここで諦めてこのままスルーするのも後味が悪いので、以前に製作したアセンブラを組み込んだCPU付きLEDの制御プログラムを関数としてアップします。
ご興味のある方は、追試などされてはいかがでしょうか?

関数の形です。


//-------------------------------------------------------------------
// r,g,bに1バイトのRGBの各輝度データをセットしてDisp_CPU_LEDを呼ぶと
// そのデータをシリアル変換して RC1 から出力する関数
// あらかじめRC1を出力用に設定する事
// 下記のPORTC,1 を希望のポートに変更しても可
//--------------------------------------------------------------------

void Disp_CPU_LED(unsigned char r, unsigned char g, unsigned char b) {

volatile unsigned char rr, gg, bb, c; //ローカル変数
rr = r;
gg = g;
bb = b;


  // GIE = 0; // 割り込み禁止にセット(必要に応じて)

#asm // ここからアセンブラの記述

putbit MACRO var, bit // ビット操作のマクロを定義する
btfsc var, bit // var変数の所定のビットをチェックし1なら61行へ

// goto $ + 7 // ジャンプする

goto $ + 8
bsf PORTC, 1 // 0ならRC1をHにして
nop // 約2マシンサイクル(20MHzの場合は0.4マイクロ秒)後に
bcf PORTC, 1 // Lに戻す
nop // Lのまま4マシンサイクル維持しマクロ終了
nop
nop
goto $ + 9

bsf PORTC, 1 // 1ならRC1をHにして(61行目)
nop // 約7マシンサイクル(1.4マイクロ秒)後に
nop
nop
nop
nop
nop
bcf PORTC, 1 // Lに戻す
//Lのまま2マシンサイクル維持し、マクロ終了

ENDM

BANKSEL Disp_CPU_LED@rr // 変数rr(RED)の場所にバンクを切り換える
putbit Disp_CPU_LED@rr, 7 // RED dataのビット7から順次チェックする
putbit Disp_CPU_LED@rr, 6
putbit Disp_CPU_LED@rr, 5
putbit Disp_CPU_LED@rr, 4
putbit Disp_CPU_LED@rr, 3
putbit Disp_CPU_LED@rr, 2
putbit Disp_CPU_LED@rr, 1
putbit Disp_CPU_LED@rr, 0

putbit Disp_CPU_LED@gg, 7 // Green
putbit Disp_CPU_LED@gg, 6
putbit Disp_CPU_LED@gg, 5
putbit Disp_CPU_LED@gg, 4
putbit Disp_CPU_LED@gg, 3
putbit Disp_CPU_LED@gg, 2
putbit Disp_CPU_LED@gg, 1
putbit Disp_CPU_LED@gg, 0

putbit Disp_CPU_LED@bb, 7 // Blue
putbit Disp_CPU_LED@bb, 6
putbit Disp_CPU_LED@bb, 5
putbit Disp_CPU_LED@bb, 4
putbit Disp_CPU_LED@bb, 3
putbit Disp_CPU_LED@bb, 2
putbit Disp_CPU_LED@bb, 1
putbit Disp_CPU_LED@bb, 0
#endasm
// GIE = 1; // 必要なら上記処理中の間、割込みを禁止にしてください。その際は、
// 処理を終える際に、割込み許可をONに。
}


このプログラムで出力されるパルス波形の例です。


CPU_LED_asem.jpg

上の二つの波形は同じものです。
【ジャンル】:趣味・実用 【テーマ】:電子工作
コメント(2)

管理者のみに表示する