////////////////////////////////////// // i2cで動くサーボモータの制御 // 2021.03.13 /////////////////////////////////////// // Master: Arduino Uno Digital Pinの左端にSCLとSDAのピンあり // (Arduino Duemilianove Analog 4: I2C SD Analog 5: I2C SCL) // 接続図 // +----------+ // | Aruduino |==i2c===(Servo1)===(Servo2)===(Servo3)===(Servo4) // +----------+ Address #5b #5c #5d #5e // #include <stdio.h> #include <Wire.h> //i2cを使うのに必要なライブラリ #define SV1_ADR 0x5b //スレーブ1のアドレス #define SV2_ADR 0x5c //スレーブ2のアドレス #define SV3_ADR 0x5d //スレーブ3のアドレス #define SV4_ADR 0x5e //スレーブ4のアドレス #define LEFT 0x12 //Duty Value LEFT #define CENTER 0x2f //Duty Value Center #define RIGHT 0x4b //Duty Value Right //************************************ // servo データ書き込み // 入力 sv_adr サーボモータアドレス // t_data デューティー値 //************************************ void writeData(byte sv_adr,byte t_data){ Wire.beginTransmission(sv_adr); //スレーブのアドレスを発信 Wire.write(t_data); //データ転送 Wire.endTransmission(); //通信の終了 delay(1); } //////////////////////// // Set up //////////////////////// void setup() { delay(1000); Wire.begin(); //i2c初期化 delay(1000); } /////////////////////// // main loop /////////////////////// void loop(){ writeData(SV1_ADR,RIGHT); //スレーブ1サーボを右90° delay(500); writeData(SV2_ADR,RIGHT); //スレーブ2サーボを右90° delay(500); writeData(SV3_ADR,RIGHT); //スレーブ3サーボを右90° delay(500); writeData(SV4_ADR,RIGHT); //スレーブ4サーボを右90° delay(500); writeData(SV1_ADR,CENTER); //スレーブ1サーボを中央0° delay(500); writeData(SV2_ADR,CENTER); //スレーブ2サーボを中央0° delay(500); writeData(SV3_ADR,CENTER); //スレーブ3サーボを中央0° delay(500); writeData(SV4_ADR,CENTER); //スレーブ4サーボを中央0° delay(500); writeData(SV1_ADR,LEFT); //スレーブ1サーボを左90° delay(500); writeData(SV2_ADR,LEFT); //スレーブ2サーボを左90° delay(500); writeData(SV3_ADR,LEFT); //スレーブ3サーボを左90° delay(500); writeData(SV4_ADR,LEFT); //スレーブ4サーボを左90° delay(500); writeData(SV1_ADR,CENTER); //スレーブ1サーボを中央0° writeData(SV2_ADR,CENTER); //スレーブ2サーボを中央0° writeData(SV3_ADR,CENTER); //スレーブ3サーボを中央0° writeData(SV4_ADR,CENTER); //スレーブ4サーボを中央0° 以下略 } |
/* * i2cマスターからduty値を受け取りサーボモータを制御するi2cスレーブ側のシステム * スレーブCPU PIC12F1840 サーボモータSG-90(秋月電子より購入) * CPU ピン配置 |--u--| VDD=|1 8|=VSS PWM(RA5)=|2 7|=(RA0) (RA4)=|3 6|=(RA1)SCL MCLR(RA3)=|4 5|=(RA2)SDA ~~~~~~ */ #include<stdio.h> #include <xc.h> #include <pic12f1840.h> //config1 #pragma config FOSC=INTOSC //Oscillator Selection 内部クロック使用 #pragma config WDTE=OFF //Watchdog Timer off #pragma config PWRTE=ON //Power up timer on(スイッチを入れた直後電源が安定するまで待つ) #pragma config MCLRE=OFF //MCLR PIN off (ハードウェアリセットのピンの用途を無しにしてdigital pinとして使えるようにする) #pragma config CP=OFF //CODE PROTECT OFF プログラムの読み出しのプロテクトoff #pragma config CPD=OFF //Data Protect OFF データ領域の読み出しのプロテクトoff #pragma config BOREN=ON // Brownout on (もし電源が不安定のとき一時停止する) #pragma config CLKOUTEN=OFF // CLOCK 信号の外部出力をOFF #pragma config IESO=OFF // 2段階クロックoff(立ち上がりで即安定する内部クロックを使いその後外部クロックに切り替える設定) #pragma config FCMEN=OFF //Fale-safe Clock Monitor off(外部クロックが壊れたとき内部クロックに切り替える設定) //config2 #pragma config WRT=OFF //Write Protection プログラム領域の書き込み禁止 off #pragma config PLLEN=OFF //クロック逓倍off (onにすると発生したクロックが4倍になる) #pragma config STVREN=ON //スタック領域をオーバーしたらリセットする(offは何もしない) #pragma config BORV=HI // Brounout電圧設定 (HI:電源電圧がちょっとさがるとリセット、LO:うんと下がるとリセット) #pragma config LVP=OFF //プログラム書き込み電圧(ON;低電圧書き込み有効 マイコンの電圧で書き込める off:低電圧書き込み無効 PICKIT3のときoffに) #define _XTAL_FREQ 2000000 //内部clock2MHz for delay macro #define SLVADR 0xB6 //SLAVE ADDRESS //#define SLVADR 0xB8 //SLAVE ADDRESS //#define SLVADR 0xBA //SLAVE ADDRESS //#define SLVADR 0xBC //SLAVE ADDRESS #define PWMPRD 159 //PWM period for PR2 #define D_LEFT 0x4B // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x12 //Duty 12% Servo Right void dutyset(char); //Duty値出力処理 void i_read(void); //i2c 受信要求処理 void i_write(void); //i2c 送信要求処理 //void __interrupt() i2cslave(void); //割込処理 /**************************** * 割込処理 *****************************/ void __interrupt() i2cslave(void){ char x; x=SSP1STAT & 0x2C; if(x==0x08){ i_read(); //受信要求 }else if(x==0x0C){ i_write(); //送信要求 } } /***************************** * 受信要求処理 *****************************/ void i_read(void){ char x; //wrk char d_val; //duty値 x=SSP1BUF; //最初は読み捨てる do{ SSP1CON1bits.CKP=1; //stretch enable PIR1bits.SSP1IF=0; //割込フラグクリア if(SSP1STATbits.BF==0){ if(SSP1STATbits.P==1){ break; //stop検出 } }else{ //受信有り データ受信処理 d_val=SSP1BUF; if(D_LEFT < d_val ){ d_val = D_LEFT; //D_LEFTの値を超えたので修正 } if(D_RIGHT > d_val){ d_val = D_RIGHT; //D_RIGHTの値を下回ったので修正 } dutyset(d_val); //duty値出力 } }while(1); } /***************************** * 送信要求処理 * duty値を取り出してmasterに送信する *****************************/ void i_write(void){ char d_val; //duty値 char x; do{ x=CCP1CON & 0x30; //<5:4>抽出 x= x >> 4; d_val=CCPR1L <<2; d_val=d_val | x; SSP1BUF=d_val; //バッファにduty値セット SSP1CON1bits.CKP=1; //stretch解除 PIR1bits.SSP1IF=0; //割込フラグクリア }while((PIR1bits.SSP1IF==1)&&(SSP1STATbits.P==0)); } /**************************************** ; d_valの値をCCPR1L:CCP1CON<5:4> に転送 *****************************************/ void dutyset(char d_val){ char x; //wrk CCP1CON=CCP1CON & 0xCF; //4bit目と5bit目クリア x=d_val & 0x03; //下2桁をxに抽出 x=x<<4; //4ビット左シフト CCP1CON=CCP1CON | x; // CCP1CONの5bit,4bitにd_valの2bit 1bitをセット CCPR1L=d_val; CCPR1L=CCPR1L >>2; //CCPR1Lにd_valの7〜2bitをセット } /********************************** main **********************************/ int main(void){ char d_val; //duty値 OSCCON=0x60; //内部Clock 2MHz INTCONbits.GIE=0; //割り込み禁止 INTCONbits.PEIE=0; //割り込み禁止 //PORTAをディジタルI/Oにする PORTA=0; LATA=0; ANSELA=0; TRISA=0x06; //SCL,SDAのRA1,RA2は入力 RA5はPWMの出力 //ここからI2Cの設定 SSP1STAT=0x80; //SMP ON SSP1CON1=0x36; //SSP1EN=ON,I2C slave mode 7bit address SSP1ADD=SLVADR; //SLAVE ADDR SET SSP1CON2bits.SEN=1; //stretch enabled SSP1CON1bits.CKP=1; //stretch enabled PIR1bits.SSP1IF=0; //割り込みフラグクリア //ここまでI2Cの設定 //Servo 初期化 APFCONbits.CCP1SEL=1; //1:RA5をPWM出力PINに設定 //CCP1CONの下位4bitに1100をセットしてPWMを有効にする CCP1CON=CCP1CON & 0xF0; CCP1CON=CCP1CON | 0x0C; PR2=PWMPRD; //pwmの周期20msを設定 T2CON=T2CON | 0x03; //T2CONのb1,b0を11(プリスケーラ64) // Duty値設定 d_val=D_CENTER; //センターの値を設定 dutyset(d_val); //PWMスタート T2CONbits.TMR2ON=1; // ここに割り込み許可をしてからメインループへ INTCON=0; INTCONbits.INTE=1; //外部割込み許可 INTCONbits.PEIE=1; //周辺割込許可 INTCONbits.GIE=1; //周辺割込許可 PIE1bits.SSP1IE=1; //i2c 割り込み 許可 Enables the MSSP interrupt //loop while(1){ } return 0; } |