1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

高速uartシリアル通信で、Stepper-motor (28BYJ-48) を動かす

Last updated at Posted at 2025-02-11

28BYJ-48は、5線のモノポーラのステッピングモーターです。
初回から前回まで、マイコンPIC18FとワンボードコンピューターであるRPI4B(ラズベリーパイ4B)の2.3Mbpsでの高速uart通信を実施しました。

今回は、マイコンPIC側では、uart通信により8bitコードを2個受信して、ステッピングモーター (28BYJ-48) を動かすだけです。一方、Raspberry Pi、Nano Pi、Banana Piなどは、4~6個のコアを搭載した高性能ワンボードコンピューターです。32bitまたは64bitのMPUが1.0~2.4GHzで動作し、高速大容量メモリーも搭載していますから、桁違いに大きな画像ファイルも処理できます。さらに各コアで、カメラからの入力、画像解析、画面表示などの時間の掛かる処理を分担できます。

さらにステッピングモーターを、直接ワンボードコンピューターから動かすこともできます。しかし実際にステッピングモーターを動かす場合、大幅な待ち時間があります。待ち時間を短くすると、ステッピングモーターを素早く動かせそうですが、待ち時間を短縮し過ぎるとステッピングモーターは誤動作します。ステッピングモーターは、内部に複数のコイルが配置されていて、各コイルを順番にON/OFFして回しています。しかしコイルですから、ON→OFFにしても、まだ電流は流れ続けようとして、尾をひきます。逆に、OFF→ONにしても、電流が流れない状態を維持しようとして電流が流れるのを妨げ、少し遅延した後に設定した電流が流れ始めます。この遅延している時に、OFF→ON→OFFと繰り返すと、やっと電流が少し流れ始めた時に、再びOFFとなり電流がゼロになります。つまり回りません。ゆえに遅延することを考慮して、待ち時間が必要です。ワンボードコンピューターの1個のコアは、時間的に99%以上が待ち時間のステッピングモータに常時占有されます。実質的に、ワンボードコンピューターの4コアが3コアに目減りします。

そこで、ここでの試行です。ステッピングモーターを動かすのを、マイコンへ移動すれば、ワンボードコンピューターの1個のコアは、開放され、他の用途に使えます。ワンボードコンピューターからマイコンへ、2.3Mbpsの高速uart通信で8bitコマンドを2個送信するだけです。時間は7μsecです。これ以外、ワンボードコンピューターの1個のコアは他の用途に使えます。マイコン側では、8bitコマンドを2個受信して、ステッピングモーターを指定位置へ動かします。そしてマイコンは、再び8bitコマンドの受信待機です。

7.png

配線図です。モノポーラステッピングモーター28BYJ-48を動かすのに、TI社製のULN2003を使います。Uartシリアル通信の配線は、初回と同じです。
次図は新規に作成した基板の写真です。28BYJ-48とULN2003はアマゾンで購入しました。(28BYJ-48+ULN2003)の4セットで1280円だったので、使用した2セットで640円です。これは完全に動きます。ブランドの互換品をうたう商品は、あたりはずれがありますが。この(28BYJ-48+ULN20034)セットは、アマゾンで1ヶ月100点以上売れている、ヒット商品でした。9V電池はDAISOの110円を2個並列で使っています。カメラはラズベリーパイカメラV2(NoIR)です。今回、ラズベリーパイ4B側のOSは、Buster(x32)を使いました。LED、Crystalなどは面実装タイプを使っています。抵抗はリード線タイプ100本入を購入済なので、まだまだ沢山あります。抵抗・整流ダイオードは、裏面にハンダ付していますので、写真では見えません。

photo-45.jpg

ワンボードコンピューター側は、1例としてRaspberry Pi 4B上でPythonプログラムを動かします。高速uart通信で、8bitコマンドを2個を、マイコン側へ送信します。マイコン側で受信した8bitコマンドが、大文字「A」の場合は+45度(時計回り)、小文字「a」の場合は-45度(反時計回り)、大文字「B」の場合は+90度(時計回り)、小文字「b」の場合は-90度(反時計回り)、それぞれ回ります。これ以外は回りません。また1個目の8bitコマンドが、水平方向のステッピングモーターです。2個目の8bitコマンドは、垂直方向です。

