// -------------------------------------------------- // Global Versatile Controler http://www.gvc-on.net/ // -------------------------------------------------- // -------------------------------------------------- // Revision Memo (Y.M.D Editor/Memo) // -------------------------------------------------- // // 温度・湿度モジュール用 // // 温度センサー(MCP9700-E/TO)のOUTPUTを、PIC(18F26K22)のAN2(RA2)に接続して電圧から温度を取得する // ・なお、12F1822の時と違って、18F26K22のRAはもともとプルアップしていない。(RBxはしてる) // ・データは2バイトに右詰とする // ・16MHz駆動の時には、FOSC/16 で1us使って電圧測定する必要がある // ・内部固定電圧をVREFCON0で定義するといい(REFCONの名称がPICによって微妙に違う…むぅ) // 参考→http://homepage3.nifty.com/mitt/pic/pic2320_02.html // // 2013.05.08 T.Kabu // GVC Rev.2としてのもろもろを定義 // // ------------------------------ // BASE // ------------------------------ // 2013.06.14 T.Kabu 温度・湿度用でいったんFix // 2013.06.03 T.Kabu Rev.2用に色々修正 //--------------------------------------------------- // Include Header //--------------------------------------------------- // ---------------------------------------- // Standard Header // ---------------------------------------- #include <xc.h> #include <plib.h> #include <htc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> // ---------------------------------------- // User Header // ---------------------------------------- // Pragma Header #include "pragma.h" // PIC Parameter define and initialize #include "pic_init.h" // GVC Parameter define and initialize #include "gvc_init.h" // -------------------------------------------------- // Const Define // -------------------------------------------------- #define VERSION "=== GVC SLAVE MODULE DEVICE PROGRAM for 18F26K22 (TEMP/HUMI) ===" // PICのI2Cアドレス、適時変更すること #define I2C_ADDR 0x20 // モジュールごとにアドレスを変えること!! // 受信バッファサイズ #define SERIAL_RCV_BUFFSIZE 16 #define SERIAL_RCV_BUFFRING 15 // SERIAL_RCV_BUFFSIZEから1減らした値を設定 // シリアルバッファサイズ #define SERIAL_BUFF_SIZE 512 // I2Cバッファサイズ #define RX_BUFF_SIZE 512 #define TX_BUFF_SIZE 512 // シリアルバッファとI2Cバッファは、それぞれのGVCモジュールで想定しているデータに合わせたサイズにすること // 赤外線データだけは、どうがんばっても3096バイトをひとつ確保したら終わりなので、それぞれで使い回しをしないといけないので、使い方に注意すること // -------------------------------------------------- // Variable Param // -------------------------------------------------- // 割り込み処理内でのレジスタの値を格納する変数はここで宣言すること、割り込み処理内で宣言してはいけない!! T.Kabu 2013.05.14 unsigned char reg_RCSTA1; // 受信ステータスレジスタ unsigned char reg_SSP1STAT; // SSP1ステータスレジスタ unsigned char temp_buffer; // SSP1BUFの空読み用 GVC_I2C_MESSAGE_t * gvc_i2c_message; // GVC I2Cメッセージ用ポインタ(tx_buffer/rx_bufferにかぶせる) unsigned char serial_rcvptr; // 受信バッファポインタ unsigned char serial_readptr; // 受信読み出しポインタ unsigned char serial_rcvbuff[SERIAL_RCV_BUFFSIZE]; // 受信リングバッファ(RCREG1) unsigned char serial_buffer[SERIAL_BUFF_SIZE]; // シリアルバッファ(作業用) //char rcv_data; // 受信データ unsigned char rx_buffer[RX_BUFF_SIZE]; // 受信バッファ unsigned int rx_count = 0; // 受信バッファ位置 unsigned char tx_buffer[TX_BUFF_SIZE]; // 送信バッファ unsigned int tx_count = 0; // 送信バッファ位置 unsigned int i2c_data_len; // I2Cのデータ長(data_len) static char i2c_status = 0; // I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了 // -------------------------------------------------- // Function prototype // -------------------------------------------------- // -------------------------------------------------- // Sub Routine // -------------------------------------------------- // ------------------------------ // Recieve serialdata // ------------------------------ char rcv_serialdata(void) { unsigned char data; // 返り値用データに受信データコピー data = serial_rcvbuff[serial_readptr]; // 受信読み出しポインタを加算 serial_readptr ++; // 受信読み出しポインタをリングる serial_readptr &= SERIAL_RCV_BUFFRING; // 受信データを返す return data; } // ---------------------------------------- // Setup 18F26K22 for Analog Voltage // ---------------------------------------- void init_pic_for_analogvoltage(void) { // ------------------------------ // ポートA設定 // ------------------------------ // bit7 : RA7 1 = input, 0 = output // bit6 : RA6 1 = input, 0 = output // bit5 : RA5 1 = input, 0 = output // bit4 : RA4 1 = input, 0 = output // bit3 : RA3 1 = input, 0 = output // bit2 : RA2 1 = input, 0 = output // bit1 : RA1 1 = input, 0 = output // bit0 : RA0 1 = input, 0 = output TRISA = 0b00001111; // RA0-RA3をを電圧測定用にinputモード // ANSELA: PORTA ANALOG SELECT REGISTER ポートのI/Oモードの設定。 // bit7-6 : none (0) // bit5 : ANSA4: Analog Select between Analog or Digital Function on pins RA5, respectively // 0 = Digital I/O. Pin is assigned to port or digital special function. // 1 = Analog input. Pin is assigned as analog input(1). Digital input buffer disabled. // bit4 : none (0) // bit3 : ANSA3: Analog Select between Analog or Digital Function on pins RA3, respectively // bit2 : ANSA2: Analog Select between Analog or Digital Function on pins RA2, respectively // bit1 : ANSA1: Analog Select between Analog or Digital Function on pins RA1, respectively // bit0 : ANSA0: Analog Select between Analog or Digital Function on pins RA0, respectively ANSELA = 0b00001111; // AN0(=RA0),AN1(=RA1),AN2(=RA2),AN3(=RA3) Analog input // ADCON0 は、実際に電圧を読むときに、そのポートを指定しないといけないのでここではいじらない // bit 7 TRIGSEL: Special Trigger Select bit // 1 = Selects the special trigger from CTMU // 0 = Selects the special trigger from CCP5 // bit 6-4 Unimplemented: Read as ‘0’ // bit 3-2 PVCFG<1:0>: Positive Voltage Reference Configuration bits // 00 = A/D VREF+ connected to internal signal, AVDD // 01 = A/D VREF+ connected to external pin, VREF+ // 10 = A/D VREF+ connected to internal signal, FVR BUF2 // 11 = Reserved (by default, A/D VREF+ connected to internal signal, AVDD) // bit 1-0 NVCFG0<1:0>: Negative Voltage Reference Configuration bits // 00 = A/D VREF- connected to internal signal, AVSS // 01 = A/D VREF- connected to external pin, VREF- // 10 = Reserved (by default, A/D VREF+ connected to internal signal, AVSS) // 11 = Reserved (by default, A/D VREF+ connected to internal signal, AVSS) // ADCON1 = 0b00000000; // VREF+、VREF-ともに内部供給電圧Vddに対しての値となる ADCON1 = 0b00001000; // VREF+はFVRから、VREF-はGNDに対しての値となる // AD変換制御レジスタ2設定 A/D CONTROL REGISTER 2 // bit 7 ADFM: A/D Conversion Result Format Select bit // 1 = Right justified // 0 = Left justified // bit 6 Unimplemented: Read as ‘0’ // bit 5-3 ACQT<2:0>: A/D Acquisition time select bits. Acquisition time is the duration that the A/D charge holding // capacitor remains connected to A/D channel from the instant the GO/DONE bit is set until conversions // begins. // 000 = 0(1) // 001 = 2 TAD // 010 = 4 TAD // 011 = 6 TAD // 100 = 8 TAD // 101 = 12 TAD // 110 = 16 TAD // 111 = 20 TAD // bit 2-0 ADCS<2:0>: A/D Conversion Clock Select bits // 000 = FOSC/2 // 001 = FOSC/8 // 010 = FOSC/32 // 011 = FRC(1) (clock derived from a dedicated internal oscillator = 600 kHz nominal) // 100 = FOSC/4 // 101 = FOSC/16 // 110 = FOSC/64 // 111 = FRC(1) (clock derived from a dedicated internal oscillator = 600 kHz nominal) ADCON2 = 0b10110101; // 右寄せ、16TAD、FOSC/16 // 電圧リファレンス制御レジスタ0 FIXED VOLTAGE REFERENCE CONTROL REGISTER // bit 7 FVREN: Fixed Voltage Reference Enable bit // 0 = Fixed Voltage Reference is disabled // 1 = Fixed Voltage Reference is enabled // bit 6 FVRST: Fixed Voltage Reference Ready Flag bit // 0 = Fixed Voltage Reference output is not ready or not enabled // 1 = Fixed Voltage Reference output is ready for use // bit 5-4 FVRS<1:0>: Fixed Voltage Reference Selection bits // 00 = Fixed Voltage Reference Peripheral output is off // 01 = Fixed Voltage Reference Peripheral output is 1x (1.024V) // 10 = Fixed Voltage Reference Peripheral output is 2x (2.048V)(1) // 11 = Fixed Voltage Reference Peripheral output is 4x (4.096V)(1) // bit 3-2 Reserved: Read as ‘0’. Maintain these bits clear. // bit 1-0 Unimplemented: Read as ‘0’. VREFCON0 = 0b10110000; // FVR有効、x4の4.096Vとする } // ---------------------------------------- // Get temperature data // ---------------------------------------- float get_temperature(char format, char * result_buff) { // float をスタックにいっぱい用意しようとすると、オーバーフローになるよ!! "fixup overflow referencing psect..." といわれて // リンクできなかったら、変数はstatic宣言でちゃんと固定メモリ領域を使おう 2013.06.10 T.Kabu static int an_data = 0; static float temp_volt = 0.0; static float temp_c = 0.0; static float temp_f = 0.0; static float temp_k = 0.0; static int ftoa_status; // ftoa()用のステータス変数 // センサーが接続されているPICのポート(AN2)から現在の電圧データを取得する an_data = get_port_voltage(2); // 電圧データを電圧に変換 temp_volt = (FVR_VOLT / 1024) * an_data; // 温度を計算 temp_c = (temp_volt - 0.5) * 100; temp_f =(1.8 * temp_c) + 32; temp_k =temp_c + 273.15; // フォーマット別に処理分岐 switch (format) { case 0x01: // 摂氏[C]、文字列で小数点表記の実数16文字 sprintf(result_buff, "%s", ftoa(temp_c, &ftoa_status)); break; case 0x02: // 華氏[F]、文字列で小数点表記の実数16文字 sprintf(result_buff, "%s", ftoa(temp_f, &ftoa_status)); break; case 0x03: // 絶対温度[K]、文字列で小数点表記の実数16文字 sprintf(result_buff, "%s", ftoa(temp_k, &ftoa_status)); break; case 0x11: // 摂氏[C]、文字列で小数点表記の実数16文字、TAB区切りでT,Vref,分解能とか sprintf(result_buff, "%s\t%.3f\t1024", ftoa(temp_c, &ftoa_status), FVR_VOLT); break; case 0x12: // 華氏[F]、文字列で小数点表記の実数16文字、TAB区切りでT,Vref,分解能とか sprintf(result_buff, "%s\t%.3f\t1024", ftoa(temp_k, &ftoa_status), FVR_VOLT); break; case 0x13: // 絶対温度[K]、文字列で小数点表記の実数16文字、TAB区切りでT,Vref,分解能とか sprintf(result_buff, "%s\t%3f\t1024", ftoa(temp_c, &ftoa_status), FVR_VOLT); break; case 0x81: // モジュール情報 sprintf(result_buff, "GVC Temperature Module Verx.xx Sensor=MCP9700-E/TO Vdd=%0.3f Vref=%0.3f", vdd_volt, FVR_VOLT); break; case 0x82: // モジュール情報 sprintf(result_buff, "GVC Temperature Module,x.xx,MCP9700-E/TO,%0.3f,%0.3f", vdd_volt, FVR_VOLT); break; case 0x83: // モジュール情報 sprintf(result_buff, "GVC Temperature Module\tx.xx\tMCP9700-E/TO\t%0.3f\t%0.3f", vdd_volt, FVR_VOLT); break; case 0x8B: sprintf(result_buff, "Unsupported %02x", format); break; default: break; } // 摂氏[C]を返す return temp_c; } // ---------------------------------------- // Get humidity data // ---------------------------------------- float get_humidity(char format, float temp_c, char * result_buff) { // float をスタックにいっぱい用意しようとすると、オーバーフローになるよ!! "fixup overflow referencing psect..." といわれて // リンクできなかったら、変数はstatic宣言でちゃんと固定メモリ領域を使おう 2013.06.10 T.Kabu static int an_data = 0; static float humi_volt = 0.0; static float humi_sensor; // センサーからの湿度(浮動小数点) static float humi_real; // 補正後の湿度(浮動小数点) static int ftoa_status; // ftoa()用のステータス変数 // HIH-5031は、25度の時の出力電圧が、供給電圧×((0.00636×センサー湿度)+0.1515)、となる。 // つまりセンサー湿度は、((出力電圧/供給電圧)-0.1515)÷0.00636となる。 // 実際の湿度は、センサー湿度÷(1.0546-(0.00216×temperature))となる。 // 湿度センサーが接続されているPICのポート(AN1)から現在の電圧データを取得する an_data = get_port_voltage(1); // 電圧データを電圧に変換 humi_volt = (FVR_VOLT / 1024) * an_data; humi_sensor = (humi_volt - (0.1515 * vdd_volt)) / (0.00636 * vdd_volt); humi_real = humi_sensor / (1.0546 - (0.00216 * temp_c)); // フォーマット別に処理分岐 switch (format) { case 0x01: // 相対湿度、Short intで湿度を100倍した整数値 sprintf(result_buff, "%d", (int)(humi_real * 100)); break; case 0x11: // 相対湿度[%]、文字列で小数点表記の実数16文字 sprintf(result_buff, "%s", ftoa(humi_real, &ftoa_status)); break; case 0x81: // モジュール情報 sprintf(result_buff, "GVC Humidity Module Verx.xx Sensor=HIH-5031 Vdd=%0.3f Vref=%0.3f", vdd_volt, FVR_VOLT); break; case 0x82: // モジュール情報 sprintf(result_buff, "GVC Humidity Module x.xx,HIH-5031,%0.3f,%0.3f", vdd_volt, FVR_VOLT); break; case 0x83: // モジュール情報 sprintf(result_buff, "GVC Humidity Module x.xx\tHIH-5031\t%0.3f\t%0.3f", vdd_volt, FVR_VOLT); break; default: sprintf(result_buff, "Unsupported %02x", format); break; } // 相対湿度[%]を返す return humi_real; } // ------------------------------ // Setup MSSP1 18F26K22 // ------------------------------ void init_mssp1_18F26K22(void) { // ------------------------------ // MSSP1制御データ設定 スレーブとして設定する場合 // ------------------------------ // bit 7 : SMP 1 = Slew rate control disabled for standard speed mode (100 kHz and 1 MHz) // : 0 = Slew rate control enabled for high speed mode (400 kHz) // bit 6 : CKE 1 = Enable input logic so that thresholds are compliant with SMbus specification // : 0 = Disable SMbus specific inputs // bit 5 : D/A: Data/Address bit (I2C mode only) // : 1 = Indicates that the last byte received or transmitted was data // : 0 = Indicates that the last byte received or transmitted was address // bit 4 : P: Stop bit // : (I2C mode only. This bit is cleared when the MSSPx module is disabled, SSPxEN is cleared.) // : 1 = Indicates that a Stop bit has been detected last (this bit is ‘0’ on Reset) // : 0 = Stop bit was not detected last // bit 3 : S: Start bit // : (I2C mode only. This bit is cleared when the MSSPx module is disabled, SSPxEN is cleared.) // : 1 = Indicates that a Start bit has been detected last (this bit is ‘0’ on Reset) // : 0 = Start bit was not detected last // bit 2 : R/W: Read/Write bit information (I2C mode only) // : In I2 C Master mode: // : 1 = Transmit is in progress // : 0 = Transmit is not in progress // : OR-ing this bit with SEN, RSEN, PEN, RCEN or ACKEN will indicate if the MSSPx is in Idle mode. // : (このビットと、SEN、RSEN、PEN、RCEN、またはACKEN との論理和を取ると、マスタモードがアクティブかどうかを判断できる) // bit 1 : UA: Update Address bit (10-bit I2C mode only) // bit 0 : BF: Buffer Full Status bit // : Receive (SPI and I2 C modes): // : 1 = Receive complete, SSPxBUF is full // : 0 = Receive not complete, SSPxBUF is empty // : Transmit (I2 C mode only): // : 1 = Data transmit in progress (does not include the ACK and Stop bits), SSPxBUF is full // : 0 = Data transmit complete (does not include the ACK and Stop bits), SSPxBUF is empty SSP1STAT= 0b00000000; // 400kHz Slew rate // bit7 : WCOL master(1 = Collision, 0 = No Collision), slave(1 = must be cleard, 0 = No Collision) // bit6 : SSP1OV SPI(pass), I2C(1 = overflow, 0 = not Overflow) // bit5 : SSP1EN SPI(pass), I2C(1 = enable SDA/SCL w/input mode, 0 = disable) // bit4 : CKP SPI(pass), I2C(master(1 = enable clock, 0 = hold clock low), slave (unused)) // bit3-0 : SSP1M 0110 I2C Slave mode, 7bit address // : SSP1M 0111 I2C Slave mode, 10bit address // : SSP1M 1000 I2C Master mode, clock = Fosc/(4 * (SSP1ADD + 1)) // : SSP1M 1011 I2C F/W controled Master mode(Slave Idle) // : SSP1M 1110 I2C Slave mode, 7bit address w/Start/Stop bit INT // : SSP1M 1111 I2C Slave mode, 10bit address w/Start/Stop bit INT SSP1CON1 = 0b00110110; // SSP1EN = 1, CKP = 1, SSP1M = Slave mode 7bit SSP1CON2bits.SEN = 1; // Start Condition Enabled bit ... SSP1CON2) ←マスターからデータを受け取るなら設定必要 // このデバイスのI2Cアドレスを設定 SSP1ADD = I2C_ADDR << 1; // MSSP1割り込み初期化 PIR1bits.SSP1IF = 0; // MSSP1バス衝突割り込みフラグを初期化 PIR2bits.BCL1IF = 0; // 100ms待つ Delay_10ms(10); } // ------------------------------ // Interrupt Routine // ------------------------------ // I2Cのマスターとスレーブとのやり取りは、データシートの説明が言葉足らずなために // 非常に判りづらい。ただし、判ってしまうと何だそれだけか、となる。 // // 特にスレーブ側であれこれ設定したり判定や処理に必要なのは次のビット // ・D/A…1=SSP1BUFの中はデータ、0=SSP1BUFの中はアドレス(空っぽ…空の読み出し要求時) // ・R/W…1=マスターがスレーブから受信、0=マスターがスレーブへ送信 // ・BF…1=バッファに何か入っている(空の読み出し要求時も)、0=バッファは空っぽ // ・CKP…マスターにデータ送信を許可するとき、スレーブから送信するときに1にしてSCLをリリースする // ・SSP1IF…割り込みフラグ、なんかしたらクリアする // ・SEN…マスターからデータを受信する時に、ソフト側でCKPを制御するために1にする。0だとうまく動かないよ!! //(・S…スタートビット、特に使わなくてもいい気がする) // // で、判定に使うビットが多いけど、基本的にはSSP1STATなので、マスクして一括判定すればOK。 // -------------------------------------------------- // 18F26K22 Interrupt Routine // -------------------------------------------------- // 割り込みはすべてinterrupt宣言されたこの関数が呼ばれる static void interrupt interrupt_18F26K22() { // 全割り込みを禁止(=0) (Global Interrupt Enable bit ... INTCON) INTCONbits.GIE = 0; // ---------------------------------------- // MSSP1割り込み処理 (Rev.1の18F26K22_I2C.cを参照すること // ---------------------------------------- // MSSP割り込み(=1)なら (Synchronous Serial Port (MSSP) Interrupt Flag bit ... PIR1) if (PIR1bits.SSP1IF == 1) { // ステータスLEDを点灯 PORT_STATUS_LED = LED_ON; // MSSP割り込みクリア(=0) (Synchronous Serial Port (MSSP) Interrupt Flag bit ... PIR1) PIR1bits.SSP1IF = 0; // SSP1ステータスを取得、D/A、R/W、BFビットをマスク reg_SSP1STAT = SSP1STAT & 0b00100101; // SSP1ステータスが、アドレス(D/A=0)で、かつマスターがスレーブへ送信(R/W=0)、かつバッファに何かある(BF=1)なら if (reg_SSP1STAT == 0b00000001) { // リザルトLEDを点灯 PORT_RESULT_LED = LED_ON; // SSP1BUFを空読みして temp_buffer = SSP1BUF; // 受信バッファ位置を初期化 rx_count = 0; // I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了 i2c_status = 1; // SCLをリリースしてマスターにデータの送信を許可する SSP1CON1bits.CKP1 = 1; // リザルトLEDを消灯 PORT_RESULT_LED = LED_OFF; } // SSP1ステータスが、データ(D/A=1)で、かつマスターがスレーブへ送信(R/W=0)、かつバッファに何かある(BF=1)なら else if (reg_SSP1STAT == 0b00100001) { // リザルトLEDを点灯 PORT_RESULT_LED = LED_ON; // SSP1BUFからデータを読み出して、受信バッファの受信バッファ位置に設定 rx_buffer[rx_count] = SSP1BUF; // 受信バッファ位置が3まで来てたら if (rx_count == 3) { // このあと受信するデータ長を設定 i2c_data_len = *(int *)(rx_buffer + 2); } // 受信バッファ位置がchecksum(つまりメッセージ終了)なら if (rx_count == (GVC_I2C_MESSAGE_HEADER_SIZE + i2c_data_len)) { // -------------------------------------------------------------------------------- // 必要ならメッセージ受信したよフラグでも立ててメインループ内で処理してもらう // -------------------------------------------------------------------------------- // I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了 i2c_status = 10; // // まぁこの時点でtx_bufferに指定されたフォーマットでデータを生成しておいた方がいいと思うんだけどどうだろう? // // ・メッセージデータのCRCを検査 // ・OKならフォーマットやコマンドに基づいて処理、NGならシリアルにその旨出力 // // CRCチェックがOKなら if (GetCRC8((void *)rx_buffer, rx_count + 1) == 0) { // 送信バッファをI2Cメッセージポインタに設定 gvc_i2c_message = (GVC_I2C_MESSAGE_t *)tx_buffer; // 要求コマンドが温度(0x03:テスト時、0x10ないしは0x11:正式)なら if ((rx_buffer[1] == 0x03) || (rx_buffer[1] == 0x10) || (rx_buffer[1] == 0x11)) { // フォーマットの指定に基づいて現在の値から返すデータを生成する get_temperature(rx_buffer[0], gvc_i2c_message->data); } // 要求コマンドが湿度(0x13:テスト時、0x12:正式)なら else if ((rx_buffer[1] == 0x13) || (rx_buffer[1] == 0x12)) { // フォーマットの指定に基づいて現在の値から返すデータを生成する get_humidity(rx_buffer[0], get_temperature(rx_buffer[0], gvc_i2c_message->data), gvc_i2c_message->data); } else { // コマンドエラーを設定 sprintf(gvc_i2c_message->data, "COMMAND ERROR!?, %02x", temp_buffer); } // メッセージフォーマットに基づいて設定する gvc_i2c_message->format = rx_buffer[0]; // マスターからの要求フォーマットをそのまま返す gvc_i2c_message->cmd = rx_buffer[1]; // エラーの場合にはここを違うデータにするのがいいと思う…TBD gvc_i2c_message->data_len = strlen(gvc_i2c_message->data); // データ長 // CRCを計算して、メッセージの最後に設定 gvc_i2c_message->data[gvc_i2c_message->data_len] = GetCRC8((void *)tx_buffer, GVC_I2C_MESSAGE_HEADER_SIZE + gvc_i2c_message->data_len); } // CRCチェックがNGなら else { // エラーメッセージを生成 sprintf(tx_buffer, "MASTER MESSAGE CRC ERROR!?"); } } // 受信バッファ位置を+1 rx_count ++; // SCLをリリースしてマスターにデータの送信を許可する SSP1CON1bits.CKP1 = 1; // 受信データがバッファいっぱいになったりしたらフラグでも立ててエラー処理とかする if (rx_count >= RX_BUFF_SIZE) { rx_count = 0; } // リザルトLEDを消灯 PORT_RESULT_LED = LED_OFF; } // アドレス(D/A=0)で、かつマスターがスレーブから受信(R/W=1)、かつバッファに何かある(BF=1)な else if (reg_SSP1STAT == 0b00000101) { // リザルトLEDを点灯 PORT_RESULT_LED = LED_ON; // SSP1BUFを空読みして temp_buffer = SSP1BUF; // 送信バッファ位置を初期化 tx_count = 0; // 送信バッファの最初のデータをSSP1BUFに設定 SSP1BUF = tx_buffer[tx_count]; // SCLをリリースしてマスターにデータの送信を許可する SSP1CON1bits.CKP1 = 1; // 送信バッファ位置を+1; tx_count ++; // リザルトLEDを消灯 PORT_RESULT_LED = LED_OFF; } // データ(D/A=1)で、かつマスターがスレーブから受信(R/W=1)、かつバッファが空(BF=0)なら else if (reg_SSP1STAT == 0b00100100) { // リザルトLEDを点灯 PORT_RESULT_LED = LED_ON; // 送信バッファの送信バッファ位置のデータをSSP1BUFに設定 SSP1BUF = tx_buffer[tx_count]; // SCLをリリースしてマスターにデータの送信を許可する SSP1CON1bits.CKP1 = 1; // 送信バッファ位置を+1; tx_count ++; // 送信バッファ位置が送信バッファを越えそうになったりしたらフラグでも立ててエラー処理とかする if (tx_count >= TX_BUFF_SIZE) { tx_count = 0; } // リザルトLEDを消灯 PORT_RESULT_LED = LED_OFF; } // これら以外は else { // SSP1BUFを空読みして temp_buffer = SSP1BUF; // SCLをリリースしてマスターに次の命令を促す SSP1CON1bits.CKP1 = 1; } // ステータスLEDを消灯 PORT_STATUS_LED = LED_OFF; } // ---------------------------------------- // シリアル1受信割り込み処理 // ---------------------------------------- // シリアル1受信割り込み(=1)なら (RC1IF: EUSART1 Receive Interrupt Flag bit ... INTCON) // 1 = The EUSART1 receive buffer, RCREG1, is full (cleared when RCREG1 is read) // 0 = The EUSART1 receive buffer is empty if (PIR1bits.RC1IF == 1) { // 受信ステータスを取得 reg_RCSTA1 = RCSTA1; // 受信ステータスを確認してフレーミングエラー、オーバーランエラーがなければ if ((reg_RCSTA1 & 0b00000110) == 0b00000000) { // 受信バッファ(RCREG1)から1バイト取得 serial_rcvbuff[serial_rcvptr] = RCREG1; // 受信バッファポインタを加算(+1) serial_rcvptr ++; // 受信バッファポインタをリングる serial_rcvptr &= SERIAL_RCV_BUFFRING; } // 受信ステータスを確認してオーバーランエラーがあるなら else if (reg_RCSTA1 & 0b00000010) { // CREN レシーバイネーブルビットをクリアして再設定 RCSTA1bits.CREN = 0; RCSTA1bits.CREN = 1; } // エラーがないなら else { // 受信バッファ(RCREG1)から1バイト取得 serial_rcvbuff[serial_rcvptr] = RCREG1; } // シリアル1受信割り込みクリア(=0)…は1バイト受信すれば自動的にクリアされるので必要ない //PIR1bits.RC1IF = 0; // ほんとはここで、受信バッファポインタserial_rcvptrがリングバッファを上書きしないように // するとか、あわせてフロー制御するとか、いろいろあるけど、今回はとりあえずほっとく } // 全割り込みを許可(=1) (Global Interrupt Enable bit ... INTCON) INTCONbits.GIE = 1; } // -------------------------------------------------- // Main loop // -------------------------------------------------- void main(void) { char rcv_data; // 受信データ int ftoa_status; // ftoa()用のステータス変数 // Setup 18F26K22 init_pic_18F26K22(); // Setup MSSP1 18F26K22 init_mssp1_18F26K22(); // Setup EUSART 18F26K22 init_eusart_18F26K22(); // ---------------------------------------- // これより下に、個別の設定を記述 // ---------------------------------------- // LED Brink led_brink(1); // Setup 18F26K22 for Analog Voltage init_pic_for_analogvoltage(); // Get Vdd Voltage vdd_volt = get_vdd(); // もしVddが4.0Vより大きいとか、1.0V未満なら if (vdd_volt > 4.0 || vdd_volt < 1.0) { // たぶんちゃんと測定できていないってことで、5.00に固定 vdd_volt = 5.00; } // 各種グローバル変数の初期化…グローバル変数は宣言時に初期化していても実際にはしてくれない…orz 2013.07.11 T.Kabu rx_count = 0; // 受信バッファ位置 tx_count = 0; // 送信バッファ位置 i2c_status = 0; // I2Cステータス 0:待機状態 1:データ受信中 10:データ受信完了 // ---------------------------------------- // 個別設定終了 // ---------------------------------------- // LED Brink led_brink(2); // 受信バッファポインタを初期化 serial_rcvptr = 0; // 受信読み出しポインタを初期化 serial_readptr = 0; // バッファを初期化 memset((void *)serial_buffer, 0x00, sizeof(serial_buffer)); // EUSART1 RX 割り込み許可(=1) (EUSART1 Receive Interrupt Enable bit ... PIE1) PIE1bits.RC1IE = 1; // MSSP割り込み許可(=1) (Synchronous Serial Port (MSSP) Interrupt Enable bit ... PIE1) PIE1bits.SSP1IE = 1; // 周辺割り込み許可(=1) (Peripheral Interrupt Enable bit ... INTCON) INTCONbits.PEIE = 1; // 全割り込みを許可(=1) (Global Interrupt Enable bit ... INTCON) INTCONbits.GIE = 1; // バージョンを送信 send_strdata(VERSION); send_cr(); // LED Brink led_brink(3); // メインループ while(1) { // シリアルバッファに未読データがないならスルー if (serial_rcvptr == serial_readptr) { } // あるなら else { // 受信バッファから一文字取得 rcv_data = rcv_serialdata(); // Tが来たら温度センサーの情報を返す if (rcv_data == 'T') { // ステータスLEDを点灯 PORT_STATUS_LED = LED_ON; // 温度データ取得(T、Vref、解像度の,区切りで) get_temperature(0x11, serial_buffer); // 温度データを送信 send_strdata(serial_buffer); send_cr(); // ステータスLEDを消灯 PORT_STATUS_LED = LED_OFF; } // Hが来たら湿度センサーの情報を返す else if (rcv_data == 'H') { // ステータスLEDを点灯 PORT_STATUS_LED = LED_ON; // 温度データ取得(摂氏[C]、文字列で小数点表記の実数16文字) get_temperature(0x01, serial_buffer); // 湿度データ取得(相対湿度[%]、文字列で小数点表記の実数16文字で) get_humidity(0x11, atof(serial_buffer), serial_buffer); // 湿度データを送信 send_strdata(serial_buffer); send_cr(); // ステータスLEDを消灯 PORT_STATUS_LED = LED_OFF; } // Hが来たらVdd情報を返す else if (rcv_data == 'V') { // ステータスLEDを点灯 PORT_STATUS_LED = LED_ON; // Vddを設定して出力する sprintf(serial_buffer, "Vdd=%s", ftoa(vdd_volt, &ftoa_status)); // 湿度データを送信 send_strdata(serial_buffer); send_cr(); // ステータスLEDを消灯 PORT_STATUS_LED = LED_OFF; } } // 特に何もしないで次のデータを待つ } }