单频电波钟接收模块解析中国码(BPC码) (下)-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4726|回复: 13

单频电波钟接收模块解析中国码(BPC码) (下)

[复制链接]
发表于 2021-7-13 22:35 | 显示全部楼层 |阅读模式
本帖最后由 topdog 于 2021-7-16 00:20 编辑

上篇小伙伴们已经看到了神奇的电波,本篇的任务就是解析出时间和日期,用sd卡来记录下来,如有需要还可以对RTC模块如ds1307进行校时。
1,解析出时间和日期
(1),本例使用的是美科科技的core+在模块上标示为 D2(interrupt0),D3(interrupt1),D6(interrupt2),有三个中断。Arduino 官方建议使用attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);  也可以简化写成attachInterrupt(interrupt, ISR, mode) 缺省值interrupt可以直接写中断编号2。ISR: 中断处理函数。此函数不带参数,没有返回值。CHANGE:管脚状态改变触发。
(2),解析围绕着BPC码的结构展开,从波形图中看出每一段20秒的定时波开始的提示波总波长是1800ms至2100ms,接下来每一秒的波长900ms至1000ms,其中高电平持续时间表示一个四进制数值,即100ms至200ms表示0,200ms至300ms表示1,300ms至400ms表示2,400ms至500ms表示3。
(3),一次采集成功的一分钟三阶段代码如下,其中Cycle是总波长,Pulse是高电平持续时间。把高电平表示的涵义连接起来形成string Buff ,再使用字符串函数进行解析很有Arduino 特色。如果出现波长小于900ms就说明有杂波串入,那么就需要从新的提示波开始重新计算。
(4),第0栈表示秒,如果其是0就表示1秒,1就表示21秒,2就表示41秒,只有三段所以此栈的值不会出现3。其他的栈也只会出现0、1、2、3,否者不会触发解析动作。
(5),第9栈表示第0栈至第8栈的校验,前半部标识上午和下午,后半部表示偶校验。譬如:第9栈的值是1,二进制就是01,二进制前半部是0,就表示上午。所谓偶校验就是原始码流加校验位 总共有偶数个1,譬如:002213302(2),二进制就是000010100111110010(10),第0栈至第8栈加起来就是8个1,8是偶数,括号里是校验位第9栈,其中后半部标识偶校验,0就表示传输正确,校验pass。第18栈表示第10栈至第17栈的校验,后半部表示偶校验。
(6),四进制的计算,譬如第15栈至第17栈表示年份,值是111,就是1x16+1x4+1=21,起算年份是2000年,2000+21 = 2021。
(7),叠加一个sd卡模块 就是可以实现无人值守的无线信号记录仪。
2,程序代码开源如下:
[pre]
//https://github.com/greiman/SdFat
#include <SPI.h>
#include "SdFat.h"

SdFat SD;
File myFile;

const int  BPCPIN = 6;
const int  BPC_EN_PIN = 5;
const int SD_CS_PIN = 7;
const int BPC_TOTAL_NUM = 19;

int  Cycle = 0;
int  Pulse = 0;
int flankUp = 0;
int flankDown = 0;
int PreviousflankUp = 0;
bool Up = false;
bool flag1 = false;
int i = 0;
char data;
String Buff = "";

void BPC_EN() {
  pinMode(BPC_EN_PIN , OUTPUT);
  digitalWrite(BPC_EN_PIN, HIGH);
  delay(50);
  digitalWrite(BPC_EN_PIN, LOW);
}

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  pinMode(BPCPIN, INPUT);
  BPC_EN();

  if (!SD.begin(SD_CS_PIN)) {
    return;
  }
}