#uart-stepping-motor-dual.py
#Serial Console OFF, Serial ON
#RPI4B Buster(x32) Python 3.7.3 (x32) Thonny, and RUN  or 
#RPI4B bookworm(x64) Python 3.11.2 Thonny, and RUN    

import serial
    
#Open SERIALttyS0
SERIALttyS0 = serial.Serial('/dev/ttyS0', 2304000, timeout=1)
    
#Set SendMessage
SendMessage = "Aa"
    
#Send Command
SERIALttyS0.write(SendMessage.encode())
    
#Receive ReturnMessage and print
binary_ReturnMessage = SERIALttyS0.readline()
ReturnMessage = binary_ReturnMessage.decode()
print(ReturnMessage)
    
#Close SERIALttyS0
SERIALttyS0.close()

マイコン側は、1例としてPIC18F2620(またはPIC18F26K22)を使います。マイコン側は、8bitコマンド2個を受信して、2個のステッピングモーターを動かすだけのプログラムです。シンプルなプログラムです。今回は、モノポーラのステッピングモーターの28BYJ-48とパワーユニットULN2003を使っています。初回のuart通信に、ステッピングモーター用ドライバーを追加しただけです。2相励磁で動かします。今回も、xc8とC18のプログラムです。PIC18FのXC8プログラムです。

//main.c    MPLAB  X IDE v6.00,  XC8 Compiler v2.4.0, (C90),  PICkit3
#include <xc.h>

#define	_XTAL_FREQ		36864000
#define LED_A0			LATA0
#define FXMA_CS0_TRIS	TRISC0
#define FXMA_CS0_IO		LATC0
#define TAIN1_TRIS		TRISA1
#define TAIN1_IO		LATA1
#define TBIN1_TRIS		TRISA2
#define TBIN1_IO		LATA2
#define TAIN2_TRIS		TRISA3
#define TAIN2_IO		LATA3
#define TBIN2_TRIS		TRISA4
#define TBIN2_IO		LATA4
#define PAIN1_TRIS		TRISB1
#define PAIN1_IO		LATB1
#define PBIN1_TRIS		TRISB2
#define PBIN1_IO		LATB2
#define PAIN2_TRIS		TRISB3
#define PAIN2_IO		LATB3
#define PBIN2_TRIS		TRISB4
#define PBIN2_IO		LATB4
//PIC18F2620
#pragma config OSC = HSPLL
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = ON
#pragma config BOREN = OFF
#pragma config BORV = 3
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config CCP2MX = PORTBE
#pragma config PBADEN = OFF
#pragma config LPT1OSC = OFF
#pragma config MCLRE = ON
#pragma config STVREN = OFF
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF
#pragma config WRTC = OFF
#pragma config WRTB = OFF
#pragma config WRTD = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF
#pragma config EBTRB = OFF
////PIC18F26k22
//#pragma config FOSC = HSHP
//#pragma config PLLCFG = ON
//#pragma config PRICLKEN = ON
//#pragma config FCMEN = OFF
//#pragma config IESO = OFF
//#pragma config PWRTEN = ON
//#pragma config BOREN = OFF
//#pragma config BORV = 190
//#pragma config WDTEN = OFF
//#pragma config WDTPS = 32768
//#pragma config CCP2MX = PORTC1
//#pragma config PBADEN = OFF
//#pragma config CCP3MX = PORTB5
//#pragma config HFOFST = OFF
//#pragma config T3CMX = PORTC0
//#pragma config P2BMX = PORTB5
//#pragma config MCLRE = EXTMCLR
//#pragma config STVREN = OFF
//#pragma config LVP = OFF
//#pragma config XINST = OFF
//#pragma config CP0 = OFF
//#pragma config CP1 = OFF
//#pragma config CP2 = OFF
//#pragma config CP3 = OFF
//#pragma config CPB = OFF
//#pragma config CPD = OFF
//#pragma config WRT0 = OFF
//#pragma config WRT1 = OFF
//#pragma config WRT2 = OFF
//#pragma config WRT3 = OFF
//#pragma config WRTC = OFF
//#pragma config WRTB = OFF
//#pragma config WRTD = OFF
//#pragma config EBTR0 = OFF
//#pragma config EBTR1 = OFF
//#pragma config EBTR2 = OFF
//#pragma config EBTR3 = OFF
//#pragma config EBTRB = OFF

