/* ======================================================== LED.c ======================================================== */ #pragma sfr #include "incs.h" #include "led.h" // ======================================================== // TPS0 #define BIT_PRS012 ( 1 << 2 ) #define BIT_PRS002 ( 1 << 6 ) // TMR0 #define BIT_CKS0 15 #define BIT_CCS0 12 #define BIT_MASTER0 11 #define BIT_STS0 8 #define BIT_CIS0 6 #define BIT_MD123 1 #define BIT_MD0 0 // ======================================================== static void led_pow_normal( ); static void led_pow_hotaru( ); // ======================================================== static const char MSG_MAIL[] = { 0b11110110, 0b11011010, 0b01101110, 0b10010100 }; #define MSG_SPD 60 // ↑255/3以下であること! // ======================================================== void LED_init( ) { /** PWMのセット、とりあえず全部消灯 マスタチャネル:0 (P01:/reset2) マスターは偶数チャネルしかできない スレーブ    1 SLTO。(3D LED?)         2 カメラ         3 WiFi         4 (ピンはRTC32kHz out に使用)         5 充電         6 電源 L         7 電源 H */ TAU0EN = 1; TPS0 = BIT_PRS012 | BIT_PRS002; // マスタークロックはCK01,8M/2 /2^4 = 250kHz TMR00 = 1 << BIT_CKS0 | 0 << BIT_CCS0 | 1 << BIT_MASTER0 | 0 << BIT_STS0 | 0 << BIT_CIS0 | 0 << BIT_MD123 | 1 << BIT_MD0; TMR01 = TMR02 = TMR03 = TMR04 = TMR05 = TMR06 = TMR07 = 1 << BIT_CKS0 | 0 << BIT_CCS0 | 0 << BIT_MASTER0 | 4 << BIT_STS0 | 0 << BIT_CIS0 | 4 << BIT_MD123 | 1 << BIT_MD0; ISC = 0; TOM0 = 0b0000000011111110; // 出力モード。4はPWM出力しないが1にしないとTO5以降にクロックが届かない #ifdef _MCU_BSR_ TOL0 = 0b0000000000000000; // 出力を反転させるかフラグ #else TOL0 = 0b0000000000000100; // 出力を反転させるかフラグ #endif TO0 = 0; // タイマー動作中で、タイマー出力にしてないときのピンのラッチ。タイマー出力を使わないなら0 TOE0 = 0b0000000011101110; // TOxをタイマーモジュールが制御? TS0 = 0b0000000011101111; // 動作開始 TDR00 = LED_BRIGHT_MAX - 1; // 10bit, 周期 if( system_status.reboot ) { vreg_ctr[VREG_C_LED_POW] = LED_POW_ILM_AUTO; LED_duty_pow_H = LED_BRIGHT_MAX; } } void LED_stop( ) { TT0 = 0b0000000011101111; // 一斉停止(しないとだめ) TOE0 = 0b0000000000000000; // TOxをタイマーモジュールが制御?(GPIOになる) TAU0EN = 0; } /* ======================================================== // 電源LED LED_POW_B,R 6,7 TDR00 周期(0x03FF。TPS0で250kHzでカウントアップ。10bitなら250Hz位になる) TDR0x Duty 0で消灯、TDR00(より大 =0x03FF以上)で点灯です。 enum pwr_state_{ OFF_TRIG = 0, OFF, ON_TRIG, ON, SLEEP_TRIG, SLEEP }; enum LED_ILUM_MODE{ LED_POW_ILM_AUTO, LED_POW_ILM_ON, LED_POW_ILM_HOTARU, LED_POW_ILM_CEOFF }; ======================================================== */ void tsk_led_pow( ) { switch ( vreg_ctr[VREG_C_LED_POW] ) { // 自動切り替え case ( LED_POW_ILM_AUTO ): switch ( system_status.pwr_state ) { case SLEEP: led_pow_hotaru( ); break; case ON: led_pow_normal( ); break; default: break; } break; // 強制 case ( LED_POW_ILM_OFF ): LED_duty_pow_H -= ( LED_duty_pow_H == 0x0000 ) ? 0 : 1; LED_duty_pow_L -= ( LED_duty_pow_L == 0x0000 ) ? 0 : 1; break; case ( LED_POW_ILM_HOTARU ): led_pow_hotaru( ); break; case ( LED_POW_ILM_ON ): default: led_pow_normal( ); break; case ( LED_POW_ILM_ONLY_RED ): LED_duty_pow_H = 0x0000; LED_duty_pow_L = LED_BRIGHT_MAX; break; case ( LED_POW_ILM_ONLY_BLUE ): LED_duty_pow_H = LED_BRIGHT_MAX; LED_duty_pow_L = 0x0000; break; } } /* ======================================================== 電池残量で、 青→赤→赤点滅 ======================================================== */ static void led_pow_normal( ) { static u8 state; if( vreg_ctr[VREG_C_BT_REMAIN] < 3 ) { // 赤点滅 state++; if( state < 127 ) { LED_duty_pow_H = 0x0000; LED_duty_pow_L = 0x0000; } else { LED_duty_pow_L = vreg_ctr[VREG_C_LED_BRIGHT]; } return; } else if( vreg_ctr[VREG_C_BT_REMAIN] < 12 ) { // 赤点灯 if( LED_duty_pow_H != 0x0000 ) { // 青フェードアウト LED_duty_pow_H -= 1; } if( LED_duty_pow_L != vreg_ctr[VREG_C_LED_BRIGHT] ) { // 赤フェードイン LED_duty_pow_L += ( LED_duty_pow_L < vreg_ctr[VREG_C_LED_BRIGHT] ) ? 1 : -1; } return; } else { // 青点灯 if( LED_duty_pow_H != vreg_ctr[VREG_C_LED_BRIGHT] ) { LED_duty_pow_H += ( LED_duty_pow_H < vreg_ctr[VREG_C_LED_BRIGHT] ) ? 1 : -1; } if( LED_duty_pow_L != 0x0000 ) { LED_duty_pow_L -= 1; } } return; } /* ======================================================== ホタルパターン ======================================================== */ static void led_pow_hotaru( ) { static u8 delay; static u8 state; static u16 blue_to; static u16 red_to; if( delay != 0 ) { delay -= 1; return; } else { delay = 10; } if( LED_duty_pow_L != red_to ) { if( LED_duty_pow_L > red_to ) { LED_duty_pow_L -= 1; } else { LED_duty_pow_L += 2; } } if( LED_duty_pow_H != blue_to ) { if( LED_duty_pow_H > blue_to ) { LED_duty_pow_H -= 1; } else { LED_duty_pow_H += 2; } } switch ( state ) { // フェードイン case ( 0 ): case ( 2 ): case ( 4 ): if( vreg_ctr[VREG_C_BT_REMAIN] < 12 ) { // 赤いとき blue_to = 0; red_to = vreg_ctr[VREG_C_LED_BRIGHT]; } else { blue_to = vreg_ctr[VREG_C_LED_BRIGHT]; red_to = 0; } break; default: // フェードアウト if( vreg_ctr[VREG_C_BT_REMAIN] < 12 ) { red_to = 2; } else { blue_to = 2; } break; } if( ( LED_duty_pow_H == blue_to ) && ( LED_duty_pow_L == red_to ) ) { state += 1; } return; } /* ======================================================== * 割り込みそのものは使いません * LED_Wifi 3 todo 直書きの点滅間隔など ======================================================== */ void tsk_led_wifi( ) { static u8 task_interval; static u8 remain_wifi_tx; static u8 state_wifi_tx; static u8 flag_wifi_TX; if( task_interval-- != 0 ) { return; } // 送信パルスのラッチ if( vreg_ctr[VREG_C_LED_WIFI] == WIFI_LED_TXAUTO ) { if( WIFI_txLatch ) { WIFI_txLatch = 0; flag_wifi_TX = 2; } } else { flag_wifi_TX = 0; } switch ( vreg_ctr[VREG_C_LED_WIFI] ) { case ( WIFI_LED_OFF ): default: LED_duty_WiFi = 0; state_wifi_tx = 0; remain_wifi_tx = 0; break; case ( WIFI_LED_ON ): LED_duty_WiFi = vreg_ctr[VREG_C_LED_BRIGHT]; state_wifi_tx = 0; remain_wifi_tx = 0; break; case ( WIFI_LED_TXAUTO ): if( flag_wifi_TX != 0 ) // 短いパルスを捕まえるために、割り込みフラグを見る { // 送信パターン switch ( state_wifi_tx ) { case ( 1 ): case ( 3 ): case ( 5 ): LED_duty_WiFi = 0; break; default: LED_duty_WiFi = vreg_ctr[VREG_C_LED_BRIGHT]; } state_wifi_tx++; if( state_wifi_tx == 32 ) { state_wifi_tx = 0; flag_wifi_TX -= 1; } task_interval = 22; return; } else { // 送信フラグ待ち LED_duty_WiFi = vreg_ctr[VREG_C_LED_BRIGHT]; task_interval = 200; return; } break; } } /* ======================================================== * 割り込みそのものは使いません * LED_Wifi2 P24 (未) ======================================================== */ void tsk_led_notify( ) { static u8 task_interval; static u8 flg_char_space; static u8 state_notify_led; // 点灯パターンの進行具合 static u8 flag_wifi_TX; if( task_interval-- != 0 ) { return; } switch ( vreg_ctr[VREG_C_LED_NOTIFY] ) { case ( NOTIFY_LED_OFF ): default: LED_duty_NOTIFY = 0; state_notify_led = 0; flg_char_space = 0; break; case ( NOTIFY_LED_ON ): LED_duty_NOTIFY = vreg_ctr[VREG_C_LED_BRIGHT]; state_notify_led = 0; flg_char_space = 0; break; case ( NOTIFY_LED_PTN0 ): // ゆっくりバースト switch ( state_notify_led ) { case ( 1 ): case ( 3 ): case ( 5 ): LED_duty_NOTIFY = vreg_ctr[VREG_C_LED_BRIGHT]; break; default: LED_duty_NOTIFY = 0; } state_notify_led++; if( state_notify_led == 16 ) { state_notify_led = 0; } task_interval = 50; return; case ( NOTIFY_LED_PTN1 ): // データテーブルに従って点滅 { u8 dat; task_interval = MSG_SPD; // 共通のため。場合によって上書き if( flg_char_space != 0 ) { LED_duty_NOTIFY = 0; flg_char_space = 0; return; } // データバッファの見る位置の更新 dat = ( MSG_MAIL[state_notify_led / 4] << ( ( state_notify_led % 4 ) * 2 ) ) & 0xC0; if( dat == 0 ) { state_notify_led = 0; } else { state_notify_led += 1; } flg_char_space = 1; if(( dat & 0b10000000 ) != 0 ) { // 点灯はさせる LED_duty_NOTIFY = vreg_ctr[VREG_C_LED_BRIGHT]; if(( dat & 0b01000000 ) == 0 ) { // 短 // nothing to do } else { // 長 task_interval = ( MSG_SPD * 3 ); } // 次は単語間休み、とかの判定をさせたかったが /// 1バイトに2ビットずつデータが並んでおり、次のバイトに /// またがるようなときが面倒なのでやめる return; } else { if(( dat & 0b01000000 ) == 0 ) { // 一文終了 task_interval = ( MSG_SPD * 3 ); } else { // 単語間 // nothing to do } return; } } } } /******************************************************//** LED_Cam TO02 \n BLINK,*_PLUSE の時は、1周期分は必ずその状態になります。 \n その間に OFF→BLINK などされると、OFFが無視されます。 *********************************************************/ void tsk_led_cam( ) { static u8 state_led_cam = 0; static u8 task_interval; static u8 state_led_cam_twl; if( task_interval != 0 ) { task_interval -= 1; return; } // ブリンクのように待たせたいとき以外は毎週起動する // (レジスタの変更にすぐに反応する) switch ( vreg_ctr[VREG_C_LED_CAM] ) { case ( CAM_LED_OFF ): default: LED_duty_CAM = 0; state_led_cam = 0; break; case ( CAM_LED_ON ): LED_duty_CAM = vreg_ctr[VREG_C_LED_BRIGHT]; state_led_cam = 0; break; case ( CAM_LED_BLINK ): if( state_led_cam == 0 ) { LED_duty_CAM = vreg_ctr[VREG_C_LED_BRIGHT]; state_led_cam = 1; } else { LED_duty_CAM = 0; state_led_cam = 0; } task_interval = 250; break; case ( CAM_LED_ON_PLUSE ): if( state_led_cam == 0 ) { LED_duty_CAM = vreg_ctr[VREG_C_LED_BRIGHT]; state_led_cam = 1; task_interval = 250; } else { vreg_ctr[VREG_C_LED_CAM] = CAM_LED_OFF; } break; case ( CAM_LED_OFF_PLUSE ): if( state_led_cam == 0 ) { LED_duty_CAM = 0; state_led_cam = 1; task_interval = 250; } else { vreg_ctr[VREG_C_LED_CAM] = CAM_LED_ON; } break; case ( CAM_LED_BY_TWL ): switch ( vreg_twl[ REG_TWL_INT_ADRS_CAM ] ){ // switchのネストとか… case( TWL_CAMLED_OFF ): LED_duty_CAM = 0; state_led_cam = 0; break; case( TWL_CAMLED_BLINK ): if( state_led_cam == 0 ) { LED_duty_CAM = vreg_ctr[VREG_C_LED_BRIGHT]; state_led_cam = 1; } else { LED_duty_CAM = 0; state_led_cam = 0; } task_interval = 250; break; case( TWL_CAMLED_ON ): case( TWL_CAMLED_DEF_ON ): default: LED_duty_CAM = vreg_ctr[VREG_C_LED_BRIGHT]; state_led_cam = 1; break; } } return; }