PIC24F

 GPS Data Logger - 2nd Project

IMAGE11.GIF - 980BYTES  概要
IMAGE11.GIF - 980BYTES   ハードウェア
IMAGE11.GIF - 980BYTES  ソフトウェア 
IMAGE11.GIF - 980BYTES  ソフトウェアソースコード
IMAGE11.GIF - 980BYTES  参考文献
IMAGE12.GIF - 2,801BYTES

変更履歴
2010年1月16日 新規作成
2010年1月17日 写真追加
2010年1月24日 コメント追加
2010年2月7日 コメント追加 ソフトウェア電圧低下検出

データロガー外観


上面には、紙のパネルを内側から

こんなに満杯にするつもりはなかったが

データロガーの組立工程


アクリルボックスは
東急ハンズにて入手

ウレタンのマットも
東急ハンズ

穴あけは注意して
ピンジャックは電源SW

LCDはアクリルに入れて
いるだけで固定せず

アクリル板(黄色)で
基板をサポート

黄色のアクリルは右下で
スイッチの為に切欠き

アクリル板で仕切り
ケースには止めない

eneloop単三
4個予定

端子に直接
ハンダ付け

グランドプレーンは
最終的には削除

GPSとPIC24USBの
位置関係

電線はオヤイデで
BX-S0.08sqを購入

Gセンサーは
GPSの裏

下部に温度センサと
シャントレギュレータ

ほぼ配線終了
PICには32KHzのクリスタル付加

microSD Adaptorは
ハンダ直付け

全てを入れたところ

配線が太く
ほぼ満杯状態

スイッチ周り

GPS→アクリル→Gセンサ

USBの穴は未だ

赤い電線が集まった
下が3.3V電源

USBコネクタは
アクリルの穴経由で
デバック時は
左のような状態で










Data Logger ----- 概要
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

<2ndの位置付け>















Data Logger ----- ハードウェア
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES


先のデータロガーからの主な変更点は、下記の点です。

SD Memory
PIC24USB CARD
CN2 13 RD4/RP25 CS 1 SD_CS
CN2 14 RD3/RP22 SD0 2 SD_D1
CN2 1 GND GND 3 Vss
CN1 3 +3.3V Vdd 4 Vdd
CN2 15 RD2/RP23 SCK 5 SD_SCLK
CN2 1 GND GND 6 Vss
CN2 12 RD5/RP20 SDI 7 SD_D0
N/A 8
N/A 9
CN2 10 RD7 CD GND
CN2 11 RD6 WE GND

GPS
PIC24USB GM-318
CN1 1 GND 1 GND
CN1 3 +3.3.V 2 +3.3V
CN1 17 RB6/RP6/AN6/RX1 3 TX
CN1 18 RB7/RP7/AN7/TX1 4 RX
CN1 5 RE7 5 PWR_CTRL.

気付いたこと
GPS内には、ボタン電池が内蔵されており電圧を測定したところ、0.7V以下になっていたので品番を確認するため外して見た。
品番からWeb検索したところ、下記と思われる(ボタン電池には品番全桁が書かれていないので断定できないが、サイズは一致)。

セイコーインスツル株式会社 MS621FE

カタログによれば、MS(マンガン・シリコン)リチウム二次電池で使い捨ての一次電池ではないことがわかり、再度ハンダ付けして利用再開した。その後、確かに端子電圧は上昇して、ちゃんと動作している模様です。
端子電圧が低いからと言って、決して交換しないように。
その後、GM-318のカタログをよく読むと、
Please note that the backup battery is already included in GM-318. You saved the space, charging circuit and related materials.
とありました。充電回路を用意しなくてよいと書いてあり、二次電池搭載を意識して書かれているのでしょうが、その他のページを含め明示的には書かれていないように思えます。
明示的に書かなくてもGPSのバックアップは、二次電池か電気二重層キャパシタと業界では決まっているのでしょうか?


グランドプレーンの廃止

