2020.10.10
2021.02.18
クロックは内部発振器を使う。
#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 D_LEFT 0x4E // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x0F //Duty 12% Servo Right #define LCDADR 0x7C //i2c LCD AQM1602XAのアドレス+R/wビット0 #define ADTADR_W 0x90 //ADT7410スレーブアドレス書き込みモード #define ADTADR_R 0x91 //ADT7410スレーブアドレス読み込みモード #define SERVOADR_W 0xB6 //サーボモータモジュール書き込みアドレス #define SERVOADR_R 0xB7 //サーボモータモジュール読み込みアドレス |
OSCCONレジスタに値を設定してCPUのクロックを2MHzに設定する。(スレーブ側ではサーボモータSG-90をPWM制御するの
に、これ以上高い周波数は使えない。)
OSCCON=0x60; //内部Clock 2MHz |
マスター側PICもスレーブ側PICもi2cのポートとなるSCL(RA1),SDA(RA2)はデジタルピンの入力に設定す
る
//PORTAをディジタルI/Oにする PORTA=0; LATA=0; ANSELA=0; TRISA=0x06; //SCL,SDAのRA1,RA2は入力 RA5はPWMの出力 |
//ここからI2Cの設定 SSP1STAT=0x80; //SMP ON SSP1CON1=0x28; //SSP1EN=ON,I2C master mode SSP1CON2=0; SSP1ADD=0x04; //2MHz/((04H+1)*4)=100kHz 100Kbpsの設定 PIR1bits.SSP1IF=0; //割り込みフラグクリア //ここまでI2Cの設定 |
Fig2はi2c通信の7bitアドレス方式のデータの流れである。
上段がマスターからスレーブへのデータ書き込みである。
マスターが開始条件を送信したのち7bitのスレーブアドレスにWrite=0のフラグを付加して8bitにして送信する。
バス上のアドレスが一致したスレーブからACKが返信された後マスター側は8bit毎にデータを送る。
送信データが尽きたら終了条件を送信する。
下段はマスターがスレーブからデータを受信する場合である。
マスターが開始条件を送信したのち7bitのスレーブアドレスにRead=1のフラグを付加して8bitにして送信する。
バス上のアドレスが一致したスレーブからAckが返信される。その後、スレーブが8ビットのデータをが送られるのでマスターは受信の都度
ACKを返す。
i2cモードで動作している場合はデータの送受信はSSP1BUFを介して自動で行われる。送受信の完了はそれぞれ関連するフ
ラグをチェックすることで判定できる。
/*========================================================================= ; I2C 制御モジュール群 ;=========================================================================*/ /*********************************************************************** ; 開始条件送信 ; (1)通信状態ではないときSDA,SCLともにHIGH状態(22KΩの抵抗でこの2本をプルアップ ; (2) SCLがHのままSDAがH --> L に変化したときが開始状態 ************************************************************************/ void i2cstart(void){ do{ SSP1CON1bits.WCOL=0; //SSPCONの衝突フラグクリア SSP1CON2bits.SEN=1; //開始条件送信 }while(SSP1CON1bits.WCOL==1); //衝突有り? 有りならループ継続 while(SSP1CON2bits.SEN==1){ //SEN==0でスタート処理終了 } } /********************************************************************** ; 受信処理の再開始条件送信 **********************************************************************/ void i2crestart(void){ PIR1bits.SSP1IF=0; //割込みフラグクリア SSP1CON2bits.RSEN=1; //再開始条件送信 while(SSP1CON2bits.RSEN==1){ //RSEN==0で再開始条件出力処理終了 } } /********************************************************************** データ送信 入力 W: 送信データ **********************************************************************/ void i2csend(unsigned char t_data){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1BUF=t_data; //送信データセット while(PIR1bits.SSP1IF==0){ //SSP1IF==1 送信完了になるまで待つ } while(SSP1CON2bits.ACKSTAT==1){ //ACK受信まで待つ } } /********************************************************************* ; 1バイトデータ受信 出力 受信データ *********************************************************************/ unsigned char i2crcv(void){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1CON2bits.RCEN=1; //受信許可 while(SSP1CON2bits.RCEN==1){ //RCEN==0 受信完了まで待つ } SSP1CON2bits.ACKDT=0; //ACKをセット SSP1CON2bits.ACKEN=1; //ACK送信 while(SSP1CON2bits.ACKEN==1){ //ACKEN==0 ACK送信完了まで待つ } return SSP1BUF; //データ出力 } /********************************************************************** ; 最終バイト受信 (最終バイトを受信して終了の時はCPUからNACKを送信) ; 出力 受信データ ;*********************************************************************/ unsigned char i2crend(void){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1CON2bits.RCEN=1; //受信許可 while(SSP1CON2bits.RCEN==1){ //RCEN==0 受信完了まで待つ } SSP1CON2bits.ACKDT=1; //NACKをセット SSP1CON2bits.ACKEN=1; //NACK送信 while(SSP1CON2bits.ACKEN==1){ //ACKEN==0 NACK送信完了まで待つ } return SSP1BUF; //データ出力 } /********************************************************************** ; 終了条件送信 ;*********************************************************************/ void i2cend(){ PIR1bits.SSP1IF=0; //割り込みフラグクリア SSP1CON2bits.PEN=1; //ストップ出力 while(SSP1CON2bits.PEN==1){ //PEN==0 出力完了まで待つ } PIR1bits.SSP1IF=0; //割り込みフラグクリア } |
#define
LCDADR 0x7C
//i2c LCD AQM1602XAのアドレス+R/wビット // Arduinoで使う場合はたぶん3EH |
/*============================================================= * LCD 制御モジュール群 * ===========================================================*/ /**************************** LCD 初期化 *****************************/ void lcd_init(void){ __delay_ms(50); //50ms wait(datasheets:40ms以上待つ) i2cstart(); //開始条件送信 i2csend(LCDADR); //LCDのスレーブアドレス+W 送信 //Function set #1 i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x38); //Instruction送信 Function Set(instruction table #0) __delay_us(30); //30μs待つ //Function set #2 i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x39); //Instruction送信 Function Set(instruction table #1) __delay_us(30); //30μs待つ //Internal OSC Frequency i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x16); //Instruction 送信 __delay_us(30); //30μs待つ //Contrast set i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x73); //Instruction 送信 __delay_us(30); //30μs待つ //Power /Con /Contrast i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x54); //Instruction 送信 __delay_us(30); //30μs待つ //Follower Control i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x6C); //Instruction 送信 __delay_ms(200); //200ms待 つ //Function set i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x38); //Function Set(instruction table #0に戻す) __delay_us(30); //30μs待つ //Clear Display i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x01); //Instruction送信 //Display ON/OFF control i2csend(0x00); //control byte 送信 00H ;Co=OFF RS=0 i2csend(0x0c); __delay_us(30); //30μs待つ i2cend(); //I2C終了条件送信処理 } /************************************** LCD COMMAND 実行 入力(コマンド1バイト) **************************************/ void lcd_exe(unsigned char lcdwbf){ i2cstart(); //i2cスタート条件送信 i2csend(LCDADR); //LCD スレーブアドレス+W 送信 i2csend(0x00); //control byte 送信 00H:Co=OFF RS=0 i2csend(lcdwbf); //Instruction(=コマンド)送信 i2cend(); //I2C終了条件送信処理 } /************************************ LCD DATA WRITE 入力(データ1バイト) ***********************************/ void lcd_write(unsigned char lcdwbf){ i2cstart(); //i2cスタート条件送信 i2csend(LCDADR); //LCD スレーブアドレス+W 送信 i2csend(0x40); //control byte 送信 00H:Co=OFF RS=1 i2csend(lcdwbf); //data送信 i2cend(); //I2C終了条件送信処理 } /************************************ LCD Off ***********************************/ void lcd_off(void){ lcd_exe(0x08); } /*********************************** LCD ON * 表示ON カーソルはoff (カーソルonの場合は0EHを設定) **********************************/ void lcd_on(void){ lcd_exe(0x0c); } /********************************** LCD CLEAR **********************************/ void lcd_clear(void){ lcd_exe(0x01); __delay_us(600); //600μ wait __delay_ms(1); //1ms wait } /******************************** カーソルの位置を1行目の先頭にセット ********************************/ void lcd_l1(void){ lcd_exe(0x80); //MSB=1 +DDRAMADDRESS(000 0000) } /******************************** カーソルの位置を2行目の先頭にセット ********************************/ void lcd_l2(void){ lcd_exe(0xC0); //MSB=1 +DDRAMADDRESS(100 0000) } /******************************** カーソルの位置を右シフト(使ってないけど) ********************************/ void lcd_right(void){ lcd_exe(0x14); __delay_us(50); //50μS wait } /********************************** 16進数--> LCD 表示 例 3AH --> 3A とカレントのカーソル位置から表示 **********************************/ void hex2lcd( char hex2wrk){ char x; //wrk //上位4bitの処理B x = hex2wrk >> 4; //上位4bitを下位に x = x & 0x0f; if (x > 9){ x=0x40 + (x-9); }else{ x = 0x30 + x; } lcd_write(x); //下位4bitの処理 x=hex2wrk & 0x0f; //下位4bitを抽出 if (x > 9){ x=0x40 + (x-9); }else{ x=0x30+x; } lcd_write(x); } |
#define
ADTADR_W 0x90
//ADT7410スレーブアドレス書き込みモード #define ADTADR_R 0x91 //ADT7410スレーブアドレス読み込みモード |
/******************************** ADT7410から温度を読み込む ********************************/ void adt_read(char *temph, char *templ){ i2cstart(); //開始条件送信 i2csend(ADTADR_W); //ADTアドレス(書込用) i2csend(0x00); //温度レジスタHigh 0番地 i2crestart(); //開始条件再送 i2csend(ADTADR_R); //ADTアドレス(読込用) *temph=i2crcv(); //ADTより温度上位バイト受信 *templ=i2crcv(); //ADTより温度下位バイト受信 i2cend(); } /************************************************************* ; 温度計算 ; (TEMPH,TEMPL)から10進数の温度(ondo4,ondo3,ondo2,ondo1,ondo0)に変換 * ondo4は符号(-) *ondo3 十進2桁目 *ondo2 十進1桁目 *ondo1 小数1位 *ondo0 小数2位 ; (1)*ondo4にスペース20H,*ondo3,*ondo2はそれぞれ0クリア ; (2)TEMPHのMSBが1なら *ondo4'-'を入れる ; (3)TEMPHのMSBが1なら (TEMPH,TEMPL)の0と1をひっくり返して+1する ; (4)(TEMPH,TEMPL)を2倍(左シフト)してT_WRKH,T_WRKLに入れる ; (5)T_WRKHを10進数にして十の位を*ondo3に、一の位を*ondo0に入れる ; (6)T_WRKlの上位4bitを十進数小数部1位、2位にセットする ; (7) *ondo3がスペースかつ*ondo3〜*ondo0が0なら- 0.00なので*ondo4の'-'をスペースに置き換える ; (8)*ondo3〜*ondo0の数値を文字コードにする。ただし*ondo3がスペースのときは*ondo2〜*ondo0を文字コードにする。 *************************************************************/ void t_cal(char temph,char templ,char *ondo4,char *ondo3,char *ondo2,char *ondo1,char *ondo0){ //(1)の処理 *ondo4=0x20; //十進温度の符号 とりあえずスペースを入れる *ondo3=0; //十進温度十の位 とりあえず0 *ondo2=0; //十進温度一の位 とりあえず0 //(2),(3)の処理 if((temph & 0x80) ==0x80){ //temphのMSBが1なら氷点下 *ondo4='-'; temph=~temph; //ビット反転 templ=~templ; //ビット反転 templ=templ+1; if(STATUSbits.C==1){ temph=temph+1; } } //(4)の処理 if((templ & 0x80 ) ==0){ templ=templ << 1; temph=temph << 1; }else{ templ=templ<<1; temph=temph<<1; temph=temph | 0x01; } //(5)の処理 while(temph>=10){ *ondo3=*ondo3+1; temph=temph-10; } *ondo2=temph; //(6)の処理 switch(templ & 0xF0){ case 0x00: *ondo1=0; *ondo0=0; break; case 0x10: *ondo1=0; *ondo0=6; break; case 0x20: *ondo1=1; *ondo0=3; break; case 0x30: *ondo1=1; *ondo0=9; break; case 0x40: *ondo1=2; *ondo0=5; break; case 0x50: *ondo1=3; *ondo0=1; break; case 0x60: *ondo1=3; *ondo0=8; break; case 0x70: *ondo1=4; *ondo0=4; break; case 0x80: *ondo1=5; *ondo0=0; break; case 0x90: *ondo1=5; *ondo0=6; break; case 0xA0: *ondo1=6; *ondo0=3; break; case 0xB0: *ondo1=6; *ondo0=9; break; case 0xC0: *ondo1=7; *ondo0=5; break; case 0xD0: *ondo1=8; *ondo0=1; break; case 0xE0: *ondo1=8; *ondo0=8; break; case 0xF0: *ondo1=9; *ondo0=4; break; default: *ondo1=0; *ondo0=0; } //(7)の処理 - 0.00 は-を消す if ((*ondo3==0x20)&& (*ondo2 + *ondo1 + *ondo0 == 0)){ *ondo4=0x20; } //(8)の処理 if(*ondo3 != 0x20){ *ondo3=*ondo3+0x30; //文字に変換 } *ondo2=*ondo2+0x30;//文字に変換 *ondo1=*ondo1+0x30;//文字に変換 *ondo0=*ondo0+0x30;//文字に変換 //(8)の処理 if(*ondo3==0x30){ *ondo3=0x20; //ondo1が'0'ならスペースに置き換える } //(9)の処理 if((*ondo3==0x20) && (*ondo2 == 0x30)){ *ondo4=0x20; // 0℃のときは*ondo2,*ondo1ともにスペースにする '-'は表示しない } } |
#define
SERVOADR_W 0xB6
//サーボモータモジュール書き込みアドレス #define SERVOADR_R 0xB7 //サーボモータモジュール読み込みアドレス #define D_LEFT 0x4E // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x0F //Duty 12% Servo Right |
/************************************************ ; DUTY値送信 ;***********************************************/ void send_duty(char d_val){ i2crestart(); //開始条件送信 i2csend(SERVOADR_W); //サーボモータ書込用アドレス i2csend(d_val); i2cend(); } /************************************************ ; DUTY値受信 ;************************************************/ char receive_duty(void){ char rcv_wrk; //受信用ワーク i2crestart(); //開始条件送信 i2csend(SERVOADR_R); //サーボモータ読込用アドレス rcv_wrk=i2crend(); i2cend(); return rcv_wrk; } /*====================================== main ========================================*/ int main(void){ char d_val; //Duty 5%〜10% 初期値 7.25% char temph; //adtから受信した温度上位バイト char templ; //adtから受信した温度下位バイト char ondo4; //10進温度の + - の符号 char ondo3; //10進温度の2桁目 char ondo2; //10進温度の1桁目 char ondo1; //10進温度の小数1桁目 char ondo0; //10進温度の小数2桁目 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=0x28; //SSP1EN=ON,I2C master mode SSP1CON2=0; SSP1ADD=0x04; //2MHz/((04H+1)*4)=100kHz 100Kbpsの設定 PIR1bits.SSP1IF=0; //割り込みフラグクリア //ここまでI2Cの設定 lcd_init(); //LCD初期化 lcd_on(); //LCD ON //main loop while(1){ adt_read(&temph, &templ); //温度取得 --> temph,templ lcd_exe(0xc0); //2行目0文字目に位置設定 hex2lcd(temph); //温度上位バイトをそのまま16進数でLDDに表示 hex2lcd(templ); //温度上位バイトをそのまま16進数でLDDに表示 t_cal(temph,templ,&ondo4,&ondo3,&ondo2,&ondo1,&ondo0); //温度の10進数--->ondo2,ondo1,ondo0 lcd_exe(0xc8); //2行目8文字をセット lcd_write(ondo4); lcd_write(ondo3); lcd_write(ondo2); lcd_write('.'); //小数点 lcd_write(ondo1); lcd_write(ondo0); lcd_write(0xf2);//℃の丸 lcd_write('C'); //℃のC if((ondo2 & 0x01) ==0){ d_val=D_RIGHT; //温度が偶数ならサーボを右にきる }else{ d_val=D_LEFT; //温度が奇数ならサーボを右にきる } send_duty(d_val); //サーボモータduty値を送信 //送信したduty値の表示 lcd_exe(0x80); //表示位置セット 1行目1文字目 lcd_write('T'); lcd_write('X'); lcd_write(':'); hex2lcd(d_val); //d_valを16進数で表示 __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait //serbo motor モジュールからDuty値受信 d_val=receive_duty(); //duty値-->rcv_wrk lcd_exe(0x88); //表示位置セット 1行目8文字目 lcd_write('R'); lcd_write('X'); lcd_write(':'); hex2lcd(d_val); //d_valを16進数で表示 } } |
/* 2021.02.18 作成 ; CPU ピン配置 PIC12F1840 ; |--u--| ; VDD=|1 8|=VSS ; PWM(RA5)=|2 7|=(RA0) ; (RA4)=|3 6|=(RA1)SCL ; (RA3)=|4 5|=(RA2)SDA ; ~~~~~~ ; クロック2MHz ; 摂氏の温度(10進数)が偶数ならスレーブ(0B6HのCPU)のサーボを右に、奇数ならサーボを左にする ; スレーブアドレス0B6HのマイコンからDuty値を受信してLCD1行目8文字目に表示 */ #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 D_LEFT 0x4E // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x0F //Duty 12% Servo Right #define LCDADR 0x7C //i2c LCD AQM1602XAのアドレス+R/wビット0 #define ADTADR_W 0x90 //ADT7410スレーブアドレス書き込みモード #define ADTADR_R 0x91 //ADT7410スレーブアドレス読み込みモード #define SERVOADR_W 0xB6 //サーボモータモジュール書き込みアドレス #define SERVOADR_R 0xB7 //サーボモータモジュール読み込みアドレス /**************************** * 割込処理 *****************************/ void __interrupt() isr(void){ //今回は割り込み処理は使わない } /*========================================================================= ; I2C 制御モジュール群 ;=========================================================================*/ /*********************************************************************** ; 開始条件送信 ; (1)通信状態ではないときSDA,SCLともにHIGH状態(22KΩの抵抗でこの2本をプルアップ ; (2) SCLがHのままSDAがH --> L に変化したときが開始状態 ************************************************************************/ void i2cstart(void){ do{ SSP1CON1bits.WCOL=0; //SSPCONの衝突フラグクリア SSP1CON2bits.SEN=1; //開始条件送信 }while(SSP1CON1bits.WCOL==1); //衝突有り? 有りならループ継続 while(SSP1CON2bits.SEN==1){ //SEN==0でスタート処理終了 } } /********************************************************************** ; 受信処理の再開始条件送信 **********************************************************************/ void i2crestart(void){ PIR1bits.SSP1IF=0; //割込みフラグクリア SSP1CON2bits.RSEN=1; //再開始条件送信 while(SSP1CON2bits.RSEN==1){ //RSEN==0で再開始条件出力処理終了 } } /********************************************************************** データ送信 入力 W: 送信データ **********************************************************************/ void i2csend(char t_data){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1BUF=t_data; //送信データセット while(PIR1bits.SSP1IF==0){ //SSP1IF==1 送信完了になるまで待つ } while(SSP1CON2bits.ACKSTAT==1){ //ACK受信まで待つ } } /********************************************************************* ; 1バイトデータ受信 出力 受信データ *********************************************************************/ char i2crcv(void){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1CON2bits.RCEN=1; //受信許可 while(SSP1CON2bits.RCEN==1){ //RCEN==0 受信完了まで待つ } SSP1CON2bits.ACKDT=0; //ACKをセット SSP1CON2bits.ACKEN=1; //ACK送信 while(SSP1CON2bits.ACKEN==1){ //ACKEN==0 ACK送信完了まで待つ } return SSP1BUF; //データ出力 } /********************************************************************** ; 最終バイト受信 (最終バイトを受信して終了の時はCPUからNACKを送信) ; 出力 受信データ ;*********************************************************************/ char i2crend(void){ PIR1bits.SSP1IF=0; //割込フラグクリア SSP1CON2bits.RCEN=1; //受信許可 while(SSP1CON2bits.RCEN==1){ //RCEN==0 受信完了まで待つ } SSP1CON2bits.ACKDT=1; //NACKをセット SSP1CON2bits.ACKEN=1; //NACK送信 while(SSP1CON2bits.ACKEN==1){ //ACKEN==0 NACK送信完了まで待つ } return SSP1BUF; //データ出力 } /********************************************************************** ; 終了条件送信 ;*********************************************************************/ void i2cend(){ PIR1bits.SSP1IF=0; //割り込みフラグクリア SSP1CON2bits.PEN=1; //ストップ出力 while(SSP1CON2bits.PEN==1){ //PEN==0 出力完了まで待つ } PIR1bits.SSP1IF=0; //割り込みフラグクリア } /*============================================================= * LCD 制御モジュール群 * ===========================================================*/ /**************************** LCD 初期化 *****************************/ void lcd_init(void){ __delay_ms(50); //50ms wait(datasheets:40ms以上待つ) i2cstart(); //開始条件送信 i2csend(LCDADR); //LCDのスレーブアドレス+W 送信 //Function set #1 i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x38); //Instruction送信 Function Set(instruction table #0) __delay_us(30); //30μs待つ //Function set #2 i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x39); //Instruction送信 Function Set(instruction table #1) __delay_us(30); //30μs待つ //Internal OSC Frequency i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x16); //Instruction 送信 __delay_us(30); //30μs待つ //Contrast set i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x73); //Instruction 送信 __delay_us(30); //30μs待つ //Power /Con /Contrast i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x54); //Instruction 送信 __delay_us(30); //30μs待つ //Follower Control i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x6C); //Instruction 送信 __delay_ms(200); //200ms待 つ //Function set i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x38); //Function Set(instruction table #0に戻す) __delay_us(30); //30μs待つ //Clear Display i2csend(0x80); //control byte 送信 80H ;Co=ON RS=0 i2csend(0x01); //Instruction送信 //Display ON/OFF control i2csend(0x00); //control byte 送信 00H ;Co=OFF RS=0 i2csend(0x0c); __delay_us(30); //30μs待つ i2cend(); //I2C終了条件送信処理 } /************************************** LCD COMMAND 実行 入力(コマンド1バイト) **************************************/ void lcd_exe(char lcdwbf){ i2cstart(); //i2cスタート条件送信 i2csend(LCDADR); //LCD スレーブアドレス+W 送信 i2csend(0x00); //control byte 送信 00H:Co=OFF RS=0 i2csend(lcdwbf); //Instruction(=コマンド)送信 i2cend(); //I2C終了条件送信処理 } /************************************ LCD DATA WRITE 入力(データ1バイト) ***********************************/ void lcd_write(char lcdwbf){ i2cstart(); //i2cスタート条件送信 i2csend(LCDADR); //LCD スレーブアドレス+W 送信 i2csend(0x40); //control byte 送信 00H:Co=OFF RS=1 i2csend(lcdwbf); //data送信 i2cend(); //I2C終了条件送信処理 } /************************************ LCD Off ***********************************/ void lcd_off(void){ lcd_exe(0x08); } /*********************************** LCD ON * 表示ON カーソルはoff (カーソルonの場合は0EHを設定) **********************************/ void lcd_on(void){ lcd_exe(0x0c); } /********************************** LCD CLEAR **********************************/ void lcd_clear(void){ lcd_exe(0x01); __delay_us(600); //600μ wait __delay_ms(1); //1ms wait } /******************************** カーソルの位置を1行目の先頭にセット ********************************/ void lcd_l1(void){ lcd_exe(0x80); //MSB=1 +DDRAMADDRESS(000 0000) } /******************************** カーソルの位置を2行目の先頭にセット ********************************/ void lcd_l2(void){ lcd_exe(0xC0); //MSB=1 +DDRAMADDRESS(100 0000) } /******************************** カーソルの位置を右シフト(使ってないけど) ********************************/ void lcd_right(void){ lcd_exe(0x14); __delay_us(50); //50μS wait } /********************************** 16進数--> LCD 表示 例 3AH --> 3A とカレントのカーソル位置から表示 **********************************/ void hex2lcd( char hex2wrk){ char x; //wrk //上位4bitの処理B x = hex2wrk >> 4; //上位4bitを下位に x = x & 0x0f; if (x > 9){ x=0x40 + (x-9); }else{ x = 0x30 + x; } lcd_write(x); //下位4bitの処理 x=hex2wrk & 0x0f; //下位4bitを抽出 if (x > 9){ x=0x40 + (x-9); }else{ x=0x30+x; } lcd_write(x); } /******************************** ADT7410から温度を読み込む ********************************/ void adt_read(char *temph, char *templ){ i2cstart(); //開始条件送信 i2csend(ADTADR_W); //ADTアドレス(書込用) i2csend(0x00); //温度レジスタHigh 0番地 i2crestart(); //開始条件再送 i2csend(ADTADR_R); //ADTアドレス(読込用) *temph=i2crcv(); //ADTより温度上位バイト受信 *templ=i2crcv(); //ADTより温度下位バイト受信 i2cend(); } /************************************************************* ; 温度計算 ; (TEMPH,TEMPL)から10進数の温度(ondo4,ondo3,ondo2,ondo1,ondo0)に変換 * ondo4は符号(-) *ondo3 十進2桁目 *ondo2 十進1桁目 *ondo1 小数1位 *ondo0 小数2位 ; (1)*ondo4にスペース20H,*ondo3,*ondo2はそれぞれ0クリア ; (2)TEMPHのMSBが1なら *ondo4'-'を入れる ; (3)TEMPHのMSBが1なら (TEMPH,TEMPL)の0と1をひっくり返して+1する ; (4)(TEMPH,TEMPL)を2倍(左シフト)してT_WRKH,T_WRKLに入れる ; (5)T_WRKHを10進数にして十の位を*ondo3に、一の位を*ondo0に入れる ; (6)T_WRKlの上位4bitを十進数小数部1位、2位にセットする ; (7) *ondo3がスペースかつ*ondo3〜*ondo0が0なら- 0.00なので*ondo4の'-'をスペースに置き換える ; (8)*ondo3〜*ondo0の数値を文字コードにする。ただし*ondo3がスペースのときは*ondo2〜*ondo0を文字コードにする。 *************************************************************/ void t_cal(char temph,char templ,char *ondo4,char *ondo3,char *ondo2,char *ondo1,char *ondo0){ //(1)の処理 *ondo4=0x20; //十進温度の符号 とりあえずスペースを入れる *ondo3=0; //十進温度十の位 とりあえず0 *ondo2=0; //十進温度一の位 とりあえず0 //(2),(3)の処理 if((temph & 0x80) ==0x80){ //temphのMSBが1なら氷点下 *ondo4='-'; temph=~temph; //ビット反転 templ=~templ; //ビット反転 templ=templ+1; if(STATUSbits.C==1){ temph=temph+1; } } //(4)の処理 if((templ & 0x80 ) ==0){ templ=templ << 1; temph=temph << 1; }else{ templ=templ<<1; temph=temph<<1; temph=temph | 0x01; } //(5)の処理 while(temph>=10){ *ondo3=*ondo3+1; temph=temph-10; } *ondo2=temph; //(6)の処理 switch(templ & 0xF0){ case 0x00: *ondo1=0; *ondo0=0; break; case 0x10: *ondo1=0; *ondo0=6; break; case 0x20: *ondo1=1; *ondo0=3; break; case 0x30: *ondo1=1; *ondo0=9; break; case 0x40: *ondo1=2; *ondo0=5; break; case 0x50: *ondo1=3; *ondo0=1; break; case 0x60: *ondo1=3; *ondo0=8; break; case 0x70: *ondo1=4; *ondo0=4; break; case 0x80: *ondo1=5; *ondo0=0; break; case 0x90: *ondo1=5; *ondo0=6; break; case 0xA0: *ondo1=6; *ondo0=3; break; case 0xB0: *ondo1=6; *ondo0=9; break; case 0xC0: *ondo1=7; *ondo0=5; break; case 0xD0: *ondo1=8; *ondo0=1; break; case 0xE0: *ondo1=8; *ondo0=8; break; case 0xF0: *ondo1=9; *ondo0=4; break; default: *ondo1=0; *ondo0=0; } //(7)の処理 - 0.00 は-を消す if ((*ondo3==0x20)&& (*ondo2 + *ondo1 + *ondo0 == 0)){ *ondo4=0x20; } //(8)の処理 if(*ondo3 != 0x20){ *ondo3=*ondo3+0x30; //文字に変換 } *ondo2=*ondo2+0x30;//文字に変換 *ondo1=*ondo1+0x30;//文字に変換 *ondo0=*ondo0+0x30;//文字に変換 //(8)の処理 if(*ondo3==0x30){ *ondo3=0x20; //ondo1が'0'ならスペースに置き換える } //(9)の処理 if((*ondo3==0x20) && (*ondo2 == 0x30)){ *ondo4=0x20; // 0℃のときは*ondo2,*ondo1ともにスペースにする '-'は表示しない } } /************************************************ ; DUTY値送信 ;***********************************************/ void send_duty(char d_val){ i2crestart(); //開始条件送信 i2csend(SERVOADR_W); //サーボモータ書込用アドレス i2csend(d_val); i2cend(); } /************************************************ ; DUTY値受信 ;************************************************/ char receive_duty(void){ char rcv_wrk; //受信用ワーク i2crestart(); //開始条件送信 i2csend(SERVOADR_R); //サーボモータ読込用アドレス rcv_wrk=i2crend(); i2cend(); return rcv_wrk; } /*====================================== main ========================================*/ int main(void){ char d_val; //Duty 5%〜10% 初期値 7.25% char temph; //adtから受信した温度上位バイト char templ; //adtから受信した温度下位バイト char ondo4; //10進温度の + - の符号 char ondo3; //10進温度の2桁目 char ondo2; //10進温度の1桁目 char ondo1; //10進温度の小数1桁目 char ondo0; //10進温度の小数2桁目 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=0x28; //SSP1EN=ON,I2C master mode SSP1CON2=0; SSP1ADD=0x04; //2MHz/((04H+1)*4)=100kHz 100Kbpsの設定 PIR1bits.SSP1IF=0; //割り込みフラグクリア //ここまでI2Cの設定 lcd_init(); //LCD初期化 lcd_on(); //LCD ON //main loop while(1){ adt_read(&temph, &templ); //温度取得 --> temph,templ lcd_exe(0xc0); //2行目0文字目に位置設定 hex2lcd(temph); //温度上位バイトをそのまま16進数でLDDに表示 hex2lcd(templ); //温度上位バイトをそのまま16進数でLDDに表示 t_cal(temph,templ,&ondo4,&ondo3,&ondo2,&ondo1,&ondo0); //温度の10進数--->ondo2,ondo1,ondo0 lcd_exe(0xc8); //2行目8文字をセット lcd_write(ondo4); lcd_write(ondo3); lcd_write(ondo2); lcd_write('.'); //小数点 lcd_write(ondo1); lcd_write(ondo0); lcd_write(0xf2);//℃の丸 lcd_write('C'); //℃のC if((ondo2 & 0x01) ==0){ d_val=D_RIGHT; //温度が偶数ならサーボを右にきる }else{ d_val=D_LEFT; //温度が奇数ならサーボを右にきる } send_duty(d_val); //サーボモータduty値を送信 //送信したduty値の表示 lcd_exe(0x80); //表示位置セット 1行目1文字目 lcd_write('T'); lcd_write('X'); lcd_write(':'); hex2lcd(d_val); //d_valを16進数で表示 __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait __delay_ms(500); //500ms wait //serbo motor モジュールからDuty値受信 d_val=receive_duty(); //duty値-->rcv_wrk lcd_exe(0x88); //表示位置セット 1行目8文字目 lcd_write('R'); lcd_write('X'); lcd_write(':'); hex2lcd(d_val); //d_valを16進数で表示 } } |
/* * i2cマスターからduty値を受け取りサーボモータを制御するi2cスレーブ側のシステム * スレーブCPU PIC12F1840 サーボモータSG-90(秋月電子より購入) * 2021.02.12 MPASMからXC8に移植 * 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 PWMPRD 159 //PWM period for PR2 #define D_LEFT 0x4E // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x0F //Duty 12% Servo Right void dutyset(char); //Duty値出力処理 void i_read(void); //i2c 受信要求処理 void i_write(void); //i2c 送信要求処理 |
/**************************** * 割込処理 *****************************/ 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値を取り出して送信する *****************************/ 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をセット } |
/* * i2cマスターからduty値を受け取りサーボモータを制御するi2cスレーブ側のシステム * スレーブCPU PIC12F1840 サーボモータSG-90(秋月電子より購入) * 2021.02.12 MPASMからXC8に移植 2021.02.18 最終版 * 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 PWMPRD 159 //PWM period for PR2 #define D_LEFT 0x4E // Duty 2.5% Servo Left #define D_CENTER 0x2F // Duty 7.25% Servo Center #define D_RIGHT 0x0F //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値を取り出して送信する *****************************/ 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; } |