/* * * PIC12F1822 × EEPROM(24LS256) * シリアル通信で外部シリアルROMへのデータ書き込み * - 2021/02/08 - * */ //ヘッダファイルの読み込み //-------------------------------------------------------------- #include // PIC12F1822 Configuration Bit Settings //-------------------------------------------------------------- // CONFIG1 #pragma config FOSC = INTOSC // 内部クロックを使用する #pragma config WDTE = OFF // フリーズしたときに強制リセットするか?(OFF:リセットしない) #pragma config PWRTE = OFF // 起動時、電源が安定するまで待つか?(OFF:待たない) #pragma config MCLRE = OFF // 外部からのリセット信号を受け付けるか?(OFF:受けつけない) #pragma config CP = OFF // プログラムの外部読み取りを許可するか?(OFF:許可) #pragma config CPD = OFF // データの外部読み取りを許可するか?(OFF:許可) #pragma config BOREN = ON // 電源が不安定になったとき動作を停止するか?(ON:停止する) #pragma config CLKOUTEN = OFF // 外部クロックを使用する場合の3番Pinの設定(OFF:3番Pinを入出力Pinに設定) #pragma config IESO = OFF // 外部クロックが安定するまで内部クロックを使用するか?(OFF:使用しない) #pragma config FCMEN = OFF // 外部クロックが止まったとき内部クロックを使用するか?(OFF:使用しない) // CONFIG2 #pragma config WRT = OFF // データの書き込み禁止エリアを設定するか?(OFF:設定しない) #pragma config PLLEN = OFF // 内部クロックを32MHz(8MHz×4倍)で使用するか? (OFF:使用しない) #pragma config STVREN = OFF // プログラムが暴走したときにリセットを行うか?(OFF:行わない) #pragma config BORV = LO // 電圧不足と判断してリセットされるときの電圧を設定(LO:低い電圧に設定) #pragma config LVP = OFF // PICKIT3以外のライターで書き込む場合に低電圧で書き込み可能にする(OFF:低電圧書き込み無効) // クロック周波数指定 //-------------------------------------------------------------- // __delay_ms()関数はこの数値を元にwaitする #define _XTAL_FREQ 16000000 // 割り込み関数のプロトタイプ宣言 //-------------------------------------------------------------- // C言語では使用する関数をあらかじめ宣言しておく必要がある // void:データ型なし、unsigned char:0〜255の整数) void I2C_write_set(unsigned char addr1 ,unsigned char addr2 ,unsigned char send_data); void I2C_read_set(unsigned char addr1 ,unsigned char addr2); void I2C_start(void); void I2C_send(unsigned char send_data); void I2C_receive(void); void I2C_ack(void); void I2C_nack(void); void I2C_stop(void); // ============================================================ // //   メインプログラム // // ============================================================ /*           12F1822 * −−−−−− * VDD −| 1 8 |− VSS * RA5 → PWM −| 2 7 |− AN0/RA0 * AN3/RA4 → A/D −| 3 6 |− AN1/RA1/SCL → ROM(6Pin) * RA3 → IN −| 4 5 |− AN2/RA2/SDA → ROM(5Pin) * −−−−−− */ void main(void) { //---------------------------------------------------------- // PICマイコン初期設定 //---------------------------------------------------------- // 内部クロック周波数 // | 0 | x | x | x | x | 0 | 0 | 0 | //---------------------------------------------------------- // OSCCON = 0b01011000; // 1MHz // OSCCON = 0b01100000; // 2MHz // OSCCON = 0b01101000; // 4MHz OSCCON = 0b01110000; // 8MHz //OSCCON = 0b01111000; // 16MHzに設定 // デジタル・アナログ設定(※RA3[4Pin]はデジタル固定) // | 0 | 0 | 0 | RA4 | RA3 | RA2 | RA1 | RA0 | //---------------------------------------------------------- // ANSELA = 0b00000000; // 全てデジタルモード ANSELA = 0b00010000; // RA4[3Pin]:アナログ、その他:デジタル // 入出力Pin設定(※RA3[4Pin]は入力固定) // | 0 | 0 | RA5 | RA4 | RA3 | RA2 | RA1 | RA0 | //---------------------------------------------------------- TRISA = 0b00011110; // RA5:出力、RA4:入力、RA3:入力、RA2:入力、RA1:入力、RA0:出力 // I2Cを使う場合、RA1[6Pin]とRA2[5Pin]は必ず入力にする必要がある //---------------------------------------------------------- // A/D変換設定 //---------------------------------------------------------- // アナログ入力チャネルの設定 // | 0 | x | x | x | x | x | 0 | 1 | //---------------------------------------------------------- // ADCON0 = 0b00000001; // RA0[7Pin] // ADCON0 = 0b00000101; // RA1[6Pin] // ADCON0 = 0b00001001; // RA2[5Pin] // ADCON0 = 0b00001101; // RA3{4Pin] ADCON0 = 0b00001101; // RA4[3Pin] // 出力フォーマット、クロック設定 // | y | x | x | x | 0 | 0 | 0 | 0 | //---------------------------------------------------------- // ADCON1 = 0b10100000; // 右詰め、Fosc/32 ADCON1 = 0b01010000; // 左詰め、Fosc/16 // ADCON1 = 0b00010000; // 左詰め、Fosc/8 // ADCON1 = 0b01000000; // 左詰め、Fosc/4 // ADCON1 = 0b00000000; // 左詰め、Fosc/2 //---------------------------------------------------------- // PWM設定 //---------------------------------------------------------- // PWA機能をRA5[2Pin]に設定 //---------------------------------------------------------- CCP1SEL = 1; //PWM機能を有効 //---------------------------------------------------------- CCP1CON = 0b00001100; // TMR2プリスケーラ値を設定 // | 0 | 0 | 0 | 0 | 0 | 0 | x | x | //---------------------------------------------------------- T2CON = 0b00000000; // 1倍 // T2CON = 0b00011000; // 1倍 // T2CON = 0b00000001; // 4倍 // T2CON = 0b00000010; // 16倍 // T2CON = 0b00000011; // 64倍 // PWMの周期を設定 //---------------------------------------------------------- PR2 = 128; // PWMスタート //---------------------------------------------------------- TMR2ON = 1; //---------------------------------------------------------- // シリアル通信(I2C)設定 //---------------------------------------------------------- // クロック信号速度 // | x | 0 | 0 | 0 | 0 | 0 | 0 | 0 | //---------------------------------------------------------- SSP1STAT = 0b10000000; // 標準モード(100kHz) //SSP1STAT = 0b00000000; // 高速モード(400kHz) // マスター(制御する側) or スレーブ(制御される側) //---------------------------------------------------------- SSP1CON1 = 0b00101000; // マスターモードに設定 // 通信速度設定 //---------------------------------------------------------- // クロック信号の速度(周波数) = PICマイコンの動作周波数 / ((SSP1ADDの値 + 1) x 4) // PICマイコンの動作周波数:16MHz、I2Cのクロック信号速度:400kHzに設定 // 16000kHz / 400kHz x 4) - 1 = 16000/1600 - 1 = 10 - 1 = 9 SSP1ADD = 6; // 声が低くなったので微調整 //SSP1ADD = 19; //---------------------------------------------------------- // シリアル通信 動作テスト //---------------------------------------------------------- /* *      24LC256 * −−−−−− * A0 → GND −| 1 8 |− VCC * A1 → GND −| 2 7 |− * A2 → GND −| 3 6 |− SCL → PIC(6Pin) * VSS → GND −| 4 5 |− SDA → PIC(5Pin) * −−−−−− */ /* * メモリ:256Kbit * * 256000bits÷8bits = 32000Byte = 32kByte * 32×1024 = 32768bit * 0〜32767番地まで記憶可能 * * ・ 10進数 → 最大「32767」 * ・ 16進数 → 最大「7FFF」 * ・ 2進数 → 最大「0111111111111111」 16桁 */ // データの書き込みテスト //---------------------------------------------------------- // 「1」番地に「5」というデータを書き込む // 2進数:0000000000000001 → 10進数:1 → 16進数:01 // 2進数:00000101 → 10進数:5 → 16進数:05 // 引数1:書き込む番地(上位8bit) // 引数2:書き込む番地(下位位8bit) // 引数3:書き込むデータ // I2C_write_set(0b00000000,0b00000001,0b00000101); // 書き込み処理が終わるまで待機(もっと短くても大丈夫) //---------------------------------------------------------- //__delay_ms(100); // データの読み込みテスト //---------------------------------------------------------- // 引数1:読み込むm番地(上位8bit) // 引数2:読み込む番地(下位位8bit) // I2C_read_set(0b00000000,0b00000001); //---------------------------------------------------------- // CDS(光センサ)の反応を検知 //---------------------------------------------------------- // 永久ループ while(1) { // AD変換準備時間 __delay_us(25); // AD変換スタート GO = 1; // AD変換終了まで待機(終了するとGOが0になる) while(GO); // CDS感度の調整(小さくすると感度アップ) if (ADRESH > 150) { // EEPROMの読み込み(シリアル通信) I2C_read_set(0x00,0x00); } } } // ============================================================ // //   I2C 書き込み設定 // // ============================================================ void I2C_write_set(unsigned char addr1 ,unsigned char addr2 ,unsigned char send_data) { // 通信開始の合図を送る I2C_start(); /* * スレーブアドレスとは? * スレーブアドレスは、複数のデバイスが回路上にあるときの見分けを付けるためのもの。 * * 24LC256のスレーブアドレスは、1010[A2][A1][A0] となっている。 * 24LC256のA2[3Pin]・A1[2Pin]・A0[1Pin]をGNDに繋いだら「0」、VCCに繋いだら「1」 * 例えば、A2・A1・A0をすべてGNDに繋いだら、スレーブアドレスは「1010000」となる。 * 例えば、A2・A1・A0をすべてVCCに繋いだら、スレーブアドレスは「1010111」となる。 * * ↑の7ビットの最後に、ROMの読み書き設定を1ビット追加する。 * 書き込むときは「1」、読み込むときは「0」 * もし1個しかROMを付けないなら、「0b10100000」(書き込みの場合)とすればいい。 */ // スレーブアドレスの送信(書き込みモード) I2C_send(0b10100000); // 書き込む番地(上位8bit)の送信 I2C_send(addr1); // 書き込む番地(下位8bit)の送信 I2C_send(addr2); // 書き込むデータの送信 I2C_send(send_data); // 通信終了の合図を送る I2C_stop(); return; } // ============================================================ // //   I2C 読み取り設定 // // ============================================================ void I2C_read_set(unsigned char addr1 ,unsigned char addr2) { // 通信開始の合図を送る I2C_start(); // スレーブアドレスの送信(※書き込みモード) // 読み込みだけど、一旦書き込みモードでデータを送信する必要がある I2C_send(0b10100000); // 読み取り番地(上位8bit)の送信 I2C_send(addr1); // 読み取り番地(下位8bit)の送信 I2C_send(addr2); // 通信開始の合図を送る I2C_start(); // スレーブアドレスの送信(※読み取りモード) I2C_send(0b10100001); // ROM内の全てのデータを受信する:512K(512000bits÷8bits = 64000Byte) for(unsigned short int i=1; i<64000; i++) { I2C_receive(); I2C_ack(); } // 読み取り終了の応答 I2C_nack(); // 通信終了の合図を送る I2C_stop(); return; } // ============================================================ // //   I2C 通信開始 // // ============================================================ void I2C_start() { // スタートコンディションを生成 // SENをセットすることで、通信スタートの合図となる SEN = 1; // スタートコンディション発行終了まで待機 // SENは発行終了後に0になる while (SEN) {}; return; } // ============================================================ // //   I2C データ送信 // // ============================================================ void I2C_send(unsigned char send_data) { // データ受信フラグをクリア(0:データが受信できる状態) SSP1IF = 0; // 送信モード有効 // SSPIFが0のときにSSPBUFをセットすると、データが送信される SSP1BUF = send_data; // データ送信完了まで待機 // 正常にデータが送信されると、SSPIFが1になる while (!SSP1IF) {} return; } // ============================================================ // //   I2C データ読み取り // // ============================================================ void I2C_receive() { // データ受信フラグをクリア(0:データが受信できる状態) SSP1IF = 0; // 受信モード有効 // SSPIFが0のときにRCENをセットすると、データが受信される RCEN = 1; // データ受信完了まで待機 // 正常にデータが受信されると、RCENが0になる while (RCEN) {} // 受信したデータは、SSP1BUFに入る // SSP1BUFを変数(reveive_data)に代入 unsigned char receive_data; receive_data = SSP1BUF; // 受信データを音源に(パルス幅を変更) CCPR1L = receive_data; return; } // ============================================================ // //   I2C 継続応答 // // ============================================================ void I2C_ack() { // 受信データの続きがあることを示す「ACK:0」を設定 ACKDT = 0; // ACKDTを送信 ACKEN = 1; // データ送信完了まで待機 // 送信完了後、ACKENが0になる while (ACKEN) {} return; } // ============================================================ // //   I2C 終了応答 // // ============================================================ void I2C_nack() { // 受信データの終わりを示す「NO-ACK:0」を設定 ACKDT = 1; // ACKDTを送信 ACKEN = 1; // データ送信完了まで待機 // 送信完了後、ACKENが0になる while (ACKEN); return; } // ============================================================ // //   I2C 通信終了 // // ============================================================ void I2C_stop() { // ストップコンディションの生成 // PENをセットすることで、通信終了の合図となる PEN=1; // ストップコンディション発行終了まで待機 // PENは発行終了後に0待つ while(PEN); // データ受信フラグをクリア(0:データが受信できる状態) SSP1IF = 0; return; }