/**********************************/ /* タクトスイッチ寿命テスト */ /* "sw_life_test4" */ /**********************************/ // PD3でソレノイドを駆動してスイッチをon/off。 // PC1をプルアップありの入力に。 // PC1がオンしないまでの回数を記録。 // オフが連続したら異常で停止。 // PC0でA/D入力。 (Vref=1.1Vで) // PC0とPC1をつなぐ。 // A/D0でスイッチの接触抵抗をチェック。 // 0.25秒サイクルで測定。 毎秒4回。 // 0.1秒オン、0.15秒オフを繰り返す // A/D値が2以上の時、最新200サイクル分の // サイクル数とA/D値を記録。(リングバッファで) // TXスイッチで記録データを送出。 // PD0 i 0 (RXD) // PD1 o 1 (TXD) // PD2 o 2 異常停止LED on (Lでon) // PD3 o 3 ソレノイド駆動 (Hでon) // PD4 o 4 - // PD5 o 5 - // PD6 i 6 SW1 start/stop (Lでon) // PD7 i 7 SW2 TX // PB0 o 8 (!!!) // PB1 o 9 (!!!) // PB2 o 10 (!!!) // PB3 o 11 (!!!) // PB4 o 12 - // PB5 o 13 - // PC0 i A0 SW電圧入力 A/D ch0 // PC1 i A1 pull up,PC0と接続 , SW on/off入力 // PC2 i A2 pull up,スタンバイ時A/D値出力ジャンパ // PC3 o A3 - // PC4 - A4 I2C SDA // PC5 - A5 I2C SCL // 外付けEEPROM #include // I2C 外付けEEPROM用 // wire.hの中で「BUFFER_LENGTH 32」 // と連続読み書きの大きさが指定されている #include // 内蔵EEPROMは512バイト /***** タイトルと日付 *****/ const char prg_titl[] PROGMEM = "# SW LIFE TEST4 (2021-11-27)"; // タイトル /***** マクロ *****/ #define DIMSIZ(a) (sizeof(a)/sizeof(*a)) // 配列のデータ数を返す typedef unsigned long ulong; // unsigned longの略 // ポートH/L制御出力 #define LED_ON (PORTD &= ~(1 << PD2)) // PD2:異常停止LED #define LED_OFF (PORTD |= (1 << PD2)) #define SOL_ON (PORTD |= (1 << PD3)) // PD3:ソレノイド #define SOL_OFF (PORTD &= ~(1 << PD3)) // ポート,SW入力 on,offチェック(onで1) #define INP_SW ((~PINC) & (1 << PORTC1)) // PC1 タクトスイッチ入力 #define INP_START ((~PIND) & (1 << PORTD6)) // PD6 start/stop SW #define INP_TX ((~PIND) & (1 << PORTD7)) // PD7 TX SW #define INP_JPADTX ((~PINC) & (1 << PORTC2)) // PC2 スタンバイ時A/D値出力ジャンパ // テストパルス #define PB0_H (PORTB |= (1 << PB0)) // 14pin タイマー割込 #define PB0_L (PORTB &= ~(1 << PB0)) #define PB1_H (PORTB |= (1 << PB1)) // 15pin A/D割込 #define PB1_L (PORTB &= ~(1 << PB1)) #define PB2_H (PORTB |= (1 << PB2)) // 16pin SW入力を反映 #define PB2_L (PORTB &= ~(1 << PB2)) #define PB3_H (PORTB |= (1 << PB3)) // 17pin EEPROMアクセス #define PB3_L (PORTB &= ~(1 << PB3)) /******************************/ /* データ */ /******************************/ // on/offサイクル #define CYC_MAX 99999999 // 最大サイクル数 8桁で // (05F5 E0FF) // OKでもこの回数で停止 uint32_t cyc_cnt; // on/offサイクルカウンタ // 1サイクル0.3秒 word off_cnt; // PC1入力オフを検出した回数 #define OFF_MAX 10 // オフ検出が規定回数に達すると // 異常で停止 // cyc,A/D値記録 #define MIN_AD 2 // 10bit A/D値が2以上の時に記録 // 0,1は記録しない typedef struct{ // CYCとA/D値を記録 long cyc; // サイクル数 8桁 word ad; // 10bit A/D + オフ回数(MSB 6bt) }ST_ADBFF; ST_ADBFF ad_data; // A/D保存データ // 外付けEEPROMに書き込む #define AD_SAV (8192 / sizeof(ad_data)) // 保存データ数 // 24LC16 = 2kバイト 0~07FF:341 // FM24W64 = 8kバイト 0~1FFF:1365 word ad_cnt; // A/D書き込みデータ数 word ad_ptr; // A/D書き込みポインタ // 1周したら先頭に戻す // on/off文字 const char msg_off[] PROGMEM = "off"; const char msg_on[] PROGMEM = "on"; PGM_P msg_onoff[]={ msg_off, // 0 "off" msg_on, // 1 "on" }; /******************************/ /* 内蔵EEPROM */ /******************************/ /***** EEPROMデータ *****/ word EEMEM EE_chk; // 初期化チェックデータ 0x1234と比較 // 一致しないと初期化 word EEMEM EE_off_cnt; // off_cnt word EEMEM EE_ad_cnt; // ad_cnt word EEMEM EE_ad_ptr; // ad_ptr uint32_t EEMEM EE_cyc_cnt; // cyc_cntのコピー (long) uint32_t EEMEM EE_cyc_mem[OFF_MAX]; // offを検出したcyc数 /***** パラメータセーブ *****/ // EEPROMに書き込む void eesave(void) { eeprom_write_word(&EE_off_cnt, off_cnt); eeprom_write_word(&EE_ad_cnt, ad_cnt); eeprom_write_word(&EE_ad_ptr, ad_ptr); eeprom_write_dword(&EE_cyc_cnt, cyc_cnt); } /***** パラメータロード *****/ // EEPROMから読み出す void eeload(void) { off_cnt = eeprom_read_word(&EE_off_cnt); ad_cnt = eeprom_read_word(&EE_ad_cnt); ad_ptr = eeprom_read_word(&EE_ad_ptr); cyc_cnt = eeprom_read_dword(&EE_cyc_cnt); } /******************************/ /* スイッチ入力 */ /******************************/ // SWコード #define SW_START 1 // SW1 start/stop スイッチ(短押し) #define SW_RST 2 // SW1 restart(長押し) #define SW_TX 3 // SW2 TXスイッチ volatile byte f_swon; // SW入力オン確定フラグ volatile byte sw_code; // SW on コード volatile byte sw_rpt; // SWリピート回数 /***** スイッチ入力 *****/ // PD6,PD7 onでL 1~2のSWコードで返す 0:off // SW1は短押し、長押しの判断でコードを変える byte swinp(void) { if(INP_START) return SW_START; // start/stop スイッチ if(INP_TX) return SW_TX; // TX スイッチ return 0; // 2ともoff } /***** スイッチ入力チェック *****/ // 0.78ms割り込みで処理 (1.28kHz) // 結果をf_swonとsw_codeに残す void swscan(void) { byte d; static byte dx; // 前回SWデータ static byte chk = 0; // 実行区分 static word tm1 = 0; // 1msタイマー チャタリング除去 if(tm1) tm1--; // 1ms計時 d = swinp(); // SW入力 1~2のSWコード switch(chk){ case 0: // オフチェックタイマーをセット tm1 = 13; // 10ms chk++; break; case 1: // 離されるのを待つ if(d == 0){ // 全オフ確認 if(tm1 == 0) chk++; // タイムアップで次stepへ } else{ // どれか押されている chk--; // タイマー再セット } break; case 2: // どれかon待ち if(d != 0){ // on? dx = d; // SWコードを保存 tm1 = 13; // 13ms チャタリング除去 chk++; // 安定チェックへ } break; case 3: // on確定待ち if(dx != d){ // 異なればもういちど chk--; } else{ // 安定 if(tm1 == 0){ // タイムアップでSW確定 if(d == SW_START){ // start/stopは長押しチェック tm1 = 1538; // 1.2秒経過で長押し chk = 4; // 長押しの判断へ } else{ // SW1以外 sw_code = d; // SWコード確定 f_swon = 1; // onフラグ chk = 0; // オフ確認に } } } break; case 4: // SW1の短押し、長押しの判断 if(d == dx){ // on継続 if(tm1 == 0){ // タイムアップ sw_code = SW_RST; // SW1長押しコード確定 f_swon = 1; // onフラグ chk = 0; // オフ確認に } } else{ // 離された sw_code = SW_START; // SW1短押しコード確定 f_swon = 1; // onフラグ chk = 0; // オフ確認に } break; } } /***** SW オンチェック *****/ // onしたらコードを持ってリターン // offなら0 byte swonchk(void) { if(f_swon == 0){ return 0; // SW off =0 } else{ f_swon = 0; // フラグをオフして return sw_code; // SW on =SWコード } } /*****************************/ /* タイマー処理 */ /*****************************/ /***** タイマーデータ *****/ volatile byte f_tm1; // タイマー1.28kHzフラグ volatile byte tm_0r78ms; // 0.78msタイマー volatile byte tm_10ms; // 10msタイマー volatile byte tm_led; // LED点滅用50msタイマー volatile byte tm_eep; // EEPROM 書き込み確認用 0.78msタイマー // 10msだと13で /***** タイマー1 コンペアマッチA割込み *****/ // 1.28kHz周期で割り込み (0.78125ms) ISR(TIMER1_COMPA_vect) { static byte cnt = 0; // A/D変換平均回数 PB0_H; // (!!!) f_tm1 = 1; // 1.28kHzフラグ if(tm_0r78ms) tm_0r78ms--; // 0.78msタイマー if(tm_eep) tm_eep--; // EEPROM 確認 swscan(); // スイッチ入力チェック // 10msカウント cnt++; if(cnt >= 13){ // 10.15625ms cnt = 0; if(tm_10ms) tm_10ms--; // ダウンカウント } // 内蔵A/D開始 ADCSRA |= (1 << ADSC); // A/D変換開始 PB0_L; // (!!!) } /******************************/ /* A/D処理 */ /******************************/ #define ADAVR_ADD 64 // A/D平均回数 // 1.28kHz/64=20Hz : 50ms volatile word ad_avr; // A/D変換データ 0~1023 // 平均処理された結果 volatile word ad_add; // A/D平均処理用加算データ // 64回で16bit範囲 volatile byte f_adok; // A/D変換完了フラグ 50msサイクル // 割り込みでセット /***** A/D割り込み処理 *****/ // 1msタイマー割り込みでA/D変換開始 // 256回で平均値算出 ISR(ADC_vect) { word d; static byte cnt = 0; // A/D変換平均回数 PB1_H; // (!!!) d = (word)ADCL; // A/Dデータ d |= (word)(ADCH & 0x03) << 8; // 符号なしで 0~3FF // 測定値 ad_add += d; // 平均用に加算 // 平均処理 cnt++; // 平均加算回数 if(cnt >= ADAVR_ADD){ // 64回? cnt = 0; ad_avr = (word)(ad_add / ADAVR_ADD); // 平均 ad_add = 0; // 次加算データクリア f_adok = 1; // 変換完了 if(tm_led) tm_led--; // 50msサイクルでダウンカウント } PB1_L; // (!!!) } /******************************/ /* LED点滅処理 */ /******************************/ #define LED_NOP 0 // なにもしない #define LED_STBY 1 // スタンバイ 1秒周期で点滅 #define LED_STOP 2 // 停止/異常 0.2秒周期で点滅 byte led_blink; // LED点滅処理区分 byte led_onoff; // LED点滅実行 on/off区分 /***** LED点滅処理 *****/ // tm_led:50msでカウント void ledblink(void) { if(tm_led == 0){ // タイムアップ led_onoff ^= 1; // on/off反転 switch(led_blink){ case LED_STBY: // スタンバイ 1秒周期で点滅 if(led_onoff){ tm_led = 4; // 200ms LED_ON; // on } else{ tm_led = 16; // 800ms LED_OFF; // off } break; case LED_STOP: // 停止/異常 0.2秒周期で点滅 if(led_onoff){ tm_led = 1; // 50ms LED_ON; // on } else{ tm_led = 3; // 150ms LED_OFF; // off } break; } } } /******************************/ /* 書式付シリアル出力 */ /******************************/ // クラスPrintへのポインタ Print *Cp; // クラスPrintへの関数ポインタ // Cp = &Serial; や &LCDなど /***** Printクラスへの書式付シリアル出力 *****/ // PSTR("")で書式を指定 void CpPrintf_P(const char *s, ...) { va_list vp; char bff[64]; // バッファを確保 va_start(vp, s); vsnprintf_P(bff, sizeof(bff), s, vp); // PSTRで書式を指定 Cp->print(bff); // cpへ出力 va_end(vp); } /***** 文字出力 *****/ void CpPuts_P(const char *s) { char c; while(1){ c = pgm_read_byte(s); if(c == '\x0') break; Cp->write(c); s++; } } /***** 記録データ送信 *****/ // 記録してある最新データを出力 // cyc数とA/D値 void txadbff(void) { word i; word p; byte bl; // LED点滅状態 word d; // 10bit A/D値 byte n; // off回数(MSB 6bit) uint32_t cyc; byte bk = 0; // 中断フラグ bl = led_blink; // 現在の点滅状態を保存 led_blink = LED_NOP; // 点滅なしに LED_ON; // 出力中LEDをオン // 内蔵EEPROMに記録したoff検出サイクル if(off_cnt != 0){ // オフ検出あったとき CpPuts_P(PSTR("#off cyc\r\n")); for(i = 0; i < off_cnt; i++){ // loop tm_0r78ms = 32; // 25ms待ち cyc = eeprom_read_dword(&EE_cyc_mem[i]); // off時のcyc数 CpPrintf_P(PSTR("#%3d %8ld\r\n"), i + 1, cyc); while(tm_0r78ms); // 時間待ち bk |= swonchk(); // SW入力チェック if(bk) break; // onで中断 } } // リングバッファのA/D値を出力 CpPuts_P(PSTR("# cyc A/D off\r\n")); if(ad_cnt >= AD_SAV) // バッファの大きさ p = ad_ptr; // いっぱいならptrが先頭 else p= 0; // まだなら0から for(i = 0; i < ad_cnt; i++){ // loop tm_0r78ms = 32; // 25ms待ち if((i % 8) < 4) LED_ON; // 0~3 (0.1s) else LED_OFF; // 4~7 eepreadb(p * sizeof(ad_data), // EEPROMから (byte *)&ad_data, sizeof(ad_data)); d = ad_data.ad & 0x03FF; // 10bit A/D n = (ad_data.ad >> 10) & 0x003F; // off回数 CpPrintf_P(PSTR("%8ld %4d"), ad_data.cyc, d); if(n != 0){ // off回数あり CpPrintf_P(PSTR(" %3d"), n); } Cp->println(); p++; if(p >= AD_SAV) p = 0; // 一周 while(tm_0r78ms); // 時間待ち bk |= swonchk(); // SW入力チェック if(bk) break; // onで中断 } if(bk) CpPuts_P(PSTR("# Braek.\r\n")); LED_OFF; led_blink = bl; // 点滅状態戻す } /*********************************/ /* 外付けI2C EEPROM */ /*********************************/ // tm_eepで書き込み時間待ちを行う #define DEV_ADRS 0x50 // チップのアドレス // r/wビットはアドレスに含まない // 7 6 5 4 3 2 1 0 // 1 0 1 0 A2 A1 A0 R/W // 実際は「A0」 // TWIルーチンで左シフトされてR/Wbitを付加 #define DEV_TYPE 1 // 0 : 07FF 16バイト~2kバイト // 1 : FFFF 4k~64kバイト // 2 : 1FFFF 128kバイト(現時点除外) #define DEV_PAGE 16 // ページサイズ なし,8,16,32,64,128 // Wire.hでは16までしか扱えない #define DEV_BUSY 1 // busyチェック方法 // 0 : タイマー待ち // 1 : ACK,NACKチェック // 2 : FRAM指定、busyチェックなし // FRAMはbusy待ちせずに読み書き可能。 /***** EEPROM busyチェック *****/ // DEV_BUSYにより書き込み待ちを区分 // 0 : レディ  0以外:ビジー // tm_eepで書き込み時間待ちをチェック // FRAMなら時間待ちせずに書き込みできる byte eepbusy(void) { byte r; switch(DEV_BUSY){ case 0: // タイマー待ち r = tm_eep; // タイムアップで0 break; case 1: // ACK,NACKチェック (タイマーもかます) if(tm_eep == 0){ // タイムアップしてたら r = 0; // レディ } else{ // まだならACK確認 Wire.beginTransmission(DEV_ADRS); r = Wire.endTransmission(); // 0:ACK=ok } break; case 2: // FRAM指定、busyチェックなし r = 0; // 0=ready break; } return r; // Z or NZ } /***** EEPROM デバイスアドレスを得る *****/ // 4kバイト未満と4kバイト以上のチップで区分 // 4k未満は上位3bitをデバイスアドレスの下位に付加 byte eepdevadrs(word adrs) { byte d; d = DEV_ADRS; // 0x50 if(DEV_TYPE == 0){ // 容量2kまで 0~7FF d |= (adrs >> 8) & 0x07; // アドレスの上位3bitを // デバイスアドレスの下位に } return d; // 4k以上はそのまま } /***** EEPROM デバイスアドレスの書き込み *****/ // 4kバイト未満と4kバイト以上のチップで区分 void eepadrswr(word adrs) { byte d; d = eepdevadrs(adrs); // デバイスアドレス 4k以上で区分 if(DEV_TYPE == 0){ // 容量2kまで 0~7FF Wire.beginTransmission(d); // デバイスアドレス+アドレス上位3bit Wire.write(adrs & 0xFF); // LSB } else{ // 4k~64kバイト Wire.beginTransmission(d); Wire.write(adrs >> 8); // MSB Wire.write(adrs & 0xFF); // LSB } } /***** EEPROM 1バイト書き込み *****/ void eepwrite(word adrs, byte data) { while(eepbusy()); // 書き込み時間待ち PB3_H; // (!!!) 17pin eepadrswr(adrs); // デバイスアドレス設定 Wire.write(data); // 1バイトデータ Wire.endTransmission(); // 転送開始 tm_eep = 10; // busy待ちタイマーセット PB3_L; // (!!!) 17pin } /***** EEPROM ブロック書き込み *****/ // 同一ページ内で連続書き込み(ページのチェックはしていない) void eepwriteb(word adrs, byte *data, byte siz) { byte i; while(eepbusy()); // 書き込み時間待ち PB3_H; // (!!!) 17pin eepadrswr(adrs); // デバイスアドレス設定 for (i = 0; i < siz; i++){ Wire.write(data[i]); // 内部バッファへ転送 } Wire.endTransmission(); // 転送開始 tm_eep = 10; // busy待ちタイマーセット PB3_L; // (!!!) 17pin } /***** EEPROM ページ書き込み *****/ // デバイスにより連続書き込み可能 // ページの分断に留意して書き込みを実行 void eepwritep(word adrs, byte *data, word siz) { word a, a1, a2; word n, n1; byte *p; a = adrs; n = siz; p = data; while(n){ a1 = a & (-DEV_PAGE); // 先頭ページ 16バイト単位 a2 = (a + (n - 1)) & (-DEV_PAGE); // 後尾ページ if(a1 == a2){ // 同一ページ eepwriteb(a, p, n); // ブロック書き込み n = 0; } else{ // ページが異なる n1 = a2 - a; // 先頭バイト数 if(n1 > DEV_PAGE){ // ページバイト数を越える n1 = ((a | (DEV_PAGE - 1)) + 1) - a; } eepwriteb(a, p, n1); // ブロック書き込み n = n - n1; // 残バイト数 a = a + n1; p = p + n1; } } } /***** EEPROM 1バイト読み出し *****/ // 4k未満のチップの場合,書き込みと読み出しで // 同じデバイスアドレス(上位アドレス3bit印加)にすること。 byte eepread(word adrs) { byte r = 0xFF; // 読み出しデータ byte d; // デバイスアドレス while(eepbusy()); // 書き込み時間待ち PB3_H; // (!!!) 17pin eepadrswr(adrs); // デバイスアドレス設定 Wire.endTransmission(); // 転送 d = eepdevadrs(adrs); // デバイスアドレス 4k以上で区分 Wire.requestFrom(d, 1); // 読み出し開始 if(Wire.available()) r = Wire.read(); // 1バイト読み出し PB3_L; // (!!!) 17pin return r; } /***** EEPROM ブロック読み出し *****/ // 同一ページ(256バイト)内での連続読み出し void eepreadb(word adrs, byte *bff, byte siz) { word i; byte d; // デバイスアドレス while(eepbusy()); // 書き込み時間待ち PB3_H; // (!!!) 17pin eepadrswr(adrs); // デバイスアドレス設定 Wire.endTransmission(); // 転送 d = eepdevadrs(adrs); // デバイスアドレス 4k以上で区分 Wire.requestFrom(d, siz); // 読み出し開始 for(i = 0; i < siz; i++){ // loop if(Wire.available()) bff[i] = Wire.read(); } PB3_L; // (!!!) 17pin } /*********************************/ /* 制御実行処理 */ /*********************************/ // 制御用データ byte chk_adcnt; // A/D変換回数 (50ms) /***** 制御実行区分 *****/ byte j_exc; // 実行区分 byte j_excx; // 実行区分保存用 #define J_STBY 0 // スタンバイ #define J_SOLON 2 // ソレノイド on #define J_SOLON1 3 // ソレノイド on loop #define J_STOP 6 // 停止/異常 #define J_RESTART 8 // リスタート #define J_DATATX 9 // データ送信 /***** スタンバイ *****/ void jstby(void) { if((off_cnt >= OFF_MAX) || // SW入力オフ回数? (cyc_cnt >= CYC_MAX)){ // 最大回数? j_exc = J_STOP; // 停止へ } else{ f_adok = 0; // 次のA/D変換を待つ chk_adcnt = 0; led_blink = LED_STBY; // LED点滅周期 j_exc++; // next exc } } /***** スタンバイ #1 *****/ // ADTXジャンパがonなら // 1秒周期でA/D値とSW入力on/offを出力 void jstby1(void) { word d; byte n; if(f_adok){ // 50ms経過 A/D平均値確定 f_adok = 0; chk_adcnt++; // A/D変換回数+1 if(chk_adcnt >= 20){ // 20回=1秒 chk_adcnt = 0; if(INP_JPADTX){ // A/D値送信ジャンパon cli(); // いったん割込禁止にして d = ad_avr; // A/D平均値読み出し sei(); // 割込再開 n = INP_SW ? 1 : 0; // タクトスイッチon/off CpPrintf_P(PSTR("#%5d "), d); // A/D値 CpPuts_P(msg_onoff[n]); // on/off状態 Cp->println(); // 改行 } } } switch(swonchk()){ // 操作スイッチチェック case SW_START: // スタート if((off_cnt < OFF_MAX) && // オフ回数まだok (cyc_cnt < CYC_MAX)){ // 最大回数まだok j_exc = J_SOLON; // ソレノイドonへ } break; case SW_RST: // リセットスタート j_exc = J_RESTART; // リスタート break; case SW_TX: // 送信 j_excx = j_exc; // 現実行区分を保存してから j_exc = J_DATATX; // 記録データ送信へ break; } } /***** ソレノイドon *****/ // 次のf_adokでonに void jsolon(void) { f_adok = 0; // 次のA/D変換を待つ led_blink = LED_NOP; // LED点滅やめる j_exc++; // next exc } /***** ソレノイドon #1 *****/ // on/off繰り返し 50ms経過を待つ void jsolon1(void) { if(f_adok){ // 50ms経過 f_adok = 0; SOL_ON; // ソレノイドと LED_ON; // LEDをオン chk_adcnt = 0; // A/D変換回数クリア j_exc++; // next exc } } /***** ソレノイドon #2 *****/ // onで100ms待ち SW on,off とA/D値を入力 // cycとA/D値をリングバッファに void jsolon2(void) { word d; byte n; if(f_adok){ // 50ms経過 f_adok = 0; chk_adcnt++; // A/D変換回数+1 if(chk_adcnt >= 2){ // 2回目で100ms chk_adcnt = 0; cli(); // いったん割込禁止にして d = ad_avr; // A/D平均値読み出し sei(); // 割込有効に戻す n = INP_SW ? 1 : 0; // タクトスイッチ入力 on/offチェック SOL_OFF; // ソレノイドと LED_OFF; // LEDをオフ // データ出力 12345678 1023 on cyc_cnt++; // 回数+1 CpPrintf_P(PSTR("%8ld %4d "), cyc_cnt, d); // 回数, A/D値 CpPuts_P(msg_onoff[n]); // on/off状態 if(n == 0){ // offの時 eeprom_write_dword(&EE_cyc_mem[off_cnt], cyc_cnt); // オフサイクルをEEPROMに off_cnt++; // オフ回数+1 CpPrintf_P(PSTR(" %2d"), off_cnt); } Cp->println(); // 改行 // データ記録 if(d >= MIN_AD){ // A/D値が2以上の時 ad_data.cyc = cyc_cnt; // サイクルカウンタ if(n == 0){ // offの時 d |= (off_cnt << 10); // オフ回数をA/Dの上位に } ad_data.ad = d; // バッファにA/D値を eepwritep(ad_ptr * sizeof(ad_data), // EEPROM書き込み (byte *)&ad_data, sizeof(ad_data)); ad_ptr++; // 次の書き込み位置 if(ad_ptr >= AD_SAV){ // バッファ一周? ad_ptr = 0; // 先頭に } if(ad_cnt < AD_SAV){ // 最大数チェック ad_cnt++; // データ数+1 } } // 停止判定 SWがオフ、最大回数 if((n == 0) || // SW入力オフだった (off_cnt >= OFF_MAX) || // SW入力オフ回数? (cyc_cnt >= CYC_MAX)){ // 最大回数? j_exc = J_STOP; // 停止へ } else{ j_exc++; // next exc } } } } /***** ソレノイドon #3 *****/ // offで100ms待ち void jsolon3(void) { if(f_adok){ // 50ms経過 f_adok = 0; chk_adcnt++; // A/D変換回数+1 if(chk_adcnt >= 2){ // 2回目で100ms j_exc = J_SOLON1; // 繰り返し } } switch(swonchk()){ // 操作スイッチチェック case SW_START: // ストップ eesave(); // パラメータ設定 内蔵EEPROMに j_exc = J_STBY; // スタンバイへ break; case SW_RST: // リセットスタート j_exc = J_RESTART; // リスタート break; case SW_TX: // 送信 j_excx = j_exc; // 現実行区分を保存してから j_exc = J_DATATX; // 記録データ送信へ break; } } /***** 停止/異常 *****/ void jstop(void) { led_blink = LED_STOP; // 0.2秒周期点滅 CpPuts_P(PSTR("# Stop\r\n")); eesave(); // パラメータ設定 内蔵EEPROMに j_exc++; // next exc } /***** 停止/異常 #1 *****/ // 0.2秒周期で点滅 // スイッチ操作待ち void jstop1(void) { switch(swonchk()){ // 操作スイッチチェック case SW_START: // スタート if((off_cnt < OFF_MAX) && // オフ回数まだok (cyc_cnt < CYC_MAX)){ // 最大回数まだok j_exc = J_SOLON; // ソレノイドonへ } break; case SW_RST: // リセットスタート j_exc = J_RESTART; // リスタート break; case SW_TX: // 送信 j_excx = j_exc; // 現実行区分を保存してから j_exc = J_DATATX; // 記録データ送信へ break; } } /***** リスタート *****/ // サイクル0からスタート void jrestart(void) { cyc_cnt = 0; // 回数ゼロから off_cnt = 0; // オフ検出回数 ad_ptr = 0; // EEPROM ad_data書き込みポインタ ad_cnt = 0; // バッファデータ数クリア eesave(); // パラメータ設定 内蔵EEPROMに j_exc = J_SOLON; // ソレノイドonへ } /***** データ送信 *****/ // EEPROMに保存したデータをシリアル出力 void jdatatx(void) { txadbff(); // データ出力 j_exc = j_excx; // 保存してあった実行区分へ戻る } /********************************/ /* 制御実行テーブル */ /********************************/ /***** 制御実行 *****/ void (*jexc[])(void)={ jstby, // * 0:スタンバイ jstby1, // 1:スタンバイ #1 jsolon, // * 2:ソレノイドon jsolon1, // * 3:ソレノイドon loop jsolon2, // 4:ソレノイドon 判定 jsolon3, // 5:ソレノイドon オフ時間待ち jstop, // * 6:停止/異常 jstop1, // 7:停止/異常 #1 jrestart, // * 8:リスタート jdatatx, // * 9:データ送信 }; /***************************/ /* SETUP */ /***************************/ /***** SET UP *****/ void setup() { cli(); // 割込禁止 // I/Oイニシャル PORTB = 0b00000000; // data/pull up DDRB = 0b00111111; // port指定 // |||||+---- PB0 IO8 out (テストパルス) 14pin // ||||+----- PB1 IO9 out (テストパルス) 15pin // |||+------ PB2 IO10 out (テストパルス) 16pin // ||+------- PB3 IO11 out - // |+-------- PB4 IO12 out - // +--------- PB5 IO13 out - PORTC = 0b00110110; // data/pull up DDRC = 0b00001000; // port指定 // |||||+---- PC0 AD0 in SW接点電圧A/D入力 PC1と接続 // ||||+----- PC1 AD1 in PC0と接続, pull upありで // |||+------ PC2 AD2 in JPADTXジャンパ入力 // ||+------- PC3 AD3 out - // |+-------- PC4 AD4 pull up:I2C SDA // +--------- PC5 AD5 pull up:I2C SCL PORTD = 0b11000111; // data/pull up DDRD = 0b00001110; // port指定 // |||||||+---- PD0 IO0 in RXD // ||||||+----- PD1 IO1 out TXD // |||||+------ PD2 IO2 out 異常停止LED (Lでon) // ||||+------- PD3 IO3 out ソレノイド駆動 // |||+-------- PD4 IO4 out - // ||+--------- PD5 IO5 out - // |+---------- PD6 IO6 in start/stop SW // +----------- PD7 IO7 in TX SW // タイマー1 1.28kHz(781.25uS)割込 TCCR1A = 0b00000000; // |||| ++---- WGM CTC OCR1で // ||++-------- COM1B // ++---------- COM1A TCCR1B = 0b00001001; // || ||+++---- CS 16MHz / 1 : 16MHz // || ++------- WGM CTC // |+---------- ICES1 // +----------- ICNC1 OCR1A = 12500 - 1; // 16MHz/12500=1.28kHz TIMSK1 = 0b00000010; // | ||+---- TOIE1 // | |+----- OCIE1A コンペアマッチ1A有効 // | +------ OCIE1B // +--------- ICIE1 // A/D入力 DIDR0 = 0b00000001; // AD0 デジタル入力禁止 ADMUX = 0b11000000; // 内蔵A/D // ||| ++++---- ADC0 MPX ch0 // ||+--------- ADLAR 右詰めで // ++---------- REFS 内蔵1.1Vで ADCSRA = 0b10001111; // |||||+++---- プリスケーラ 1/128 125kHz // ||||+------- ADIE 割込あり // |||+-------- ADIF // ||+--------- ADATE // |+---------- ADSC // +----------- ADEN 有効に sei(); // 割込許可 // シリアル,I2C Serial.begin(9600); // 9600BPSで Wire.begin(); // 外付けEEPROM用I2C Wire.setClock(400000L); // 100kHz→400kHzに ちょい早く } /**********************************/ /*  LOOP */ /**********************************/ /***** LOOP *****/ void loop() { Cp = &Serial; // シリアル出力に CpPuts_P(prg_titl); // タイトル Cp->println(); // 改行 // EEPROMチェック EE_chkが特定データだったらすでに起動されている if(eeprom_read_word(&EE_chk) != 0x1234){ // チェックデータ eeprom_write_word(&EE_chk, 0x1234); // 初期化する eesave(); // パラメータ設定も Cp->println(F("EEPROM init")); // } else{ // チェックデータok eeload(); // パラメータを読み出す } // 設定値表示 CpPrintf_P(PSTR("OFF_MAX : %d\r\n"), OFF_MAX); // off検出最大回数 CpPrintf_P(PSTR("AD_SAV : %d\r\n"), AD_SAV); // 保存データ数 CpPrintf_P(PSTR("MIN_AD : %d\r\n"), MIN_AD); // リングバッファに記録するA/D値 CpPrintf_P(PSTR("off_cnt : %d\r\n"), off_cnt); // off検出回数 CpPrintf_P(PSTR("ad_cnt : %d\r\n"), ad_cnt); // A/D記録数 リングバッファ CpPrintf_P(PSTR("ad_ptr : %d\r\n"), ad_ptr); // A/D記録ポインタ CpPrintf_P(PSTR("cyc_cnt : %ld\r\n"), cyc_cnt); // on/offサイクル数 // 繰り返し while(1){ // SW入力H/Lをポートに if(f_tm1){ // タイマー1.28kHzフラグ f_tm1 = 0; if(INP_SW) PB2_L; // L, SW->PB2(16pin)に else PB2_H; // H } // LED点滅 ledblink(); // LED点滅処理 // 制御実行 jexc[j_exc](); // 制御実行区分で } } /*===== end of "sw_life_test4" =====*/