当初、作り始めはGPSの周りに銅板を使用したグランドプレーンを配置したが、結果は最悪で衛星捕捉が実験中には一度も成功しなかった。
理由は、不明だがGNDの取り方を含めてノイズを拾う効果しかなかったように思える。
現在、グランドプレーンなしでの衛星捕捉のスピードは今までの中で、GM-318が一番よさそうである。














Data Logger ----- ソフトウェア
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

先のデータロガーに対して、下記のような修正を実施。

1)GPS関連
(1)初期化と速度
測地系のディフォルト値が、GM-318はWGS-84で特にコマンドを送って初期設定せずに使える。通信速度は、4800BPSのままとした。

(2)データフォーマット
同じNMEA-0183フォーマットと言っても出力に若干の差があり、それに対応した。下記の例は、受信状態が悪く、充分な情報が衛星から得られていない時の出力の差である。
52Dは、それでもイニシャル値を返してくるが、318は何も返してこない。52Dのフォーマットから必要なデータを抜き出す際に、コンマの数だけで且つ何もないことを考慮するプログラムに修正した。

GPS-52D $GPGGA,001406.948,3600.0000,N,13600.0000,E,0,00,99.9,00000.0,M,0000.0,M,000.0,0000*4D
$GPGSA,A,1,,,,,,,,,,,,,99.9,99.9,99.9*09
$GPRMC,001406.948,V,3600.0000,N,13600.0000,E,9999.99,999.99,200909,,*28
$GPVTG,999.99,T,,M,9999.99,N,9999.99,K*59
GM-318 $GPGGA,000125.034,,,,,0,00,,,M,0.0,M,,0000*57
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000125.034,V,,,,,,,291006,,,N*40
$GPVTG,,T,,M,,N,,K,N*2C

(3)緯度経度の表示
先のデータロガーのバグ発見。
LCDへの表示が、あたかも度分秒(秒は少数点以下含む)のようになっていたが、GPSが52Dでも318でも度分(分が小数点以下含む)のデータフォーマットであり、分を秒に変える必要があったにも関わらず何もしていなかった。分の小数点以下をASCIIから数値に変換の上、60をかけて秒換算後にLCD表示のために再度ASCII変換した。但し、SDカードへのデータは生データのままで未加工とした。

(4)時間表示の高速化
先のデータロガーでは、GPSが衛星捕捉が2D以上になってからJSTを修正し、これをRTCCへ送ってファイルのタイムスタンプにしていました。初期値を2009年9月9日9時9分9秒にしたため、電源ON直後からSDカードへの記録を開始すると、ファイルのタイムスタンプがその初期データに近いものが多く生まれてしまいました。
今回は、GM-318のバックアップ電源がしっかりしているため衛星捕捉前に現時刻に近い時間を返してきます。私が購入したものは、バックアップが上手く行ってない場合には、2006年10月のタイムスタンプをGPSが返すので、2010年以降の年度を返して来た時はGPSの時刻を信ずることにしました。これで、かなり早い時間にRTCCの時間設定ができます。
但し、このバックアップの時間がどのくらい正確なのかは不明です。
また、途中で正確な数値がGPSから受信出来ても、LCD表示される時刻やタイムスタンプに使う時刻はRTCCの数値を使い、現在のソフトウェアでは再更新していませんので、この点も将来の改良点でしょう。

2)ADCデータ処理
先のデータロガーでの手抜き部分の改善。
25mS毎にADCデータを取り込み、それを4回分で平均(100mS)する処理をしていたが、
@GPSの一秒間隔に意図的な同期をさせていない点、
A25mS毎の処理は4回後に正規化などの処理速度が遅くなる部分があり、正確に25mSのDelayを置くと1秒間に10回(100mS毎処理)のSDカード出力が9回になったりしていた。
そこで、3つの対策を実施。

(1)GPS受信との同期
GPSが折角、1秒間を正確に判断してメッセージを出しているのに、ADCがそれに同期していなかったので$GPGAAパケット受信時にQueueを送って、ADCを同期させました。
本来は、パケットの最初の$に同期させるのがベストだと思いますが、割込み内の処理が煩雑化するので今回はTASK#4で判断しています。
GPSによっては、1秒ごとのパルス信号を正確に送出する機能を持っている製品があるので、その信号で同期させるのが一番正確です。
次回(いつになるかは不明)は、更に低消費電力のGPSとしてGM-316を使いたいですが、これなら1PPS信号が取り出せます(残念ながらバックアップ電源は外付けしないといけない様子)。
ソースコードとしては、緑部分が関係しています。