void loop() {
  int sensorValue = digitalRead(BPCPIN);
  delay(10);

  if (sensorValue == HIGH) {
    if (!Up) {
      flankUp = millis();
      Up = true;
    }
  } else {
    if (Up) {
      flankDown = millis();
      Cycle = flankUp - PreviousflankUp;
      Pulse = flankDown - flankUp;
      PreviousflankUp = flankUp;
      Up = false;
      Serial.print("Cycle: ");
      Serial.print(Cycle);
      Serial.print("     ");
      Serial.print(" Pulse :");
      Serial.println(Pulse);

      if (Cycle < 900) {
        i = 0;
        Buff = " ";
        bool flag1 = false;
      }

      if (Cycle > 1800 && Cycle < 2200) {
        flag1 = true;
      }

      if (flag1 == true) {
        if ((Pulse  > 100) && (Pulse  < 200)) data = '0';
        else if ((Pulse  > 200) && (Pulse  < 300)) data = '1';
        else if ((Pulse  > 300) && (Pulse  < 400)) data = '2';
        else if ((Pulse  > 400) && (Pulse  < 500)) data = '3';
        Buff += data;
        i++;
      }

      if (i == BPC_TOTAL_NUM) {

        if (BPC_ZREO_ChECK(Buff) && BPC_First_Check(Buff) && BPC_Second_Check(Buff)) {
          BPC_Parsing(Buff);
        }

        // BPC_Parsing(Buff);
        flag1 = false;
        bool Up = false;

        Buff = "";
        i = 0;
      }

    }
  }
}

bool BPC_ZREO_ChECK(String _Buff) {
  if (( _Buff.charAt(0) == '0') || ( _Buff.charAt(0) == '1') || ( _Buff.charAt(0) == '2') ) {
    return true;
  } else {
    return false;
  }
}

bool BPC_First_Check(String _Buff) {
  int c ;
  int d = 0;

  for (c = 0; c < 9; c++) {
    if ( _Buff.charAt(c) == '1' || _Buff.charAt(c) == '2')   d += 1;
    if ( _Buff.charAt(c) == '3')  d += 2;
  }

  if ((d % 2) == Even_Parity(_Buff.charAt(9))) {
    return true;
  }
  else {
    return false;
  }
}

bool BPC_Second_Check(String _Buff) {
  int  e ;
  int f = 0 ;

  for (e = 10 ; e < 18 ; e++) {
    if ( _Buff.charAt(e) == '1' || _Buff.charAt(e) == '2') f += 1;
    if ( _Buff.charAt(e) == '3') f += 2;
  }

  if ((f % 2) == Even_Parity(_Buff.charAt(18))) {
    return true;
  }
  else {
    return false;
  }
}

void BPC_Parsing(String _Buff) {
  int Second;
  if (_Buff.charAt(0) == '0')  Second = 1;
  if (_Buff.charAt(0) == '1')  Second = 21;
  if (_Buff.charAt(0) == '2')  Second = 41;

  int Hour = CharToInt(_Buff.charAt(2)) * 4 + CharToInt(_Buff.charAt(3)) + PM(_Buff.charAt(9)) * 12;
  int Minute = CharToInt(_Buff.charAt(4)) * 16 + CharToInt(_Buff.charAt(5)) * 4 + CharToInt(_Buff.charAt(6));
  int Week = CharToInt(_Buff.charAt(7)) * 4 + CharToInt(_Buff.charAt(8));

  int Day = CharToInt(_Buff.charAt(10)) * 16 + CharToInt(_Buff.charAt(11)) * 4 + CharToInt(_Buff.charAt(12));
  int Month = CharToInt(_Buff.charAt(13)) * 4 + CharToInt(_Buff.charAt(14));
  int Year = CharToInt(_Buff.charAt(15)) * 16 + CharToInt(_Buff.charAt(16)) * 4 + CharToInt(_Buff.charAt(17)) + 2000;

  Serial.println(" ");
  Serial.print("Buff:");
  Serial.println( _Buff);
  Serial.println(" ");
  Serial.print("Hour =");
  Serial.println(Hour);
  Serial.print("Minute =");
  Serial.println(Minute);
  Serial.print("Second =");
  Serial.println(Second);
  Serial.print("Week =");
  Serial.println(Week);
  Serial.print("Year =");
  Serial.println(Year);
  Serial.print("Month =");
  Serial.println(Month);
  Serial.print("Day =");
  Serial.println(Day);

  myFile = SD.open("BPC_Parsing.txt", FILE_WRITE);

  if (myFile) {
    Serial.print("Writing to BPC_Parsing.txt...");
    myFile.print("Hour =");
    myFile.print(Hour);
    myFile.print("  ");
    myFile.print("Minute =");
    myFile.print(Minute);
    myFile.print("  ");
    myFile.print("Second =");
    myFile.print(Second);
    myFile.print("  ");
    myFile.print("Week =");
    myFile.print(Week);
    myFile.print("  ");
    myFile.print("Year =");
    myFile.print(Year);
    myFile.print("  ");
    myFile.print("Month =");
    myFile.print(Month);
    myFile.print("  ");
    myFile.print("Day =");
    myFile.println(Day);
    myFile.close();
    Serial.println("done.");
  } else {
    Serial.println("error opening BPC_Parsing.txt");
  }
}

