高速回転ダクトファン(3相2極ブラシレスモーターの位置センサレス駆動)
【概要】
AIR CRAFT製のDIY AC ブラシレスモーターにラジコン飛行機用ダクトファンを使用しコントローラを外付けで作成したものです。
モーター駆動はセンサレスによりV−F制御チョッピングによる強制通電パターンにて25000rpm/minまで脱調せずスムーズに回転します。
【使用部品】
|
部品名 |
型式 |
メーカー |
備考 |
|
MCU |
PIC16F877 |
マイクロチップ |
フラッシュ8Kbyte |
|
軸流ファンモーター |
DIYモータ |
AIR CRAFT |
センサレス |
|
モーター駆動トランジスタ |
2SK1567、2SJ438 |
|
|
|
LCD |
SC2004 |
秋月通商にて購入 |
チョッピングPWM、転流タイマ割込み、通電パターンを表示 |
|
電源3端子レギュレータ |
78M05 |
|
MCU電源 |
モータ駆動回路は全波(バイポーラ)駆動、始動はPWM50%で600rpm/min。
【作成日記】
初期にMCUをルネサスH8−300で作成をしていたが100回程度しかフラッシュROMに書換えができない作りで、デバック中に
MCUに書込みの際に電圧を書込み仕様の15Vにせず5Vで書込み処理をして、1回目で書けなくなったりした。
これは、1個¥3800もするH8−300は貧乏人には使えないと思い、泣く泣くPICの書換え10万回以上可能である16F877に
変更した。基板もユニバーサルでせっせと配線はんだ付けで2日かかった。
|
fig1.ダクトファンモーター回転時 fig2.ダクト停止時 |
|
fig3.基板パターン図 fig4.基板回路図 |
5). PICマイコン16F877のメインソースプログラム
★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆
#include <16F877.h>
#use delay(clock=20000000)
#fuses HS,NOWDT, NOPROTECT, BROWNOUT,PUT
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)
#define pwm_up PIN_B1
#define pwm_down PIN_B0
#define pwm_off PIN_C0
#define mot_c_up PIN_E0
#define mot_c_down PIN_E1
#define tyata 20
#define mot_str_count 100
#define mot_str_cyc 65000
#define jyuden_out_cnt 33
#include <lcd_lib5.c>
unsigned char pwm_up_cnt,pwm_down_cnt,pwm_off_cnt;
unsigned int pwm_out;
unsigned char sw_status,mot_status;
unsigned char mot_cyc_che_cnt ;
static unsigned int mot_count,uvw_out;
unsigned long jyuden_out,mot_str_tim;
static unsigned long mot_cyc;
unsigned int mot_cyc_up_cnt,mot_cyc_down_cnt;
#bit pwmoff_flag = sw_status.0
#bit pwmup_flag = sw_status.1
#bit pwmdown_flag = sw_status.2
#bit mot_cyc_up_flag = sw_status.3
#bit mot_cyc_down_flag = sw_status.4
#bit mot_start_end = mot_status.0
#bit cyc_end_flag = mot_status.1
unsigned int const mot_out1[30]={
0x09,0x09,0x09,0x09,0x09,
0x21,0x21,0x21,0x21,0x21,
0x24,0x24,0x24,0x24,0x24,
0x06,0x06,0x06,0x06,0x06,
0x12,0x12,0x12,0x12,0x12,
0x18,0x18,0x18,0x18,0x18,
}; //TPC出力テ゛ータ
unsigned int const mot_out2[30]={
0x19,0x09,0x09,0x09,0x09,
0x29,0x21,0x21,0x21,0x21,
0x25,0x24,0x24,0x24,0x24,
0x26,0x06,0x06,0x06,0x06,
0x16,0x12,0x12,0x12,0x12,
0x1A,0x18,0x18,0x18,0x18,
};
#int_timer0
void intval0()
{
set_timer0(177);
if( input(pwm_off) == 0 )
{ if( pwm_off_cnt < 1 )
{ pwmoff_flag = 1;
pwm_off_cnt = tyata;
}else{
pwm_off_cnt--;
}
}else{
}
if( input(pwm_up) == 0 )
{ if( pwm_up_cnt < 1 )
{ pwmup_flag = 1;
pwm_up_cnt = tyata;
}else{
pwm_up_cnt--;
}
}
if( input(pwm_down) == 0 )
{ if( pwm_down_cnt < 1 )
{ pwmdown_flag = 1;
pwm_down_cnt = tyata;
}else{
pwm_down_cnt--;
}
}
if( input(mot_c_up) == 0 )
{ if( mot_cyc_up_cnt < 1 )
{ mot_cyc_up_flag = 1;
mot_cyc_up_cnt = tyata;
}else{
mot_cyc_up_cnt--;
}
}
if( input(mot_c_down) == 0 )
{ if( mot_cyc_down_cnt < 1 )
{ mot_cyc_down_flag = 1;
mot_cyc_down_cnt = tyata;
}else{
mot_cyc_down_cnt--;
}
}
if(pwmoff_flag == 1){
pwm_out=0;
sw_status = 0;
// pwmoff_flag = 0;
}
if(pwmup_flag == 1){
if(pwm_out >= 255){
pwm_out=255;
}else{
pwm_out++;
}
sw_status = 0;
// pwmup_flag= 0;
}
if(pwmdown_flag == 1){
if(pwm_out <= 0){
pwm_out=0;
}else{
pwm_out--;
}
sw_status = 0;
}
if(mot_cyc_up_flag == 1){
if(mot_cyc >= 65490){
mot_cyc = 65490;
}else{
mot_cyc++;
}
sw_status = 0;
}
if(mot_cyc_down_flag == 1){
if(mot_cyc <= 0){
mot_cyc = 0;
}else{
mot_cyc--;
}
sw_status = 0;
}
set_pwm1_duty(pwm_out);
if(jyuden_out <= 0 && pwm_out > 0){
if( mot_str_tim > 0 ){
mot_str_tim --;
}else{
mot_str_tim = 0;
}
}else{
mot_str_tim = mot_str_count;
mot_start_end = 0;
}
if(mot_str_tim <= 0 && cyc_end_flag == 1){
mot_start_end = 1;
}else{
mot_start_end = 0;
}
}
#int_timer1
void intval1()
{
set_timer1(mot_cyc);
if(pwm_out > 0){
if( jyuden_out > 23 && mot_start_end == 0 ){
uvw_out = 0x2A;
jyuden_out--;
pwm_out = 250;
}else if( jyuden_out > 13 && mot_start_end == 0 ){
uvw_out = 0x12;
jyuden_out--;
pwm_out = 200;
}else if( jyuden_out > 3 && mot_start_end == 0 ){
uvw_out = 0x18;
jyuden_out--;
pwm_out = 200;
}else if( jyuden_out > 0 && mot_start_end == 0 ){
uvw_out = 0x10;
jyuden_out--;
pwm_out = 200;
}else if(jyuden_out <= 0 && mot_start_end == 0){
pwm_out = 110;
uvw_out=mot_out1[mot_count];
mot_count++;
}else if(jyuden_out <= 0 && mot_start_end == 1){
if( mot_cyc_che_cnt == 0 ){
mot_cyc = 65000;
}else{
}
uvw_out=mot_out2[mot_count];
mot_count++;
mot_cyc_che_cnt = 1;
}
}else{
mot_cyc = mot_str_cyc;
uvw_out=0x00;
mot_count = 0;
jyuden_out=jyuden_out_cnt;
cyc_end_flag = 0;
mot_cyc_che_cnt = 0;
mot_status = 0;
}
if(mot_count >= 30){
mot_count = 1;
cyc_end_flag = 1;
}
output_D( uvw_out );
}
void main()
{
set_tris_a(0x00);
set_tris_b(0x03);
set_tris_c(0x01);
set_tris_d(0x00);
set_tris_e(0x03);
output_a(0x00);
output_b(0x00);
output_c(0x00);
output_d(0x00);
output_e(0x00);
port_b_pullups(TRUE);
pwm_off_cnt = tyata;
pwm_up_cnt = tyata;
pwm_down_cnt = tyata;
mot_count = 0;
sw_status = 0;
jyuden_out=jyuden_out_cnt;
mot_cyc_che_cnt = 0;
mot_status = 0;
// pwmoff_flag = 0;
// pwmup_flag= 0;
// pwmdown_flag = 0;
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_64);
set_timer0(177);
enable_interrupts(INT_TIMER0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
//11900rpm
mot_cyc = mot_str_cyc;
set_timer1(mot_cyc);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
setup_ccp1(ccp_pwm);
setup_timer_2(T2_DIV_BY_1,255,1); //19.6khz分解能255
pwm_out = 0x00;
set_pwm1_duty(pwm_out);
lcd_init();
lcd_clear();
while(1){
lcd_cmd(0x80);
printf(lcd_data,"pwm= %3u / 255 ",pwm_out);
lcd_cmd(0xc0);
printf(lcd_data,"uvw_out= %2LX hex",uvw_out);
lcd_cmd(0x94);
printf(lcd_data,"mot_count= %3u",mot_count);
lcd_cmd(0xd4);
printf(lcd_data,"mot_cyc= %5lu",mot_cyc);
delay_ms(100);
}
}
6). ヘッダーFILE
★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆
#include <16F877.h>
#device adc=8
#use delay(clock=20000000)
#fuses HS, PUT, NOPROTECT, BROWNOUT, LVP
7). LCDのパラレルデータFILE
★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆
///////////////////////////////////////////////
// LCD control Library
// functions are below
// lcd_init()-------- initialize
// lcd_ready()------- busy check
// lcd_cmd(cmd)------ send command
// lcd_data(string)-- display string
// lcd_clear() ------ clear display
//////////////////////////////////////////////
////// port define to port B
#byte port = 6 //port B
#define set_tris_x set_tris_b
#define mode 0x03
#define rs PIN_B2
#define rw PIN_C7
#define stb PIN_C6
/////////// lcd ready check function
int lcd_ready(){
int high,low;
set_tris_x(mode | 0xF0); //upper is input
output_low(rs);
output_high(rw); //read mode
output_high(stb);
delay_us(1);
high=port & 0xF0; //input upper
output_low(stb);
output_high(stb);
delay_us(1);
low=port & 0xF0; //input lower
output_low(stb);
set_tris_x(mode);
return(high | (low>>4)); //end check
}
////////// lcd display data function
void lcd_data(int asci){
port = (asci & 0xF0) | (port & 0x0F); //set upper data
output_low(rw); //set write
output_high(rs); //set rs high
output_high(stb); //strobe
delay_us(1);
output_low(stb);
asci=asci<<4;
port = (asci & 0xF0) | (port & 0x0F); //set lower data
output_high(stb); //strobe
delay_us(1);
output_low(stb);
while(bit_test(lcd_ready(),7));
}
////////// lcd command out function
void cmdout(int cmd){
port = (cmd & 0xF0) | (port & 0x0F); //set upper data
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
delay_us(1);
output_low(stb);
cmd=cmd<<4;
port = (cmd & 0xF0) | (port & 0x0F); //set lower data
output_high(stb); //strobe
delay_us(1);
output_low(stb);
}
void lcd_cmd(int cmd){
cmdout(cmd);
while(bit_test(lcd_ready(),7)); //end check
}
////////// lcd display clear function
void lcd_clear(){
lcd_cmd(1); //initialize command
}
///////// lcd initialize function
void lcd_incmd(int cmd){
port = (cmd & 0xF0) | (port & 0x0F); //mode command
output_low(rw); //set write
output_low(rs); //set rs low
output_high(stb); //strobe
delay_us(1);
output_low(stb);
delay_ms(5);
}
void lcd_init(){
set_tris_x(mode); //initialise
delay_ms(15);
lcd_incmd(0x30); //8bit mode set
lcd_incmd(0x30); //8bit mode set
lcd_incmd(0x30); //8bit mode set
lcd_incmd(0x20); //4bit mode set
lcd_cmd(0x2E); //DL=0 4bit mode
lcd_cmd(0x08); //disolay off C=D=B=0
lcd_cmd(0x0D); //display on C=D=1 B=0
lcd_cmd(0x06); //entry I/D=1 S=0
}