(2)sprintf関数の簡易版実装
FreeRTOSのパッケージ内にデモ用ソースコードがあり、そこで"printf-stdarg.c"が使われている。例えば、バージョンV.6.0.12では、
..\FreeRTOSV6.0.1\Demo\PIC32MX_MPLAB
の中に、ファイルが見つかります。sprintfに関しては、上記ファイルを使用すると改善効果が見られます(速度実測は未実施だが変更前にはsprintfでmS単位の処理時間を費やしていた模様)。
これは、下記ソースファイル内の赤字部分に有効です。

(3)vTaskDelayUnit関数の利用
今までは、vTaskDelay関数を使っていましたが、上記関数に変更しました。FreeRTOSのWebで2つの関数の違いを説明しています
簡単に言ってしまえば、vTaskDelayは自タスクの休止時間を規定しますが、vTaskDelayUnitは先の起動時期からの時間を規定することになります。
下記の図で違いがわかると思います。タスクの処理時間に変動があっても起動周期を一定に出来ます。

下記ソースファイルで、青字が関係する部分です。

ソースファイル

/***** TASK #2 ******/
// ADC Data Control
void vTask2(void *pvParameters) {
              portTickType xLastCheckTime;
              portTickType xDelayTime;
              static char Buf[8];
              int i;

              mADC_MODULE_ON();
              EnableADC1;
#if defined(GSEN_I2C)
              i2c1_Gsensor_initialize();                                           // Use MMA7455L Three axis G-sensor
#endif /*  GSEN_I2C  */             
              vTaskDelay(  500 / portTICK_RATE_MS );// Wait 0.5sec     
              EnableIntADC1;
              mADC_ISR_ENB();
              xDelayTime = 25 / portTICK_RATE_MS;
              xLastCheckTime = xTaskGetTickCount();   // Need to initialise time prior to the first call to vTaskDelayUntil()
              while(1){
                            xQueueReceive(adctrgrQueue, Buf, portMAX_DELAY);
                            for ( i = 0; i < 10; i++ ){                                
                                         
mADC_START();                                           // Start Convertion

                                          vTaskDelayUntil( &xLastCheckTime, xDelayTime );
                                          adc_save( i * 4 + 0 );                                     // see adc_func.c
                                          mADC_START();                                           // Start Convertion
                                          vTaskDelayUntil( &xLastCheckTime, xDelayTime );
                                          adc_save( i * 4 + 1 );                                     // see adc_func.c
                                          mADC_START();                                           // Start Convertion
                                          vTaskDelayUntil( &xLastCheckTime, xDelayTime );
                                          adc_save( i * 4 + 2 );;                                    // see adc_func.c
                                          mADC_START();                                           // Start Convertion
                                          vTaskDelayUntil( &xLastCheckTime, xDelayTime );
                                          adc_save( i * 4 + 3 );
                                          adc_data_processing( i * 4);                         // see adc_func.c
                                          adc_g_sensor_processing();                                                                                 
                                          sprintf( MsgBuf_ADC, "$ADC, %4d, %4d, %4d,%4d, %4d, %4d,*00\r\n",
                                          adc_DG_X, adc_DG_Y, adc_DG_Z, lng_adc_TEMP_old, lng_adc_VBAT_old, lng_adc_REF_old);

                                          msg_count_ADC = strlen(MsgBuf_ADC);  
                                          if (File_state == SD_FILE_WR){
                                                        xQueueSendToBack(sdcardQueue, "ADC", portMAX_DELAY);
                                          }
                            }
                            long_ave_batt();
                            adc_to_physical_value(); 
              }
}

3)電圧低下検出とファイル操作
使用中に下記のような電源電圧低下をログ出来ました(クリックで拡大可)。