static unsigned char vBANK01[256];
static unsigned char vBuffer[32];
near uint8_t i, DirectionT, DirectionP;
near unsigned char Temp1;
near uint16_t Wi, Wi_last, iT, iT_last, iP, iP_last;
near uint32_t Di;

//   stepper-motor functions
void tCW_pCW(near uint16_t iT_last, near uint16_t iP_last);
void tCCW_pCW(near uint16_t iT_last, near uint16_t iP_last);
void tCW_pCCW(near uint16_t iT_last, near uint16_t iP_last);
void tCCW_pCCW(near uint16_t iT_last, near uint16_t iP_last);

void main()
{
    //Analog setting 2620
    ADCON0 = 0x00;
    ADCON1 = 0x00;
    ////Analog setting 26k22
    //ANSELA = 0b00000000 ;    // all digital
    //ANSELB = 0b00000000 ;
    //ANSELC = 0b00000000 ;
    TRISA  = 0b00000000 ;     // all output
    TRISB  = 0b00000000 ;
    TRISC  = 0b00000000 ;
    PORTA  = 0b00000000 ;
    PORTB  = 0b00000000 ;
    PORTC  = 0b00000000 ;
    /// uart init
    // C port	//1			0		0		1		0		0		0		0
    //			//RX		TX		SDO		SDI		SCK		C2		C1		C0
    TRISC = 0x90;
    // TXSTA	//0			0		1		0		0		1		0		0
    //			//CSRC		TX9		TXEN	SYNC	-		BRGH	TRMT	TX9D
    TXSTA = 0x24;
    // RCSTA	//1			0		0		1		0		0		0		0
    //			//SPEN		RX9		SREN	CREN	ADDEN	FERR	OERR	RX9D
    RCSTA = 0x90;
    // BAUDCON	//0			0		0		0		0		0		0		0
    //			//ABDOVF	RCIDL	RXDTP	TXCKP	BRG16	-		WUE		ABDEN
    BAUDCON = 0x00;	
    // SPBRG	(36.864 MHz)	
    // SPBRG = 0x13,  013H=19, 36.864/(16(1+19)) =	115.2 Kbps
    // SPBRG = 0x04,  004H=4,  36.864/(16(1+4))  =	460.8 Kbps
    // SPBRG = 0x01,  001H=1,  36.864/(16(1+1))  =	1.152 Mbps
    // SPBRG = 0x00,  000H=0,  36.864/(16(1+0))  =	2.304 Mbps
    SPBRG = 0x00;

    FXMA_CS0_TRIS =0;
    FXMA_CS0_IO=0;

    while(1) {
        LED_A0 = 1;
        Wi=0;
        Wi_last=1;
        for(; ; )
        {
            if (RCSTAbits.OERR)
            {
                RCSTAbits.CREN = 0;
                Temp1 = RCREG;
                RCSTAbits.CREN = 1;
            }
            if(RCIF==1) 
            {
                vBANK01[Wi]  = RCREG;
                Wi++;
            }
            if(Wi>Wi_last) {  break;  }
        }
        vBuffer[0] = vBANK01[0];
        vBuffer[1] = vBANK01[1];
        vBuffer[2] = 0x0A;  // LF
        Wi=0;
        Wi_last=2;
        for(; ; )
        {
            //2620
            if(TRMT==1)
            ////26k22
            //if(TXSTAbits.TRMT==1)
            {
                TXREG  =  vBuffer[Wi];
                Wi++;
            }
            if(Wi>Wi_last) {  break;  }
        }

        /// 2-phase mode on full-step drive
        LED_A0 = 0;

        // preparation of the received commands
        switch(vBuffer[0])
        {
            case 'A':
                DirectionT =1;    // CW
                iT_last=64;         // 45 degree
                break;
            case 'a':
                DirectionT =2;    // CCW
                iT_last=64;         // 45 degree
                break;
            case 'B':
                DirectionT =1;    // CW
                iT_last=128;       // 90 degree
                break;
            case 'b':
                DirectionT =2;    // CCW
                iT_last=128;       // 90 degree
                break;
            default:    
                DirectionT =1;    // CW
                iT_last=0;          // 0 degree
        }
        switch(vBuffer[1])
        {
            case 'A':
                DirectionP =1;    // CW
                iP_last=64;         // 45 degree
                break;
            case 'a':
                DirectionP =2;    // CCW
                iP_last=64;         // 45 degree
                break;
            case 'B':
                DirectionP =1;    // CW
                iP_last=128;       // 90 degree
                break;
            case 'b':
                DirectionP =2;    // CCW
                iP_last=128;       // 90 degree
                break;
            default:    
                DirectionP =1;    // CW
                iP_last=0;          // 0 degree
        }

        /// drive motor
        if(DirectionT==1 && DirectionP==1)              // T-CW & P-CW
        { 
            tCW_pCW(iT_last, iP_last);
        }
        if(DirectionT==2 && DirectionP==1)              // T-CCW & P-CW
        { 
            tCCW_pCW(iT_last, iP_last);
        }
        if(DirectionT==1 && DirectionP==2)              // T-CW & P-CCW
        { 
            tCW_pCCW(iT_last, iP_last);
        }
        if(DirectionT==2 && DirectionP==2)              // T-CCW & P-CCW
        { 
            tCCW_pCCW(iT_last, iP_last);
        }
    }
    FXMA_CS0_IO=1;
}

