0
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?

PIC16F1827 バイポーラステッピングモータ

Last updated at Posted at 2024-06-13

PICマイコンで、バイポーラステッピングモータの制御

PIC16F1827
IMG_4786.JPG

・PIC16F1827使用。

・いらなくなったDVDプレイヤーを分解し、バイポーラ型ステッピングモータを駆動させました。テスターで、コイル端子のペアを探し、半田づけしました。

バイポーラ型は、2つのコイルを、2つのHブリッジ回路で駆動します。
NJU7386HブリッジICを2個使用して、2つのコイルを制御しています。

・ステッピングモータの移動制御に、ファミコンコントローラを使用しました。

・ボリュームで、移動速度を調整します。

NJU7386 低電圧動作 H ブリッジドライバ基板

IMG_4789.JPG

自作した、基板回路図
NJU基板回路図.png

フォトカプラを使って、モーターグランドと、制御グランドを分離しています。
出力論理が、ピックマイコン側と、NJU7386側で反転しています。

ドライバーICデータシート
NJU7386題名.png

NJU7386.png
INA端子とINB端子に、ピックマイコンから信号を送信します。

NJU7386_真理値表.png

回路図(フォトカプラを省略しています。)
回路図改.png

NJU7386 2相励磁で動かす場合の出力タイミング

16F1827ピン番号 NJU7386配線名
RB4 X1(INA) 1 1 0 0
RB5 X2(INB) 0 0 1 1
RB6 Y1(INA) 0 1 1 0
RB7 Y2(INB) 1 0 0 1

※2個のNJU7386を使用。 0:OFF(Low) 1:ON(High)
①→②→③→④の順番で出力すると正転。
④→③→②→①の順番で出力すると反転。

タイミングチャート図.jpg

ステッピングモータの配線

はんだ.jpg
テスターで、導通がある端子のペアを探します。100Ωぐらいの抵抗がありました。
端子配列は、そのDVDドライブごとに違っていそうなので、テスターで確認してください。

IMG_4804.JPG
端子名が明記されているドライブもありました。

PIC16F1827 バイポーラステッピングモータ コード

PIC16F1827ピン割り当て

ADC
RA0:ANA0 input

USART
TX:RB2
RX:RB1

famicon.h
PS:RA1
CLK:RA3
DATA1: RA2

steppingMotor
RB4:X1(INA)
RB5:X2(INB)
RB6:Y1(INA)
RB7:Y2(INB)

main.c

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
//#pragma config FOSC = HS      // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP =ON      // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include "Interrupt.h"
#include "Peripheral.h"
#include "famicon.h"

#define _XTAL_FREQ  16000000

void Oscillator_Init(void);
void Port_Init(void);
void delay_ms(uint16_t time);

//バイポーラ2相励磁
/*  NJU7386に直接接続する場合の出力
    uint8_t table[4]={
    0b10010000,
    0b01010000,
    0b01100000,
    0b10100000
};*/

//自作基板の出力テーブル
//注:フォトカプラで論理が反転しています。
uint8_t table[4]={
    0b01100000,
    0b10100000,
    0b10010000,
    0b01010000
};


