|
本帖最后由 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模块的写程序完成对时。
(完)
|
|