// --------------------------------------------------
// Global Versatile Controler http://www.gvc-on.net/
// --------------------------------------------------
// --------------------------------------------------
// Revision Memo (Y.M.D Editor/Memo)
// --------------------------------------------------
//
// 測距モジュール用
//
// 測距センサー(LV-EZシリーズ)のAN(アナログ出力:Vcc/512=per inch)を、PIC(18F26K22)のAN1(RA1)に接続して電圧から距離を取得する
// ・なお、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.17 T.Kabu 温度湿度から測距に流用
// 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 (DISTANCE) ==="
// PICのI2Cアドレス、適時変更すること
#define I2C_ADDR 0x50 // モジュールごとにアドレスを変えること!!
// 受信バッファサイズ
#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 distance data
// ----------------------------------------
float get_distance(char format, char * result_buff)
{
// float をスタックにいっぱい用意しようとすると、オーバーフローになるよ!! "fixup overflow referencing psect..." といわれて
// リンクできなかったら、変数はstatic宣言でちゃんと固定メモリ領域を使おう 2013.06.10 T.Kabu
static int an_data = 0;
static float dist_volt = 0.0;
static float dist_inch = 0.0;
static float dist_meter = 0.0;
static int ftoa_status; // ftoa()用のステータス変数
// センサーが接続されているPICのポート(AN1)から現在の電圧データを取得する
an_data = get_port_voltage(1);
// 電圧データを電圧に変換
dist_volt = (FVR_VOLT / 1024) * an_data;
dist_inch = dist_volt / (vdd_volt / 512);
dist_meter = dist_inch * 0.0254;
// フォーマット別に処理分岐
switch (format)
{
case 0x01: // [m]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter, &ftoa_status));
break;
case 0x02: // [mm]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter * 1000, &ftoa_status));
break;
case 0x03: // [um]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter * 1000 * 1000, &ftoa_status));
break;
case 0x04: // [nm]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter * 1000 * 1000 * 1000, &ftoa_status));
break;
case 0x05: // [km]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter / 1000, &ftoa_status));
break;
case 0x06: // [cm]、文字列で小数点表記の実数16文字
sprintf(result_buff, "%s", ftoa(dist_meter * 100, &ftoa_status));
break;
case 0x81: // モジュール情報
sprintf(result_buff, "GVC Distance Module Verx.xx Sensor=LV-EZ4 Vdd=%0.3f Vref=%0.3f", vdd_volt, FVR_VOLT);
break;
case 0x82: // モジュール情報
sprintf(result_buff, "GVC Distance Module x.xx,LV-EZ4\t,%0.3f,%0.3f", vdd_volt, FVR_VOLT);
break;
case 0x83: // モジュール情報
sprintf(result_buff, "GVC Distance Module x.xx\tLV-EZ4\t%0.3f\t%0.3f", vdd_volt, FVR_VOLT);
break;
default:
sprintf(result_buff, "Unsupported %02x", format);
break;
}
// [m]、文字列で小数点表記の実数16文字を返す
return dist_meter;
}
// ------------------------------
// 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:テスト時、0x11:正式)なら
if ((rx_buffer[1] == 0x03) || (rx_buffer[1] == 0x11))
{
// フォーマットの指定に基づいて現在の値から返すデータを生成する
get_distance(rx_buffer[0], 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; // 受信データ
// 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();
// Dが来たら測距湿度センサーの情報を返す
if (rcv_data == 'D')
{
// ステータスLEDを点灯
PORT_STATUS_LED = LED_ON;
// 測距データ取得([cm]、文字列で小数点表記の実数16文字)
get_distance(0x06, serial_buffer);
// 温度データを送信
send_strdata(serial_buffer);
send_cr();
// ステータスLEDを消灯
PORT_STATUS_LED = LED_OFF;
}
}
// 特に何もしないで次のデータを待つ
}
}