//////   stepper-motor functions
void tCW_pCW(near uint16_t iT_last, near uint16_t iP_last)
{
    /// T-CW & P-CW
    uint16_t iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCCW_pCW(near uint16_t iT_last, near uint16_t iP_last)
{
    /// T-CCW & P-CW
    uint16_t iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCW_pCCW(near uint16_t iT_last, near uint16_t iP_last)
{
    /// T-CW & P-CCW
    uint16_t iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCCW_pCCW(near uint16_t iT_last, near uint16_t iP_last)
{
    /// T-CCW & P-CCW
    uint16_t iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        __delay_ms(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

PIC18FのC18プログラムです。includeに必要なHardwareProfile.hとConfiguration Bitsの画面コピーも添付します。

/// MainDemo.c     MPLAB_IDE_8_92,  MPLAB_C18_3.46,  PICkit3
#include <p18f2620.h>
//#include <p18f26k22.h>/
#include <GenericTypeDefs.h>
#include <delays.h>
#include <HardwareProfile.h>

#pragma udata bank1  = 0x100
static unsigned char vBANK01[256];
#pragma udata bank2 = 0x200
static unsigned char vBuffer[32];

#pragma udata access my_access
near unsigned char Temp1;
near BYTE i, DirectionT, DirectionP;
near WORD Wi, Wi_last, iT, iT_last, iP, iP_last;
near DWORD Di;

//   stepping motor functions
void tCW_pCW(near WORD iT_last, near WORD iP_last);
void tCCW_pCW(near WORD iT_last, near WORD iP_last);
void tCW_pCCW(near WORD iT_last, near WORD iP_last);
void tCCW_pCCW(near WORD iT_last, near WORD iP_last);

#pragma code
void main(void){
	//2620
	ADCON0 = 0x00;
	ADCON1 = 0x00;
	////26k22
	//ANSELA = 0b00000000 ;    // all digital
	//ANSELB = 0b00000000 ;
	//ANSELC = 0b00000000 ;
	TRISA  = 0b00000000 ;      // all output
	TRISB  = 0b00000000 ;
	TRISC  = 0b00000000 ;
	PORTA  = 0b00000000 ;
	PORTB  = 0b00000000 ;
	PORTC  = 0b00000000 ;
	// C port		//1			0		0		1		0		0		0		0
	//				//RX		TX		SDO		SDI		SCK		C2		C1		C0
	TRISC = 0x90;
	// TXSTA		//0			0		1		0		0		1		0		0
	//				//CSRC		TX9		TXEN	SYNC	-		BRGH	TRMT	TX9D
	TXSTA = 0x24;
	// RCSTA		//1			0		0		1		0		0		0		0
	//				//SPEN		RX9		SREN	CREN	ADDEN	FERR	OERR	RX9D
	RCSTA = 0x90;
	// BAUDCON		//0			0		0		0		0		0		0		0
	//				//ABDOVF	RCIDL	RXDTP	TXCKP	BRG16	-		WUE		ABDEN
	BAUDCON = 0x00;	
	// SPBRG	(36.864 MHz)	
	// SPBRG = 0x13,  013H=19,  36.864/(16(1+19)) =	115.2 Kbps
	// SPBRG = 0x04,  004H=4,  36.864/(16(1+4)) =	460.8 Kbps
	// SPBRG = 0x01,  001H=1,  36.864/(16(1+1)) =	1.152 Mbps
	// SPBRG = 0x00,  000H=0,  36.864/(16(1+0)) =	2.304 Mbps
	SPBRG = 0x00;

	FXMA_CS0_TRIS = 0;
	FXMA_CS0_IO = 0;

	while(1){
		LED0_IO = 1;
		for(Wi = 0; Wi < 2; Wi++)
		{
			if (RCSTAbits.OERR) 
			{
				RCSTAbits.CREN = 0;
				Temp1 = RCREG;
				RCSTAbits.CREN = 1;
			}
			_asm BTFSS  PIR1, 5, 0 _endasm      // RCIF in P1R1 = 5
			_asm BRA -2	       _endasm
			vBANK01[Wi]  = RCREG;
		}
		vBuffer[0] = vBANK01[0];
		vBuffer[1] = vBANK01[1];
		vBuffer[2] = 0x0A;  // LF
		for(i = 0; i < 3; i++)		
		{
			_asm BTFSS TXSTA, 1, 0 _endasm      // TRMT in TXSTA = 1
			_asm BRA   -2	       _endasm
			TXREG  =  vBuffer[i];
		}

		/// 2-phase mode on full-step drive
		LED0_IO = 0;
		// preparation of the received commands
		switch(vBuffer[0])
		{
			case 'A':	
				DirectionT =1;    // CW
				iT_last=64;         // 45 degree
				break;
			case 'a':
				DirectionT =2;    // CCW
				iT_last=64;         // 45 degree
				break;
			case 'B':
				DirectionT =1;    // CW
				iT_last=128;       // 90 degree
				break;
			case 'b':
				DirectionT =2;    // CCW
				iT_last=128;       // 90 degree
				break;
			default:    
				DirectionT =1;    // CW
				iT_last=0;          // 0 degree
		}
		switch(vBuffer[1])
		{
			case 'A':
				DirectionP =1;    // CW
				iP_last=64;         // 45 degree
				break;
			case 'a':
				DirectionP =2;    // CCW
				iP_last=64;         // 45 degree
				break;
			case 'B':
				DirectionP =1;    // CW
				iP_last=128;       // 90 degree
				break;
			case 'b':
				DirectionP =2;    // CCW
				iP_last=128;       // 90 degree
				break;
			default:    
				DirectionP =1;    // CW
				iP_last=0;          // 0 degree
		}

		/// drive motor
		if(DirectionT==1 && DirectionP==1)              // T-CW & P-CW
		{ 
			tCW_pCW(iT_last, iP_last);
		}
		if(DirectionT==2 && DirectionP==1)              // T-CCW & P-CW
		{ 
			tCCW_pCW(iT_last, iP_last);
		}
		if(DirectionT==1 && DirectionP==2)              // T-CW & P-CCW
		{ 
			tCW_pCCW(iT_last, iP_last);
		}
		if(DirectionT==2 && DirectionP==2)              // T-CCW & P-CCW
		{ 
			tCCW_pCCW(iT_last, iP_last);
		}
	}
	FXMA_CS0_IO = 1;		
}

#pragma tmpdata
//////   stepper-motor functions
void tCW_pCW(near WORD iT_last, near WORD iP_last)
{
    /// T-CW & P-CW
    WORD iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCCW_pCW(near WORD iT_last, near WORD iP_last)
{
    /// T-CCW & P-CW
    WORD iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCW_pCCW(near WORD iT_last, near WORD iP_last)
{
    /// T-CW & P-CCW
    WORD iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

void tCCW_pCCW(near WORD iT_last, near WORD iP_last)
{
    /// T-CCW & P-CCW
    WORD iiT, iiP;
    iiT=0;
    iiP=0;
    for(; ; )
    {
        if(iiT>=iT_last && iiP>=iP_last) {  break;  }
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =1 ;
            TAIN2_IO =0 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =1 ;
            PAIN2_IO =0 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =1 ;
            TAIN2_IO =1 ;
            TBIN2_IO =0 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =1 ;
            PAIN2_IO =1 ;
            PBIN2_IO =0 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =0 ;
            TBIN1_IO =0 ;
            TAIN2_IO =1 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =0 ;
            PBIN1_IO =0 ;
            PAIN2_IO =1 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        if(iiT<iT_last){
            TAIN1_IO =1 ;
            TBIN1_IO =0 ;
            TAIN2_IO =0 ;
            TBIN2_IO =1 ;
        }
        if(iiP<iP_last){
            PAIN1_IO =1 ;
            PBIN1_IO =0 ;
            PAIN2_IO =0 ;
            PBIN2_IO =1 ;
        }
        Delay10KTCYx(2) ;        //  28BYJ-48
        iiT++;
        iiP++;
    }
}

C18用のHardwareProfile.hです。

// HardwareProfile.h
#ifndef __HARDWARE_PROFILE_H
#define __HARDWARE_PROFILE_H
// Clock frequency value.  This value is used to calculate Tick Counter value
	#define GetSystemClock()		(36864000ul)		  // 9.216MHz Crystal,  PLLx4
	#define GetInstructionClock()	(GetSystemClock()/4)
	#define GetPeripheralClock()	GetInstructionClock()
// IO pins
	#define 	LED0_TRIS		(TRISAbits.TRISA0)	// LED
	#define 	LED0_IO			(LATAbits.LATA0)
    #define		FXMA_CS0_TRIS	(TRISCbits.TRISC0)	// fxma OE
	#define		FXMA_CS0_IO		(LATCbits.LATC0)
	#define		TAIN1_TRIS		(TRISAbits.TRISA1)
	#define		TAIN1_IO		(LATAbits.LATA1)
	#define		TBIN1_TRIS		(TRISAbits.TRISA2)
	#define		TBIN1_IO		(LATAbits.LATA2)
	#define		TAIN2_TRIS		(TRISAbits.TRISA3)
	#define		TAIN2_IO		(LATAbits.LATA3)
	#define		TBIN2_TRIS		(TRISAbits.TRISA4)
	#define		TBIN2_IO		(LATAbits.LATA4)
	#define		PAIN1_TRIS		(TRISBbits.TRISB1)
	#define		PAIN1_IO		(LATBbits.LATB1)
	#define		PBIN1_TRIS		(TRISBbits.TRISB2)
	#define		PBIN1_IO		(LATBbits.LATB2)
	#define		PAIN2_TRIS		(TRISBbits.TRISB3)
	#define		PAIN2_IO		(LATBbits.LATB3)
	#define		PBIN2_TRIS		(TRISBbits.TRISB4)
	#define		PBIN2_IO		(LATBbits.LATB4)
#endif

C18用2620のConfiguration Bitsの画面コピーです。
Configuration Bits PIC18F2620.png

C18用26K22のConfiguration Bitsの画面コピーです。
Configuration Bits PIC18F26K22.png

スマートなプログラムではありませんが、ぎこちない動作ながら、どうにか動きます。よく見かけるプログラムです。何かのお役に立てるのであれば、変更なども含め、ご自由にお使いください。

最後に、今回使用したモーターに関して: モノポーラのステッピングモーター28BYJ-48は、今回の120Hz以上速く動かすことはできません。0.703度/8msですから、32msでは2.812度しか動きません。45度回転させるのに、約500msもかかります。しかしHOLD Torqueは、わずか250mAの消費電流で約0.4 Kgf・cmもありますから、コスパは最高です。重量もわずか40gです。モバイルバッテリーで、微小角を動かしながらの静止保持に最適です。今回は、ラズパイカメラ等のジンバルなども想定していました。

一方、さらに大きなHOLD Torqueが必要な場合、バイポーラのステッピングモーターST-42BYH1004-5013(Nema17相当品)は、HOLD Torqueが10倍の4.4 Kgf・cmもあります。パワーユニットをDRV8835に変え、プログラム中のfunctionsの待ち時間を変えるだけで動かすことができます。ただし消費電流が1個1Aですから、2個で2Aです。相当大きなモバイルバッテリーが必要です。さらに重量も10倍の400gです。XYプロッター・3Dプリンターに使われているNema17に近い性能があり、小さいながら本格的なステッピングモーターです。そして28BYJ-48とは異なり、相当速く回転させることができます。XYプロッターが、素早く動いて位置決めするイメージです。スッ、スッ、と素早く動きます。しかし値段も10倍します。構造的にも、さらに精密ですから。

結局、28BYJ-48の回転が遅い根本的な原因は、トルクをかせぐために、ギヤ比を1/64にしているためのようです。ギヤ歯車を外すと、比較的簡素な構造の28BYJ-48は、トルクが得られません。28BYJ-48の位置付けは、ホビー用のようです。(再び、但しホビーながら、待ち時間を2ms→5msにすると確実に動きます。)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?