void main(void)
{    
    uint8_t cnt=0;
    uint8_t i,j,temp;
    uint16_t buttonState;
    uint8_t  direction;
    
    //Basic Hard Initialize
    Oscillator_Init();
    Port_Init(); 
    //Peripheral 
    Timer0_INIT();
    Timer2_INIT();
    USART_INIT();
    ADC_INIT();
    //ファミコンコントローラ初期化
    famiconInit();
    //割り込み許可
    Interrupt_START();
    direction=false;
    while(1)
    {
        //USART interrupt processing
        if(usart.rxCompleted)
        {
            usart.rxCompleted=false;
            printf("%s\n",usart.rxBuf);
            usart.length=0;
            PIE1bits.RCIE=1;
        }
        
        //Timer0 interrupt processing
        if(tm0.up)
        {
            tm0.up=false;
            LATBbits.LATB0=~LATBbits.LATB0;
            //printf("%d\n",cnt++);
            if(ADC.Completed)
            {
                ADC.Completed=false;
                printf("%d\n", ADC.data[0]);
                PIE1bits.ADIE=1;
                PIE1bits.TMR2IE=1;
            }
            direction++;
            if(direction==3)
                direction=0;
            INTCONbits.TMR0IE=1;
        }
        
        buttonState = getButton();//ファミコン押下情報取得
        if(buttonState==0xFFF0)
        {//何も押されていない
            LATB=LATB&0x0F;
            delay_ms((1038-ADC.data[0])/10);//1023
        }
      
#if 1
        //ファミコンコントローラで移動させる。
        if((buttonState&0x0200)==0x0)//Left
        {//左へ移動。
            printf("%02X\n",buttonState);
            for(i=0; i<30; i++)
                for(j=0; j<4; j++)
                {
                    temp=table[j];
                    table[j]|=(LATB&0x0F);
                    LATB = table[j];
                    table[j]=temp;
                    delay_ms((1038-ADC.data[0])/10);//1023
                }
            
        }
        if((buttonState&0x0100)==0x0)//Right
        {//右に移動
           printf("%02X\n",buttonState);
           for(i=0; i<30; i++)
                for(j=0; j<4; j++)
                {
                    temp=table[3-j];
                    table[3-j]|=(LATB&0x0F);
                    LATB = table[3-j];
                    table[3-j]=temp;
                    delay_ms((1038-ADC.data[0])/10);
                }
           
        }
#else
        //自動で左右に移動させる。
        if(direction==0)//Left
        {
            for(i=0; i<30; i++)
            for(j=0; j<4; j++)
            {
                temp=table[j];
                table[j]|=(LATB&0x0F);
                LATB = table[j];
                table[j]=temp;
                delay_ms((1038-ADC.data[0])/10);//1023
            }
        }
        if(direction==1)
        {
           for(i=0; i<30; i++)
            for(j=0; j<4; j++)
            {
                temp=table[3-j];
                table[3-j]|=(LATB&0x0F);
                LATB = table[3-j];
                table[3-j]=temp;
                delay_ms((1038-ADC.data[0])/10);
            }
        }
        if(direction==2)
        {
            LATB=LATB&0x0F;
            delay_ms((1038-ADC.data[0])/10);//1023
        }
#endif
    }
    return;
}

void Oscillator_Init(void)
{
    OSCCONbits.SPLLEN=0;
    OSCCONbits.IRCF=0b1111;//16Mhz
    OSCCONbits.SCS=0b10;//InternalOscillator
}

void Port_Init(void)
{
    TRISA=0x00;
    ANSELA=0x00;
    TRISB=0x02;     //RX:RB1
    ANSELB=0x00;
    PORTA=0x00;
    PORTB=0x00;  
    //Altanative Pin Selective
    APFCON0bits.RXDTSEL=0;  //RX:RB1
    APFCON1bits.TXCKSEL=0;  //TX:RB2
}

void delay_ms(uint16_t time)
{
    uint16_t t;
    for(t=0; t<time; t++)
        __delay_ms(1);
}
Peripheral.h

#ifndef PERIPHERAL_H
#define	PERIPHERAL_H

#include <xc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define _XTAL_FREQ 16000000

#ifdef	__cplusplus
extern "C" {
#endif

//**************************************************//    
//   USART 
//**************************************************//    
//#define BAUDRATE 19200
#define BAUDRATE 115200  
#define SET_SPBRG_DATA  (((unsigned int)((_XTAL_FREQ/16)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((_XTAL_FREQ/4)/BAUDRATE))-1)    
extern void USART_INIT(void);
extern void putch(uint8_t byte);
extern uint8_t getch(void);
#define rxLength 30
typedef struct {
    uint8_t length;
    uint8_t rxBuf[30];
    bool rxCompleted;
}_usart;    
extern _usart usart;

#define rxBuffer_length 30
typedef struct{
    uint8_t ch;
    uint8_t Buffer[rxBuffer_length];
    uint8_t index;
    uint8_t Completed;
}_rx;
extern _rx rx;

//************************************************//
//Timer0 8bits timer
//************************************************//
#define T0_UP 1
#define T0_STOP 0
typedef struct{
    bool up;
    uint16_t cnt;
}_tm0;    
extern _tm0 tm0;

//************************************************//
//Timer1
//************************************************//
#define T1_UP 1
#define T1_STOP 0
typedef struct{
    bool up;
    uint16_t cnt;
}_tm;    
extern _tm tm1;

//************************************************//
//ADC
//************************************************//
#define ADC_Sampling_Num 10    
typedef struct{
    uint8_t Ch;
    uint16_t val;
    bool    Completed;
    uint16_t data[ADC_Sampling_Num+1];
    uint8_t index;
    uint16_t RMS;
    int32_t cal;
}_ADC;
extern _ADC ADC;

extern void Timer0_INIT(void);
extern void Timer1_INIT(void); 
extern void Timer2_INIT(void);
extern void Timer4_INIT(void);
extern void Timer6_INIT(void);
extern void Interrupt_START(void);
extern void ADC_INIT(void);
extern void CCP1_PWM_Init(void);
extern void CCP2_PWM_Init(void);
extern void CCP3_PWM_Init(void);
extern void CCP4_PWM_Init(void);
#ifdef	__cplusplus
}
#endif

