Aitendo 電波時計モジュール(40/60KHz)[MAS6181-DB] を使うためのプログラムです。 どちらかというと、JJY信号の学習用です。手軽に時間を扱いたい人は、デジタルで出力してくれるモジュールを探した方がよいと思います。
Information
このプログラムはJJYの信号や処理の参考になりますが、正確な時間や手軽に扱いたい人には不向きです。
概要
Aitendoの電波時計モジュール[MAS6181-DB]からの信号を受信して処理を行う方法の一つの例を示します。
JJYの信号はhttp://jjy.nict.go.jp/QandA/reference/Lfsymposium1.pdfの10ページを参考にしました。
1秒で一つの信号を送り60秒かけて時間情報を送信します。
信号は、マーカ、1、0の三種類です。
マーカは0.2s ON 0.8s OFF
1は0.5s ON 0.5s OFF
0は0.8s ON 0.2s OFF
です。
ハードウエアの設定
電波時計モジュールは、1.1-3.6Vで動作します。mbedの出力電圧3.3Vで動作するので、そのまま接続することもできます。
出力は、信号を受信していない場合はLow
信号を受信している場合はLow
信号を受信していない場合はHigh
になっています。
なお、JJY受信モジュールの出力インピーダンスが高いので、mbedとは直接接続できませんでした。接続した状態でオシロスコープを見るとほとんど0Vの状態です。
したがって、オペアンプやトランジスタなどのバッファを仲介する必要があります。
今回は下記の回路で実行しています。この回路だと、信号が反転するので、ちょうど信号を受信しているときは1、していないときは0になりました。
信号が受信できると以下のような信号を得られます。
Warning
受信モジュールはノイズに弱いみたいなので、信号の弱い場所では電池での駆動がよいです。PCからmbed経由での電源供給でも、PCにACアダプタを挿すと受信できなくなることがありました。
プログラムの説明
RTOSを利用してデータの受信は別スレッドで10ms毎に動くようにしています。つまり、1信号(1秒)あたり100回の信号を取っています。
リングバッファrcvにデータを保存します。
この辺りは、電波の強弱やMPUの能力で最適値に変更すると良いと思います、
なお、受信スレッドには、timingの位置でメッセージキューにデータを置き、メインスレッドにタイミングを伝えています。
プログラムは2段階で動作するようにしています。
1.同期ポイントを探る
2.信号から時間を得る
同期ポイントは20秒受信します。受信しながらバッファの総和を求めます。
データは10回に1回以上がマーカなので、
0.0-0.2sがONになるのは100%(マーカ+0+1)
0.2-0.5sがOnになるのは 90%以下(0+1)
0.5-0.8sがOnになるのは ?%(0)
0.8-1.0sは100%でOFFになるはずです。
したがって、度数分布を作成し、受信した信号が90%より上(今回は20回受信するので19回以上受信した点)がマーカの信号の位置になります。
処理が終了後、変数timingに値を書き、メインスレッドとの同期点を変更します。
後の処理は1秒受信してそのONの比率でマーカ、1、0の判別を行いますので、同期点がマーカの位置であれば時間の誤差(0.2秒以内)が生じますが、データ処理には問題が生じません。
信号から時間を得る部分は、ステートマシンで表しています。
state=0でマーカが2回続く同期点(0秒になる点)を待ちます。
あとは1信号ごとに処理しています。信号が0もしくは1になる個所はデータをチェックし、マーカや不明が来たらstate=0にしマーカ待ちに戻します。
実行
LED0は受信状況を表します。
LED1は”マーカ”を受信
LED2は”1”を受信
LED3は”0”を受信
信号不明時はLED1,2,3を同時点灯
になります。
main.cpp
- Committer:
- yueee_yt
- Date:
- 2013-04-24
- Revision:
- 1:d9553f32e949
- Parent:
- 0:f111c5224cd0
File content as of revision 1:d9553f32e949:
#include "mbed.h"
#include "rtos.h"
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
Queue<uint32_t, 5> queue;
DigitalIn jjy(p20);
Serial pc(USBTX, USBRX);
char rcv[100];
char timing=0;
void jjy_rcv(void const *n)
{
static int count=0;
if(jjy) {
rcv[count]=1;
} else {
rcv[count]=0;
}
led1=rcv[count];
if(count==timing) {
queue.put((uint32_t*)1);
//printf("thread out timing=%d \n\r",timing);
}
// pc.printf("%d %d \n\r",count,rcv[count]);
if(count==99)
count=0;
else
count++;
}
int main()
{
unsigned char state=0;
unsigned char sig,old_sig;
unsigned char count1=0;
bool flag1,flag2;
char m,h;
char mm[3];
int i,j;
char sum_rcv[100];
pc.baud(115200);
flag1=true;
flag2=true;
old_sig=9;
m=0;h=0;
for(i=0; i<100; i++)sum_rcv[i]=0;
RtosTimer jjy_rcv_timer(jjy_rcv, osTimerPeriodic,(void *)0);
jjy_rcv_timer.start(10); //10mS
printf("*********************stage1 (Sync)*********************\n\r");
while (flag1) {
osEvent evt = queue.get();
if (evt.status == osEventMessage) {
printf("%d thread out timing=%d \n\r",count1,timing);
for(i=0; i<100; i++)sum_rcv[i]+=rcv[i];
if(count1==20) {
for(i=1; i<100; i++) {
if(sum_rcv[i]>18) {
timing=i-1;
flag1=false;
break;
}
}
if(flag1==true) {
count1=0;
for(i=0; i<100; i++)sum_rcv[i]=0;
}
} else {
count1++;
}
}
}
//for(i=0; i<100; i++)printf("%d %d \n\r",i,sum_rcv[i]);
printf("*********************stage1 end*****************************\n\r");
printf("timing= %d\n\r",timing);
osEvent evt = queue.get();
printf("*********************stage2 time setting********************\n\r");
state=0;
while (flag2) {
osEvent evt = queue.get();
if (evt.status == osEventMessage) {
j=0;
for(i=0; i<100; i++)j+=rcv[i];
if(j<30) {
sig=2;
strcpy(mm,"M");
led2=1;
led3=0;
led4=0;
} else {
if(j<65) {
sig=1;
strcpy(mm,"1");
led2=0;
led3=1;
led4=0;
} else {
if(j<90) {
sig=0;
strcpy(mm,"0");
led2=0;
led3=0;
led4=1;
} else {
sig=9;
strcpy(mm,"?");
led2=1;
led3=1;
led4=1;
}
}
}
printf("Signal %d %s\n\r",j,mm);
switch(state) {
case 0:
if((old_sig==2)&&(sig==2)) {
state=1;
}
break;
case 1:
if((sig==0)||(sig==1)) {
m=40*sig;
state=2;
} else {
state=0;
}
break;
case 2:
if((sig==0)||(sig==1)) {
m+=20*sig;
state=3;
} else {
state=0;
}
break;
case 3:
if((sig==0)||(sig==1)) {
m+=10*sig;
state=4;
} else {
state=0;
}
break;
case 4:
if((sig==0)||(sig==1)) {
state=5;
} else {
state=0;
}
break;
case 5:
if((sig==0)||(sig==1)) {
m+=8*sig;
state=6;
} else {
state=0;
}
break;
case 6:
if((sig==0)||(sig==1)) {
m+=4*sig;
state=7;
} else {
state=0;
}
break;
case 7:
if((sig==0)||(sig==1)) {
m+=2*sig;
state=8;
} else {
state=0;
}
break;
case 8:
if((sig==0)||(sig==1)) {
m+=sig;
state=9;
} else {
state=0;
}
break;
case 9:
state=10;
break;
case 10:
if((sig==0)||(sig==1)) {
state=11;
} else {
state=0;
}
break;
case 11:
if((sig==0)||(sig==1)) {
state=12;
} else {
state=0;
}
break;
case 12:
if((sig==0)||(sig==1)) {
h=20*sig;
state=13;
} else {
state=0;
}
break;
case 13:
if((sig==0)||(sig==1)) {
h+=10*sig;
state=14;
} else {
state=0;
}
break;
case 14:
if((sig==0)||(sig==1)) {
state=15;
} else {
state=0;
}
break;
case 15:
if((sig==0)||(sig==1)) {
h+=8*sig;
state=16;
} else {
state=0;
}
break;
case 16:
if((sig==0)||(sig==1)) {
h+=4*sig;
state=17;
} else {
state=0;
}
break;
case 17:
if((sig==0)||(sig==1)) {
h+=2*sig;
state=18;
} else {
state=0;
}
break;
case 18:
if((sig==0)||(sig==1)) {
h+=sig;
state=19;
} else {
state=0;
}
break;
case 19:
flag2=0;
state=0;
break;
}
printf("%d %02d:%02d \n\r",state,h,m);
old_sig=sig;
}
}
jjy_rcv_timer.stop();
printf("Now = %02d:%02d:20 \n\r",h,m);
}