センサレスブラシレスDCモータ
T.北斗ボードを使った実験
U.ESCを使った実験
T.北斗ボードを使った実験
ブラシレスモータに取り組んでみました。ここでは、HOKUTO DENSHI 製ブラシレスモータドライブボード+コンパレータボードBLM_R8C1 VER2.1(非売品)を使ってセンサレスブラシレスDCモータを回してみました。コンパレータボードBLM_R8C1 VER2.1はコンパレータ回路3個内蔵のボードです。コンパレータ信号をINT割り込みに使用してブラシレスモータを制御しています。

ブラシレスモータドライブボード |

コンパレータボード+CPUボード |
 ブラシレスモータ |
(1)ブラシレスモータの動作原理
ここでは、下図のように互いに120度に配置された3相の電磁コイルU、V、Wを持つ、ブラシレスモータについて考えてみます。動作原理の説明はRENESASのサイトに解りやすく解説されています。
◎ロータリースイッチによる実験
モータコイルの通電パターンを、W(+)V(-) → U(+)V(-) → U(+)W(-) → V(+)W(-) → V(+)U(-) → W(+)U(-)
のように60度毎の変化を繰り返すことによってコイル磁束を変化させ、回転子と永久磁石との間にトルクを生じさせ、CW(時計回り)方向に回転します。 反時計回り(CCW)に回したいときには、上とは逆方向に通電パターンを変化させます。確認のため、2入力12接点のロータリースイッチを使って手動で回転させてみました。

ブラシレスモータ断面 |
 ブラシレスモータと手動ロータリースイッチ |
◎ボード側との結線
その他、U、V、W相共通にANDゲートに繋がった+側QU端子、−側QL端子があります。QU端子、QL端子にRBタイマの出力を入力し、全体のモータ駆動信号をPWM制御しています。また、モータドライブボード上の半固定抵抗VRの値をマイコン側のP1_7に接続し、AD変換して読み込み、周期25μsのPWM波形のデユーティ比を変えて速度制御しています。
モータドライブボード側
コンパレータボード側 |
R8C/M12A側 |
| Q1U(5) |
P1_6 |
| Q1L(4) |
P1_4 |
| Q2U(7) |
P4_7 |
| Q2L(6) |
P4_5 |
| Q3U(9) |
P3_7 |
| Q3L(10) |
P3_5 |
| QU(11) |
P4_2(PWM信号)出力 |
| QL(12) |
P4_2(PWM信号)出力 |
| VR(13) |
P1_0(AD変換)入力 |
| FET温度(20) |
P1_3(AD変換)入力 |
| ドライブ電流(21) |
P1_2(AD変換)入力 |
| コンパレータ U相 |
P3_3(INT3) |
| コンパレータ V相 |
P3_4(INT2) |
| コンパレータ W相 |
P1_7(INT1) |
| UART0(TXD0) |
P4_6 |
| UART0(RXD0) |
P1_5 |
(2)コンパレータボード
電力消費を抑えて効率良く回転させるためには、通電させるタイミングが重要になります。そのためには、回転子の位置を知る必要があります。ここで扱うブラシレスモータはセンサレスブラシレスDCモータですので、回転子の位置を検出し通電タイミングをとるためにコイルの誘起電圧を検出して位置を推定します。詳しい理論や解説は専門書に譲るとして、それぞれの相の誘起電圧が正から負、負から正に変わるゼロクロス点の組み合わせが通電させるタイミングの目安になります。ここでは、ゼロクロス点を検出するために、誘起電圧をコンパレータに入力して、その出力信号を利用してタイミングをとっています。3相の誘起電圧の和(U相+V相+W相)の値は常に平均値0、一定となりますので、3相の誘起電圧の和とU相の誘起電圧とをコンパレータに入力し、出力値をp3_3(INT3)に、また同じように、V相と比較した出力値をp3_4(INT2)に、W相と比較した出力値をP1_7(INT1)に入力します。使用したコンパレータボードの回路は下図のようになります。
コンパレータボード