#endif	/* MYLIB_H */


Peripheral.c
#include <pic16f1827.h>

#include "Peripheral.h"

/*-----------------------------------------
 *USART
 *-----------------------------------------*/
_usart usart;
_rx rx;
void USART_INIT(void)
{
    uint8_t buf;
    unsigned int brg;
    //SPBRG value set
    brg = SET_SPBRG_DATA1;
    SP1BRGL =(unsigned char) brg;
    SP1BRGH =(unsigned char) (brg>>8); 
    //TX-------------------------------------
    TXREG=0x00;
    //TXSTA SYNC:1 BRGH:1 TXEN:1 TX9:0
    buf =TXSTA & 0x83;
    TXSTA = buf | 0x24;
    //RX-------------------------------------
    //RCSTA  SPEN:1 RX9:0 CREN:1
    buf =RCSTA & 0x2F;
    RCSTA =buf | 0x90;
    //BAUR RATE CONTROL REGISTER
    BAUDCON = 0x08;
    //if interrupt is desired, TXIE set(PIE1)
    PIE1bits.TXIE=0;//disable
    //if interrupts are desired, RCIE set(PIE1)
    PIE1bits.RCIE=1;//enable
    
    usart.length=0;
    usart.rxCompleted=false;
}
void putch(uint8_t byte)
{
    while(!PIR1bits.TXIF)continue;
    TXREG=byte;
}

uint8_t getch(void)
{
    while(!PIR1bits.RCIF){};
    return RCREG;
}



/*---------------------------------------------------
 Timer0     8bits Timer 
 ---------------------------------------------------*/
_tm0 tm0;
void Timer0_INIT(void)
{
    OPTION_REGbits.TMR0CS = 0;  //ClockSource:Fosc/4
    OPTION_REGbits.PSA = 0;     //assingned to the Timer0
    OPTION_REGbits.PS = 0b111;  //1:256
    TMR0=0x63;  //Fosc:32Mhz interval time 10ms
    INTCONbits.T0IE = 1;
    tm0.cnt=0;
}


/*---------------------------------------------------
 Timer1
 ---------------------------------------------------*/
 _tm tm1;
void Timer1_INIT(void)
{
    TMR1L=0x0B;//16MHz 1ms PSC:1:8
    TMR1H=0xFE;
    T1CON=0x31;    
    T1GCON=0x00;
    PIE1bits.TMR1IE=1;
    tm1.up=T0_STOP;
    tm1.cnt=0x0000;
}

/*-------------------------------------------
Timer2
--------------------------------------------*/
void Timer2_INIT(void)
{
    T2CONbits.T2OUTPS=0b0000;//post sc 1:16
    T2CONbits.T2CKPS=0b11;//PSC 1:16
    T2CONbits.TMR2ON=1;
    PR2=0xFA;//1ms matching.
    TMR2=0;
    PIR1bits.TMR2IF=0;
    PIE1bits.TMR2IE=1;
}

/*---------------------------------------------------
 Timer4
 ---------------------------------------------------*/
void Timer4_INIT(void)
{
    T4CONbits.T4OUTPS=0b1111;//1:16 Postscaler
    TMR4=0;
    T4CONbits.T4CKPS=0b01;//prescle1:4
    PR4=0x4B;
    PIE3bits.TMR4IE=1;
    PIR3bits.TMR4IF=0;
    T4CONbits.TMR4ON=1;
}

/*---------------------------------------------------
 Timer6
 ---------------------------------------------------*/
void Timer6_INIT(void)
{
    T6CONbits.T6OUTPS=0b0000;//1:16 Postscaler
    T6CONbits.T6CKPS=0b11;//prescle1:16
    T6CONbits.TMR6ON=1;
    PR6=0xFA;
    TMR6=0;
    PIR3bits.TMR6IF=0;
    PIE3bits.TMR6IE=1;
}
//interrupt start
void Interrupt_START(void)
{
    INTCONbits.PEIE=1;
    INTCONbits.GIE=1;
}
/*---------------------------------------------------
 AD converter
 -------------------------------------------------------*/
