ATOM Lite(ESP32)とPIC12F1840でI2C通信を介してLチカ

今回、ATOM Lite(ESP32)をマスター、PIC12F1840をスレーブとして、I2C通信を使って、ATOM LiteからPICのLEDをオンオフさせました。
ATOM Lite(ESP32)の操作はMicroPythonを使いました。

追記:不具合発覚につき、参考程度にしてください(解決法模索中)

 

■ 回路

PIC12F1840のPin5(RA2)をSDA、Pin6(RA1)をSCLにし、Pin3(RA4)の出力でLEDを点灯させます。SDA、SCLは1~10kΩくらいでプルアップします。

 

■ プログラム

PICF121840側

下記のサイトのスレーブ側プログラムを拝借して(ありがたや)、PWM制御だと分かる範囲のところをそぎ落としました。

PIC12F1840 i2cの設定とPWMの設定 (XC8編)
https://karappi.mydns.jp/kousaku/pic12f1840/pic12f1840_c.html

 

追記:I2Cで読み取りを行った後、メインループに戻らない不具合を確認。解決法模索中

main.c

#include <stdio.h>
#include <xc.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

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 d_val;
    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_val == 0){
                RA4 = 0;
            }else{
                RA4 = 1;
            }
        }
    }while(1);
}
/*****************************
 *      送信要求処理       
 *****************************/
void i_write(void){
    do{
    SSP1BUF = 0x63; //仮値
    SSP1CON1bits.CKP=1; //stretch解除
    PIR1bits.SSP1IF=0; //割込フラグクリア
    }while((PIR1bits.SSP1IF==1)&&(SSP1STATbits.P==0));
}

/**********************************
        main
 **********************************/
int main(void){
    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は入力

    //ここから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の設定

    // 初値設定
    RA4 = 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;
}

RA4に接続してるLEDが光ればとりあえず動いているはず。

 

ATOM Lite(ESP32)側

from machine import Pin, SoftI2C

i2c = SoftI2C(scl=Pin(21), sda=Pin(25), freq=100000)

ls = i2c.scan()
print(ls)
if len(ls) == 0:
    print('no slave device')
    exit()
    
i2c.writeto(ls[0],b'\x00')

実行するとRA4のLEDが消えます。
送信のところを下記にすると、LEDがつきます。

i2c.writeto(ls[0],b'\x01')

 

なお、読み込みすると仮値で入れている0x63(99)が得られます。

v = i2c.readfrom(ls[0], 1) #1バイト読込
print(int.from_bytes(v,'big'))

 

中身はほとんどわかっていませんが、とりあえず動きました。嬉しい。
さてこの先、センサー値を渡したり独自処理できるところまでできるかどうか・・・。

 

ところで、I2Cがしたかった理由は、ATOM Liteと離れたところにセンサー等を置きたいからなんですが、I2C自体は基板間のごく短い距離を想定した通信規格で、ノイズに弱いとのこと。

まぁでもやろうとする人はいて、LANケーブル(Cat6)なら45mでもいけたという実験をした人も。

I²C延長実験(HRM1017+BME280+HDC1000)
https://t-yosh.hatenablog.com/entry/2018/10/05/145336

配線が長い場合に、出力を上げるため、I2CリピータICとかI2CバッファICとか呼ばれるICをかませる方法もあるらしい。

想定してる用途としては、最大3mといったところで、ネット情報を読み漁る限り、それなりの線ならいけるよう気がします。が、対策としてシールドケーブルや、バッファICに費用をかけるなら、M5Stamp Picoで無線通信した方が良いかもしれないし・・・、うーむ。

追記:1-wireという電線2本で長距離通信可能な通信規格があって、それをI2Cに変換してくれるDS28E18というICもあるらしい。使ってみたい、、、けど、情報少ないなぁ。。。

1-Wireスレーブ-I2C/SPIマスターブリッジデバイスモジュールキット
https://akizukidenshi.com/catalog/g/gK-15790/

Updated: 2023年2月20日 — 13:22

1 Comment

Add a Comment

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です