U、V、W相の誘起電力信号は、ブラシレスモータボードのLPF(Low Pass Filter)を経由したAD0〜AD2の信号を入力として使っています。

(4)プログラム
参考文献等によるゼロクロス法の解説では、通電タイミング、誘起電力、コンパレータの出力信号の関係から、通常はゼロクロス点の中間点がコイルの電磁切り換え位置になります。その位置を検出するためにコンパレータからのそれぞれの出力信号の重なる部分の長さをカウントし、その中間地点を計算することになります。コイル誘導電圧は、本来、U相の場合はUVとUWの中間地点にピークがきます。V相はVWとVUの中間地点に、W相はWUとWVの中間地点にピークがきます。しかし、実際の出力波形を観察した上図からわかるように、かなり本来の位置より右側に遅れて出ています。そこで、実際の通電タイミングをあえてゼロクロス点の中間点を計算によって検出することはせず、コンパレータ出力信号をINT割り込みに使用して、INT3(U相)、INT2(V相)、INT1(W相)を利用して、コンパレータ信号の立ち上がり、立ち下がり位置で切り換えるようにしてみました。6カ所ある通電タイミング切り替えの全てに使用しています。回るタイミングを実験しながらプログラムした結果が下記のプログラムなっています。正しい切り替えポイントで切り替わっているかどうかは確信がありませんが、。とりあえずは、消費電流も少ない状態で極めて高速で回転させることができていますので、切り換えのタイミングがうまくかみ合っていると考えています。 PWM周期25μS、回転開始時、duty60%、外部供給電圧5V、0.85A、8,000RPM、最低、duty25%、0.3A、2、000 RPMの範囲で変速コントロールしています。
下のプログラムで使用しているモータは、アウトランナー(Outrunner)タイプのモータの場合ですが、TAMIYAモータのようなインナータイプのモータの場合は回転子が重いので、起動させるときの回転速度に変更が必要です。TAMIYAモータの場合は7Vで駆動させていますが、同じように消費電流の少ない状態で極めて高速に回転させることができていますので、モータの種類にかかわらず切り替えのタイミングがうまくかみ合っていると思います。
RCタイマを使って800μS毎に各通電切り換えタイミング間隔をカウントしてみると、コンパレータ信号を利用するブラシレスモータの回転で各通電切り換えタイミングに回転毎に変動が生じているのがわかります。フィードバック制御を行って切り換えタイミングを一定に保つように補正する必要があるようです。(Ref:Microchip Technology AN1305「PIC16XXXを使用するセンサレス3相ブラシレスモータ制御」)
下記のプログラムでは、UART0を使ってPWM値、電流値、FET温度値などを必要に応じて一定時間毎にパソコン上のTelaTerm画面に表示させています。
1)メインプログラム M12_BM3_03.c
#include "sfr_r8m12a.h"
#include "ctrl_blm3.h"
unsigned long cnt_rb;
int i,j;
unsigned char flag_int1,flag_int2,flag_int3;
unsigned int tot_len,len_cnt1,len_cnt2,len_cnt3,len_cnt4,len_cnt5,len_cnt6;
unsigned int ad_cnt0,ad_cnt1,ad_cnt2,ad_cnt3;
unsigned int ad,ad_tmp,ad_id;
unsigned int m,n,k;
unsigned char chk_flag1,chk_flag2,chk_flag3;
unsigned char d,t_data,r_data;
unsigned char rd[4],str1[8];
void main(void)
{
init();
uart0_init(); // UART0初期化
timer_rb2_init(); // Timer RB2 initialized
m=5000;// TAMIYA:8000 1.37A cnt:38
for(i=0;i<450;i++){
if(m>500) m-=10;
OUT_WV(0);wait_us(m);// WV W+ V-
OUT_UV(0);wait_us(m);// UV U+ V-
OUT_UW(0);wait_us(m);// UV U+ W-
OUT_VW(0);wait_us(m);// VW V+ W-
OUT_VU(0);wait_us(m);// VU V+ U-
OUT_WU(0);wait_us(m);// WU W+ U-
}
timer_rj2_init(); // Timer RJ2 initialized
CLK_ON();
n=0xff;
int123_init(); // INT1,INT2,INT3 割り込み初期化
while(1){
// ad_cnt2=Get_AD2()>>2;// 電流モニタ
// ad_cnt3=Get_AD3()>>2;// 温度モニタ
ad_cnt3= n;
ad_cnt2=len_cnt1;
ad_cnt0=Get_AD0()>>2;// ボリューム値PWM
d=(unsigned char)ad_cnt0;// 0〜255
d=d/2;//0〜127
trbsc = 0x64+d; // 100〜170 (10.0us〜17.0us)
asm("nop"); // wait for at least two cycles
asm("nop"); // wait for at least two cycles
trbpr = 0x96-d; // 150〜 80 (15.0us〜8.0us)60%〜32%
asm("nop"); // wait for at least two cycles
asm("nop"); // wait for at least two cycles
trccnt =0;
flag_int2= 0;
while(1){// int2(V相立ち上がり)
OUT_WV(0);// WV W+ V-
if(flag_int2==1 ) break;
}
flag_int2=0;
len_cnt1 = trccnt;
trccnt =0;
flag_int3= 0;
while(1){// int3(U相立ち下がり)
OUT_UV(0);// UV U+ V-
if(flag_int3==1 ) break;
}
flag_int3=0;
len_cnt2 = trccnt;
trccnt =0;
flag_int1= 0;
while(1){// int1(W相立ち上がり)
OUT_UW(0);// UV U+ W-
if(flag_int1==1 ) break;
}
flag_int1=0;
len_cnt3 = trccnt;
trccnt =0;
flag_int2=0;
while(1){// int2(V相立ち下がり)
OUT_VW(0);// VW V+ W-
if(flag_int2==1 ) break;
}
flag_int2=0;
len_cnt4 = trccnt;
trccnt =0;
flag_int3=0;
while(1){// int3(U相立ち上がり)
OUT_VU(0);// VU V+ U-
if(flag_int3==1 ) break;
}
flag_int3=0;
len_cnt5 = trccnt;
trccnt =0;
flag_int1=0;
while(1){// int1(W相立ち下がり)
OUT_WU(0);// WU W+ U-
if(flag_int1==1 ) break;
}
flag_int1=0;
len_cnt6 = trccnt;
tot_len = len_cnt1+len_cnt2+len_cnt3+len_cnt4+len_cnt5+len_cnt6;
n = (tot_len)/6;
}
}
/**********************************************************/
/* I/O 初期化関数 */
/**********************************************************/
void init(void)
{
int i;
prc0 = 1; // プロテクトレジスタ解除
hocoe = 1; // 高速オンチップオシレータ発振開始
for(i=0;i<50;i++); // 発振安定まで待つ
hscksel = 1; // 高速オンチップオシレータ選択ビットを1にする
scksel = 1; // システム基準クロックを高速にする
prc0 = 0; // プロテクトレジスタ禁止
pd1 = 0x52; // p1_1,p1_6,p1_4:出力 p1_0,p1_2,p1_3,p1_5,p1_7:入力 0101 0010
pd4 = 0xe4; // p4_2,p4_5,p4_6,p4_7 出力 1110 0100
pd3 = 0xa0; // p3_5,p3_7:出力 p3_3,p3_4:入力 1010 0000
}
/**********************************************************/
/* INT123 初期化 */
/**********************************************************/
void int123_init(void)
{
// INT1(W相) 初期化
p17sel0 = 1; // p1_7をINT1端子にする W相
p17sel1 = 0; // 〃
int1en = 1; // 外部入力許可レジスタ
int1f1 = 1; // 01:f1(20MHZ単位)
int1f0 = 1; // 11:f32(0.625MHZ単位)1.6us毎にサンプリング
/* INT1入力エッジ選択レジスタ W相 */
int1sb = 1; // INT入力エッジ選択レジスタ
int1sa = 1; // 10:立ち上がりで割り込み 11:両エッジで割り込み
ilvlc5 = 1; // 割り込み優先レベル設定ビット
ilvlc4 = 0; // レベル2に設定
// INT2(V相) 初期化
p34sel1 = 1; // p3_4をINT2端子にする V相
p34sel0 = 0; // 〃
int2en = 1; // 外部入力許可レジスタ
int2f1 = 1; // 01:f1(20MHZ単位)
int2f0 = 1; // 11:f32(0.625MHZ単位)1.6us毎にサンプリング
/* INT2入力エッジ選択レジスタ V相 */
int2sb = 1; // INT入力エッジ選択レジスタ
int2sa = 1; // 10:立ち上がりで割り込み 11:両エッジで割り込み
ilvla5 = 1; // 割り込み優先レベル設定ビット
ilvla4 = 0; // レベル2に設定
// INT3(U相) 初期化
p33sel1 = 1; // p3_3をINT3端子にする U相
p33sel0 = 0; // 〃
int3en = 1; // 外部入力許可レジスタ
int3f1 = 1; // 01:f1(20MHZ単位)
int3f0 = 1; // 11:f32(0.625MHZ単位)1.6us毎にサンプリング
/* INT3入力エッジ選択レジスタ U相 */
int3sb = 1; // INT入力エッジ選択レジスタ
int3sa = 1; // 00:立ち下がりで割り込み 11:両エッジで割り込み
ilvld1 = 1; // 割り込み優先レベル設定ビット
ilvld0 = 0; // レベル2に設定
asm(" fset I "); // 割り込み許可
}
/**********************************************************/
/* UART0垂れ流し */
/* p1_4:TXD0 p1_5:RXD0 に割り当てる */
/**********************************************************/
void uart0_init(void)
{
mstcr = 0x00; // モジュールスタンバ制御イレジスタを0にする
// pmh1 = 0x05; // p1_4をTXD0、p1_5をRXD0に割り当てる
// pmh1e = 0x00;
pmh1 = 0x04; // p1_5のみをRXD0に割り当てる
pmh1e = 0x00; // 〃
pmh4 = 0x20; // p4_6をTXD0
pmh4e = 0x00; // 〃
u0mr = 0x05; // 8ビット長、パリティなし、ストップビットなし
u0brg = 0x81; // uart0初期化 20MHZ/(9600*16)-1=0x81
dfe_u0c0= 1; // ディジタルフィルタ許可
te_u0c1 = 1; // 送信許可
// re_u0c1 = 1; // 受信許可
// ilvl9_addr.bit.b0=1;// UART0割り込みレベル1に設定
// ilvl9_addr.bit.b1=0;//
// u0rie = 1; // 受信割り込み許可
}
/**********************************************************/
/* RB2初期化 */
/**********************************************************/
void timer_rb2_init(void)
{
msttrb = 0; // msttrb=0タイマRBスタンバイビット タイマRBを有効
tstart_trbcr=0; // タイマRBカウント停止
while(tcstf_trbcr==1);// timer RB count stop waiting
tstop_trbcr = 1; // タイマRB制御レジスタ:レジスタ,カウンタ初期化
trbir = 0x00; // タイマRB割り込み制御レジスタ 割り込み禁止
trbmr = 0x31; // タイマRBモードレジスタ:プログラマブル波形発生モード01:f1 31:f2 0011 0001
trbioc = 0x00; // タイマRB I/O 制御レジスタ
/* 8ビットタイマ時の設定 */
trbpre= 0x00; // 8ビットタイマ:prescaler 0x09 : 18:24 31:49 63:99 c7:199 0x77:119
0xf9:249
trbsc = 0x64; // 8ビットタイマ:secondary period 100:1/10MHz * 1 * 100=10.0us
asm("nop"); // wait for at least two cycles
asm("nop"); // wait for at least two cycles
trbpr = 0x96; // 8ビットタイマ:primary period 150:1/10MHz * 1 * 150=15.0us
asm("nop"); // wait for at least two cycles
asm("nop"); // wait for at least two cycles
trbif_trbir=0; // タイマRB割り込み要求フラグ clear
trbie_trbir=1; // タイマRB割り込み許可
ilvlc = 0x01; // 割り込み優先レベル設定 Level=1
pml4 = 0x10; // p4_2を出力端子に設定
tstart_trbcr=1; // タイマRBカウントstart
while(tcstf_trbcr == 0);// タイマRB count start waiting
}
/**********************************************************/
/* タイマRC初期化 */
/**********************************************************/
void timer_rc_init(int ad)
{
msttrc = 0; // モジュールスタンバイ制御レジスタ タイマRCを有効にする
p11sel0 = 1; // ポート1機能マッピングレジスタ0(PML1)
p11sel1 = 0; // p1_1をTRCIOA端子に設定
ilvl3 = 0x00; // 割り込み優先レベルレジスタ:0 割り込み禁止
pwm2_trcmr = 1; // タイマRCモードレジスタをタイマモードに設定
cts_trcmr = 0; // タイマRCモードレジスタ TRCCNTカウント停止
trccr1 = 0xb0; // タイマRC制御レジスタ1 コンペアマッチAでカウントクリャー カウントソース=f8(2.5MHz)
// trccr1 = 0x80; // タイマRC制御レジスタ1 コンペアマッチAでカウントクリャー カウントソース=f1(20MHz)
asm("nop"); // wait
asm("nop"); // wait
trcior0 = 0x8b; // タイマRC I/O制御レジスタ0 コンペアマッチでTRCIOA端子トグルアウトプット
trccr2 = 0x18; // タイマRC制御レジスタ2 Count continues after the compare match
trccnt = 0; // TRCCNT カウント値イニシャライズ
trcgra = 2000-1;// 800us=400ns * 2000
// trcgra = 2000-1;// 100us = 50ns * 2000
trcadcr = 0xf0; // タイマRC A/D変換トリガ制御レジスタ disable
trcopr = 0x00; // タイマRC 波形出力操作レジスタ disable
trcier = 0x70; // タイマRC 割り込み許可レジスタ disable
trcsr &=0x70; // タイマRC ステータスレジスタ ステータスフラグクリャー
trcoer = 0x7e; // タイマRC 出力許可レジスタ TRCIOA Pin:enabled
cts_trcmr = 1; // タイマRCモードレジスタ TRCCNTカウント開始 }
/**********************************************************/
/* RJ2初期化 ON幅−OFF幅=1:1 */
/**********************************************************/
void timer_rj2_init(void)
{
msttrj = 0; // タイマRJ2スタンバイビット タイマJ2を有効にする
trjmr = 0x10; // タイマRJモードレジスタ f8:2.5MHz( 400ns毎カウントダウン),タイマモードに設定
trj = 2500-1; // 400ns × 2500 = 1ms
ilvlb0 = 1; // 優先レベル1
ilvlb1 = 0; //
trjie_trjir=1; // タイマRJ割り込み制御レジスタ 割り込み許可ビット
}
/****** タイマRJ2 スタート ストップ ************/
void CLK_ON(void)
{
tstart_trjcr = 1;// タイマースタート
}
void CLK_OFF(void)
{
tstart_trjcr = 0;// タイマーストップ
}
/**********************************************************/
/* 割り込みプログラム */
/**********************************************************/
#pragma interrupt intTRB(vect=24)
void intTRB(void)
{
trbif_trbir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
}
/**********************************************************/
/* INT1割り込み処理関数 */
/**********************************************************/
#pragma interrupt intINT1(vect=25)
void intINT1(void)
{
flag_int1=1;
}
/**********************************************************/
/* INT2割り込み処理関数 */
/**********************************************************/
#pragma interrupt intINT2(vect=21)
void intINT2(void)
{
flag_int2=1;
}
/**********************************************************/
/* INT3割り込み処理関数 */
/**********************************************************/
#pragma interrupt intINT3(vect=26)
void intINT3(void)
{
flag_int3=1;
}
/**********************************************************/
/* 割り込みプログラム */
/**********************************************************/
#pragma interrupt intTRJ(vect=22) // TRJ割り込み
void intTRJ(void)
{
// 温度 16進コード2バイト送信
trjif_trjir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
cnt_rb++;
if(cnt_rb>2000){ // 2秒毎に割り込み
cnt_rb=0;
ad=ad_cnt3>>2; // AD変換値(AN3)入力
d=(unsigned char)ad;
UART0_hex_send(d);
}
UART0_sp_send(); // スペースコード送信
// 電流 16進コード2バイト送信
trjif_trjir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
cnt_rb++;
if(cnt_rb>2000){ // 2秒毎に割り込み
cnt_rb=0;
ad=ad_cnt2>>2; // 電流値入力
d=(unsigned char)ad;
UART0_hex_send(d);
}
UART0_sp_send(); // スペースコード送信
// ボリューム値 16進コード2バイト送信
trjif_trjir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
cnt_rb++;
if(cnt_rb>2000){ // 2秒毎に割り込み
cnt_rb=0;
ad=ad_cnt0>>2; // AD変換値(AN7)入力
d=(unsigned char)ad;
UART0_hex_send(d);
}
UART0_sp_send(); // スペースコード送信
UART0_crlf_send(); // CR LFコード送信
}
2)コントロールファイル uvw_ctrl3.c
/****************************************/
/* uvw_ctrl.c */
/****************************************/
#include "sfr_r8m12a.h" /* R8C/M12A SFRの定義ファイル */
#include "ctrl_blm.h"
/************************************/
/* タイマ本体 us単位のwait関数 */
/************************************/
void wait_us(long int usec)
{
usec = (usec * CLOCK) / 45000;
while(usec --);{}
}
/*************************************/
/* タイマ本体 ms単位のwait関数 */
/*************************************/
void wait_ms(long int msec)
{
unsigned int i;
for(i=0;i<msec;i++){
wait_us(1000);
}
}
/**************************************/
/* 6usの遅れ関数 */
/**************************************/
void delay(void)
{
unsigned char i;
for(i=0;i<5;i++){}
}
/**********************************************************/
/* AN0端子AD変換関数 */
/**********************************************************/
int Get_AD0(void)
{
int i;
p10sel0 = 0;// ポート1機能マッピングレジスタ0
p10sel1 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x00; // A/D入選択レジスタ AN0
adcon0 = 0x01; // AD変換スタート
while(adcon0 && 0x01); // A/D変換終了待ち(単発モード)
i=ad0;
return i;
}
/**********************************************************/
/* AN1端子AD変換関数 */
/**********************************************************/
int Get_AD1(void)
{
int i,data;
p11sel0 = 0;// ポート1機能マッピングレジスタ0
p11sel1 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x01;// A/D入選択レジスタ AN1
adcon0 = 0x01;// AD変換スタート
while(adcon0 && 0x01);// A/D変換終了待ち(単発モード)
data = ad1;
return data;
}
/**********************************************************/
/* AN2端子AD変換関数 */
/**********************************************************/
int Get_AD2(void)
{
int i,data;
// p12sel0 = 0;// ポート1機能マッピングレジスタ0
// p12sel1 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x40;// A/D入選択レジスタ AN2
adcon0 = 0x01;// AD変換スタート
while(adcon0 && 0x01); // A/D変換終了待ち(単発モード)
data = ad0;
return data;
}
/**********************************************************/
/* AN3端子AD変換関数 */
/**********************************************************/
int Get_AD3(void)
{
int i,data;
p13sel0 = 0;// ポート1機能マッピングレジスタ0
p13sel1 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x41;// A/D入選択レジスタ AN3
adcon0 = 0x01;// AD変換スタート
while(adcon0 && 0x01); // A/D変換終了待ち(単発モード)
data = ad1;
return data;
}
/**********************************************************/
/* AN4端子AD変換関数 */
/**********************************************************/
int Get_AD4(void)
{
int i,data;
p14sel0 = 0;;// ポート1機能マッピングレジスタ1 AN4入力
p14sel1 = 0;
p14sel2 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x80;// A/D入選択レジスタ AN4
adcon0 = 0x01;// AD変換スタート
while(adcon0 && 0x01); // A/D変換終了待ち(単発モード)
data = ad0;
return data;
}
/**********************************************************/
/* AN7端子AD変換関数 */
/**********************************************************/
int Get_AD7(void)
{
int i,data;
p17sel0 = 0;// ポート1機能マッピングレジスタ1 AN7入力
p17sel1 = 0;
mstad = 0; // モジュールスタンバイ制御レジスタをアクティブ
mstcr = 0x00;// モジュールスタンバイ制御レジスタをアクティブ
admod = 0x03;// A/D動作 0x0b:繰り返しモード 0x03:単発モード f1(20MHz)
adinsel = 0x81;// A/D入選択レジスタ AN7
adcon0 = 0x01;// AD変換スタート
while(adcon0 && 0x01); // A/D変換終了待ち(単発モード)
data = ad1;
return data;
}
/* WV W+V- W+:p3_7 V-:p4_5 */
void OUT_WV(int m)
{
p3=0x80;wait_us(m);p4=0x20;// WV W+V- p3:1000 0000 p4:0010 0000
}
/* UV U+V- U+:p1_6 V-:p4_5 */
void OUT_UV(int m)
{
p1=0x40;wait_us(m);p4=0x20;// UV U+V- p1:0100 0000 p4:0010 0000
}
/* UW U+W- U+:p1_6 W-:p3_5 */
void OUT_UW(int m)
{
p1=0x40;wait_us(m);p3=0x20;// UW U+W- p1:0100 0000 p3:0010 0000
}
/* VW V+W- V+:p4_7 W-:p3_5 */
void OUT_VW(int m)
{
p4=0x80;wait_us(m);p3=0x20;// VW V+W- p4:1000 0000 p3:0010 0000
}
/* VU V+U- V+:p4_7 U-:p1_4 */
void OUT_VU(int m)
{
p4=0x80;wait_us(m);p1=0x10;// VU V+U- p4:1000 0100 p1:0001 0000
}
/* WU W+U- W+:p3_7 U-:p1_4 */
void OUT_WU(int m)
{
p3=0x80;wait_us(m);p1=0x10;// WU W+U- p3:1000 0000 p1:0001 0000
}
/* UART0 1文字受信関数 */
int UART0_rx(void)
{
unsigned int data;
char err;
while(ri_u0c1 != 1);
data = u0rb & 0x00ff;
return data;
}
/* UART0 1文字送信関数 */
int UART0_tx(char data)
{
while(ti_u0c1 != 1);// 送信バッファ空フラグ
u0tbl = data;
}
/* UART0 文字列送信関数 */
void UART0_tx_str(char *str)
{
while(*str != '\0'){
UART0_tx(*str);
str++;
}
}
/* UART0 改行表示関数 */
void CRLF(void)
{
UART0_tx(0x0a);
UART0_tx(0x0d);
}
/* UART0 スペースコード送信関数 */
void UART0_sp_send(void)
{
extern unsigned long cnt_rb;
trjif_trjir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
cnt_rb++;
if(cnt_rb>2000){ // 2秒毎に割り込み
cnt_rb=0;
UART0_tx(' ');
}
}
/* UAR0 CR LF 送信関数 */
void UART0_crlf_send(void)
{
extern unsigned long cnt_rb;
trjif_trjir = 0; // 割り込み制御レジスタの割り込み要求フラグをクリア
cnt_rb++;
if(cnt_rb>2000){ // 2秒毎に割り込み
cnt_rb=0;
UART0_tx(0x0a);UART0_tx(0x0d);
}
}
/* UAR0 16進コード 送信関数 */
void UART0_hex_send(unsigned char d) // 16進コード送信関数
{
extern int i;
extern unsigned char d;
extern unsigned char rd[4],str1[8];
for(i=0;i<2;i++){ // 0〜255を各桁に分解する
rd[i] = d%16;
d = d/16;
}
if(rd[1]<10) str1[0]=rd[1]+0x30;else str1[0]=rd[1]+0x41-0x0A;
if(rd[0]<10) str1[1]=rd[0]+0x30;else str1[1]=rd[0]+0x41-0x0A;
UART0_tx_str(str1);
}
3)ヘッダーファイル ctrl_blm3.h
/*****************************************************/
/* ctrl_blm3.h */
/*****************************************************/
#define CLOCK 20000
void init(void);
void wait_us(unsigned long int usec); // us単位のタイマ
void wait_ms(unsigned long int msec); // ms単位のタイマ
void delay(void); // 6usの遅延関数
void timer_rb2_init(void); // タイマRB2初期化
void timer_rj2_init(void); // タイマRJ2初期化
void timer_rc_init(int ad); // タイマRC初期化
void uart0_init(void);
void int123_init(void); // INT123 初期化
void CLK_ON(void); // タイマRJ2 スタート 関数
void CLK_OFF(void); // タイマRJ2 ストップ関数
int Get_AD0(void); // AN0端子 AD変換関数
int Get_AD1(void); // AN1端子 AD変換関数
int Get_AD2(void); // AN2端子 AD変換関数
int Get_AD3(void); // AN3端子 AD変換関数
int Get_AD4(void); // AN4端子 AD変換関数
int Get_AD7(void); // AN7端子 AD変換関数
void OUT_WV(int m);// WV W+:p3_7 V-:p4_5
void OUT_UV(int m);// UV U+:p1_6 V-:p4_5
void OUT_UW(int m);// UW U+:p1_6 W-:p3_5
void OUT_VW(int m);// VW V+:p4_7 W-:p3_5
void OUT_VU(int m);// VU V+:p4_7 U-:p1_4
void OUT_WU(int m);// WU W+:p3_7 U-:p1_4
int UART0_tx(char data); // 1文字送信関数
int UART0_rx(void); // 1文字受信関数
void UART0_tx_str(char *str);// 文字列送信関数
void CRLF(void); // 改行表示関数
void UART0_sp_send(void); // UART0 スペースコード送信関数
void UART0_crlf_send(void); // CR LFコード送信
void UART0_hex_send(unsigned char d);// 16進コード送信関数

実行時のパソコンモニター画面(PWM値、FET温度、電流値)
プロジェクトファイルのダウンロード
U.ESCを使った実験
ESC(Electronic Speed Control)はドローン用に開発されたブラシレスモータのコントローラです。クワッドコプターの場合、それぞれのモータに1個必要になります。

ESCの内部にはモータ駆動FET回路やFETドライバが内蔵されています。
左の青い3本の線がモーター側、右の赤、黒がモータの駆動電源、
3本のコネクタ端子が受信機のサーボ端子に繋がります。
モータのスピードコントロールは、サーボ端子の信号線(白色)
に20ms周期のパルスのH幅を0.7〜2.3msの範囲で入力する
ことによって行うことができます。
メニューに戻る