mirror of
https://github.com/rvtr/ctr_mcu.git
synced 2025-10-31 13:51:10 -04:00
・ログいっぱいフラグ(HOSU_SETTING.4)を追加 ・電源LEDが赤点灯する条件な電池を接続したとき、直後の一回だけお知らせLEDの赤がつきっぱなしになるのを修正(2回目以降の電源投入では大丈夫) git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_mcu@305 013db118-44a6-b54f-8bf7-843cb86687b1
543 lines
14 KiB
C
543 lines
14 KiB
C
/* ********************************************************
|
||
歩数計
|
||
3軸加速度のリアルタイムデータから、ベクトルのノルムを出し、
|
||
閾値を超える時間、間隔、ノルムの大きさで閾値を切り替えるなど
|
||
********************************************************* */
|
||
#pragma mul
|
||
#pragma div
|
||
#pragma bcd
|
||
|
||
#include "incs.h"
|
||
#include <math.h>
|
||
|
||
#include "accero.h"
|
||
#include "pedometer.h"
|
||
|
||
#include "pedo_lpf_coeff.h"
|
||
#include "pool.h"
|
||
|
||
// ========================================================
|
||
static void hosu_increment();
|
||
|
||
|
||
|
||
// ========================================================
|
||
u16 get_long_hour();
|
||
|
||
|
||
extern uni_pool pool;
|
||
bit pedolog_overflow;
|
||
|
||
|
||
// ========================================================
|
||
#define _use_my_sqrt_
|
||
#ifdef _use_my_sqrt_
|
||
unsigned long my_sqrt();
|
||
#endif
|
||
|
||
|
||
|
||
/*=========================================================
|
||
歩数計
|
||
========================================================*/
|
||
void pedometer()
|
||
{
|
||
static s16 th_H = 15000; // 閾値。動的変更します
|
||
static s16 th_L = 11000;
|
||
static u16 acc_norm[3]; // 加速度の大きさのヒストリ。数字が大きい方が古い
|
||
static u16 acc_norm_temp;
|
||
static u8 interval_hh = 0xFF; // 山-山間の時間。短過ぎたらはじく。
|
||
static u8 time_l; // 前回の極小からの経過時間
|
||
static u16 peak_l; // 谷の深さ
|
||
static u16 norm_hist[TAP];
|
||
|
||
static u8 hist_indx;
|
||
|
||
signed long filterd;
|
||
|
||
u8 i;
|
||
|
||
u16 sx16 = abs( (u16)vreg_ctr[VREG_C_ACC_XH] * 256 + vreg_ctr[VREG_C_ACC_XL] );
|
||
u16 sy16 = abs( (u16)vreg_ctr[VREG_C_ACC_YH] * 256 + vreg_ctr[VREG_C_ACC_YL] );
|
||
u16 sz16 = abs( (u16)vreg_ctr[VREG_C_ACC_ZH] * 256 + vreg_ctr[VREG_C_ACC_ZL] );
|
||
|
||
// ベクトルのノルム
|
||
#ifdef _mcu_
|
||
# ifndef _use_my_sqrt_
|
||
norm_hist[ hist_indx & TAP-1 ] = sqrt( (long)sx16 * ( sx16 / 2 ) +
|
||
(long)sy16 * ( sy16 / 2 ) +
|
||
(long)sz16 * ( sz16 / 2 )
|
||
);
|
||
# else
|
||
norm_hist[ hist_indx & TAP-1 ] = my_sqrt( (long)sx16 * ( sx16 / 2 ) +
|
||
(long)sy16 * ( sy16 / 2 ) +
|
||
(long)sz16 * ( sz16 / 2 )
|
||
);
|
||
# endif
|
||
#endif
|
||
|
||
#ifdef _pc_
|
||
norm_hist[ hist_indx & TAP-1 ] = normh * 256 + norml;
|
||
#endif
|
||
|
||
hist_indx += 1;
|
||
|
||
// ヒストリにフィルタを掛けて、今回の値を求める
|
||
filterd = 0;
|
||
// for( i = 8; i != 55; i++ ) // 係数が0ばかりのため
|
||
for( i = 0; i != 46; i++ ) // 係数テーブルをいじりました。パラメータ調整時注意
|
||
{
|
||
filterd += (signed long)norm_hist[ ( hist_indx + i ) & TAP-1 ] * lpf_coeff[ i ];
|
||
}
|
||
|
||
filterd += (4096)*512;
|
||
acc_norm_temp = (s16)( filterd /1024 & 0xFFFF ); // ←FIL_COEFF_QUANTから正規化
|
||
/*
|
||
if( acc_norm[0] < acc_norm_temp )
|
||
{
|
||
t_rise += 1;
|
||
if( t_rise == 0 )
|
||
t_rise == 254;
|
||
}
|
||
else
|
||
{
|
||
t_rise = 0;
|
||
}
|
||
*/
|
||
if( acc_norm[0] != acc_norm_temp )
|
||
{
|
||
acc_norm[2] = acc_norm[1]; // ヒストリ
|
||
acc_norm[1] = acc_norm[0];
|
||
acc_norm[0] = acc_norm_temp;
|
||
}
|
||
|
||
if( acc_norm[2] <= acc_norm[1] && acc_norm[1] > acc_norm[0]
|
||
&& acc_norm[0] > th_H )
|
||
// 極大で、閾値を超えていた
|
||
{
|
||
if( 21 < interval_hh )
|
||
// 前回の極大からの間隔がほどよい
|
||
{
|
||
if(( interval_hh < 160 ) && ( time_l < interval_hh ))
|
||
// 谷を挟んでいる
|
||
{
|
||
if( acc_norm[0] - peak_l > 4200 ){
|
||
// ■一歩増えました
|
||
hosu_increment();
|
||
}
|
||
}
|
||
interval_hh = 0;
|
||
}
|
||
if( acc_norm[0] > 18000 )
|
||
{
|
||
th_L = acc_norm[0] - 10000;
|
||
}
|
||
else
|
||
{
|
||
th_L = 11000;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
interval_hh += ( interval_hh != 255 ) ? 1: 0; // 飽和加算って楽に書けたらいいのに
|
||
}
|
||
|
||
// (2) 直近の極小からの時間
|
||
if( acc_norm[2] >= acc_norm[1] && acc_norm[1] < acc_norm[0]
|
||
&& acc_norm[0] < th_L )
|
||
{
|
||
// 極小を検出
|
||
time_l = 0;
|
||
peak_l = acc_norm[0];
|
||
}
|
||
else
|
||
{
|
||
time_l += ( time_l != 255 ) ? 1: 0;
|
||
}
|
||
|
||
#ifdef _DBG_PEDO_AUTO_ENABLE_
|
||
{
|
||
static u8 i = 0;
|
||
|
||
vreg_ctr[ 0x50 ] = i++;
|
||
|
||
vreg_ctr[ 0x51 ] = (u8)( acc_norm[0] / 256 & 0x00FF );
|
||
vreg_ctr[ 0x52 ] = (u8)( acc_norm[0] & 0x00FF );
|
||
|
||
vreg_ctr[ 0x53 ] = (u8)( norm_hist[ hist_indx -1 & TAP-1 ] / 256 & 0xFF );
|
||
vreg_ctr[ 0x54 ] = (u8)( norm_hist[ hist_indx -1 & TAP-1 ] & 0xFF );
|
||
|
||
vreg_ctr[ 0x55 ] = interval_hh;
|
||
vreg_ctr[ 0x56 ] = time_l;
|
||
|
||
vreg_ctr[ 0x57 ] = vreg_ctr[ VREG_C_ACC_HOSU_L ];
|
||
vreg_ctr[ 0x58 ] = (u8)( peak_l / 256 & 0x00FF );
|
||
vreg_ctr[ 0x59 ] = (u8)( peak_l & 0x00FF );
|
||
// vreg_ctr[ 0x5A ] = (u8)( norm_avg[0] / 256 & 0x00FF );
|
||
// vreg_ctr[ 0x5B ] = (u8)( norm_avg[0] & 0x00FF );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
/*=========================================================
|
||
歩数+1
|
||
累積をインクリメント
|
||
履歴を更新
|
||
*2011/01/20
|
||
仕様変更 ログがいっぱいになったらそこで止める
|
||
========================================================*/
|
||
u8 p_record;
|
||
u8 log_year;
|
||
|
||
u8 pedo_log_latest[ 6 ];
|
||
enum {
|
||
LEDO_LOG_LATEST_HOUR,
|
||
LEDO_LOG_LATEST_DAY,
|
||
LEDO_LOG_LATEST_MONTH,
|
||
LEDO_LOG_LATEST_YEAR,
|
||
LEDO_LOG_LATEST_MIN,
|
||
LEDO_LOG_LATEST_SEC
|
||
};
|
||
|
||
/*
|
||
u8 last_hour; // 履歴の最新は何時?
|
||
u8 last_day;
|
||
u8 last_month;
|
||
u8 pedo_log_latest[ LEDO_LOG_LATEST_YEAR ];
|
||
u8 last_min;
|
||
u8 last_sec;
|
||
*/
|
||
|
||
#define HOSU_NODATA 0xFFFF
|
||
#define HOSU_MAX 0xFFFE
|
||
|
||
static void hosu_increment()
|
||
{
|
||
static u16 last_hour_fny; // from new year
|
||
|
||
// 空白の時間を考慮する。1時間以上放置されたなど。
|
||
u16 now_longhour;
|
||
u8 now_year;
|
||
|
||
u8 temp_year, temp_hour, temp_day, temp_month, temp_min, temp_sec, log_year_temp;
|
||
|
||
// 時計を止める必要が有るので↓は一気に行って下さい
|
||
DI();
|
||
RWAIT = 1;
|
||
while( !RWST ){;}
|
||
log_year_temp = temp_year = bcdtob( YEAR );
|
||
|
||
// 履歴読み出し時に使用。BCDのままでよい
|
||
temp_hour = HOUR;
|
||
temp_day = DAY;
|
||
temp_month = MONTH;
|
||
temp_min = MIN;
|
||
temp_sec = SEC;
|
||
now_longhour = get_long_hour();
|
||
|
||
// RWAIT = 0; ↑で行っています
|
||
// EI(); 〃
|
||
|
||
// 元旦零時台で昨日扱いになった場合の帳尻合わせ
|
||
if( now_longhour == 65535 )
|
||
{
|
||
now_longhour = ( ( 365 + (( temp_year & 0x03 ) == 1 ? 1: 0 )) * 24 ) -1; // 閏年を考慮
|
||
temp_year -= 1;
|
||
}
|
||
|
||
// 書き込みポインタの更新
|
||
if(( vreg_ctr[ VREG_C_ACC_HOSU_L ] | vreg_ctr[ VREG_C_ACC_HOSU_M ] | vreg_ctr[ VREG_C_ACC_HOSU_H ] ) != 0 )
|
||
{
|
||
// 歩数計が止まっていた時間を考慮して必要なら進める
|
||
if( pedo_log_latest[ LEDO_LOG_LATEST_YEAR ] == temp_year )
|
||
{
|
||
if( now_longhour > last_hour_fny )
|
||
{
|
||
fill_hosu_hist_hours( now_longhour - last_hour_fny );
|
||
}
|
||
}
|
||
else if( pedo_log_latest[ LEDO_LOG_LATEST_YEAR ] == ( temp_year -1 ) )
|
||
{
|
||
// 年をまたいでいるとき
|
||
fill_hosu_hist_hours( ( ( 365 + (( temp_year & 0x03 ) == 1 ? 1: 0 )) * 24 ) - last_hour_fny + now_longhour );
|
||
}
|
||
else if( pedo_log_latest[ LEDO_LOG_LATEST_YEAR ] < temp_year )
|
||
{
|
||
// 数年放置
|
||
fill_hosu_hist_hours( 0 );
|
||
}
|
||
else
|
||
{
|
||
// カレンダーが巻き戻るなど
|
||
// ノーケアでよい
|
||
}
|
||
|
||
// ログあふれで記録停止?
|
||
if( pedolog_overflow )
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
// インクリメントして良い
|
||
pedo_log_latest[ LEDO_LOG_LATEST_HOUR ] = temp_hour;
|
||
pedo_log_latest[ LEDO_LOG_LATEST_DAY ] = temp_day;
|
||
pedo_log_latest[ LEDO_LOG_LATEST_MONTH ] = temp_month;
|
||
pedo_log_latest[ LEDO_LOG_LATEST_YEAR ] = temp_year;
|
||
pedo_log_latest[ LEDO_LOG_LATEST_MIN ] = temp_min;
|
||
pedo_log_latest[ LEDO_LOG_LATEST_SEC ] = temp_sec;
|
||
|
||
last_hour_fny = now_longhour;
|
||
log_year = log_year_temp;
|
||
|
||
// 累積の更新 //
|
||
// いろいろ失敗した...
|
||
if( ++vreg_ctr[ VREG_C_ACC_HOSU_L ] == 0 )
|
||
{
|
||
if( ++vreg_ctr[ VREG_C_ACC_HOSU_M ] == 0 )
|
||
{
|
||
if( ++vreg_ctr[ VREG_C_ACC_HOSU_H ] == 0 ){
|
||
vreg_ctr[ VREG_C_ACC_HOSU_L ] = 255; // カンスト orz
|
||
vreg_ctr[ VREG_C_ACC_HOSU_M ] = 255;
|
||
vreg_ctr[ VREG_C_ACC_HOSU_H ] = 255;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 毎時ログインクリメント
|
||
if( pool.vreg_c_ext.pedo_log[ p_record ] == HOSU_NODATA )
|
||
{
|
||
pool.vreg_c_ext.pedo_log[ p_record ] = 1;
|
||
}
|
||
else if( pool.vreg_c_ext.pedo_log[ p_record ] != HOSU_MAX )
|
||
{
|
||
pool.vreg_c_ext.pedo_log[ p_record ] += 1;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/* ========================================================
|
||
空白の時間を適切に0にして、
|
||
今を含む1時間のデータを書く位置にポインタ?を進める
|
||
======================================================== */
|
||
void fill_hosu_hist_hours( u16 hours )
|
||
{
|
||
// ログ最大容量以上放置された?
|
||
if( hours > PEDOMETER_LOG_SIZE )
|
||
{
|
||
hours = PEDOMETER_LOG_SIZE;
|
||
}
|
||
|
||
if( p_record >= PEDOMETER_LOG_SIZE )
|
||
{
|
||
pedolog_overflow = true;
|
||
return;
|
||
}
|
||
|
||
if( p_record + hours >= PEDOMETER_LOG_SIZE )
|
||
{
|
||
pedolog_overflow = true;
|
||
return;
|
||
}
|
||
|
||
|
||
// 空白の数時間の設定
|
||
do
|
||
{
|
||
// 新仕様 いっぱいで停止
|
||
p_record += 1;
|
||
if( p_record >= PEDOMETER_LOG_SIZE )
|
||
{
|
||
pedolog_overflow = true;
|
||
NOP(); // ここに来るようだとバグ
|
||
break;
|
||
}else{
|
||
pool.vreg_c_ext.pedo_log[ p_record ] = 0;
|
||
}
|
||
hours -= 1;
|
||
}
|
||
while( hours != 0 );
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
/* ========================================================
|
||
空白の時間を適切に0にして、
|
||
今を含む1時間のデータを書く位置にポインタ?を進める
|
||
======================================================== */
|
||
void clear_hosu_hist()
|
||
{
|
||
u8 hours = PEDOMETER_LOG_SIZE;
|
||
do
|
||
{
|
||
hours -= 1;
|
||
pool.vreg_c_ext.pedo_log[ hours ] = 0xFFFF;
|
||
}
|
||
while( hours != 0 );
|
||
vreg_ctr[ VREG_C_ACC_HOSU_L ] = 0;
|
||
vreg_ctr[ VREG_C_ACC_HOSU_M ] = 0;
|
||
vreg_ctr[ VREG_C_ACC_HOSU_H ] = 0;
|
||
p_record = 0;
|
||
pedolog_overflow = false;
|
||
}
|
||
|
||
|
||
extern u8 iic_burst_state;
|
||
bit record_read_msb_lsb;
|
||
|
||
/* ========================================================
|
||
歩数計ヒストリ読み出しの後処理(初期化)
|
||
読み出しポインタのクリア
|
||
======================================================== */
|
||
void hosu_read_end( )
|
||
{
|
||
record_read_msb_lsb = 0;
|
||
}
|
||
|
||
|
||
/* ========================================================
|
||
歩数計のヒストリを返す。
|
||
1回呼ぶ度に、ヒストリの下位、上位、一時間遡って下位上位...
|
||
======================================================== */
|
||
u8 hosu_read( )
|
||
{
|
||
u8 rv;
|
||
static u8 p_record_buffer;
|
||
static u8 dat_temp[6]; // 一応、アトミック処理に
|
||
|
||
if( iic_burst_state == 0 )
|
||
{
|
||
p_record_buffer = p_record;
|
||
}
|
||
|
||
if( iic_burst_state <= 5 )
|
||
{
|
||
rv = pedo_log_latest[ iic_burst_state ];
|
||
if( iic_burst_state == LEDO_LOG_LATEST_YEAR ) // BCDに直さなきゃという失態
|
||
{
|
||
rv = btobcd( rv );
|
||
}
|
||
iic_burst_state += 1;
|
||
return( rv );
|
||
}
|
||
else
|
||
{
|
||
u16 temp;
|
||
// 16ビットで記録してあるのでばらして送る todo: もっと楽する方法があるんじゃ
|
||
temp = pool.vreg_c_ext.pedo_log[ p_record_buffer ];
|
||
if( record_read_msb_lsb == 0 )
|
||
{
|
||
rv = (u8)( temp & 0x00FF );
|
||
}
|
||
else
|
||
{
|
||
rv = (u8)(( temp >> 8 ) & 0x00FF );
|
||
if( p_record_buffer == 0 )
|
||
{
|
||
p_record_buffer = PEDOMETER_LOG_SIZE-1;
|
||
}
|
||
else
|
||
{
|
||
p_record_buffer -= 1;
|
||
}
|
||
}
|
||
record_read_msb_lsb ^= 1;
|
||
return( rv );
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/* ========================================================
|
||
今年の元旦からの経過時間(hour)を返す。
|
||
引数 無し
|
||
返値 u16 long_hour
|
||
======================================================== */
|
||
const u16 DAYS_FROM_HNY[] = {
|
||
0,
|
||
0, 31, 31+28, 59+31, 90+30,
|
||
120+31, 151+30, 181+31, 212+31, 243+30,
|
||
273+31, 304+30 };
|
||
|
||
u16 get_long_hour()
|
||
{
|
||
u16 long_hour;
|
||
u8 year_hex;
|
||
u8 month_hex;
|
||
u8 day_hex;
|
||
u8 hour_hex;
|
||
|
||
u8 min;
|
||
u8 sec;
|
||
|
||
// RWAIT = 1 を確認してから↓に進んで下さい
|
||
year_hex = YEAR;
|
||
month_hex = MONTH;
|
||
day_hex = DAY;
|
||
hour_hex = HOUR;
|
||
min = MIN;
|
||
sec = SEC;
|
||
|
||
RWAIT = 0;
|
||
EI();
|
||
|
||
year_hex = bcdtob( year_hex );
|
||
month_hex = bcdtob( month_hex );
|
||
day_hex = bcdtob( day_hex );
|
||
hour_hex = bcdtob( hour_hex );
|
||
|
||
// まず日数の部分
|
||
long_hour = DAYS_FROM_HNY[ month_hex ];
|
||
if(( ( year_hex & 0x03 ) == 0 ) && ( ( 3 <= month_hex )))
|
||
{
|
||
// 閏年で、閏日より後
|
||
long_hour += 1;
|
||
}
|
||
long_hour += day_hex - 1;
|
||
long_hour *= 24; // 日数→時間
|
||
|
||
long_hour += hour_hex;
|
||
|
||
if( ( min > vreg_ctr[ VREG_C_ACC_HOSU_HOUR_BOUNDARY ] )
|
||
|| ( ( min >= vreg_ctr[ VREG_C_ACC_HOSU_HOUR_BOUNDARY ] )
|
||
&& ( sec > vreg_ctr[ VREG_C_ACC_HOSU_HOUR_BOUNDARY_SEC ] ))
|
||
)
|
||
{
|
||
return( long_hour );
|
||
}
|
||
else
|
||
{
|
||
return( long_hour -1 ); // 1時間前に含める 注意:元旦の0時
|
||
}
|
||
}
|
||
|
||
|
||
unsigned long my_sqrt(unsigned long x)
|
||
{
|
||
unsigned long s, t;
|
||
|
||
if (x <= 0) return 0;
|
||
|
||
s = 1;
|
||
t = x;
|
||
while (s < t)
|
||
{
|
||
s <<= 1;
|
||
t >>= 1;
|
||
}
|
||
do
|
||
{
|
||
t = s;
|
||
s = (x / s + s) >> 1;
|
||
} while (s < t);
|
||
|
||
return t;
|
||
}
|