今まで、電源低下でシステムが停止した際のファイル喪失防止に、一時間毎にファイル更新をすることで対応していました。しかし、上記データが取れたことで、下記の動作を追加することにしました。
@電源電圧低下の時間推移がある閾値に達した際に、1時間毎の更新でなくその時点でファイルをクローズする。
A設定電圧以下になった場合には、2分毎にファイルのクローズ/オープンを繰り返し、システム停止までなるべく多くのデータ記録を実施する。

この機能は、下記のようにタスクに実装しました(上記説明文の色と下記ソースファイルの色が対応しています)。
TASK1は1秒ごとに起動され、他にGPSからの時刻情報に基づきRTCC(Real-Time Clock & Calender)に時刻設定します(一回限り)。
実際の判定値は、下記のように設定しています。
20秒間の電圧変化が0.15Vを越えた場合には、その時点で一度ファイルをクローズして、再度ファイルをオープンする(delta_batt >= QUICK_DROP)。
また、電源電圧が2.3V以下に低下した後は、2分毎のファイルのクローズ/オープンを繰り返す(ad_batt <= BAT_END)。

/***** TASK #1 ******/
// General and Other functions
void vTask1(void *pvParameters) {
              int tim;
              int count;
              int bad_cnt;
              int low_bat_cnt;
              int delta_batt;
              int batt_20sec;
              int batt_10sec;
                           
              tim=0;
              vTaskDelay(  100 / portTICK_RATE_MS );                                    // Wait 0.1sec
              while(1){
                            vTaskDelay(  1000 / portTICK_RATE_MS );                    // Wait 1sec          
                            xQueueSendToBack(lcdQueue, "1SEC", portMAX_DELAY);         
                            if ( Time_ADJ_not_yet == TRUE ){      // Only twice to set the time
                                          if ( Time_is_okay == TRUE ){
                                                        if ( set_time()){
                                                                      Time_ADJ_not_yet = FALSE;
                                                        }
                                          } 
                            }
                            if ( File_state == SD_FILE_WR ){             // Data save termination every 1 hour
                                          if (tim == 0 ){
                                                        tim = TIM1HR;
                                          } else {
                                                        if ( --tim == 0 ){                                                // Termination command
                                                                    xQueueSendToBack(sdcardQueue, "HOUR", portMAX_DELAY);
                                                        }            
                                          }
                                          if ( ++count == 10 ){                                                      // Check every 10sec
                                                        count = 0;
                                                        batt_20sec = batt_10sec;
                                                        delta_batt = batt_20sec - (int)ad_batt;
                                                        batt_10sec = ad_batt;
                                                        if ( delta_batt >= QUICK_DROP ){
                                                                      bad_cnt++;
                                                                      if ( bad_cnt >= 2 ){
                                                                                   xQueueSendToBack(sdcardQueue,"HOUR", portMAX_DELAY);
                                                                      }            
                                                        } else {
                                                                      bad_cnt = 0;

                                                        }
                                                        if ( ad_batt <= BAT_END ){
                                                                      if ( ++low_bat_cnt >= 12 ){   // File close, every 2 minitus
                                                                                   
xQueueSendToBack(sdcardQueue, "HOUR", portMAX_DELAY);
                                                                                    low_bat_cnt = 0;
                                                                      }
                                                        } else {
                                                                      low_bat_cnt = 0;
                                                        } 

                                          }

                            } else {
                                          count = 0;
                                          batt_20sec = batt_10sec;

                                          batt_10sec = ad_batt;
                            }                                                                    
              }

}








Data Logger -----  ソフトウェアソースコード
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES


ソースファイル一式を用意出来ます。
必要な方はお手数ですが、メールにてお知らせください。
kenjia の後に@sannet.ne.jp
です。

下記をベースとしています。
FreeRTOS  V.6.0.1
Microchip MDD File System, USB  v2009-11-18






















Data Logger -----  参考文献
IMAGE12.GIF - 2,801BYTES
TOP02_001.PNG - 934BYTES

GPS-GM318関連
aitendo
http://www.aitendo.co.jp/
http://www.aitendo.co.jp/product/1007











































download.html