int CharToInt (char a) {
  if (a == '0') return 0;
  if (a == '1') return 1;
  if (a == '2') return 2;
  if (a == '3') return 3;
}

int PM(char k) {
  if (k == '0') return 0;
  if (k == '1') return 0;
  if (k == '2') return 1;
  if (k == '3') return 1;
}

int Even_Parity(char m) {
  if (m == '0') return 0;
  if (m == '1') return 1;
  if (m == '2') return 0;
  if (m == '3') return 1;
}[/pre]


把装置放在面向北方的窗口,SD卡记录下来了本地区BPC码接收到的时间。如果有校时需要的话,就可以在此时间段开启针对ds1307等RTC模块的写程序完成对时。


(完)





一次完美的接收到的bpc码.rar

1.07 KB, 下载次数: 15

发表于 2022-5-5 18:15 | 显示全部楼层
本帖最后由 fanqizc 于 2022-5-5 18:24 编辑

你好,我是小白。请教你一下,程序的最后部分
int CharToInt (char a) {
  if (a == '0') return 0;
  if (a == '1') return 1;
  if (a == '2') return 2;
  if (a == '3') return 3;
}

int PM(char k) {
  if (k == '0') return 0;
  if (k == '1') return 0;
  if (k == '2') return 1;
  if (k == '3') return 1;
}

int Even_Parity(char m) {
  if (m == '0') return 0;
  if (m == '1') return 1;
  if (m == '2') return 0;
  if (m == '3') return 1;
}

起到什么作用。因为 ,编译后显示这个
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino: In function 'int CharToInt(char)':
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino:179:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino: In function 'int PM(char)':
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino:186:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino: In function 'int Even_Parity(char)':
C:\Users\pinghe\Documents\Arduino\BPC2\BPC2.ino:193:1: warning: control reaches end of non-void function [-Wreturn-type]
}

谢谢了

 楼主| 发表于 2022-5-6 00:31 | 显示全部楼层
fanqizc 发表于 2022-5-5 18:15
你好,我是小白。请教你一下,程序的最后部分
int CharToInt (char a) {
  if (a == '0') return 0;

int CharToInt (char a) 对应第(4)点。
int PM(char k) 对应第(5)点前半部标识上午和下午。
int Even_Parity(char m)对应第(5)点后半部表示偶校验。

程序复制黏贴要正确,我测试了一下一切正常没有报错。
发表于 2022-5-6 10:11 | 显示全部楼层
topdog 发表于 2022-5-6 00:31
int CharToInt (char a) 对应第(4)点。
int PM(char k) 对应第(5)点前半部标识上午和下午。
int Even ...

复制的没问题啊。我用的是arduino ide 1.8.12进行编译的
发表于 2022-5-6 10:12 | 显示全部楼层
topdog 发表于 2022-5-6 00:31
int CharToInt (char a) 对应第(4)点。
int PM(char k) 对应第(5)点前半部标识上午和下午。
int Even ...

但是可以上传到arduino。
 楼主| 发表于 2022-5-6 21:10 | 显示全部楼层
fanqizc 发表于 2022-5-6 10:12
但是可以上传到arduino。

那就是好的。
 楼主| 发表于 2022-5-6 21:10 | 显示全部楼层
fanqizc 发表于 2022-5-6 10:11
复制的没问题啊。我用的是arduino ide 1.8.12进行编译的

这三个函数理解。
发表于 2022-5-8 18:16 | 显示全部楼层
topdog 发表于 2022-5-6 21:10
这三个函数理解。

试了一下,接收不到信号,干扰太严重了。
发表于 2022-5-8 18:17 | 显示全部楼层
fanqizc 发表于 2022-5-8 18:16
试了一下,接收不到信号,干扰太严重了。

使用手机APP也不是很理想。
发表于 2022-5-8 18:18 | 显示全部楼层
topdog 发表于 2022-5-6 21:10
这三个函数理解。

准备做个时钟,这信号。只能放弃了。打算改用ESP8266。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-27 15:54 , Processed in 0.114670 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表