2003/02/05 【ソフトウエア編TOPに戻る】
今回はPICのA/D変換機能を使ってみましょう。PIC16F84AにはA/D変換機能が付いていませんので、今回もPIC16F873の出番ということになります。世の中にはツワモノがいて、外部に接続したコンデンサの充電時間を計測してPIC16F84AでA/D変換もどきをしてしまう人もいるようですが、ここでは素直に内蔵のA/D変換機能を利用することにします。
A/D変換とは連続的に変化するアナログ電圧量を、ある一定期間ごとに切り取って(サンプリングして)所定のビット数のデジタル値で近似する技術です。外界の事象を電気回路に取り込むためのセンサーの多くは、検知した情報をアナログ量で出力しますが、マイコンはデジタル値しか扱うことができないため、マイコンに取り込むためにA/D変換を行うわけです。PIC16F873では、最大で10BITのA/D変換出力を得ることができます。これは、アナログの基準電圧を5Vとした場合、5/1023 = 約5mVのアナログ電圧の変化をデジタルで取り込むことができるということです。
今回は、アセンブラでのA/D変換プログラムと、CCSのCコンパイラを使ったA/D変換プログラムの両方をご紹介します。ついでに、I2C通信を使って、ひとつのボリュームによって4個のサーボモータを同時に首振りさせるプログラムもご紹介しましょう。
318−1.PIC16F873のA/D変換
PIC16F873などの28ピンデバイスには、5チャンネルのA/D変換用アナログ入力がついています。ただし、PICの内部には1チャンネル分のA/D変換機能しか持っていないので、これらの入力端子からどれかひとつを選択して、A/D変換を実行する形となります。
A/D変換を行う場合に必要となるレジスタには以下の2つがあります。
■ADCON0レジスタの機能
A/D変換の動作設定を行います。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| ADCS1 | ADCS0 | CHS2 | CHS1 | CHS0 | GO/DONE | - | ADON |
ADCS1〜0:A/D変換のクロック選択
| ADCS1,0 |
クロック |
| 0 0 | Fosc/2 |
| 0 1 | Fosc/8 |
| 1 0 | Fosc/32 |
| 1 1 | Frc(RC発振) |
CHS2〜0:A/D変換アナログ入力チャンネル選択
| CHS2〜0 |
アナログチャンネル |
| 0 0 0 | CH 0 (RA0/AN0) |
| 0 0 1 | CH 1 (RA1/AN1) |
| 0 1 0 | CH 2 (RA2/AN2) |
| 0 1 1 | CH 3 (RA3/AN3) |
| 1 0 0 | CH 4 (RA5/AN4) |
| 1 0 1 | CH 5 (RE0/AN5) |
| 1 1 0 | CH 6 (RE1/AN6) |
| 1 1 1 | CH 7 (RE2/AN7) |
CH5〜7はPIC16F873ではサポートしていません。
GO/DONE:A/D変換ステータスビット
1 = A/D変換中(このビットをセットするとA/D変換を開始する)
0 = A/D変換中ではない(変換が終了すると自動的にクリアされる)
ADON:A/D変換ONビット
1 = A/D変換モジュールを動作させる
0 = A/D変換モジュールを使用しない。消費電流なし。
■ADCON1レジスタの機能
A/D変換の基本設定を行います。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| ADFM | - | - | - | PCFG3 | PCFG2 | PCFG1 | PCFG0 |
ADFM:A/D結果のフォーマット選択
1 = 右詰 ADRESHの6MSBは「0」とリードされる。
0 = 左詰 ADRESLの6LSBは「0」とリードされる。
A/D変換結果の10BITは、ADRESHとADRESLの2個の8ビットレジスタに格納されます。その時、以下の2種類のフォーマットから格納方法を選択できるということです。
【右詰】:A/D変換結果のLSB8ビット分を取り出し安いフォーマットです。
| ADRESH | ADRESL | |||||||||||||||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| - | - | - | - | - | - | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
【左詰】:A/D変換結果のMSB8ビット分を取り出しやすいフォーマットです。
| ADRESH | ADRESL | |||||||||||||||
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - | - | - | - | - | - | |
PCFG3〜0:A/Dポートの構成選択
|
PCFG 3-0 |
AN7 RE2 |
AN6 RE1 |
AN5 RE0 |
AN4 RA5 |
AN3 RA3 |
AN2 RA2 |
AN1 RA1 |
AN0 RA0 |
Verf+ |
Vref- |
Chan/ Refs |
| 0 0 0 0 | A | A | A | A | A | A | A | A | VDD | VSS | 8/0 |
| 0 0 0 1 | A | A | A | A | Vref+ | A | A | A | RA3 | VSS | 7/1 |
| 0 0 1 0 | D | D | D | A | A | A | A | A | VDD | VSS | 5/0 |
| 0 0 1 1 | D | D | D | A | Vref+ | A | A | A | RA3 | VSS | 4/1 |
| 0 1 0 0 | D | D | D | D | A | D | A | A | VDD | VSS | 3/0 |
| 0 1 0 1 | D | D | D | D | Vref+ | D | A | A | RA3 | VSS | 2/1 |
| 0 1 1 x | D | D | D | D | D | D | D | D | VDD | VSS | 0/0 |
| 1 0 0 0 | A | A | A | A | Vref+ | Vref- | A | A | RA3 | RA2 | 6/2 |
| 1 0 0 1 | D | D | A | A | A | A | A | A | VDD | VSS | 6/0 |
| 1 0 1 0 | D | D | A | A | Vref+ | A | A | A | RA3 | VSS | 5/1 |
| 1 0 1 1 | D | D | A | A | Vref+ | Vref- | A | A | RA3 | RA2 | 4/2 |
| 1 1 0 0 | D | D | D | A | Vref+ | Vref- | A | A | RA3 | RA2 | 3/2 |
| 1 1 0 1 | D | D | D | D | Vref+ | Vref- | A | A | RA3 | RA2 | 2/2 |
| 1 1 1 0 | D | D | D | D | D | D | D | A | VDD | VSS | 1/0 |
| 1 1 1 1 | D | D | D | D | Vref+ | Vref- | D | A | RA3 | RA2 | 1/2 |
PCFG3〜0にセットするビットによって、RE2〜0,RA5〜0の各端子を通常のPIOとして利用するか、アナログ入力端子として利用するかを、上のパターンから選択します。Vref+とVref-は、電源電圧VDD、電源GND VSS以外をA/D変換の基準電圧にしたい場合に利用するものです。Chan/Refsで示しているものは、それぞれのパターンにおいてのアナログ入力チャンネル数/外部基準電圧入力端子数を示しています。
逆に言うと、端子の用途を上記以外のパターンで構成することは出来ませんので、ハードウエアを組むときには、予めどのパターンにするかを決めておかなければなりません。
ちなみに、AN7〜AN5はPIC16F873ではサポートしていません。
PICのA/D変換では、これらのレジスタを使ってA/D変換機能を実行させます。実際の使い方は、この後のアセンブラによるプログラム事例を見て頂くと良く分かります。
318−2.アセンブラでのA/D変換プログラム例 adtest1.asm
このプログラムでは、AN0チャンネルから0V〜5Vのアナログ電圧を入力し、A/D変換結果を左詰フォーマットにして上位8ビットをPORTBに出力することを永遠に繰り返します。AN0チャンネルにボリュームを接続すれば、ボリュームツマミを左右に回転させることによってPORTBに接続された8ビットのLEDの2進数表示が上下します。
ソースコードはここをクリックするとダウンロードできます。adtest1.asm また、実験のハードウエア環境は、PIC学習用ボードと簡易型実験用I/Oボードを組み合わせて使用します。
| ;********************************************************************** ;A/D CONV TEST1 RIKIYA 2001.11.08 ;DEVICE : PIC16F873 ;CLOCK : 20MHz ; ;********************************************************************** list p=16F873 #include <p16F873.inc> __CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _LVP_OFF TCNT EQU 20H ;********************************************************************** ORG 0x000 ; processor reset vector GOTO MAIN ; go to beginning of program MAIN BSF STATUS,RP0 ;メモリーバンクを1にセット CLRF TRISB ;TRISBをクリア PORT-Bを出力にセット MOVLW 081H ;Wレジスタに81Hをセット MOVWF OPTION_REG ;OPTION_REGに81Hをセット PORT-B PULL UPなし MOVLW 00EH ;Wレジスタに0EHをセット MOVWF ADCON1 ;CH0のみAIN REF = VDD MOVLW 001H ;Wレジスタに01Hをセット MOVWF TRISA ;TRISAに01Hをセット PORT-A0だけを入力 BCF STATUS,RP0 ;メモリーバンクを0にセット ;*********************************************************************** ;A/D変換処理を繰り返す ;*********************************************************************** LOOP MOVLW 081H ;Wレジスタに81Hをセット MOVWF ADCON0 ;ADCON0に81Hをセット A/D CH0,Fosc/32,CHARGE CALL ADWAIT ;20uSの待機 BSF ADCON0,GO ;ADCON GOビットを1にセット 変換開始 WAIT BTFSC ADCON0,GO ;GOビットが0なら、次の命令をジャンプ GOTO WAIT ;ラベルWAITに戻る MOVF ADRESH,W ;AD変換データを取り込む MOVWF PORTB ;データをPORT-Bに出力 CALL ADWAIT ;1アクイジション待機 GOTO LOOP ;ラベルLOOPに戻る ;*********************************************************************** ;20uSのタイマ ;20MHz 1サイクル 0.2uS ;100サイクルx0.2uS = 20uS ;*********************************************************************** ADWAIT MOVLW 020H ;1 Wレジスタに20H(32)をセット MOVWF TCNT ;1 TCNT変数に1AHをセット NOP ;1 TLOOP DECFSZ TCNT ;1x31+2 TCNT-1を行い0になったら次の命令ジャンプ GOTO TLOOP ;2x31 ラベルTLOOPに戻る RETURN ;2 戻る END |
ソフトの動作については、コメント文が全てです。なので、細かな解説は省略させて頂きますが、ここでは要点だけを説明することにしましょう。
MOVLW
00EH
;Wレジスタに0EHをセット
MOVWF
ADCON1 ;CH0のみAIN REF = VDD
MOVLW
001H
;Wレジスタに01Hをセット
MOVWF
TRISA
;TRISAに01Hをセット PORT-A0だけを入力
MAINラベルから4行後に上記の記述があります。ここでは、ADCON1レジスタに0EH(0000 1110)を書き込んでいます。ADCON1レジスタの機能は以下のような意味でした。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| ADFM | - | - | - | PCFG3 | PCFG2 | PCFG1 | PCFG0 |
| 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
なので、ここでは「A/D変換結果を左詰で格納し、AN0チャンネルのみをアナログ入力にする」という意味になります。
そしてすぐ後に、PORTAの0ビットだけを入力に設定しています。これは、アナログ入力に指定したビットは、TRISレジスタによって入力端子に設定しなければならないためです。これを忘れると、A/D変換機能は正常に動作しないので注意してください。
LOOP
MOVLW
081H
;Wレジスタに81Hをセット
MOVWF
ADCON0 ;ADCON0に81Hをセット A/D CH0,Fosc/32,CHARGE
CALL
ADWAIT ;20uSの待機
BSF
ADCON0,GO ;ADCON GOビットを1にセット 変換開始
WAIT
BTFSC
ADCON0,GO ;GOビットが0なら、次の命令をジャンプ
GOTO
WAIT
;ラベルWAITに戻る
次に、実際のA/D変換処理を開始します。先ず始めに、ADCON0レジスタに81H(1000 0001)を書き込んでいます。ADCON0レジスタの機能は以下のような意味でした。
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| ADCS1 | ADCS0 | CHS2 | CHS1 | CHS0 | GO/DONE | - | ADON |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
なので、ここでは「A/D変換クロックをFosc/32にして、A/D変換の動作をONにする」という意味になります。ここで、A/D変換の動作をONにするということは、具体的にはA/D変換入力のサンプルホールド回路に、入力電圧を充電(チャージ)するということです。
アナログ量をデジタル値に変換するには一定の時間が必要です。1ビット当たりの変換時間はTadとして定義されており、例えばデバイスのクロックが20MHzのときにFosc/32の設定にしてあると、Tadは1.6μSになるようです。10ビットのA/D変換では12Tad分の時間が必要になることから、19.2μSの変換時間が必要になるということになります。
例えば、この19.2μSの間に入力されるアナログ電圧が変化してしまうと、サンプリングしたい瞬間の電圧値を正確にデジタルに変換することができません。そこで、A/D変換器には入力電圧を充電して一定に保つためのサンプルホールド回路という部分があります。ADONビットを1にするということは、この充電を開始するという動作になります。
ADCON0レジスタに上記の値をセットした後、ADWAITというラベル部分をCALLして、20μSの時間潰しをしています。これは、サンプルホールド回路に入力電圧が充電される時間を確保しています。この時間が短いと、デジタルに変換される値は、実際の入力電圧よりも常に小さめになります。
20μSの待機後、ADCON0レジスタのGOビットを1にセットして、実際のA/D変換を開始します。
A/D変換には先ほどご紹介したように12Tad分の時間が必要なため、
WAIT
BTFSC
ADCON0,GO ;GOビットが0なら、次の命令をジャンプ
GOTO
WAIT
;ラベルWAITに戻る
でA/D変換が終了するまで待機しています。ADCON0レジスタのGOビットは、A/D変換が終了すると自動的に0にクリアされるため、GOビットが1の間ループで時間潰しをしています。
MOVF
ADRESH,W ;AD変換データを取り込む
MOVWF
PORTB
;データをPORT-Bに出力
CALL
ADWAIT ;1アクイジション待機
GOTO
LOOP
;ラベルLOOPに戻る
あとは、ADRESHレジスタからA/D変換結果の上位8ビットを取り出し(左詰なので)、ポートBに出力しています。出力後にもう一度ADWAITがCALLされているのは、次の入力電圧の充電を開始するまでの間に待機時間を設けなければならないためです。本当は2Tadだけ待てばよいのですが、ここではすでに存在しているサブルーチンを使ってしまっています。その後LOOPラベルに飛んで、再度A/D変換を繰り返します。
ADWAITのサブルーチンでは、20μSの待機時間を作り出しています。待機時間の生成については、312.PICの実行速度を予測するのページを参照して下さい。
318−3.CCS CコンパイラでのA/D変換プログラム例 adtest11.c
次に、adtest1.asmと同じことを、C言語で組んでみましょう。
ソースコードはここをクリックするとダウンロードできます。adtest11.c また、実験のハードウエア環境は、先ほどと全く同じです。
| ////////////////////////////////////////////////// // A/Dテストプログラム // // PIC16F873 RIKIYA 2003.01.16 // // ADTEST11.C // // AN0チャンネルからアナログ入力してRBに出力 // ////////////////////////////////////////////////// #include <16f873.h> #fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #device ADC=10 // 10BIT A/D変換 #use delay(clock = 10000000) // clock 10MHz #use fast_io(B) // 固定入力モード //メイン関数//////////////////////////////////// main(){ long data; set_tris_b(0x00); // RB 7-0:OUT setup_adc_ports(RA0_ANALOG); // AN0チャンネル有効 setup_adc(ADC_CLOCK_DIV_32); // Fosc/32 while(1){ set_adc_channel(0); // ANチャンネルの選択 delay_us(20); // 充電時間の待機 data = read_adc(); // A/Dデータの読み込み output_b(data >> 2); // 上位8bitのデータを表示 } } |
先にご紹介したアセンブラで記述したプログラムと同じ機能が、C言語ではこれだけの記述で実現できます。ソースコード中の記述はCCSのCコンパイラ上の約束ごとばかりで、全てコメント文に記載されている通りですので、ここでの解説は省略させて頂きます。
このように、C言語にすると見た目にも簡単で分かりやすいソースで済んでしまいます。
しかし、PICに流し込むHEXファイルの大きさで見てみると、以下のような開きがあるのも事実です。
| アセンブラでのHEXファイル | 186バイト |
| CコンパイラでのHEXファイル | 357バイト |
どちらが良いかは、開発効率、HEXファイルの容量、実行時間の管理、必要な記述のきめ細かさなどから総合的に判断して選ぶのが良いでしょう。
318−4.I2C通信を利用した4個のサーボモータの首振り adtest2.c
ここまででご紹介したA/D変換のプログラム例ではちょっとつまらないので、I2C通信との組合せの事例をご紹介しましょう。ただし、C言語だけですが...。
ここでは、マスターとなるPICにボリュームを取り付けてA/D変換を行い、取り込んだデジタル値をI2C経由で4個のスレーブとなるPICに送ります。スレーブでは受け取ったデータに基づいてPWM波形を出力し、サーボモータの首振りを行います。なので、ここでは4個のサーボモータが同時に、同じように首振りをするという動作になります。
以下にマスター用とスレーブ用のプログラムを、それぞれご紹介しましょう。
■マスター用プログラム
ソースコードはここをクリックするとダウンロードできます。adtest2.c また、実験のハードウエア環境は、PIC学習用ボードと簡易型実験用I/OボードとI2Cテストボードを組み合わせて使用します。
| ////////////////////////////////////////////////// // A/Dテストプログラム // // PIC16F873 RIKIYA 2003.01.16 // // adtest2.C // // I2Cマスター役となりA/Dからの入力をもとに // // スレーブ4個のPWM制御をする // ////////////////////////////////////////////////// #include <16f873.h> #fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #device ADC = 10 // 10BIT A/D変換 #use delay(clock = 10000000) // clock 10MHz #use fast_io(B) // 固定入力モード #use i2c(MASTER,SDA=PIN_C4,SCL=PIN_C3,FAST,FORCE_HW) int add[4] = {0,2,4,6}; //スレーブアドレス //メイン関数//////////////////////////////////// main(){ int i; long data; setup_adc_ports(RA0_ANALOG); // AN0チャンネル有効 setup_adc(ADC_CLOCK_DIV_32); // Fosc/32 set_tris_b(0xf0); //RB 7-4:IN 3-0:OUT set_tris_c(0x00); //RC 7-0:OUT output_float(PIN_C3); //I2C pin float output_float(PIN_C4); //I2C pin float // 4個のサーボの首振りを繰り返す while(1){ set_adc_channel(0); // ANチャンネルの選択 delay_us(20); // 充電時間の待機 data = read_adc(); // A/Dデータの読み込み for(i=0;i<4;i++){ i2c_start(); //スタートコンディション i2c_write(add[i]); //アドレスaddに送信 i2c_write(data >> 2); //データ上位8bitを送信 i2c_stop(); //ストップコンディション delay_ms(3); } } } |
プログラムの内容としては、先ほどご紹介したadtest11.cと、316.PICでI2C通信のページでご紹介しているI2C通信プログラムを合体させただけですので、細かな説明は省略させて頂きます。
送信したいスレーブのアドレスをadd[4] = {0,2,4,6};で配列変数に格納し、 for文の中のi2c_write(add[i]);で送信しています。i2c_write(data >> 2); で、10ビットデータの上位8ビットだけをデータとして送信しています。
■スレーブ用プログラム
ソースコードはここをクリックするとダウンロードできます。picpwm21s.c
| ////////////////////////////////////////////////// // PWMテストプログラム21(2改) // // PIC16F873 RIKIYA 2003.02.01 // // picpwm21s.c // // I2Cスレーブ役としてマスターからのデータに // // 基づいてサーボモータを動かす。 // // スレーブアドレスは、PB4〜7ビット // // から読み込むデータで自動設定する // ////////////////////////////////////////////////// #include <16f873.h> #fuses HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use delay(clock = 10000000) // clock 10MHz #use fast_io(B) // 固定入力モード #use i2c(SLAVE,SDA=PIN_C4,SCL=PIN_C3,ADDRESS=0x00,FAST,FORCE_HW) void add_set(int add); // プロトタイプ宣言 void ccp1_int(void); // プロトタイプ void ccp2_int(void); // プロトタイプ //メイン関数///////////////////////////////////////// void main (){ int *sspcon = (int *)20; //変数*sspconにSSPCONのアドレス20をセット long data; setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); setup_ccp1(CCP_COMPARE_INT); // CCP1コンペアマッチ割込み設定 setup_ccp2(CCP_COMPARE_INT); // CCP2コンペアマッチ割込み設定 set_timer1(0x0000); // TMR1クリア CCP_1 = 3752; // パルス幅 0.4u * 1 * 3752 = 1.5mS CCP_2 = 50000; // 周期 0.4u * 1 * 50000 = 20mS set_tris_b(0xf0); //RB 7-4:IN 3-0:OUT set_tris_c(0x18); //RC 4,3:IN 7-5,2-0:OUT output_float(PIN_C3); //I2C pin float output_float(PIN_C4); //I2C pin float output_b(0x01); //正常起動確認 // スレーブアドレス設定 add_set((input_b() >> 3) & 0x0e); enable_interrupts(INT_CCP1); //CCP1コンペアマッチ割込み許可 enable_interrupts(INT_CCP2); //CCP2コンペアマッチ割込み許可 enable_interrupts(GLOBAL); //全ての割り込みを許可 while (1) { *sspcon = *sspcon & 0xBF; //OVFのクリア data = i2c_read(); //データ受信 if(data != 0){ CCP_1 = 2500+(data*10); //パルス幅の設定 output_b(data); //受信データのモニタ } } } //パルスクリア/////////////////////////////////// #INT_CCP1 void ccp1_int(){ output_bit(PIN_C2,0); // RC3BITを0にする。 } //パルス出力///////////////////////////////////// #INT_CCP2 void ccp2_int(){ if(CCP_1 != 0x0000){ // CCP_1が0でなければ、 output_bit(PIN_C2,1); // RC3BITを1にする。 } set_timer1(0x0000); // TMR1クリア } //アドレス自動設定//////////////////////////////////// void add_set(int add){ int *sspadd = (int *)147; // 変数*sspaddにSSPADDのアドレス147をセット *sspadd = add; // SSPADDレジスタにアドレスをセット } |
このスレーブ側のプログラムは、317.PICでサーボを動かすのページでご紹介したpicpwm2.sの改良版です。基本的には同じですが、以下の点を付け加えています。
先ず、*sspconというポインタ変数にアドレス20を設定しています。これにより、sspconレジスタを操作できるようにしています。
int *sspcon = (int *)20; //変数*sspconにSSPCONのアドレス20をセット
次に、data = i2c_read();でデータ受信を行う前に、*sspcon = *sspcon & 0xBF; を実行しています。これは、sspconのビット6(オーバーフローフラグ)をクリアするための処理です。
*sspcon = *sspcon & 0xBF;
//OVFのクリア
data = i2c_read(); //データ受信
if(data != 0){
CCP_1 = 2500+(data*10); //パルス幅の設定
output_b(data); //受信データのモニタ
}
高速ループで繰り返しデータの送受信を行う場合、スレーブ側が受信データレジスタから受信データを読み出す前に、マスター側から次のデータが送られてきてしまう場合があります。このときsspconレジスタのオーバーフローフラグが立ち、ソフト上で明示的にクリアしてあげるまで正常なデータ受信が再開できません。
今回、マスター側からのデータ送信の間隔が早く、スレーブ側の受信準備とうまくタイミングが合わずにオーバーフローを起こしてしまうため、上記のような処理でフラグをクリアしています。
ちなみに、オーバーフロー状態に陥ると、受信データとして自分のスレーブアドレスが取り出されるという現象が起き、それ以降の通信が出来なくなるようです。上記のようにフラグをクリアしてあげると、どんなに早く送受信を繰り返しても、通信動作は保たれることが確認できました。
しかし、たまに取りこぼしを起こすのか、受信データが0になる現象が数秒に1度の割合で起こる場合があります。そため、サーボの首振りがたまにピク付くことがあります。残念ながら原因の追求までには至っていませんが、とりあえず「くさいものにはふたをする」という精神のもと、if(data != 0){ } 文によってピク付きを抑えています。
318−5.I2C実験風景
以下の写真が、I2C通信を使ったA/D変換実験の風景です。
![]() |
右上の基板がI2Cテストボードでスレーブ用のPICが4個実装されています。右下の基板がPIC学習用ボードで、マスター用のPICとして利用しています。左側の基板が簡易型実験用I/Oボードで、A/D変換入力とPWM出力のコネクタ変換を行っている部分です。 写真の下側にポテンショメータが写っていますが、これを廻すと写真上側のサーボ4個が同じように首振りをします。 |
実際問題としてポテンショメータでサーボを制御するという用途にわざわざI2Cを使うということ自体、本当に必要なのか?という点が疑問ではありますが、I2C通信とA/D変換を組み合わせた事例のひとつとしてご紹介してみました。
力弥としては、これをステップとしてI2C通信を使ったギヤードモータのサーボ化に進むのが目的です。351.ギヤードモータのサーボ化1や352.ギヤードモータのサーボ化4CH対応のページでご紹介している角度制御を改良し、もっとレスポンス良く精度の高い角度制御にしたいと思っていますので、その取り組みは、また追ってご紹介したいと思います。