#include /* サーミスタ 近似計算用 諸定義    */ #define PolygonTable_Member(table) (sizeof (table) /sizeof (table[0]) ) //一次配列の要素数を計算する typedef struct { // 折線近似テーブルの要素を定義する unsigned int x; //  入力 int y; //  出力 }SC_PolygonTable; const SC_PolygonTable T_ScPolygonTable[]={ // サーミスタ屈折点定数 {5148,105*128}, {6508,95*128}, {8270,85*128}, {10530,75*128}, //  105℃から-45℃まで {13422,65*128}, {17062,55*128}, {21525,45*128}, {26795,35*128}, // 10℃ことに設定する {32732,25*128}, {38986,15*128}, {45123,5*128}, {50672,-5*128}, {55283,-15*128},{58820,-25*128},{61353,-35*128},{63047,-45*128} }; typedef enum { // 折線近似結果を数え上げで定義する NO_ERROR, // 正常 INPUT_OVER, // オーバーフロー INPUT_UNDER //   アンダーフロー }SimTable_Suatus; typedef struct { // 折線近似データブロック unsigned int input_data; //  入力 int output_data; //  出力 SC_PolygonTable *table; //  使用折線テーブル unsigned int TableMember; //  折線テーブルの要素数 SimTable_Suatus result; //  近似計算結果 }SC_SimTable_DataBlock; /* 折線近似計算ルーチン */ void Polygon_Sim(SC_SimTable_DataBlock *dp) { int i; long output_temp; for( i= dp->TableMember-1; i >= 0; i--){ // 入力値が折線テーブルのどの範囲にあるか if(dp->input_data >= dp->table[i].x){ // 調べるため、テーブルの下からスキャンしていく if (i== (dp->TableMember-1)){ dp->result = INPUT_UNDER; // テーブルの最小値を超えている場合 dp->output_data = 0; return; } output_temp = // テーブル内に入力値があった場合は (long)(dp->input_data - dp->table[i].x ) // テーブルDATAから直線近似を計算して * (long)(dp->table[i+1].y - dp->table[i].y) // 結果を返す。 / (long)(dp->table[i+1].x - dp->table[i].x) + (long)dp->table[i].y; dp->output_data = (int)output_temp; dp->result = NO_ERROR; return; } } dp->result = INPUT_OVER; // テーブルの最後までスキャンして無かった場合 dp->output_data = 0; } /* I2Cインターフェースの諸定義     */ #define I2C_DataBuffer_Size sizeof(int) // DATAバッファのサイズ #define I2C_InitAddr (0x49) // スレーブ・アドレスの初期値 #define SDA_OutMode (USICTL0 |= USIOE) // マクロ定義 SDAを出力に切替 #define SDA_InMode (USICTL0 &= ~USIOE) // マクロ定義 SDAを入力に切替 struct{ unsigned char SlaveAddr; // 自局のスレーブ・アドレス unsigned char RcvAddr; // MASTERからの送信アドレス   unsigned char DataBuffer [I2C_DataBuffer_Size]; // I2C送受信DATAバッファ int DataCounter; // I2C送受信ポインタ enum{ // I2Cステートマシン状態の定義 Idle, Start_Sequnce, Check_Addr, Read_SQ1, Read_SQ2, Write_SQ1, Write_SQ2 }State; // I2Cステートマシン }I2C; /* メイン 関数  */ void main(void) { SC_SimTable_DataBlock T_Sc; // サーミスタ近似計算用のDATAブロックを確保 /* 使用ペリフェラルの初期化 */ /* システム・クロックの設定 */ WDTCTL = WDTPW + WDTHOLD; // watchdogタイマを停止する BCSCTL1 = CALBC1_8MHZ; // DCO較正値8MHzにセット DCOCTL = CALDCO_8MHZ; // DCOを8MHzにセット /* PORT P1,P2 設定 */ P1OUT = BIT6 + BIT7; // P1.6,P1.7 のプルアップ・ダウン抵抗をプルアップに設定 P1REN |= BIT6 + BIT7; // P1.6,P1.7 のプルアップ抵抗を有効にする(I2C用) P1DIR |= BIT0 + BIT6 + BIT7; // P1のうちI2C用 2BITとLED用のBITを出力にする P1SEL |= BIT3; // A/D内部基準電源を外部出力する P2OUT = 0; // 未使用ピンは P2DIR = 0xFF; // L出力に設定しておく /* A/Dコンバータ SD16_A の設定 */ SD16CTL = SD16REFON + SD16VMIDON // 内蔵基準電源ON 基準電源BUF ON + SD16SSEL_1 + SD16XDIV_2; // 供給クロックSMCLK、1/16分周(500KHz) SD16INCTL0 = SD16INCH_4; // 入力CH4を選択 SD16CCTL0 = SD16IV_NONE // 割込不使用 + SD16OSR_1024 + SD16SNGL; // オーバーサンプリング1024 単発変換 SD16AE = SD16AE1 + SD16AE2; // 入力CH4に対応するA/D入力ポートをOPEN SD16CCTL0 |= SD16SC; // A/D変換器を起動 /* USIシリアルの設定 */ USICTL0 = USIPE6+USIPE7+USISWRST; // USIをリセットして使用ポートを有効にする USICTL1 = USII2C+USIIE+USISTTIE; // USIをI2Cモードにして割込を有効にする USICKCTL = USICKPL; // I2Cクロックの極性(正) USICNT |= USIIFGCC; // 自動クリア機能を無効にする USICTL0 &= ~USISWRST; // USI起動 USICTL1 &= ~USIIFG; // USI割込みフラグのクリア _EINT(); // CPU 割込み有効 /* システム定数の初期化 */ T_Sc.table = (SC_PolygonTable*)T_ScPolygonTable; // サーミスタ用近似TABLEをセット T_Sc.TableMember = PolygonTable_Member(T_ScPolygonTable); // TABLEの要素数をセット I2C.SlaveAddr = I2C_InitAddr; // I2Cアドレスの初期値設定 /* メイン・ループ */ for(;;){ if ((SD16CCTL0 & SD16SC) == 0){ // A/D変換の終了を確認 T_Sc.input_data = SD16MEM0; // A/D変換結果をDataBlockにセット Polygon_Sim(&T_Sc); // 折線近似ルーチンで温度を得る _DINT(); // CPU割込をDATA更新の間だけ無効にする I2C.DataBuffer[0] = (unsigned char)(T_Sc.output_data/256); // 温度DATAをI2C I2C.DataBuffer[1] = (unsigned char)(T_Sc.output_data%256); // バッファにセット _EINT(); // CPU割込無効解除 SD16CCTL0 |= SD16SC; // 次回A/D変換を開始 }else { continue; // 無イベント時の空処理 } } } /* USI 割込ルーチン */ __interrupt void USI_ISR(void); // 割込ルーチンのプロトタイプ宣言 #pragma vector=USI_VECTOR // 割込ベクターの設定 __interrupt void USI_ISR(void) /* USI割込ルーチン 本体  */ { if( USICTL1 & USISTTIFG) // 割込要因 プリ・プロセッサ { // START条件時I2Cシーケンス スタート USICTL1 &= ~USISTTIFG; // 割込要因のクリア I2C.State = Start_Sequnce; // スタート・シーケンスに設定 } // スタート条件以外は現シーケンスを続行 switch(I2C.State) // I2Cステート・マシン { case Start_Sequnce: I2C.State = Check_Addr; // 次ステートでアドレスのチェックに移行 SDA_InMode; // SDAを入力に USICNT = (USICNT & 0xE0) + 0x08; // アドレス受信BIT数を設定 break; case Check_Addr: I2C.RcvAddr = USISRL; // USIレジスタより受信値の読出 I2C.RcvAddr = I2C.RcvAddr>>1; // 1BITシフト 呼出アドレスの取得 if (I2C.RcvAddr == I2C.SlaveAddr) // 自局判定 { // 自局の場合 if (USISRL & 0x01){ // R/Wの判定 I2C.State = Read_SQ1; // Read,次ステートでReadDATA送信 }else{ I2C.State = Write_SQ1; // Write,次ステートでWriteDATA受信 } I2C.DataCounter = 0; // バッファカウンタ クリア SDA_OutMode; // ACKのため SDAを出力に USISRL = 0x00; // ACKフラグセット USICNT |= 0x01; // 送信Bit数のセット break; }else{ // 他局の場合 I2C.State = Idle; // ステート・マシンの初期化 USICNT |= USICNT; // SCLを開放 SDA_InMode; // SDAを入力に break; // シーケンス終了 } case Read_SQ1: if (USISRL & 0x01) // NAck/Ackを判定 { // NAck受信 シーケンス中断 SDA_InMode; // SDAを入力に I2C.State = Idle; // IDLEステートに移行 break; }else{ // Ack受信 I2C.State = Read_SQ2; // 続行 次ステートを設定 SDA_OutMode; // DATA送出のため SDAを出力に if (I2C.DataCounter < I2C_DataBuffer_Size) { // バッファ内である場合 USISRL = // 送出DATAのセット I2C.DataBuffer[I2C.DataCounter++]; }else{ // バッファ・オーバーフロー時 USISRL = 0x00; // ダミー・データをセット } USICNT |= 0x08; // 送信Bit数のセット break; } case Read_SQ2: I2C.State = Read_SQ1; // 次のDATAを送信するためLOOP SDA_InMode; // (N)ACK受信のため SDAを入力に USICNT |= 0x01; // (N)Ack用Bit数セット break; case Write_SQ1: if (I2C.DataCounter < I2C_DataBuffer_Size) { I2C.State = Write_SQ2; // 次ステートを設定 SDA_InMode; // WRITE DATA受信のため SDAを入力に USICNT |= 0x08; // WRITE DATA用Bit数セット break; }else{ // バッファ規定数を受信 SDA_InMode; // SDAを入力に I2C.State = Idle; // IDLEステートに移行 break; } case Write_SQ2: I2C.DataBuffer[I2C.DataCounter++] = USISRL; // WRITE DATAをバッファに格納 I2C.State = Write_SQ1; // 次DATAに備えてLOOP SDA_OutMode; // ACKのため SDAを出力に USISRL = 0x00; // ACKフラグセット USICNT |= 0x01; // 送信Bit数のセット break; default: // シーケンサ異常終了 // ステート・マシンの初期化 I2C.State = Idle; // IDLEへ移行 SDA_InMode; // SDAを入力に break; } USICTL1 &= ~USIIFG; // カウンタ割込要因のクリア }