_ADC ADC;
void ADC_INIT(void)
{
    uint8_t buf;
    
    //1.Configure PortA
    buf=TRISA;
    TRISA=buf|0x01;
    ANSELA|=0x01;
  
    //2.Configure the ADC module
    ADCON1bits.ADFM=1;      //Right justified.
    ADCON1bits.ADCS=0b101;  //FOSC/16  Select ADC conversion clock
    ADCON1bits.ADNREF=0;    //Vref-:AVss Configure voltage referrence 
    ADCON1bits.ADPREF=0b00; //Vref+ is connected to Vdd.
    ADCON0bits.CHS=0x00;    //RA0:Select ADC input channel
    
    //Turn on ADC module
    ADCON0bits.ADON=1;
    PIR1bits.ADIF=0;
    PIE1bits.ADIE=1;
    
    //ADC struct data initialize
    ADC.index=0;
    ADC.cal=0;
    ADC.Completed=false;
    
  
}

/*----------------------------------------------*/
//PWM
/*-----------------------------------------------*/

//RB0
void CCP1_PWM_Init(void)
{
    CCP1CONbits.CCP1M=0b1100;//PWMmode
    CCPTMRSbits.C1TSEL0=0b00;//Timer2 in PWM mode
    CCPR1L=0x00;
    TRISB0=0;
    APFCON0bits.CCP1SEL=1;//RB0
}

//RA7
void CCP2_PWM_Init(void)
{
    CCP2CONbits.CCP2M=0b1100;//PWMmode
    CCPTMRSbits.C2TSEL0=0b00;//Timer2 in PWM mode
    CCPR2L=0x00;
    TRISA7=0;
    APFCON0bits.CCP2SEL=1;//RA7
}

//RA3
void CCP3_PWM_Init(void)
{
    CCP3CONbits.CCP3M=0b1100;//PWMmode
    CCPTMRSbits.C3TSEL0=0b00;//Timer2in PWM mode
    CCPR3L=0x00;
    TRISA3=0;
}

//RA4
void CCP4_PWM_Init(void)
{
    CCP4CONbits.CCP4M=0b1100;//PWMmode
    CCPTMRSbits.C4TSEL0=0b00;//Timer2in PWM mode
    CCPR4L=0x00;
    TRISA4=0;
}

famicon.h
#ifndef FAMICON_H
#define	FAMICON_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include "Peripheral.h"    
    
//PS:オレンジ
//CLK:黄色
//DATA1:赤    
#define PS PORTAbits.RA1
#define CLK PORTAbits.RA3
#define DATA1 PORTAbits.RA2

extern uint16_t famiconButtonState;
extern  void famiconInit(void);    
extern  uint16_t getButton(void);
    
   
#ifdef	__cplusplus
}
#endif

#endif	/* FAMICON_H */

famicon.c
#include "famicon.h"

uint16_t famiconButtonState;
///@brief コントローラーの初期化
void famiconInit(void)
{
    TRISAbits.TRISA2=1;//DATA1線
}

///@brief ボタン押下状況取得関数
///return ボタン押下16ビットデータ
uint16_t getButton(void)
{
    uint16_t w_val;
    uint8_t cnt;
    w_val=0x0000;
        cnt=0;
        
        //最初の1ビット
        PS=1;
        CLK=1;
        __delay_us(10);
        PS=0;
        CLK=0;
        __delay_us(10);
        
        w_val|=DATA1;
        w_val<<=1;
        cnt++;
        //残り15ビットの取得
        do{
            CLK=1;
            __delay_us(10);
            CLK=0;
           // __delay_us(5);
            w_val|=DATA1;
            if(cnt!=15)
            {
                w_val<<=1;
            }
            cnt++;
        }while(cnt!=16);
        //受信完了    
        w_val&=0xFFF0;//ボタンデータのみを、抽出
        /*if(w_val!=0xFFF0)    
        {
            if((w_val&0x8000)==0x0)
            {
                printf("B ");
            }
            
            if((w_val&0x4000)==0x0)
            {
                printf("Y ");
            }
            
            if((w_val&0x2000)==0x0)
            {
                printf("SELECT ");
            }
            
            if((w_val&0x1000)==0x0)
            {
                printf("START ");
            }
            
            if((w_val&0x0800)==0x0)
            {
                printf("UP ");             
            }
                        
            if((w_val&0x0400)==0x0)
            {
                printf("DOWN ");
            }
            
            if((w_val&0x0200)==0x0)
            {
                printf("LEFT ");
            }
            
            if((w_val&0x0100)==0x0)
            {
                printf("RIGHT ");
            }
            
            if((w_val&0x0080)==0x0)
            {
                printf("A ");
            }
            
            if((w_val&0x0040)==0x0)
            {
                printf("X ");
            }
            
            if((w_val&0x0020)==0x0)
            {
                printf("L ");
            }
            
            if((w_val&0x0010)==0x0)
            {
                printf("R ");
            }
            printf("%04x\r",w_val);
        }*/
        return w_val;
}

0
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
0
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?